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

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

问题描述

我正在处理一个XML文件,我希望保持节点数量的计数,以便在编写新节点时将它用作ID。



目前我有一个叫做'counter'的全局变量。我可以在模板中访问它,但我还没有找到在模板中操作它的方法。



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

 < xsl:variable name =counterselect =1as =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>

<! - 在此增加'counter' - >

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

有什么建议如何离开这里?


我有迄今为止提出的解决方案的替代方案。它避免了参数传递(这在XSLT中是冗长和丑陋的 - 即使我承认这一点)。



在XPath中,您可以简单计数<$ c

 < xsl:template}中的$ c>< section> 元素: NAME = 部分 > 
< span class =titleid =title- {1 + count(preceding-sibling :: section)}>
< xsl:value-of select =title/>
< / span>
< / xsl:template>

(注意:空白代码格式不会出现在结果中,因为只有空格的文本节点这样可以自动从样式表中剥离出来,所以不要强迫将指令放在同一行上。)

这种方法的一大优点(与使用 position())是只依赖于当前节点,而不是当前节点列表。如果你以某种方式改变了你的处理过程(比如,< xsl:for-each> 不仅处理了部分,还处理了其他一些元素),那么 position()不再需要对应于文档中< section> 元素的位置。另一方面,如果您像上面一样使用 count(),那么它将始终对应于每个< section> 元素。这种方法减少了与代码的其他部分的耦合,这通常是非常好的。



count()的一个替代方法是使用< xsl:number> 指令。它的默认行为将为同一级别的所有相似命名的元素进行编号,这恰好就是您想要的:

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

这是一种折衷的折衷方案(如果您仍想使用属性,则需要额外的变量声明价值模板大括号),但只是稍微如此,因为它也极大地简化了XPath表达式。



还有更多的改进空间。虽然我们已经取消了对当前节点列表的依赖,但仍然依赖于当前节点。这本身并不是一件坏事,但从模板看当前节点是什么并不明显。我们所知道的是该模板被命名为部分;要确切知道正在处理的内容,我们必须查看我们的代码中的其他地方。但即便如此,也不一定是这种情况。



如果您觉得被引导为使用< xsl:for-each> < xsl:call-template> 在一起(如你的例子),退一步,并找出如何使用< ; xsl:apply-templates> 代替。

 < 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 =titleid =title - {$ count}>
< xsl:value-of select =title/>
< / span>
< / xsl:template>

这种方法不仅不那么冗长(< xsl:apply-templates /> 替换< xsl:for-each> < xsl:call-template /> ),但它也立即清楚当前节点是什么。您只需查看 match 属性即可知道您正在处理< section> 元素,并且< section> 元素就是您要计算的元素。



如何使用模板规则(即< xsl:template> 具有匹配属性的元素),请参阅XSLT如何运作


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.

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.

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?

解决方案

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

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).

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.)

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.

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>

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.

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>

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.

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天全站免登陆