XSLT xsl:序列。到底有啥好处呢..?
Posted
技术标签:
【中文标题】XSLT xsl:序列。到底有啥好处呢..?【英文标题】:XSLT xsl:sequence. What is it good for..?XSLT xsl:序列。到底有什么好处呢..? 【发布时间】:2012-12-30 23:05:16 【问题描述】:我知道下面的问题有点初学者,但我需要你的帮助来理解一个基本概念。
首先我想说的是,我是一名 3 年的 XSLT 程序员,但是我在这里学到了一些新的和非常基础的东西,我从来不知道(在我的工作中,任何人都学习如何单独编程,那里不涉及课程)。
我的问题是:
xsl:sequence
有什么用?
我一直使用xsl:copy-of
来复制节点,xsl:apply-templates
用于修改我选择的节点,value-of
用于简单文本。
我从来没有必要使用xsl:sequence
。如果有人可以向我展示xsl:sequence
用法的示例,我将不胜感激,如果没有我上面提到的那些,这是首选或无法实现的。
还有一件事,我当然读过xsl:sequence
的定义,但我无法推断它有什么用处。
【问题讨论】:
【参考方案1】:<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 运算符等于它。
在传统(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
的结果完全不同。
【讨论】:
【参考方案2】: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 的性能更好?那么,copy-of 相对于 xsl:sequence 的优势在哪里? 我怀疑很少有你真正需要 xsl:copy-of 的情况。除非您使用validation=strict 或copy-namespaces=no,否则可能。在大多数情况下,使用 xsl:copy-of 代替 xsl:sequence 是无害的,但在某些情况下,它肯定会导致不必要且昂贵的复制,除非优化器足够聪明以防止它发生。但是在上面的例子中,这两者是不等价的:$x/.. 如果你进行复制,则不返回任何内容,但如果你使用 xsl:sequence 选择它们,则返回原始节点的父节点。 啊,我明白了。非常感谢!【参考方案3】:要返回某个类型的值,您可以使用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 指令只能用于在结果树中创建新节点,但有了它,它们也可以返回原子值和对现有节点的引用。”。
【讨论】:
【参考方案4】:另一个用途是仅当标签有子时才创建标签。需要一个例子:
<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() 是“有子元素吗?”的成语,引擎可以对其进行优化。这样做,您可以减轻每个人的生活。
【讨论】:
以上是关于XSLT xsl:序列。到底有啥好处呢..?的主要内容,如果未能解决你的问题,请参考以下文章