XSLT xsl:sequence. What is it good for..?

后端 未结 4 609
北恋
北恋 2020-12-24 05:28

I know the following question is a little bit of beginners but I need your help to understand a basic concept.

I would like to say first that I\'m a XSLT programmer

相关标签:
4条回答
  • 2020-12-24 06:01

    <xsl:sequence> on an atomic value (or sequence of atomic values) is the same as <xsl:copy-of> both just return a copy of their input. The difference comes when you consider nodes.

    If $n is a single element node, eg as defined by something like

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

    Then

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

    Returns a copy of the node, it has the same name and child structure but it is a new node with a new identity (and no parent).

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

    Returns the node $n, The node returned has the same parent as $n and is equal to it by the is Xpath operator.

    The difference is almost entirely masked in traditional (XSLT 1 style) template usage as you never get access to the result of either operation the result of the constructor is implicitly copied to the output tree so the fact that xsl:sequence doesn't make a copy is masked.

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

    is the same as

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

    Both make a new element node and copy the result of the content as children of the new node x.

    However the difference is quickly seen if you use functions.

    <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>
    

    Produces

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

    Here the results of xsl:sequence and xsl:copy-of are radically different.

    0 讨论(0)
  • 2020-12-24 06:15

    Another use is to create a tag only if it has a child. An example is required :

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

    Somewhere in your 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>
    

    You may see the demo here : http://xsltransform.net/eiZQaFz

    It is way better than testing each tag like this :

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

    Because you would end up editing it in two places. Also the processing speed would depend on which tags are in your imput. If it is the last one from your test, the engine will test the presence of everyone before. As $foo/node() is an idioms for "is there a child element ?", the engine can optimize it. Doing so, you ease the life of everyone.

    0 讨论(0)
  • 2020-12-24 06:16

    The most common use case for xsl:sequence is to return a result from xsl:function.

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

    But it can also be handy in other contexts, for example

    <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>
    

    The key thing here is that it returns references to the original nodes, it doesn't make new copies.

    0 讨论(0)
  • 2020-12-24 06:22

    Well to return a value of a certain type you use xsl:sequence as xsl:value-of despite its name always creates a text node (since XSLT 1.0). So in a function body you use

      <xsl:sequence select="42"/>
    

    to return an xs:integer value, you would use

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

    to return an xs:string value and

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

    to return an xs:date value and so on. Of course you can also return sequences with e.g. <xsl:sequence select="1, 2, 3"/>.

    You wouldn't want to create a text node or even an element node in these cases in my view as it is inefficient.

    So that is my take, with the new schema based type system of XSLT and XPath 2.0 a way is needed to return or pass around values of these types and a new construct was needed.

    [edit]Michael Kay says in his "XSLT 2.0 and XPath 2.0 programmer's reference" about xsl:sequence: "This innocent looking instruction introduced in XSLT 2.0 has far reaching effects on the capability of the XSLT language, because it means that XSLT instructions and sequence constructors (and hence functions and templates) become capable of returning any value allowed by the XPath data model. Without it, XSLT instructions could only be used to create new nodes in a result tree, but with it, they can also return atomic values and references to existing nodes.".

    0 讨论(0)
提交回复
热议问题