XSLT样式表用空配对标记替换自闭合标记

Car*_*ond 8 xslt

我正在使用XSLT处理我的ASP.Net web.config文件以插入一些额外的log4net配置.它由NANT标准任务应用<style>.在成功插入新内容的同时,它会将许多自动关闭标记转换为空配对标记.例如,部分web.config在此之前如下所示:

<?xml version="1.0"?>
<configuration xmlns="http://schemas.microsoft.com/.NetConfiguration/v2.0">
<configSections>
    <section name="log4net"
             type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"/>
</configSections>
<appSettings>
    <add key="SomeKey" value="SomeValue"/>
</appSettings>
Run Code Online (Sandbox Code Playgroud)

应用样式表后,<section><add>标签(以及所有其他标签)不再自动关闭:

<configuration xmlns="http://schemas.microsoft.com/.NetConfiguration/v2.0">
    <configSections>
        <section name="log4net"
         type="log4net.Config.Log4NetConfigurationSectionHandler, log4net">
        </section>
    </configSections>
    <appSettings>
        <add key="SomeKey" value="SomeValue">
        </add>
    </appSettings>
Run Code Online (Sandbox Code Playgroud)

我的样式表看起来像这样:

<?xml version="1.0" encoding="utf-8"?>
<!-- This stylesheet is applied to web.config files to insert log4net appender
filters that will prevent logging messages resulting from pages requested by
AIS monitoring systems. -->
<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:msxsl="urn:schemas-microsoft-com:xslt" 
    exclude-result-prefixes="msxsl">
    <xsl:output method="xml" indent="yes" />
    <xsl:preserve-space elements="configuration"/>
    <!-- Copy input to output, most of the time -->
    <xsl:template match="@* | node()">
        <xsl:copy>
            <xsl:apply-templates select="@* | node()" />
        </xsl:copy>
    </xsl:template>

    <!-- Within log4net <appender> elements, insert standard filters to
    exclude logging traffic resulting from AIS monitoring.  Any existing
    filters are preserved. -->
    <xsl:template match="/configuration/log4net/appender">
        <xsl:copy>
            <xsl:apply-templates select="@* | node()" />
            <xsl:comment
            > Filters inserted by build server during deployment </xsl:comment>
            <filter name="AIS monitor"
             type="log4net.Filter.PropertyFilter">
                <regexToMatch value="^35\.8\.113\.[0-9]+$"/>
                <key value="ClientIP"/>
                <acceptOnMatch value="false"/>
            </filter>
            <filter name="AIS load balancer"
             type="log4net.Filter.PropertyFilter">
                <regexToMatch value="^10\.160\.0\.[0-9]+$" />
                <key value="ClientIP"/>
                <acceptOnMatch value="false"/>
            </filter>
            <filter name="localhost" type="log4net.Filter.PropertyFilter">
                <stringToMatch value="127.0.0.1"/>
                <key value="ClientIP"/>
                <acceptOnMatch value="false"/>
            </filter>
        </xsl:copy>
    </xsl:template>

</xsl:stylesheet>
Run Code Online (Sandbox Code Playgroud)

在使用NANT处理样式表之前,我使用MSBuild扩展包任务尝试了MSBuild XmlTask.它保留了自动关闭标签,但会丢失大部分换行符,这使得文件难以理解(尽管其他方面是正确的).使用NANT非常适合我的构建过程,所以如果可以,我更愿意使用它.

看起来我应该能够指定我想在样式表中保留自闭标签,但我无法弄清楚如何.

jas*_*sso 11

自闭标签<empty/>和带有开始和结束标签的空元素<empty></empty>在语义上是相同的.因此,XSLT处理器可以输出最佳效果.

您可以尝试通过在元素中添加空内容来欺骗处理器.在这种情况下,可以通过修改身份模板来完成.

<!-- Define a dummy variable with empty content -->
<xsl:variable name="empty" select="''"/>

<!-- Copy input to output, most of the time -->
<xsl:template match="@* | node()">
    <xsl:copy>
        <xsl:apply-templates select="@* | node()" />
<!-- Insert empty content into copied element -->
        <xsl:value-of select="$empty"/>
    </xsl:copy>
</xsl:template>
Run Code Online (Sandbox Code Playgroud)

或者您可以通过保留原始标识模板并添加以下内容来将此限制为空元素:

<!-- Identity template for empty elements -->
<xsl:template match="*[not(node())]">
    <xsl:copy>
        <xsl:apply-templates select="@* | node()" />
        <xsl:value-of select="$empty"/>
    </xsl:copy>
</xsl:template>
Run Code Online (Sandbox Code Playgroud)

功能取决于XSLT处理器.

注意:正确的XML工具应该在自闭标签或带有开始和结束标记的空元素之间没有区别.因此,如果这种语法差异确实导致您出现问题,则应重新考虑使用哪些方法或工具或如何使用它们.


更新

废话.不知怎的,我继续以你的意思相反的方式阅读你的问题(可能意味着我该睡觉的时间).所以...上面的代码试图将自闭合标签转换为空对,而你想要相反<tag></tag>- > <tag/>.抱歉不匹配,让我再试一次.

在评论中你说:

在它出现在新行之前并缩进到与开始标记相同的位置.

从XML数据模型的角度来看,这意味着该节点仅具有空白空间作为子内容.尝试避免复制这些文本节点的一种方法是为它们提供空模板.但是,这可能会导致混合内容出现问题.

<xsl:template match="text()[normalize-space() = '']"/>
Run Code Online (Sandbox Code Playgroud)

另一种可能的解决方案是,当我们面对空元素时,我们创建一个具有相同名称的新元素,而不是复制它.

<xsl:template match="*[not(comment() | processing-instruction() | *)][normalize-space(text()) = '']">
    <xsl:element name="{name()}" namespace="{namespace-uri()}">
        <xsl:for-each select="@* | namespace::*">
            <xsl:copy/>
        </xsl:for-each>
    </xsl:element>
</xsl:template>
Run Code Online (Sandbox Code Playgroud)

此模板还在空元素中复制(未使用的)命名空间定义,这实际上似乎是非常不必要的.<xsl:for-each>使用而<xsl:apply-templates>不仅仅是因为template match不允许使用namespace轴.<xsl:apply-templates select="@*"/>如果您不想保留额外的命名空间定义,也可以使用.

但最终,AFAIK所有这些只是处理器特定的解决方法.当XSLT 1.0处理器创建一个空元素时,可以自由选择是使用自闭标签还是空对.如果我错了,请有人纠正我.


小智 5

只需在元素中添加注释,它就不会自我关闭.

<xsl:comment> </ xsl:comment>