web-dev-qa-db-fra.com

XPath: sélectionner tous les frères et sœurs suivants jusqu'à un autre frère

Voici un extrait de mon xml:

<node/>
<node/>
<node id="1">content</node>
<node/>
<node/>
<node/>
<node id="2">content</node>
<node/>
<node/>

Je suis positionné dans le node[@id='1']. J'ai besoin d'un Xpath pour faire correspondre tous les éléments <node/> Jusqu'au prochain nœud non vide (ici node[@id='2']).


Edit: les attributs @id sont uniquement pour expliquer mon problème plus clairement, mais ne sont pas dans mon XML d'origine. J'ai besoin d'une solution qui n'utilise pas les attributs @id.


Je veux pas faire correspondre les frères et sœurs vides après node[@id='2'], Donc je ne peux pas utiliser une following-sibling::node[text()=''] naïve.

Comment puis-je atteindre cet objectif ?

36
glmxndr

Vous pourriez le faire de cette façon:

 ../ nœud [pas (text ()) et précédent-frère :: nœud [@id] [1] [@ id = '1']] 

'1' est l'id du noeud courant (générer l'expression dynamiquement).

L'expression dit:

  • du contexte actuel aller au parent
  • sélectionnez les nœuds enfants
  • n'ont pas de texte et
  • parmi tous les "nœuds frères précédents qui ont un id", le premier doit avoir un id de 1

Si vous êtes en XSLT, vous pouvez sélectionner dans l'axe frère suivant, car vous pouvez utiliser la fonction current():

<!-- the for-each is merely to switch the current node -->
<xsl:for-each select="node[@id='1']">
  <xsl:copy-of select="
    following-sibling::node[
      not(text()) and
      generate-id(preceding-sibling::node[@id][1])
      =
      generate-id(current())
    ]
  " />
</xsl:for-each>

ou plus simple (et plus efficace) avec une clé:

<xsl:key 
  name="kNode" 
  match="node[not(text())]" 
  use="generate-id(preceding-sibling::node[@id][1])"
/>

<xsl:copy-of select="key('kNode', generate-id(node[@id='1']))" />
21
Tomalak

Plus simple que la réponse acceptée:

//node[@id='1']/following-sibling::node[following::node[@id='2']]
  • Trouvez un nœud n'importe où dont l'ID est "1"
  • Recherchez maintenant tous les éléments frères node suivants
  • ... mais seulement si ces éléments ont également un node avec id="2" quelque part après eux.

Montré en action avec un document de test plus clair (et des valeurs légales id):

xml = '<root>
<node id="a"/><node id="b"/>
<node id="c">content</node>
<node id="d"/><node id="e"/><node id="f"/>
<node id="g">content</node>
<node id="h"/><node id="i"/>
</root>'

# A Ruby library that uses libxml2; http://nokogiri.org
require 'nokogiri'; doc = Nokogiri::XML(xml)

expression = "//node[@id='c']/following-sibling::node[following::node[@id='g']]"
puts doc.xpath(expression)
#=> <node id="d"/>
#=> <node id="e"/>
#=> <node id="f"/>
9
Phrogz

XPath 2.0 a les opérateurs "<<" et ">>" où node1 << node2 est vrai si node1 précède node2 dans l'ordre des documents. Donc, basé sur cela avec XPath 2.0 dans une feuille de style XSLT 2.0 où le nœud actuel est le nœud [@id = '1'] que vous pourriez utiliser

  following-sibling::node[not(text()) and . << current()/following-sibling::node[@od][1]]

Cela nécessite également la fonction current () de XSLT, c'est pourquoi j'ai dit "avec XPath 2.0 dans une feuille de style XSLT 2.0". La syntaxe ci-dessus est XPath pur, dans une feuille de style XSLT, vous devez échapper "<<" en tant que "lt; lt;".

8
Martin Honnen