xslt 遍历整个列表或直到匹配

xslt iterate through a whole list or until match

我需要遍历对象列表并在 xslt 中比较它们。如果找到匹配项,我需要停止处理文档。如果我到达列表的末尾但没有找到匹配项,那么我需要处理该文档。 问题是 xslt 变量一旦声明就无法更改。在其他常用语言中,这将是一个带有 true/false 变量的简单 For 循环。

     <!--I need to iterate through this list-->
        <xsl:variable name="exclude">
          <exclude block="999" />
          <exclude block="111" />
        </xsl:variable>

        <xsl:template match="@*|node()">
          <xsl:copy>
            <xsl:apply-templates select="@*|node()" />
          </xsl:copy>
        </xsl:template>

<!-- Here I iterate through the docs, but I don't iterate though the objects in the list.The main problem is I don't know how to search the list and make a decision at the end or when I encounter a match. This code only works on the first object "999" -->
        <xsl:template match="/">
          <xsl:if test="not(contains($url, exsl:node-set($exclude)/exclude/@block))">
            <xsl:copy-of select="." />
          </xsl:if>
        </xsl:template>

如果您使用的是 XSLT 2.0,则可以在模板或函数中使用尾端递归,最好使用主要的 choose-when-otherwise 构造(when 语句提供终止机制,否则准备下一个循环并调用自身)。

如果您使用的是 3.0,请尝试 xsl:iterate

你没有显示输入文档,也没有显示你如何设置变量以及你到底想检查什么,但我认为你不需要任何迭代,如果你想检查 none block 属性值包含在您的变量中 then

<xsl:if test="not(exsl:node-set($exclude)/exclude/@block[contains($url, .)])">

足以做到这一点。

我在

放了三个样本
  1. http://xsltfiddle.liberty-development.net/3Nqn5Y9
  2. http://xsltfiddle.liberty-development.net/3Nqn5Y9/1
  3. http://xsltfiddle.liberty-development.net/3Nqn5Y9/2

前两个匹配(参数 url 分别为 <xsl:param name="url">file://111</xsl:param> <xsl:param name="url">file://999</xsl:param>)并且没有创建输出,最后一个不匹配(<xsl:param name="url">file://888</xsl:param>)并且输出已创建。

因此,至少在具有如图所示的变量或参数的正常 XSLT 1 设置的上下文中,该方法有效。

这里有很多可能的策略。

通常,可以编写一个路径表达式,其中包含 select 您要处理的项目,并在 xsl:for-each 的 select 属性中使用它。

这种方法不起作用的情况是一个项目的处理(或终止决定)取决于为先前项目计算的信息(并且每次重复计算的成本太高)。

这种情况下的经典解决方案是使用头尾递归:编写一个模板或函数,将项目列表作为参数。 template/function 必须 (a) 决定是否继续处理(通常在输入列表为空时退出,但也可能有其他终止条件),(b) 处理第一个 ("head") 项,并且(c) 递归地调用自己来处理列表的其余部分("tail")。

在 XSLT 3.0 中,有一个名为 xsl:iterate 的便捷指令,许多人发现它更易于使用该递归,因为它看起来更像传统的过程编程。它就像 xsl:for-each 除了执行是严格按顺序执行的,并且在处理完一个项目后,您可以设置在处理下一个项目时可用的参数;并且有一个 xsl:break 提前退出的指令。

最后,在 3.0 中,您可以使用更高级别的 fold-left 或 fold-right 函数的函数式编程方法。除非您是从其他函数式编程语言转向 XSLT,否则这可能不是您的第一选择。此外,它始终处理整个输入序列:没有提前退出的选项。