web-dev-qa-db-fra.com

XSLT xsl: séquence. À quoi ça sert..?

Je sais que la question suivante est un peu pour les débutants mais j'ai besoin de votre aide pour comprendre un concept de base.

Je voudrais d'abord dire que je suis un programmeur XSLT depuis 3 ans et pourtant il y a des choses nouvelles et assez basiques que j'apprends ici que je n'ai jamais connues (Dans mon travail, n'importe qui apprend à programmer seul, il n'y a pas de cours impliqué).

Ma question est: Quelle est l'utilisation de xsl:sequence?

J'utilise xsl:copy-of afin de copier le nœud tel quel, xsl:apply-templates afin de modifier les nœuds que j'ai sélectionnés et value-of pour un texte simple.

Je n'ai jamais eu la nécessité d'utiliser xsl:sequence. J'apprécierais que quelqu'un me montre un exemple de xsl:sequence une utilisation qui est préférée ou qui ne peut pas être obtenue sans celles que j'ai notées ci-dessus.

Encore une chose, j'ai lu sur le xsl:sequence définition bien sûr, mais je n'ai pas pu en déduire l'utilité.

33
user1942476

<xsl:sequence> sur une valeur atomique (ou une séquence de valeurs atomiques) est identique à <xsl:copy-of> les deux renvoient simplement une copie de leur entrée. La différence vient quand on considère les nœuds.

Si $ n est un nœud d'élément unique, par exemple tel que défini par quelque chose comme

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

Alors

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

Renvoie un copie du nœud, il a le même nom et la même structure enfant mais c'est un nouvea nœud avec une nouvelle identité (et aucun parent).

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

Renvoie le nœud $ n, Le nœud renvoyé a le même parent que $ n et lui est égal par l'opérateur is Xpath.

La différence est presque entièrement masquée dans l'utilisation de modèle traditionnelle (style XSLT 1) car vous n'obtenez jamais accès au résultat de l'une ou l'autre opération, le résultat du constructeur est implicitement copié dans l'arborescence de sortie, donc le fait que xsl:sequence ne fait pas de copie est masqué.

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

est le même que

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

Les deux créent un nouveau nœud d'élément et copie le résultat du contenu en tant qu'enfants du nouveau nœud x.

Cependant, la différence est rapidement visible si vous utilisez des fonctions.

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

Produit

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

Voici les résultats de xsl:sequence et xsl:copy-of sont radicalement différents.

40
David Carlisle

Le cas d'utilisation le plus courant pour xsl: sequence est de renvoyer un résultat à partir de xsl: function.

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

Mais cela peut aussi être utile dans d'autres contextes, par exemple

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

L'essentiel ici est qu'il renvoie des références aux nœuds d'origine, il ne fait pas de nouvelles copies.

23
Michael Kay

Eh bien, pour renvoyer une valeur d'un certain type, vous utilisez xsl:sequence comme xsl:value-of malgré son nom crée toujours un nœud de texte (depuis XSLT 1.0). Donc, dans un corps de fonction que vous utilisez

  <xsl:sequence select="42"/>

pour retourner un xs:integer valeur, vous utiliseriez

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

pour retourner un xs:string valeur et

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

pour retourner un xs:date valeur et ainsi de suite. Bien sûr, vous pouvez également retourner des séquences avec par exemple <xsl:sequence select="1, 2, 3"/>.

Vous ne voudriez pas créer un nœud de texte ou même un nœud d'élément dans ces cas à mon avis car il est inefficace.

C'est donc mon point de vue, avec le nouveau système de type basé sur schéma de XSLT et XPath 2.0, un moyen est nécessaire pour renvoyer ou transmettre les valeurs de ces types et une nouvelle construction était nécessaire.

[modifier] Michael Kay dit dans sa "référence du programmeur XSLT 2.0 et XPath 2.0" à propos de xsl:sequence: "Cette instruction d'apparence innocente introduite dans XSLT 2.0 a des effets d'une grande portée sur la capacité du langage XSLT, car elle signifie que les instructions XSLT et les constructeurs de séquences (et donc les fonctions et les modèles) deviennent capables de renvoyer n'importe quelle valeur autorisée par XPath sans lui, les instructions XSLT ne pourraient être utilisées que pour créer de nouveaux nœuds dans une arborescence de résultats, mais avec elle, elles peuvent également renvoyer des valeurs atomiques et des références à des nœuds existants. ".

6
Martin Honnen

Une autre utilisation consiste à créer une balise uniquement si elle a un enfant. Un exemple est requis:

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

Quelque part dans votre 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>

Vous pouvez voir la démo ici: http://xsltransform.net/eiZQaFz

C'est bien mieux que de tester chaque balise comme ceci:

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

Parce que vous finiriez par le modifier à deux endroits. De plus, la vitesse de traitement dépendrait des balises dans votre imput. Si c'est le dernier de votre test, le moteur testera la présence de tout le monde avant. Comme $ foo/node () est un idiome pour "y a-t-il un élément enfant?", Le moteur peut l'optimiser. Ce faisant, vous facilitez la vie de tout le monde.

0
programaths