【问题标题】:Variable scope in XSLTXSLT 中的变量范围
【发布时间】:2010-02-05 01:46:46
【问题描述】:

我在试图找出 xslt 上的 var 作用域时遇到问题。我真正想做的是忽略具有重复“旅游代码”的“旅行”标签。

示例 XML:

<trip>
 <tourcode>X1</tourcode>
 <result>Budapest</result>
</trip>
<trip>
 <tourcode>X1</tourcode>
 <result>Budapest</result>
</trip>
<trip>
 <tourcode>X1</tourcode>
 <result>Budapest</result>
</trip>
<trip>
 <tourcode>Y1</tourcode>
 <result>london</result>
</trip>
<trip>
 <tourcode>Y1</tourcode>
 <result>london</result>
</trip>
<trip>
 <tourcode>Z1</tourcode>
 <result>Rome</result>
</trip>

XSLT 处理器:

<xsl:for-each select="trip">    
    <xsl:if test="not(tourcode = $temp)">
      <xsl:variable name="temp" select="tour"/>
      // Do Something (Print result!)
    </xsl:if>
</xsl:for-each>

所需的输出: 布达佩斯伦敦罗马

【问题讨论】:

  • 问题的标题应该是 .. 类似“使用 XSLT 从 xml 中删除重复节点”

标签: xslt variables scope


【解决方案1】:

不能更改 XSLT 中的变量。

您需要更多地将其视为functional programming 而不是过程性的,因为 XSLT 是一种函数式语言。想想这个伪代码中的变量范围:

variable temp = 5
call function other()
print temp

define function other()
  variable temp = 10
  print temp

您期望输出是什么?它应该是10 5,而不是10 10,因为函数other 内的temp 与函数外的temp 不是同一个变量。

在 XSLT 中也是如此。变量一旦创建就无法重新定义,因为它们是一次写入多次读取的变量。

如果你想让一个变量的值有条件地定义,你需要有条件地定义变量,像这样:

<xsl:variable name="temp">
  <xsl:choose>
    <xsl:when test="not(tourcode = 'a')">
      <xsl:text>b</xsl:text>
    </xsl:when>
    <xsl:otherwise>
      <xsl:text>a</xsl:text>
    </xsl:otherwise>
  </xsl:choose>
</xsl:variable>
<xsl:if test="$temp = 'b'">
  <!-- Do something -->
</xsl:if>

变量只定义在一个地方,但它的值是有条件的。现在temp的值已经设置好了,以后就不能重新定义了。在函数式编程中,变量更像是只读参数,因为它们可以设置但以后不能更改。您必须正确理解这一点才能在任何函数式编程语言中使用变量。

【讨论】:

  • 对不起,伙计,你的回答很好,但是我已经稍微改变了这个问题,让它更接近我所追求的。谢谢
  • @Mazzi:总是针对您想做的事情(输入->期望的输出)写问题,而不仅仅是针对您认为自己可以做到的如何。在这种情况下:您不想更改变量值,而是想从输入中生成一个唯一值列表。
  • 有人应该改变这个问题,所以这个答案再次适合。这比问题要好得多。无论如何,问题被高估了......
  • 抱歉各位更改问题。现在我得到了答案,你想让我把问题改成什么?
  • I have a larger number of variables and they all depend on the same two tests - 有没有办法只测试两次但将变量保持在范围内?
【解决方案2】:

期望的输出:布达佩斯伦敦罗马

您所追求的是按城市名称​​分组输出。在 XSLT 中有两种常用的方法。

其中一个是这样的:

<xsl:template match="/allTrips">
  <xsl:apply-templates select="trip" />
</xsl:template>

<xsl:template match="trip">
  <!-- test if there is any preceding <trip> with the same <result> -->
  <xsl:if test="not(preceding-sibling::trip[result = current()/result])">
    <!-- if there is not, output the current <result> -->
    <xsl:copy-of select="result" />
  </xsl:if>
</xsl:template>

另一个叫做 Muenchian grouping,@Rubens Farias 刚刚发布了一个答案,说明了如何做到这一点。

【讨论】:

  • 谢谢伙计,尽管在 4 个重复项中它仍然显示 2 个,但它让我更接近我的想法。
  • @Mazzi:是吗?当我用你的样品测试它时它没有。如果您发布实际使用的 XML 和 XSL,我相信我可以指出问题所在。
  • @Tomalak:xsl 和 xml 有点笨重,我尽量简化它们。不知道stackoverflow有没有发送消息功能?!所以我可以直接发给你。
  • @Mazzi:我已将您的 XSLT 的全新版本上传到 tinypaste.com/f3a23。随意提出后续问题,并享受解决问题的乐趣。 :-)
  • @Mazzi:该死的。我在&lt;xsl:sort&gt; 中犯了一个小错误。排序表达式不正确,但只有一点点。这很明显,我相信你很快就会找到它。 :)
【解决方案3】:

试试这个:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:key name="trip" match="trip" use="result" />

  <xsl:template match="/trips">

    <xsl:for-each select="trip[count(. | key('trip', result)[1]) = 1]">
      <xsl:if test="position() != 1">, </xsl:if>
      <xsl:value-of select="result"/>
    </xsl:for-each>

  </xsl:template>
</xsl:stylesheet>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-06-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-10
    • 2021-11-14
    相关资源
    最近更新 更多