2010-09-30 6 views

Répondre

27

Dans XPath 1.0 une façon d'y parvenir est d'utiliser la méthode Kayessian pour intersection ensemble de nœuds:

$ns1[count(.|$ns2) = count($ns2)] 

L'expression ci-dessus sélectionne exactement les noeuds qui font partie à la fois de l'ensemble de nœuds $ns1 et l'ensemble de nœuds $ns2.

Pour appliquer à la question spécifique - disons que nous devons sélectionner tous les noeuds entre le 2ème et 3ème élément h3 dans le document XML suivant:

<html> 
    <h3>Title T31</h3> 
    <a31/> 
    <b31/> 
    <h3>Title T32</h3> 
    <a32/> 
    <b32/> 
    <h3>Title T33</h3> 
    <a33/> 
    <b33/> 
    <h3>Title T34</h3> 
    <a34/> 
    <b34/> 
    <h3>Title T35</h3> 
</html> 

Nous devons remplacer $ns1 avec:

/*/h3[2]/following-sibling::node() 

et de remplacer $ns2 avec:

/*/h3[3]/preceding-sibling::node() 

Ainsi, l'expression XPath complète est:

/*/h3[2]/following-sibling::node() 
      [count(.|/*/h3[3]/preceding-sibling::node()) 
      = 
       count(/*/h3[3]/preceding-sibling::node()) 
      ] 

Nous pouvons vérifier que cela est l'expression XPath correcte:

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

<xsl:template match="/"> 
    <xsl:copy-of select= 
    "/*/h3[2]/following-sibling::node() 
      [count(.|/*/h3[3]/preceding-sibling::node()) 
      = 
       count(/*/h3[3]/preceding-sibling::node()) 
      ] 
    "/> 
</xsl:template> 
</xsl:stylesheet> 

Lorsque cette transformation est appliqué sur le document XML présenté ci-dessus, le wante d, résultat correct est produit:

<a32/> 

<b32/> 

II. XPath 2.0 Solution:

Utilisez l'opérateur intersect:

/*/h3[2]/following-sibling::node() 
intersect 
    /*/h3[3]/preceding-sibling::node() 
+1

+ 1 mai le droit prévaudra toujours. :-) – LarsH

+1

+1 pour la solution la plus générale et l'invocation de Theory –

+1

nice stuff. il a travaillé en ligne un charme – klumsy

1

Une solution plus générale - dans XPath 2.0 - en supposant que vous voulez noeuds à toutes les profondeurs d'arbres entre les deux éléments h3, qui ne serait pas nécessairement être frères et soeurs.

/path/to/first/h3/following::node()[. << /path/to/second/h3] 
7

Autre solution XPath 1.0 quand vous savez que les deux marques sont les mêmes éléments (ce cas h3):

/html/body/h3[2]/following-sibling::node() 
          [not(self::h3)] 
          [count(preceding-sibling::h3)=2] 
+0

@ utilisateur3457812 , merci, ça marche pour moi! –

1

Basé sur dimitre-novatchev excellente réponse que je peux avec la solution de suivi que, plutôt que hardcoding [ 2] et [3] pour les différents H3 je donne juste le contenu de l'en-tête du premier item.

//h3[text()="Main Page Section Heading"]/following-sibling::node() 
[ count(.|//h3[text()="Main Page Section Heading"]/following-sibling::h3[1]/preceding-sibling::node()) = 
    count(//h3[text()="Main Page Section Heading"]/following-sibling::h3[1]/preceding-sibling::node()) ] 

où je veux aller plus loin si est d'être en mesure de traiter le scénario quand je regarde le dernier H3, et obtenir tout ce qui suit, dans le cas ci-dessus, je ne peux pas obtenir ce qui suit le dernier H3.

0

Il y a une autre grande solution générique à l'aide des touches, en supposant que vos <h3> balises ont une propriété unique (par exemple, le texte ou un attribut id):

<xsl:key name="siblings_of_h3" match="*[not(self::h3)]" use="preceding-sibling::h3[1]/text()"/> 

<xsl:template match="h3"> 
    <!-- now select all tags belonging to the current h3 --> 
    <xsl:apply-templates select="key('siblings_of_h3', text())"/> 
</xsl:template> 

Elle regroupe toutes les balises de leur précédent <h3>

Questions connexes