5 votes

fragment d'arbre de résultat en ensemble de nœuds : approche générique pour tous les moteurs xsl

En réponse à un autre fil de discussion (voir stackoverflow : générer des schémas de couleurs css ) Je suis tombé sur le problème ci-dessous, où différents moteurs xsl semblent avoir besoin de différentes approches pour transformer les fragments de l'arbre de résultats en ensembles de nœuds.

En simplifiant le problème (mais voir le lien ci-dessus pour l'histoire complète), je souhaite avoir un arbre en ligne contenant une liste de valeurs de couleur. Comme cela doit être utilisé dans des expressions Xpath, j'ai dû créer un ensemble de noeuds spécifiquement pour le moteur xsl de MSXML x.x (XML Spy intégré avait moins de difficultés à interpréter les expressions Xpath contenant des variables construites comme des rtf).
Un autre fil de discussion stackoverflow : automatisation de l'ensemble des nœuds d'extrusion (Exsltnode-set) m'a aidé. L'ensemble de nœuds résultant est utilisé pour créer une nouvelle variable rtf à partir du XML d'entrée.
Là encore, MSXML se plaint lorsque la nouvelle variable est utilisée dans des expressions Xpath, j'ai donc utilisé la fonction node-set pour créer un node-set à partir de cette variable.
Jusqu'à présent, tout va bien, et MSXML x.x ne provoque plus d'erreur.
Mais lorsque j'exécute la même opération avec XML Spy built-in ou Saxon 9he, j'obtiens une autre erreur : il semble que la fonction node-set soit inconnue :

Cannot find a matching 1-argument function named {urn:schemas-microsoft-com:xslt}node-set() in variable colorList

Notez que cette approche en deux étapes n'est pas nécessaire dans cet exemple particulier, mais comme je l'ai dit, j'ai simplifié les choses ; je souhaite simplement savoir comment écrire une transformation XSLT 1.0 qui fonctionnera dans tous les moteurs xsl.

Le XSLT que j'ai utilisé :

<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet
    version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:std="http://whatever"
    xmlns:exslt="urn:schemas-microsoft-com:xslt"
    exclude-result-prefixes="std exslt">

    <xsl:output method="xml" indent="yes"/>

    <std:colors>
        <color>#0000FF</color>
        <color>#FF0000</color>
    </std:colors>

    <xsl:variable name="colors" select="document('')/*/std:colors"/>

    <xsl:variable name="std:colorList">
        <xsl:for-each select="//testid">
            <xsl:variable name="pos" select="position() mod 2"/>
            <xsl:element name="color">
                <xsl:attribute name="testid"><xsl:value-of select="."/></xsl:attribute>
                <xsl:value-of select="$colors/color[$pos + 1]"/>
            </xsl:element>
        </xsl:for-each>
    </xsl:variable>

    <xsl:variable name="colorList" select="exslt:node-set($std:colorList)"/>

    <xsl:template match="/">
        <output>
            <xsl:copy-of select="$colorList/color"/>
        </output>
   </xsl:template>

</xsl:stylesheet>

Fichier d'entrée :

<?xml version="1.0" standalone="yes"?>
<NewDataSet>
  <defects>
    <testid>111</testid>
  </defects>
  <defects>
    <testid>999</testid>
  </defects>
</NewDataSet>

Résultat en MSXML 3.0/4.0/6.0 :

<?xml version="1.0" encoding="UTF-16"?>
<output>
<color testid="111">#FF0000</color>
<color testid="999">#0000FF</color>
</output>

Résultat en Saxon9he :

Cannot find a matching 1-argument function named {urn:schemas-microsoft-com:xslt}node-set()
in variable colorList

résultat en XML Spy built-in xsl engine :

Error in XPath expression
Unknown function - Name and number of arguments do not match any function signature in the static context - 'urn:schemas-microsoft-com:xslt:node-set'

7voto

Michael Kay Points 52194

Pour les processeurs autres que MSXML, utilisez la fonction exslt:node-set(). (http://www.exslt.org/). (Il est un peu étrange de lier le préfixe exslt à la version Microsoft de la fonction - cela m'a déconcerté pendant un certain temps !)

Vous pouvez tester les fonctions disponibles à l'aide de la fonction function-available() :

<xsl:choose>
  <xsl:when test="function-available('exslt:node-set')"...
  <xsl:when test="function-available('msxsl:node-set')"...

Pour Saxon-HE et les autres processeurs XSLT 2.0, vous n'avez besoin d'aucune de ces fonctions.

<xsl:when test="xsl:version='2.0'">

5voto

David Carlisle Points 5402

Pour éviter de devoir faire

 <xsl:choose>
 <xsl:when test="function-available('exslt:node-set')"...

chaque fois que vous en avez besoin, vous pouvez définir exslt node set pour les moteurs xslt2 (en utilisant xsl:function) et pour msxml (en utilisant msxsl:script), puis utilisez simplement la fonction exslt:node-set dans le reste de votre document.

http://dpcarlisle.blogspot.co.uk/2007/05/exslt-node-set-function.html

vous montre comment le définir pour les moteurs msxml et xslt2 vous pouvez xsl:include une feuille de style

<xsl:stylesheet version="2.0"
        xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns:exslt="http://exslt.org/common"
        >

<xsl:function name="exslt:node-set">
  <xsl:param name="rtf"/>
  <xsl:sequence select="$rtf"/>
</xsl:function>

<xsl:stylesheet>

Les règles de compatibilité ascendante de XSLT1 signifient qu'il n'y a pas de danger à l'inclure, un moteur XSLT1 l'ignorera simplement.

2voto

Dimitre Novatchev Points 147842

Le programme .NET de Microsoft XsltCompiledTransform Le processeur XSLT prend en charge exslt:node-set().

Pour MSXML, on peut utiliser ma propre implémentation d'un sous-ensemble de fonctions EXSLT -- pour MSXML. Vous trouverez une description détaillée et un lien vers le téléchargement ici :

http://www.xml.com/pub/a/2003/08/06/exslt.html

1voto

Martin Honnen Points 46896

Saxon 9 est un processeur XSLT 2.0 et avec XSLT 2.0, l'une des principales améliorations est que la distinction entre les ensembles de nœuds et les fragments d'arbre de résultats a disparu et que vous n'avez plus besoin d'aucune fonction d'extension, car vous n'avez plus besoin de forcer la coercition. Ainsi, pour les feuilles de style destinées à n'importe quel processeur XSLT 2.0, il suffit d'abandonner toute tentative d'utilisation d'une telle fonction d'extension, et la feuille de style fonctionnera. Si vous voulez exécuter la même feuille de style avec les processeurs XSLT 1.0 et 2.0, je vois un problème, mais je ne pense pas qu'il y ait une solution facile. Vous devrez utiliser http://www.w3.org/TR/xslt#function-function-available et system-property pour distinguer les processeurs et la disponibilité des fonctions d'extension.

-1voto

user2724798 Points 11

Vous pouvez facilement le faire sans aucun contrôle. Il suffit de suivre le modèle décrit ici : http://dpcarlisle.blogspot.co.uk/2007/05/exslt-node-set-function.html

<xsl:stylesheet
  version="1.0" 
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:exslt="http://exslt.org/common"
  xmlns:msxsl="urn:schemas-microsoft-com:xslt"
  exclude-result-prefixes="exslt msxsl">

<msxsl:script language="JScript" implements-prefix="exslt">
 this['node-set'] =  function (x) {
  return x;
  }
</msxsl:script>

<xsl:variable name="x">
  <y/>
</xsl:variable>

<xsl:template match="x">
  <html>
    <head><title>test exslt node set</title></head>
    <body>
      <xsl:apply-templates select="exslt:node-set($x)/*"/>
    </body>
  </html>
</xsl:template>

<xsl:template match="y">
  <p>node set!</p>
</xsl:template>

</xsl:stylesheet>

Il fonctionne sans aucun doute dans FF, Chrome et IE7+.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X