除了重写大量的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。所以这些技巧可用
有什么想法吗?
答案 0 :(得分:28)
您可以使用
<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>
等同于:
<xsl:for-each select="/path/to/record">
<xsl:call-template name="SomeTemplate"/>
</xsl:for-each>
但后者在没有的情况下破坏了position()
的含义。调用模板不会更改上下文,因此.
将引用带有被调用模板的正确节点。