【问题标题】:Find the position of an element within its parent with XSLT / XPath使用 XSLT / XPath 查找元素在其父元素中的位置
【发布时间】:2011-07-20 09:42:25
【问题描述】:

除了重写大量 XSLT 代码(我不会这样做)之外,当上下文被任意设置为其他内容时,有没有办法找到元素在其父元素中的位置?这是一个例子:

<!-- Here are my records-->
<xsl:for-each select="/path/to/record">
  <xsl:variable name="record" select="."/>

  <!-- At this point, I could use position() -->
  <!-- Set the context to the current record -->
  <xsl:for-each select="$record">

    <!-- At this point, position() is meaningless because it's always 1 -->
    <xsl:call-template name="SomeTemplate"/>
  </xsl:for-each>
</xsl:for-each>


<!-- This template expects the current context being set to a record -->
<xsl:template name="SomeTemplate">

  <!-- it does stuff with the record's fields -->
  <xsl:value-of select="SomeRecordField"/>

  <!-- How to access the record's position in /path/to or in any other path? -->
</xsl:template>

注意:这是一个简化的示例。我有几个限制因素使我无法实现明显的解决方案,例如将新参数传递给SomeTemplate 等。我真的只能修改SomeTemplate 的内部结构。

注意:我正在使用带有EXSLT 的 Xalan 2.7.1。所以这些技巧是可用的

有什么想法吗?

【问题讨论】:

    标签: xslt xpath position exslt


    【解决方案1】:

    你可以使用

    <xsl:value-of select="count(preceding-sibling::record)" />
    

    甚至,一般来说,

    <xsl:value-of select="count(preceding-sibling::*[name() = name(current())])" />
    

    当然,如果您处理不统一的节点列表,则此方法将不起作用,即:

    <xsl:apply-templates select="here/foo|/somewhere/else/bar" />
    

    在这种情况下,位置信息会丢失,除非您将其存储在变量中并将其传递给被调用的模板:

    <xsl:variable name="pos" select="position()" />
    <xsl:for-each select="$record">
      <xsl:call-template name="SomeTemplate">
        <xsl:with-param name="pos" select="$pos" />
      </xsl:call-template>
    </xsl:for-each>
    

    但显然这意味着需要重写一些代码,我知道你想避免这种情况。


    最终提示:position() 告诉你节点在其父节点中的位置。它告诉您当前节点的位置相对于您现在正在处理的节点列表

    如果您只处理(即“将模板应用于”或“循环”)一个父级中的节点,这恰好是同一件事。如果你不这样做,那就不是。

    最后提示 #2:这个

    <xsl:for-each select="/path/to/record">
      <xsl:variable name="record" select="."/>
      <xsl:for-each select="$record">
        <xsl:call-template name="SomeTemplate"/>
      </xsl:for-each>
    </xsl:for-each>
    

    is 等价于:

    <xsl:for-each select="/path/to/record">
      <xsl:call-template name="SomeTemplate"/>
    </xsl:for-each>
    

    但后者的工作原理不会破坏position() 的含义。调用模板不会改变上下文,所以. 引用被调用模板的正确节点。

    【讨论】:

    • 你就是那个男人!我将您的建议修改为 1 + count(preceding-sibling::*),效果非常好!
    • 关于您的更新:在现实世界的示例中,记录在建模表时始终是统一的(尽管并不总是称为record)。所以没有两个“不兼容”的 XPath 节点集的联合运算符。由于实际代码的复杂性,可变解决方案不起作用
    • 感谢您提供有关 position() 的其他提示。因为我总是循环遍历统一元素,所以在我的例子中,循环位置确实与其父元素中的元素索引一致。
    • ;-)... 您现在可以停止添加提示。这个例子真的很简单,可以解释这个问题。现实世界的代码过于复杂,无法放入 Stack Overflow 问题
    • @Lukas:好的,没有更多提示了。 ;-) 不过,我更多的是考虑“下一个看到这个问题的人”。
    猜你喜欢
    • 2020-04-25
    • 2018-07-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-15
    • 2017-08-20
    • 1970-01-01
    • 2021-05-07
    相关资源
    最近更新 更多