我知道下面的问题对初学者来说有点难,但我需要你的帮助来理解一个基本的概念。
我想首先说的是,我做了3年的XSLT程序员,但是在这里我学到了一些新的和相当基本的东西,我从来都不知道(在我的工作中,任何人都学习如何单独编程,没有涉及到课程)。
我的问题是:xsl:sequence
的用途是什么?
我一直使用xsl:copy-of
以原样复制节点,xsl:apply-templates
以修改我选择的节点和value-of
用于简单文本。
我从来没有必要使用xsl:sequence
。如果有人能给我一个xsl:sequence
使用的例子,我将不胜感激,如果没有我上面提到的那些,我将首选或无法实现。
还有一件事,我当然读过xsl:sequence
的定义,但我不能推断它是如何有用的。
<xsl:sequence>
对原子值(或原子值序列)的操作与<xsl:copy-of>
相同,都只是返回其输入的副本。当您考虑节点时,差异就出现了。
如果$n是单个元素节点,例如由
定义<xsl:variable name="n" select="/html"/>
然后<xsl:copy-of select="$n"/>
返回节点的副本,它具有相同的名称和子结构,但它是一个具有新标识(没有父)的新节点。
<xsl:sequence select="$n"/>
返回节点$n,返回的节点与$n具有相同的父节点,并且通过is
Xpath运算符与$n相等。
在传统的(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:sequence
和xsl:copy-of
的结果是完全不同的。
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>
这里的关键是它返回对原始节点的引用,它不生成新的副本。
为了返回某种类型的值,您使用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
值,依此类推。当然,您也可以返回序列,例如<xsl:sequence select="1, 2, 3"/>
.
在我看来,在这些情况下,您不会想要创建文本节点甚至元素节点,因为它效率低下。
所以这是我的看法,对于XSLT和XPath 2.0的新的基于模式的类型系统,需要一种方法来返回或传递这些类型的值,并且需要一个新的结构。
[edit]Michael Kay在他关于xsl:sequence
的"XSLT 2.0和XPath 2.0程序员参考"中说:"XSLT 2.0中引入的这个看似无害的指令对XSLT语言的功能有深远的影响,因为它意味着XSLT指令和序列构造函数(以及函数和模板)能够返回XPath数据模型允许的任何值。没有它,XSLT指令只能用于在结果树中创建新节点,但是有了它,它们还可以返回原子值和对现有节点的引用。
另一种用法是仅在有子标记时创建标记。需要一个示例:
<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()是"是否有子元素?"的习语,引擎可以对其进行优化。