在 XSLT 中,如何从不同范围增加全局变量? [英] In XSLT how do I increment a global variable from a different scope?

查看:27
本文介绍了在 XSLT 中,如何从不同范围增加全局变量?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在处理一个 XML 文件,我想在其中记录节点数,以便在编写新节点时将其用作 ID.

I am processing an XML file where I want to keep count of the number of nodes, so that I can use it as an ID as I write new nodes.

目前我有一个名为counter"的全局变量.我可以在模板中访问它,但我还没有找到在模板中操作它的方法.

At the moment I have a global variable called 'counter'. I am able to access it within a template, but I haven't found a way of manipulating it within a template.

这是我的 XSLT 文件的精简版:

Here is a condensed version of my XSLT file:

<xsl:variable name="counter" select="1" as="xs:integer"/>

<xsl:template match="/"> 
   <xsl:for-each select="section">
      <xsl:call-template name="section"></xsl:call-template>
   </xsl:for-each>
</xsl:template>

<xsl:template name="section">

   <!-- Increment 'counter' here -->

   <span class="title" id="title-{$counter}"><xsl:value-of select="title"/></span>
</xsl:template>

有什么建议可以从这里开始吗?

Any suggestions how to go from here?

推荐答案

其他人已经解释了变量是如何不可变的——XSLT 中没有赋值语句(就像一般的纯函数式编程语言一样).

Others have already explained how variables are immutable--that there are no assignment statements in XSLT (as with purely functional programming languages in general).

对于目前提出的解决方案,我有一个替代方案.它避免了参数传递(这在 XSLT 中既冗长又丑陋——即使我承认这一点).

I have an alternative to the solutions that have been proposed so far. It avoids parameter passing (which is verbose and ugly in XSLT--even I'll admit that).

在 XPath 中,您可以简单地计算当前元素之前的

元素的数量:

In XPath, you can simply count the number of <section> elements that precede the current one:

<xsl:template name="section">
  <span class="title" id="title-{1 + count(preceding-sibling::section)}">
    <xsl:value-of select="title"/>
  </span>
</xsl:template>

(注意:空白代码格式不会出现在你的结果中,因为只有空白的文本节点会自动从样式表中剥离.所以不要觉得必须在同一行上放置说明.)

(Note: the whitespace code formatting won't appear in your result, as whitespace-only text nodes get stripped from the stylesheet automatically. So don't feel compelled to put instructions on the same line.)

这种方法的一大优点(与使用 position() 相反)是它只依赖于当前节点,而不依赖于当前节点列表.如果您以某种方式更改了处理方式(例如, 不仅处理部分,还处理其他一些元素),则 position() 的值将不再一定对应于文档中

元素的位置.另一方面,如果你像上面那样使用 count() ,那么它总是对应每个
元素的位置.这种方法减少了与代码其他部分的耦合,这通常是一件非常好的事情.

One big advantage of this approach (as opposed to using position()) is that it's only dependent on the current node, not on the current node list. If you changed your processing somehow (e.g., so <xsl:for-each> processed not only sections but some other element too), then the value of position() would no longer necessarily correspond to the position of <section> elements in your document. On the other hand, if you use count() as above, then it will always correspond to the position of each <section> element. This approach reduces coupling with other parts of your code, which is generally a very good thing.

count() 的替代方法是使用 指令.它的默认行为将在同一级别为所有同名元素编号,这恰好是您想要的:

An alternative to count() would be to use the <xsl:number> instruction. It's default behavior will number all like-named elements at the same level, which happens to be what you want:

<xsl:template name="section">
  <xsl:variable name="count">
    <xsl:number/>
  </xsl:variable>
  <span class="title" id="title-{$count}">
    <xsl:value-of select="title"/>
  </span>
</xsl:template>

这是对冗长的权衡(如果您仍然想使用属性值模板花括号,则需要额外的变量声明),但只是稍微如此,因为它还大大简化了您的 XPath 表达式.

It's a trade-off in verbosity (requiring an additional variable declaration if you still want to use the attribute value template curly braces), but only slightly so, as it also drastically simplifies your XPath expression.

还有更多的改进空间.虽然我们已经移除了对当前节点列表的依赖,但我们仍然依赖于当前节点.这本身并不是一件坏事,但通过查看模板并不能立即清楚当前节点是什么.我们只知道模板名为section";要确定正在处理什么,我们必须查看代码中的其他地方.但即使如此也不一定如此.

There's yet more room for improvement. While we've removed dependency on the current node list, we still are dependent on the current node. That, in and of itself, is not a bad thing, but it's not immediately clear from looking at the template what the current node is. All we know is that the template is named "section"; to know for sure what's being processed, we have to look elsewhere in our code. But even that doesn't have to be the case.

如果您觉得将 一起使用(如您的示例中所示),请执行步骤返回并找出如何使用 代替.

If you ever feel led to use <xsl:for-each> and <xsl:call-template> together (as in your example), step back and figure out how to use <xsl:apply-templates> instead.

<xsl:template match="/doc">
  <xsl:apply-templates select="section"/>
</xsl:template>

<xsl:template match="section">
  <xsl:variable name="count">
    <xsl:number/>
  </xsl:variable>
  <span class="title" id="title-{$count}">
    <xsl:value-of select="title"/>
  </span>
</xsl:template>

这种方法不仅不那么冗长( 替换了 <;xsl:call-template/>),但它也会立即清楚当前节点是什么.您所要做的就是查看 match 属性,您会立即知道您正在处理

元素和
元素. 元素就是您要计算的元素.

Not only is this approach less verbose (<xsl:apply-templates/> replaces both <xsl:for-each> and <xsl:call-template/>), but it also becomes immediately clear what the current node is. All you have to do is look at the match attribute, and you instantly know that you're processing a <section> element and that <section> elements are what you're counting.

有关模板规则(即具有match 属性的 元素)如何工作的简要说明,请参阅"XSLT 的工作原理".

For a succinct explanation of how template rules (i.e. <xsl:template> elements that have a match attribute) work, see "How XSLT Works".

这篇关于在 XSLT 中,如何从不同范围增加全局变量?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆