XSLT 样式表用空的成对标签替换自闭合标签 [英] XSLT stylesheet replaces self-closing tags with empty paired tags
问题描述
我正在使用 XSLT 处理我的 ASP.Net web.config 文件以插入一些额外的 log4net 配置.它由名为 的 NANT 标准任务应用.当它成功插入新内容时,它会将许多自闭合标签变成空的配对标签.例如,之前的部分 web.config 看起来像这样:
I'm using XSLT to process my ASP.Net web.config file to insert some extra log4net configuration. It's applied by the NANT standard task called <style>
. While it successfully inserts the new content, it turns the many self-closing tags into empty paired tags. For example, a partial web.config looks like this before:
<?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>
应用样式表后, 和
标签(以及所有其他标签)不再自闭合:
After applying the stylesheet, the <section>
and <add>
tags (and all other tags) are no longer self-closing:
<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>
我的样式表如下所示:
<?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>
在使用 NANT 处理样式表之前,我尝试了 MSBuild,使用 MSBuild 扩展包任务 XmlTask
.它保留了自关闭标签,但会丢失大部分换行符,这使得文件人类无法阅读(尽管在其他方面是正确的).使用 NANT 非常适合我的构建过程,因此如果可以,我更愿意使用它.
Before using NANT to process the stylesheet, I tried MSBuild, using the MSBuild Extension Pack task XmlTask
. It preserved the self-closing tags, but would lose most of the line breaks, which made the file human-unreadable (though otherwise correct). Using NANT fits in nicely with my build process, so I'd prefer to use it if I can.
似乎我应该能够指定我想在样式表中保留自关闭标签,但我不知道如何.
It seems like I should be able to specify that I want to keep self-closing tags in the stylesheet, but I can't figure out how.
推荐答案
自闭标签
和带开始和结束标签的空元素
在语义上是相同的.因此,XSLT 处理器可以输出它认为最好的任何一个.
Self-closing tags <empty/>
and empty element with start and end tags <empty></empty>
are semantically identical. Therefore XSLT processor can output whichever it sees best.
您可以尝试通过在元素中添加空内容来欺骗处理器.在这种情况下,可以通过修改身份模板来完成.
You could try to fool the processor by adding empty content in elements. In this case it can be done by modifying the identity template.
<!-- 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>
或者您可以通过保留原始身份模板并添加以下内容将其限制为空元素:
Or you could restrict this to empty elements by keeping the original identity template and adding this:
<!-- 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>
功能取决于 XSLT 处理器.
Functionality depends on the XSLT processor.
注意:一个合适的 XML 工具应该不会区分自闭合标签或带有开始和结束标签的空元素.因此,如果这种语法差异确实给您带来了问题,您应该重新考虑您使用了哪些方法或工具,或者如何使用它们.
Note: A proper XML tool should make no difference between self-closing tags or empty elements with start and end tag. So if this syntax difference is really causing you problems, you should reconsider what methods or tools you use or how you use them.
废话.不知何故,我继续以与您的意思相反的方式阅读您的问题(可能意味着我该小睡了).所以...上面的代码试图将自闭合标签转换为空对,而您想要相反的
--><代码><标签/>代码>.抱歉不匹配,让我再试一次.
Crap. Somehow I kept on reading your question the opposite way you meant (probably means it's time for me to take a nap). So... the code above tries to convert self-closing tags to empty pairs, whereas you wanted the opposite <tag></tag>
--> <tag/>
. Sorry for the mismatch, let me try again.
您在评论中说:
之前它位于新行并缩进到与开始标记相同的位置.
Before it was on a new line and indented to the same position as the opening tag.
从 XML 数据模型的角度来看,这意味着节点只有空白作为子内容.尝试避免复制这些文本节点的一种方法是为它们提供一个空模板.不过,这可能会导致混合内容出现问题.
From the viewpoint of the XML data model, this means that the node has only empty whitespace as child content. One way of trying to avoid copying these text nodes would be to provide an empty template for them. This could cause problems with mixed content, though.
<xsl:template match="text()[normalize-space() = '']"/>
另一种可能的解决方案是,当我们遇到空元素时,我们创建一个同名的新元素,而不是复制它.
Another possible solution would be that when we confront empty elements we create a new element with same name instead of copying it.
<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>
这个模板还在空元素中复制(未使用的)命名空间定义,这实际上似乎是不必要的.使用
而不是
只是因为 template match
不允许使用 namespace
轴.
也可以,如果您不想保留额外的命名空间定义.
This template also copies (unused) namespace definitions in empty elements, which actually seems quite unnecessary. <xsl:for-each>
is used instead of <xsl:apply-templates>
only because template match
doesn't allow the use of namespace
axis. <xsl:apply-templates select="@*"/>
works too, if you don't want to preserve the extra namespace definitions.
但最终,AFAIK 所有这些都只是特定于处理器的解决方法.当 XSLT 1.0 处理器创建空元素时,可以自由选择是使用自闭合标签还是空对.如果我错了,请有人纠正我.
But in the end, AFAIK all these are just processor specific workarounds. When XSLT 1.0 processor creates an empty element, can freely choose whether to use a self-closing tag or an empty pair. Someone please correct me if I'm wrong.
这篇关于XSLT 样式表用空的成对标签替换自闭合标签的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!