嵌套元素模板的 XSL 顺序
XSL order of templates for nested elements
我有一个 XML 文件,如下所示:
<text>
<a>foo1</a>
<a><b>foo2</b></a>
</text>
我有一个 XSL 文件,旨在使用模板 1 和 2 以不同方式处理 <a>
和 <a><b>
:
<?xml version="1.0" encoding="utf-8"?>
<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:template match="text">
<xsl:copy>
<xsl:apply-templates select="node()"/>
</xsl:copy>
</xsl:template>
<!-- t1 -->
<xsl:template match="a">
<xsl:element name="keep">
<xsl:value-of select="."/>
</xsl:element>
</xsl:template>
<!-- t2 -->
<xsl:template match="a/b" />
</xsl:stylesheet>
我预计这会产生:
<text>
<keep>foo1</keep>
</text>
因为 t2 应该匹配并且 'ignore' <a><b>foo2</a></b>
我认为它会优先于 t1(t1 和 t2 都匹配 <a><b>
但 t2 只是在 XSL 的后面) .但实际上输出是:
<text>
<keep>foo1</keep>
<keep>foo2</keep>
</text>
事实上,如果我把 t2 去掉,输出是一样的,很明显它甚至不匹配 <a><b>
。我一定是遗漏了什么:有人能帮忙吗?
你要找的是
<xsl:template match="a[b]" />
一个匹配 a
元素的模板,如果它们有一个名为 b
的子元素。
模板匹配如
<xsl:template match="a/b" />
不匹配 a
元素,它匹配以 a
元素作为父元素的 b
元素。但是在您的原始样式表中,永远不会提示 XSLT 处理器为 b
元素找到匹配的模板,这就是永远不会执行此模板 (none) 中包含的代码的原因。
进行此更改后,输出为
<?xml version="1.0" encoding="UTF-8"?>
<text>
<keep>foo1</keep>
</text>
如您所见,几乎您预期的输出。对于您的 XSLT 处理器 MSXSL,空行可能甚至不存在,因为 MSXSL 去除了仅包含空白节点的树。但要让您的样式表在任何处理器上产生一致的结果,以下信息仍然有用。
要删除输出中的空行,请添加 xsl:strip-space
作为顶级元素。此外,如果事先知道元素名称,则省去了键入 xsl:element name=...
的麻烦。整个样式表:
<?xml version="1.0" encoding="utf-8"?>
<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:strip-space elements="*"/>
<xsl:template match="text">
<xsl:copy>
<xsl:apply-templates select="node()"/>
</xsl:copy>
</xsl:template>
<!-- t1 -->
<xsl:template match="a">
<keep>
<xsl:value-of select="."/>
</keep>
</xsl:template>
<!-- t2 -->
<xsl:template match="a[b]" />
</xsl:stylesheet>
我有一个 XML 文件,如下所示:
<text>
<a>foo1</a>
<a><b>foo2</b></a>
</text>
我有一个 XSL 文件,旨在使用模板 1 和 2 以不同方式处理 <a>
和 <a><b>
:
<?xml version="1.0" encoding="utf-8"?>
<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:template match="text">
<xsl:copy>
<xsl:apply-templates select="node()"/>
</xsl:copy>
</xsl:template>
<!-- t1 -->
<xsl:template match="a">
<xsl:element name="keep">
<xsl:value-of select="."/>
</xsl:element>
</xsl:template>
<!-- t2 -->
<xsl:template match="a/b" />
</xsl:stylesheet>
我预计这会产生:
<text>
<keep>foo1</keep>
</text>
因为 t2 应该匹配并且 'ignore' <a><b>foo2</a></b>
我认为它会优先于 t1(t1 和 t2 都匹配 <a><b>
但 t2 只是在 XSL 的后面) .但实际上输出是:
<text>
<keep>foo1</keep>
<keep>foo2</keep>
</text>
事实上,如果我把 t2 去掉,输出是一样的,很明显它甚至不匹配 <a><b>
。我一定是遗漏了什么:有人能帮忙吗?
你要找的是
<xsl:template match="a[b]" />
一个匹配 a
元素的模板,如果它们有一个名为 b
的子元素。
模板匹配如
<xsl:template match="a/b" />
不匹配 a
元素,它匹配以 a
元素作为父元素的 b
元素。但是在您的原始样式表中,永远不会提示 XSLT 处理器为 b
元素找到匹配的模板,这就是永远不会执行此模板 (none) 中包含的代码的原因。
进行此更改后,输出为
<?xml version="1.0" encoding="UTF-8"?>
<text>
<keep>foo1</keep>
</text>
如您所见,几乎您预期的输出。对于您的 XSLT 处理器 MSXSL,空行可能甚至不存在,因为 MSXSL 去除了仅包含空白节点的树。但要让您的样式表在任何处理器上产生一致的结果,以下信息仍然有用。
要删除输出中的空行,请添加 xsl:strip-space
作为顶级元素。此外,如果事先知道元素名称,则省去了键入 xsl:element name=...
的麻烦。整个样式表:
<?xml version="1.0" encoding="utf-8"?>
<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:strip-space elements="*"/>
<xsl:template match="text">
<xsl:copy>
<xsl:apply-templates select="node()"/>
</xsl:copy>
</xsl:template>
<!-- t1 -->
<xsl:template match="a">
<keep>
<xsl:value-of select="."/>
</keep>
</xsl:template>
<!-- t2 -->
<xsl:template match="a[b]" />
</xsl:stylesheet>