Je n'aime pas demander de l'aide, mais cette fois je suis totalement coincé avec une requête xpath.
Veuillez jeter un œil à ce XML:
/doc/car/property[@id=name(/doc/attributes/*)]/attribute[@id=/doc/attributes/*/text()]
La voiture / les propriétés doivent être affichées en fonction des noms de nœuds des attributs. La sortie souhaitée est:
<property id="color"><attribute id="white" /></property> <property id="size"><attribute id="small" /></property>
Le xpath
<doc> <car> <property id="color"> <attribute id="black" /> <attribute id="white" /> <attribute id="green" /> </property> <property id="size"> <attribute id="small" /> <attribute id="medium" /> <attribute id="large" /> </property> </car> <attributes> <color>white</color> <size>small</size> </attributes> </doc>
ne produit que le premier nœud, car la fonction name () renvoie seulement le nom du premier élément.
Qui peut m'aider à trouver un xpath fonctionnel (XSLT 1.0)? Merci d'avance pour votre aide!
4 Réponses :
Vous pouvez y parvenir avec XSLT-1.0, mais pas seulement avec XPath-1.0, car dans XPath-1.0, vous ne pouvez renvoyer que le premier élément. Ce n'est pas un problème dans XSLT-1.0, car vous pouvez utiliser une boucle xsl: for-each
, comme suit:
<property id="color"><attribute id="white"/></property> <property id="size"><attribute id="small"/></property>
Ce code émet le XML suivant :
<xsl:for-each select="/doc/attributes/*"> <property id="{/doc/car/property[@id=current()/local-name()]/@id}"><attribute id="{/doc/car/property[@id=current()/local-name()]/attribute[@id=current()/.]/@id}" /></property> </xsl:for-each>
Comme on le voit, vos exigences semblent un peu redondantes, mais je suppose que votre plus grand scénario justifie les moyens.
En fait, c'est un scénario plus grand. J'ai réduit le problème au strict minimum.
Et c'est bien. Mais la question pertinente est: ma solution vous aide-t-elle. et si non, pourquoi pas?
Une approche intéressante, merci beaucoup! Il faudra un jour ou deux avant que je puisse déterminer si toutes les expressions xpath du projet peuvent être remplacées ou non.
: Merci pour la matière à réflexion. C'est vrai, je dois quitter xpath et déterminer le résultat via XSL. Avec exsl: node-set (), je peux ensuite convertir le résultat RTF. La solution XSL semble très simple.
@ E.Wiest: Merci beaucoup pour vos trois échantillons. Mais ils sélectionnent n'importe quel attribut correspondant indépendamment de la propriété parent. Si le même ID d'attribut se produit dans plusieurs propriétés, il y a un conflit.
Qu'en est-il de ces options (je ne vois toujours pas pourquoi vous utilisez name ()
car je ne vois aucun espace de noms dans vos exemples de données):
//property|//attribute[@id=//attributes/*] //attribute[@id=//attributes/*]|//attribute[@id=//attributes/*]/parent::property //property|//attribute[@id=substring-before(normalize-space(//attributes)," ") or @id=substring-after(normalize-space(//attributes)," ")]
La troisième option devrait fonctionner même si vous devez gérer un espace de noms pour le @id
à l'intérieur du nœud attributes
.
Résultat: p>
Ma solution de travail:
<xsl:stylesheet version="1.0"> <xsl:template match="/"> <xsl:for-each select="/doc/car/property"> <property id="{@id}"> <xsl:variable name="id" select="@id" /> <xsl:copy-of select="attribute[@id=/doc/attributes/*[name()=$id]/text()]" /> </property> </xsl:for-each> </xsl:template> </xsl:stylesheet>
Autre solution sans utiliser de boucle:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:template match="/"> <xsl:apply-templates select="doc/car/property"/> </xsl:template> <xsl:template match="property"> <xsl:copy> <xsl:copy-of select="@*"/> <xsl:copy-of select="attribute[@id = /doc/attributes/*[name() = current()/@id]]"/> </xsl:copy> </xsl:template> </xsl:stylesheet>
Pour chaque propriété
il copie le nœud d'élément et ses attributs. Ensuite, il copie ses enfants attribut
ayant un id
correspondant à l'élément respectif ci-dessous /doc/attributes
.