2009-12-11 5 views
4

Je suis assez nouveau pour XSLT, mais j'ai besoin de l'utiliser pour un CMS en utilisant pour le moment. J'ai déjà trouvé un problème, mais je vais essayer de le décrire sans entrer dans trop d'informations sur le CMS sous-jacent. Si vous avez besoin de plus de contexte pour m'aider, je peux l'ajouter.XSL: Comment tester si le noeud courant est un descendant d'un autre noeud

Tout ce que je veux faire est de tester si un nœud de mon xml est un descendant d'un nœud particulier.

<xsl:if test="$currentNode::IsADescendantOf($someNode)"> 
Write this out. 
</xsl:if> 

Des idées?

Merci à l'avance :)

Répondre

5

Vous devez utiliser la comparaison opération d'union et la taille node-set:

<xsl:if test="count($someNode|$currentNode/ancestor::*) = count($currentNode/ancestor::*)"> 
Write this out. 
</xsl:if> 

Si $ someNode est un ancêtre de $ currentNode, someNode de $ | currentNode de $/ancêtre :: * retournera le le même ensemble de nœuds que $ currentNode/ancestor :: * (l'ensemble de nœuds n'a pas de doublons).Si ce n'est pas le cas, le premier ensemble de nœuds aura un nœud de plus que le second à cause de l'union.

+0

@Erlock: Merci beaucoup pour l'aide. A travaillé un régal. –

1

Regardez l'axe "ancêtre" dans votre XSL/XPath

<xsl:if test="ancestor::*[. is $somenode]"> 

EDIT: j'apprends avec vous. Voir si cela fonctionne (je voudrais avoir mon débogueur XSL disponible sur ce système :-)

+0

@Jim Garrison: Merci pour la réponse rapide. Cela me semble raisonnable mais j'obtiens cette erreur: System.Xml.Xsl.XslLoadException: Attendu un test de noeud, trouvé '$'. –

+0

Vous avez raison, ma solution est incomplète. Je n'ai pas mon reflex XSL à portée de main, mais l'idée de base est que vous devez utiliser l'axe ancêtre pour sélectionner tous les nœuds ancêtres, puis le filtrer en fonction de l'égalité des nœuds à $ somenode. –

+0

Merci beaucoup. Maintenant, je reçois "is-same-node()" est une fonction XSLT inconnue " Je vais continuer à jouer avec, mais laissez-moi savoir si vous avez d'autres idées. –

0

vérification Descendant

La meilleure façon serait d'utiliser le descendant :: * axe.

Si vous avez un morceau de XML ressemblant à ceci et que vous voulez faire correspondre les noeuds descendants <a> du premier noeud <alpha>.

XML

<root> 
<!-- check for descendants of the following alpha node--> 
<alpha> 
    <!-- match the following node--> 
    <a>...</a> 
    <b>...</b> 
    <c>...</c> 
</alpha> 
<alpha> 
    <a>...</a> 
    <c>...</c> 
</alpha> 
</root> 

XSLT

<xsl:if test="/root/alpha[1]/descendant::a[. is current()]"> 

Ancêtre vérification

Ce serait probablement dans la plupart des cas.

<xsl:if test="ancestor::*[name() = $node]"> 

<xsl:variable name="node" select="name(//alpha)"/> 

Ou vous pouvez simplement utiliser generate-id() si vous avez plusieurs noeuds à comparer contre et devez vous assurer qu'il est un match de nœud et non un match de nom.

<xsl:variable name="node" select="generate-id(//alpha[3])"/> 
<xsl:if test="ancestor::*[generate-id(.) = $node]"> 

L'opérateur de comparaison is ne peut pas être utilisé de l'OMI lorsque l'on compare les ancêtres car il nécessite un nœud feuille et nœuds feuilles n'ont pas des descendants.

Mais je recommande d'utiliser l'axe descendant :: * car il est beaucoup plus lisible et flexible.

2

Une solution portable (XPath 1.0 et 2.0) serait:

<xsl:if test=" 
    $currentNode/ancestor::*[generate-id() = generate-id($someNode)] 
"> 
Write this out. 
</xsl:if> 

Cela se dirige vers l'axe de l'ancêtre et vérifie chaque élément en elle. Si (et seulement si) l'ID unique de l'un des ancêtres correspond à l'ID unique $someNode, l'ensemble de nœuds résultant n'est pas vide.

Les ensembles de noeuds non vides ont la valeur true et la condition est remplie.

Test - trouver tous les <baz> qui sont descendant de <foo>:

<xml> 
    <foo> 
    <bar> 
     <baz>Test 1</baz> 
    </bar> 
    </foo> 
    <baz>Test 2</baz> 
</xml> 

et

<xsl:stylesheet 
    version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
> 
    <xsl:template match="/"> 
    <xsl:variable name="someNode" select="//foo[1]" /> 

    <!-- test each <baz> node if it has <foo> as a parent --> 
    <xsl:for-each select="//baz"> 
     <xsl:if test=" 
     ancestor::*[generate-id() = generate-id($someNode)] 
     "> 
     <xsl:copy-of select="." /> 
     </xsl:if> 

    </xsl:for-each> 
    </xsl:template> 
</xsl:stylesheet> 

résultats dans

<baz>Test 1</baz> 

Notez que si vous faites référence à la réelle curren t noeud, comme je le fais dans le for-each, il n'y a pas besoin d'une variable distincte $currentNode. Tout XPath est relatif au nœud actuel par défaut.

Une variante serait la méthode descendante. Il est moins efficace que (probablement par plusieurs ordres de grandeur):

<xsl:if test=" 
    $someNode[//*[generate-id() = generate-id($currentNode)]] 
"> 
Write this out. 
</xsl:if> 
1

La réponse est assez facile,

tout ce que vous avez à faire est:

<xsl:if test="count(ancestor::somenode)>0"> 

      .. La logique est que si le nœud est un descendant de somenode, alors il aura un ou plusieurs de ce nœud.

Questions connexes