【发布时间】:2020-07-08 10:22:14
【问题描述】:
想象一个具有多个深度节点的 XML 树
<?xml version="1.0" encoding="UTF-8"?>
<root>
<ELEM2>
<ELEM3/>
</ELEM2>
<ELEM2>
<ELEM3/>
</ELEM2>
<ELEM2>
<ELEM3/>
</ELEM2>
</root>
我想知道每个元素在整个树中的唯一位置。
期望的输出:
<?xml version="1.0"?>
<root position="1"/>
<ELEM2 position="2"/>
<ELEM3 position="3"/>
<ELEM2 position="4"/>
<ELEM3 position="5"/>
<ELEM2 position="6"/>
<ELEM3 position="7"/>
所以,基本上,我想查看所有元素在列表中的位置,并使用该索引来查找它。
尝试 1:position(): 我尝试像这样使用 position():
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="*">
<xsl:copy>
<xsl:attribute name="position">
<xsl:value-of select="position()"/>
</xsl:attribute>
</xsl:copy>
<xsl:apply-templates select="node()"/>
</xsl:template>
</xsl:stylesheet>
这给了我重复的位置属性:
<?xml version="1.0"?>
<root position="1"/>
<ELEM2 position="2"/>
<ELEM3 position="2"/>
<ELEM2 position="4"/>
<ELEM3 position="2"/>
<ELEM2 position="6"/>
<ELEM3 position="2"/>
所以,我不能在当前节点集中使用position(),因为该位置仅限于树中的当前分支。
尝试 2:preceding:::
然后我看着像这样使用preceding:::
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="*">
<xsl:copy>
<xsl:attribute name="position">
<xsl:value-of select="count(preceding::*)"/>
</xsl:attribute>
</xsl:copy>
<xsl:apply-templates select="node()"/>
</xsl:template>
</xsl:stylesheet>
但不幸的是我得到了这个:
<?xml version="1.0"?>
<root position="0"/>
<ELEM2 position="0"/>
<ELEM3 position="0"/>
<ELEM2 position="2"/>
<ELEM3 position="2"/>
<ELEM2 position="4"/>
<ELEM3 position="4"/>
所以,preceding:::计算父兄弟的轴上的兄弟,直到根。
尝试 3:preceding-sibling:::
甚至不值得。这只会查看其他兄弟元素的位置,这意味着我将获得每个 ELEM3 元素的相同位置。
尝试 4:generate-id():
如果我们放宽@position 属性反映节点号的限制,这是一种稍微不同的方法。只要生成的值是唯一的,这在我的设置中并不重要。
这将生成唯一的@position 属性。不幸的是,id 只能保证在同一次运行中相同。这意味着我不能将它用于测试和我们的 CI/测试设置。
尝试 5:在给定列表中查找当前节点?
我正在考虑是否可以通过 XPATH 以某种方式提供元素列表,如下所示:* 或 ELEM2|ELEM3。现在,如果我可以获取 current() 节点并找到它在列表中的位置。
这可能吗?
限制:
- 我正在使用 XSLT 1/xsltproc
- 生成的@position 属性必须是唯一的
- 生成的@position 属性必须相对稳定,并且不会在运行或平台之间发生变化
【问题讨论】:
-
一个简单的 XPath 表达式计算出想要的数字...不需要使用
<xsl:number>,这有时会非常低效。