【问题标题】:XSLT: find position of node in a given nodesetXSLT:在给定节点集中查找节点的位置
【发布时间】: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 表达式计算出想要的数字...不需要使用 &lt;xsl:number&gt;,这有时会非常低效。

标签: xslt xslt-1.0


【解决方案1】:

使用&lt;xsl:number count="*" level="any"/&gt;:

https://xsltfiddle.liberty-development.net/gVhEaiH

【讨论】:

  • 这行得通!非常感谢你的例子!我并不完全知道如何使用xsl:number。这是一个完美的例子!
【解决方案2】:

或者干脆

count(ancestor::*) + count(preceding::*) +1

这是一个完整的转换(只有 10 行):

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

  <xsl:template match="*">
    <xsl:copy>
      <xsl:attribute name="position" select="count(ancestor::*) + count(preceding::*) +1"/>
      <xsl:apply-templates/>
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>

应用于提供的 XML 文档时

<root>
    <ELEM2>
        <ELEM3/>
    </ELEM2>
    <ELEM2>
        <ELEM3/>
    </ELEM2>
    <ELEM2>
        <ELEM3/>
    </ELEM2>
</root>

产生想要的正确结果

<root position="1">
      <ELEM2 position="2">
            <ELEM3 position="3"/>
      </ELEM2>
      <ELEM2 position="4">
            <ELEM3 position="5"/>
      </ELEM2>
      <ELEM2 position="6">
            <ELEM3 position="7"/>
      </ELEM2>
</root>

【讨论】:

    猜你喜欢
    • 2011-02-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多