匹配 XSLT 上的属性而不是匹配整个元素
Match attribute on XSLT instead of matching the whole element
我想编写一个匹配属性而不是节点的 XSL 模板,
我认为有这样的东西:
<xsl:template match="@href | @conref | @conrefend">
<xsl:message select="."/>
</xsl:template>
将匹配这 3 个属性名称中的任何一个并打印以控制属性的值,因为范围是属性本身而不是节点。
但我的测试证明我错了,我只能匹配包含任何这些属性的节点,如下所示:
<xsl:template match="*[@href or @conref or @conrefend]">
<xsl:message select="if(not(@href))
then
if(not(@conref))
then @conrefend
else @conref
else @href"/>
</xsl:template>
这种方法的问题在于,如果碰巧存在一个节点具有多个属性,那么只有一个被处理,我需要处理所有这些属性。
关于第一种方法为何不起作用的任何想法?
编辑1:
完整的 xslt:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs"
version="2.0">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="@conref|@conrefend|@href">
<xsl:message select="."/>
</xsl:template>
</xsl:stylesheet>
测试XML:
<links>
<image conref="COPY-GUID/*+-862416}39-37CD-4CF7-A7AA-F09F4A763944" />
</links>
现在 XSLT 没有匹配任何东西。
您确实可以像第一个模板那样匹配模板中的属性。一定是其他地方出了问题...
看看恒等变换:
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
它可以很好地匹配您正在做的备选方案,其中一个备选方案适用于所有属性 (@*
)。
现在考虑 xsl:apply-templates
语句。请注意 @*
是如何显式调用的。你确定你给你的模板一个机会来应用属性吗?如果你打电话,xsl:apply-templates
像这样,例如:
<xsl:apply-templates select="*"/>
意识到只会选择元素,而不是属性。另请注意,node()
也不包含属性。
更新
没错。您的属性匹配模板永远没有机会应用。
添加上面的标识模板,或类似这样的内容:
<xsl:template match="/">
<xsl:apply-templates select="//@*"/>
</xsl:template>
让您的属性匹配模板有机会应用。
默认情况下,XSLT 不查找匹配属性节点的模板。将模板显式应用于输入中的所有属性 XML.
顺便问一下,您确定要使用 xsl:message
吗? xsl:message
的内容不包含在转换输出中。你是说 xsl:value-of
吗?另外,如果你输出的是文本,你应该声明输出方法是文本。
样式表
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="text"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/">
<xsl:apply-templates select="//@*"/>
</xsl:template>
<xsl:template match="@conref">
<xsl:value-of select="."/>
</xsl:template>
</xsl:stylesheet>
文本输出
COPY-GUID/*+-862416}39-37CD-4CF7-A7AA-F09F4A763944
实际上,在这种非常简单的情况下,第一个模板就足以获得相同的输出:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="text"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/">
<xsl:apply-templates select="//@*"/>
</xsl:template>
</xsl:stylesheet>
这是因为,一旦将模板应用于属性节点,就会有一个默认输出其字符串值的内置模板。
您当前方法的问题在于从未应用与 attribute/s 匹配的模板。它不被应用,因为内置模板规则仅匹配根节点和元素节点,并且它仅将模板应用于子节点 nodes。要将模板应用于属性,您必须自己明确地应用它。
我想编写一个匹配属性而不是节点的 XSL 模板,
我认为有这样的东西:
<xsl:template match="@href | @conref | @conrefend">
<xsl:message select="."/>
</xsl:template>
将匹配这 3 个属性名称中的任何一个并打印以控制属性的值,因为范围是属性本身而不是节点。
但我的测试证明我错了,我只能匹配包含任何这些属性的节点,如下所示:
<xsl:template match="*[@href or @conref or @conrefend]">
<xsl:message select="if(not(@href))
then
if(not(@conref))
then @conrefend
else @conref
else @href"/>
</xsl:template>
这种方法的问题在于,如果碰巧存在一个节点具有多个属性,那么只有一个被处理,我需要处理所有这些属性。
关于第一种方法为何不起作用的任何想法?
编辑1: 完整的 xslt:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs"
version="2.0">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="@conref|@conrefend|@href">
<xsl:message select="."/>
</xsl:template>
</xsl:stylesheet>
测试XML:
<links>
<image conref="COPY-GUID/*+-862416}39-37CD-4CF7-A7AA-F09F4A763944" />
</links>
现在 XSLT 没有匹配任何东西。
您确实可以像第一个模板那样匹配模板中的属性。一定是其他地方出了问题...
看看恒等变换:
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
它可以很好地匹配您正在做的备选方案,其中一个备选方案适用于所有属性 (@*
)。
现在考虑 xsl:apply-templates
语句。请注意 @*
是如何显式调用的。你确定你给你的模板一个机会来应用属性吗?如果你打电话,xsl:apply-templates
像这样,例如:
<xsl:apply-templates select="*"/>
意识到只会选择元素,而不是属性。另请注意,node()
也不包含属性。
更新
没错。您的属性匹配模板永远没有机会应用。
添加上面的标识模板,或类似这样的内容:
<xsl:template match="/">
<xsl:apply-templates select="//@*"/>
</xsl:template>
让您的属性匹配模板有机会应用。
默认情况下,XSLT 不查找匹配属性节点的模板。将模板显式应用于输入中的所有属性 XML.
顺便问一下,您确定要使用 xsl:message
吗? xsl:message
的内容不包含在转换输出中。你是说 xsl:value-of
吗?另外,如果你输出的是文本,你应该声明输出方法是文本。
样式表
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="text"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/">
<xsl:apply-templates select="//@*"/>
</xsl:template>
<xsl:template match="@conref">
<xsl:value-of select="."/>
</xsl:template>
</xsl:stylesheet>
文本输出
COPY-GUID/*+-862416}39-37CD-4CF7-A7AA-F09F4A763944
实际上,在这种非常简单的情况下,第一个模板就足以获得相同的输出:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="text"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/">
<xsl:apply-templates select="//@*"/>
</xsl:template>
</xsl:stylesheet>
这是因为,一旦将模板应用于属性节点,就会有一个默认输出其字符串值的内置模板。
您当前方法的问题在于从未应用与 attribute/s 匹配的模板。它不被应用,因为内置模板规则仅匹配根节点和元素节点,并且它仅将模板应用于子节点 nodes。要将模板应用于属性,您必须自己明确地应用它。