<choices>
<sic />
<corr />
<reg />
<orig />
</choices>
<choice>
<corr>Red</corr>
<sic>Blue</sic>
<choice>
我想选择 <choice>
中的第一个元素其名称与 <choices>
中任何元素的名称匹配.
如果 name(node-set) 返回名称列表而不仅仅是第一个节点的名称,我可以使用
select="choice/*[name() = name(choices/*)][1]"
但事实并非如此(至少在 1.0 中不是),所以我将名称连接到一个字符串中并使用 contains():
<xsl:variable name="choices.str">
<xsl:for-each select="choices/*">
<xsl:text> </xsl:text><xsl:value-of select="concat(name(),' ')"/>
</xsl:for-each>
</xsl:variable>
<xsl:apply-templates select="choice/*[contains($choices.str,name())][1]"/>
并得到我想要的:
Red
,<corr>
的值
有没有更直接的方法?
最佳答案
我。使用此 XPath 2.0 一行:
/*/choice/*[name() = /*/choices/*/name()][1]
根据以下 XML 文档计算此 XPath 表达式时(提供的文档,但已更正为格式良好的 XML 文档):
<t>
<choices>
<sic />
<corr />
<reg />
<orig />
</choices>
<choice>
<corr>Red</corr>
<sic>Blue</sic>
</choice>
</t>
选择了正确的元素:
<corr>Red</corr>
二. XSLT 1.0(无键!):
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:variable name="vNames">
<xsl:for-each select="/*/choices/*">
<xsl:value-of select="concat(' ', name(), ' ')"/>
</xsl:for-each>
</xsl:variable>
<xsl:template match="/">
<xsl:copy-of select=
"/*/choice/*
[contains($vNames, concat(' ', name(), ' '))]
[1]"/>
</xsl:template>
</xsl:stylesheet>
当此转换应用于同一个 XML 文档(如上)时,将再次选择正确的元素(并复制到输出):
<corr>Red</corr>
三.使用按键:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="kChoiceByName" match="choice/*"
use="boolean(/*/choices/*[name()=name(current())])"/>
<xsl:template match="/">
<xsl:copy-of select="/*/choice/*[key('kChoiceByName', true())][1]"/>
</xsl:template>
</xsl:stylesheet>
当此转换应用于同一个 XML 文档(如上)时,会产生相同的正确结果:
<corr>Red</corr>
建议读者尝试了解这一切是如何“工作”的:)
关于xslt - 名称位于其他一些元素名称之中的第一个元素的 XPATH,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12850223/