40

我知道下面的问题有点初学者,但我需要你的帮助来理解一个基本概念。

首先我想说的是,我是一名 3 年的 XSLT 程序员,但是我在这里学到了一些新的和非常基础的东西,我从来不知道(在我的工作中,任何人都学习如何单独编程,没有课程涉及)。

我的问题是: 的用途是xsl:sequence什么?

我一直在使用xsl:copy-of以按原样复制节点,xsl:apply-templates以修改我选择value-of的节点和简单的文本。

我从来没有必要使用xsl:sequence. 如果有人可以向我展示一个xsl:sequence使用示例,如果没有我上面提到的那些是首选或无法实现的,我将不胜感激。

还有一件事,我xsl:sequence当然已经阅读了有关定义的内容,但我无法推断它是如何有用的。

4

4 回答 4

48

<xsl:sequence>在原子值(或原子值序列)上与两者相同,<xsl:copy-of>都只是返回其输入的副本。当您考虑节点时,差异就出现了。

如果 $n 是单个元素节点,例如由类似的定义

<xsl:variable name="n" select="/html"/>

然后

<xsl:copy-of select="$n"/>

返回节点的副本,它具有相同的名称和子结构,但它是具有标识(并且没有父节点)的新节点。

<xsl:sequence select="$n"/>

is返回节点 $n,返回的节点与 $n 具有相同的父节点,并且通过Xpath 运算符等于它。

传统(XSLT 1 风格)模板使用中几乎完全掩盖了差异,因为您永远无法访问任一操作的结果,构造函数的结果被隐式xsl:sequence复制到输出树,因此不进行复制的事实被掩盖了.

<xsl:template match="a">
   <x>
   <xsl:sequence select="$n"/>
   </x>
</xsl:template>

是相同的

<xsl:template match="a">
    <x>
    <xsl:copy-of select="$n"/>
    </x>
</xsl:template>

两者都创建一个新元素节点并将内容的结果复制x为新节点的子节点。

但是,如果您使用函数,很快就会发现差异。

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:f="data:,f">

    <xsl:variable name="s">
        <x>hello</x>
    </xsl:variable>

    <xsl:template name="main">
        ::
        :: <xsl:value-of select="$s/x is f:s($s/x)"/>
        :: <xsl:value-of select="$s/x is f:c($s/x)"/>
        ::
        :: <xsl:value-of select="count(f:s($s/x)/..)"/>
        :: <xsl:value-of select="count(f:c($s/x)/..)"/>
        ::
    </xsl:template>

    <xsl:function name="f:s">
        <xsl:param name="x"/>
        <xsl:sequence select="$x"/>
    </xsl:function>

    <xsl:function name="f:c">
        <xsl:param name="x"/>
        <xsl:copy-of select="$x"/>
    </xsl:function>

</xsl:stylesheet>

生产

$ saxon9 -it main seq.xsl
<?xml version="1.0" encoding="UTF-8"?>
::
:: true
:: false
::
:: 1
:: 0
::

这里 和 的结果xsl:sequencexsl:copy-of完全不同的。

于 2013-01-16T17:35:16.793 回答
30

xsl:sequence 最常见的用例是从 xsl:function 返回结果。

<xsl:function name="f:get-customers">
  <xsl:sequence select="$input-doc//customer"/>
</xsl:function>

但它在其他情况下也很方便,例如

<xsl:variable name="x" as="element()*">
  <xsl:choose>
    <xsl:when test="$something">
       <xsl:sequence select="//customer"/>
    </xsl:when>
    <xsl:otherwise>
       <xsl:sequence select="//supplier"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:variable>

这里的关键是它返回对原始节点的引用,它不会创建新副本。

于 2013-01-16T18:13:09.367 回答
8

好吧,返回您使用的某种类型的值,xsl:sequence因为xsl:value-of尽管它的名称总是创建一个文本节点(从 XSLT 1.0 开始)。所以在你使用的函数体中

  <xsl:sequence select="42"/>

要返回一个xs:integer值,您可以使用

<xsl:sequence select="'foo'"/>

返回一个xs:string值和

<xsl:sequence select="xs:date('2013-01-16')"/>

返回一个xs:date值等等。当然,您也可以使用 eg 返回序列<xsl:sequence select="1, 2, 3"/>

在我看来,在这些情况下,您不希望创建文本节点甚至元素节点,因为它效率低下。

这就是我的看法,对于 XSLT 和 XPath 2.0 的新的基于模式的类型系统,需要一种方法来返回或传递这些类型的值,并且需要一个新的构造。

[编辑]Michael Kay 在他的“XSLT 2.0 和 XPath 2.0 程序员参考”中说xsl:sequence:“XSLT 2.0 中引入的这条看似无辜的指令对 XSLT 语言的能力产生了深远的影响,因为它意味着 XSLT 指令和序列构造函数 (因此函数和模板)能够返回 XPath 数据模型允许的任何值。没有它,XSLT 指令只能用于在结果树中创建新节点,但有了它,它们也可以返回原子值和对现有节点。”。

于 2013-01-16T16:07:08.463 回答
0

另一个用途是仅当标签有子标签时才创建标签。需要一个例子:

<a>
    <b>node b</b>
    <c>node c</c>
</a>

在您的 XSLT 中的某处:

<xsl:variable name="foo">
    <xsl:if select="b"><d>Got a "b" node</d></xsl:if>
    <xsl:if select="c"><d>Got a "c" node</d></xsl:if>
</xsl:variable>
<xsl:if test="$foo/node()">
    <wrapper><xsl:sequence select="$foo"/></wrapper>
</xsl:if>

您可以在这里看到演示:http: //xsltransform.net/eiZQaFz

这比像这样测试每个标签要好得多:

<xsl:if test="a|b">...</xsl:if>

因为你最终会在两个地方编辑它。此外,处理速度将取决于您输入的标签。如果它是您测试的最后一个,引擎将测试之前每个人的存在。由于 $foo/node() 是“有子元素吗?”的成语,引擎可以对其进行优化。这样做,你可以减轻每个人的生活。

于 2015-04-17T09:07:38.807 回答