2010-06-01 9 views
5

Je suis nouveau à XPath, et d'après ce que j'ai lu dans certains tutoriels sur les axes, je me demande toujours comment les implémenter. Ils ne se comportent pas comme je m'y attendais. Je suis particulièrement intéressé par l'utilisation d'axes ancêtres et descendants.XPath ancêtre et descendant dans XSL copy-of

je la structure XML suivante:

<file> 
    <criteria> 
     <root>ROOT</root> 
     <criterion>AAA</criterion> 
     <criterion>BBB</criterion> 
     <criterion>CCC</criterion> 
    </criteria> 
    <format> 
     <sort>BBB</sort> 
    </format> 
</file> 

Et je le XSL suivant:

<xsl:template match="/"> 
    <xsl:copy-of select="ancestor::criterion/> 
</xsl:template> 

qui ne produit rien!

Je m'y attendais à produire:

<file> 
    <criteria> 
    </criteria> 
</file> 

Quelqu'un peut-il expliquer ancêtre et descendant axes pour moi d'une manière plus utile que les tutoriels que je l'ai déjà lu?

Merci!

+0

Bonne question (+1). Voir ma réponse pour une explication et une solution complète. –

Répondre

5

Et je le XSL suivant:

<xsl:template match="/"> 
    <xsl:copy-of select="ancestor::criterion/> 
</xsl:template> 

qui ne produit rien!

Comme il se doit!

ancestor::criterion 

est une expression relative, ce qui signifie qu'il est évalué hors du noeud courant (identifié par le modèle). Mais le nœud actuel est le nœud de document /.

Ainsi, ce qui précède équivaut à:

/ancestor::criterion 

Cependant, par définition, le nœud de document / n'a pas de parents (et cela signifie que pas d'ancêtres), de sorte que cette expression XPath ne sélectionne pas un nœud.

Je m'y attendais à produire:

<file> 
    <criteria> 
    </criteria> 
</file> 

Qu'est-ce que vous avez probablement voulu était:

//criterion/ancestor::* 

ou

//*[descendant::criterion] 

Les deux dernières expressions XPath sont équivalentes et sélectionner tous les éléments qui ont un descendant criterion.

Enfin, pour produire la sortie que vous vouliez, voici une solution possible:

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
<xsl:output omit-xml-declaration="yes" indent="yes"/> 
<xsl:strip-space elements="*"/> 

<xsl:template match="node()|@*"> 
    <xsl:copy> 
    <xsl:apply-templates select="node()|@*"/> 
    </xsl:copy> 
</xsl:template> 

<xsl:template match="root | criterion | format"/> 
</xsl:stylesheet> 

Lorsque cette transformation est appliquée sur le document XML fourni, est produit la sortie désirée:

<file> 
<criteria> 
</criteria> 
</file> 
+0

Merci pour votre réponse. // criteria/ancestor :: * et // * [descendant :: criteria] me donnent des résultats bizarres, et bien que la solution entièrement codée que vous fournissez fonctionne et produise les résultats attendus, j'ai encore besoin d'une solution moins codée en dur (ci-dessus solution nécessite la connaissance de la racine et du format .. mais il peut y avoir d'autres que je ne sais pas ..) Aussi, merci pour l'explication des axes descendant et ancêtre :) – developer

+0

@iHeartGreek: Pourquoi attendez-vous une expression XPath qui sélectionne nœuds spécifiques pour sélectionner d'autres nœuds? Dans le cas où vous avez un autre problème, posez simplement une autre question. Vous n'avez pas posé la question à laquelle on n'a pas répondu. :) –

1

ancestor est de sélectionner les nœuds qui sont plus élevés (plus proche de la racine) dans le document XML. descendant sert à sélectionner les nœuds inférieurs (enfants) dans le document XML.

Dans votre exemple, ancestor::criterion sélectionne rien parce que le nœud actuel est / (ce qui signifie la racine du document - <file> dans ce cas), comme indiqué par match="/". Le nœud racine n'a aucun ancêtre, donc l'axe ancestor ne fait rien.

Pour obtenir tous les éléments <criterion>, vous devez utiliser l'axe descendant:

<xsl:template match="/"> 
    <xsl:copy-of select="descendant::criterion"/> 
</xsl:template> 

Ou son raccourci //:

<xsl:template match="/"> 
    <xsl:copy-of select="//criterion"/> 
</xsl:template> 

qui renverra les éléments suivants:

<criterion>AAA</criterion> 

aide une boucle ou un autre modèle, vous pouvez obtenir tous les trois les:

<xsl:template match="/"> 
    <file> 
    <xsl:apply-templates select="//criterion"/> 
    </file> 
</xsl:template> 
<xsl:template match="criterion"> 
    <xsl:copy-of select="."/> 
</xsl:template> 

Cela produira les résultats suivants:

<file> 
    <criterion>AAA</criterion> 
    <criterion>BBB</criterion> 
    <criterion>CCC</criterion> 
</file> 

Si vous voulez obtenir l'élément <file>, aussi, il est un peu plus compliqué. XPath spécifie les nœuds et les copies simples ne copient pas les éléments qui contiennent les éléments que vous sélectionnez. Je peux clarifier ce point plus si vous êtes encore confus.

+0

Vous dites que: ' ' renverra les éléments suivants: ' AAA' Ce n'est pas le cas. Le résultat sera: ' AAA BBB CCC' –

+0

Juste un point, mais 'descendant :: criterion' ne correspond pas à' // criterion'; ce dernier trouvera tous les nœuds de critère dans le document entier. Le raccourci correct est '.// criteria'. – Flynn1179

Questions connexes