使用XSLT/XPath在其父级中查找元素的位置

Luk*_*der 13 xslt xpath position exslt

除了重写大量的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>
Run Code Online (Sandbox Code Playgroud)

注意:这是一个简化的示例.我有几个限制阻止我实现明显的解决方案,例如传递新的参数SomeTemplate,等等.我真的只能修改内部的SomeTemplate.

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

有任何想法吗?

Tom*_*lak 29

你可以用

<xsl:value-of select="count(preceding-sibling::record)" />
Run Code Online (Sandbox Code Playgroud)

甚至,一般来说,

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

当然,如果处理不一致的节点列表,这种方法将不起作用,即:

<xsl:apply-templates select="here/foo|/somewhere/else/bar" />
Run Code Online (Sandbox Code Playgroud)

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

<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>
Run Code Online (Sandbox Code Playgroud)

但显然这意味着一些代码重写,我意识到你想避免.


最后提示: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>
Run Code Online (Sandbox Code Playgroud)

是等于这个:

<xsl:for-each select="/path/to/record">
  <xsl:call-template name="SomeTemplate"/>
</xsl:for-each>
Run Code Online (Sandbox Code Playgroud)

但后者在破坏其含义的情况下起作用position().调用模板不会更改上下文,因此. 将使用调用的模板引用正确的节点.

  • @Lukas:好的,没有更多提示.;-)但我更想到"下一个看到这个问题的人". (5认同)
  • 你是男人!我把你的建议改编为'1 + count(前兄弟::*)`,它就像一个魅力! (2认同)