web-dev-qa-db-fra.com

XPath contient (text (), 'une chaîne') ne fonctionne pas lorsqu'il est utilisé avec un nœud avec plusieurs sous-nœuds Text

J'ai un petit problème avec Xpath contient avec dom4j ...

Disons que mon XML est

<Home>
    <Addr>
        <Street>ABC</Street>
        <Number>5</Number>
        <Comment>BLAH BLAH BLAH <br/><br/>ABC</Comment>
    </Addr>
</Home>

Disons que je veux trouver tous les nœuds qui ont ABC dans le texte étant donné l'élément racine ...

Donc, le xpath que j’aurais besoin d’écrire serait

//*[contains(text(),'ABC')]

Cependant, ce n’est pas ce que Dom4j renvoie .... s’agit-il d’un problème de dom4j ou de ma compréhension du fonctionnement de xpath? puisque cette requête renvoie uniquement l'élément Street et non l'élément Comment.

Le DOM fait de l’élément Comment un élément composite avec quatre balises deux

[Text = 'XYZ'][BR][BR][Text = 'ABC'] 

Je supposerais que la requête devrait toujours retourner l'élément, car elle devrait trouver l'élément et exécuter en contient, mais ce n'est pas le cas ... ...

la requête suivante renvoie l'élément mais elle renvoie beaucoup plus que l'élément, elle renvoie également les éléments parents ... ce qui n'est pas souhaitable pour le problème ...

//*[contains(text(),'ABC')]

Est-ce que quelqu'un connaît la requête xpath qui ne renverrait que les éléments <Street/> et <Comment/>?

226
Mike Milkin

La balise <Comment> contient deux nœuds de texte et deux nœuds <br> en tant qu'enfants.

Votre expression xpath était

//*[contains(text(),'ABC')]

Pour décomposer cela,

  1. * est un sélecteur qui correspond à n'importe quel élément (c'est-à-dire une balise) - il retourne un ensemble de nœuds.
  2. Les [] sont des conditions qui agissent sur chaque nœud individuel de cet ensemble de nœuds. Il correspond si l'un des nœuds individuels sur lequel il opère remplit les conditions indiquées entre parenthèses.
  3. text() est un sélecteur qui correspond à tous les nœuds de texte enfants du nœud de contexte. Il renvoie un ensemble de nœuds.
  4. contains est une fonction qui agit sur une chaîne. Si un ensemble de nœuds est transmis, celui-ci est converti en une chaîne en renvoyant la valeur de chaîne du nœud dans l'ensemble de nœuds en premier dans l'ordre du document . Par conséquent, il ne peut correspondre qu'au premier nœud de texte de votre élément <Comment>, à savoir BLAH BLAH BLAH. Puisque cela ne correspond pas, vous n'obtenez pas de <Comment> dans vos résultats.

Vous devez changer cela en

//*[text()[contains(.,'ABC')]]
  1. * est un sélecteur qui correspond à n'importe quel élément (c'est-à-dire une balise) - il retourne un ensemble de nœuds.
  2. Les [] extérieurs sont des conditions qui agissent sur chaque nœud individuel de cet ensemble de nœuds - ici, ils agissent sur chaque élément du document.
  3. text() est un sélecteur qui correspond à tous les nœuds de texte enfants du nœud de contexte. Il renvoie un ensemble de nœuds.
  4. Inner [] est une condition qui agit sur chaque nœud de cet ensemble de nœuds - ici, chaque nœud de texte individuel. Chaque nœud de texte est le point de départ de tout chemin entre crochets et peut également être désigné explicitement par . entre crochets. Il correspond si l'un des nœuds individuels sur lequel il opère remplit les conditions indiquées entre parenthèses.
  5. contains est une fonction qui agit sur une chaîne. Ici, un nœud de texte individuel est passé (.). Puisqu'il passe individuellement le second nœud de texte dans la balise <Comment>, il verra la chaîne 'ABC' et pourra la faire correspondre.
625
Ken Bloom

[contains(text(),'')] ne renvoie que vrai ou faux. Il ne retournera aucun résultat d'élément.

6
Ratna

Cela m'a pris un peu de temps mais j'ai finalement compris. Xpath personnalisé qui contient du texte ci-dessous a parfaitement fonctionné pour moi.

//a[contains(text(),'JB-')]
0
zagoo2000

Le document XML:

<Home>
    <Addr>
        <Street>ABC</Street>
        <Number>5</Number>
        <Comment>BLAH BLAH BLAH <br/><br/>ABC</Comment>
    </Addr>
</Home>

L'expression XPath:

//*[contains(text(), 'ABC')]

//* correspond à n'importe quel élément descendant du nœud racine . C'est-à-dire n'importe quel élément sauf le nœud racine.

[...] est un prédicat , il filtre l'ensemble de nœuds. Il retourne les nœuds pour lesquels ... est true:

Un prédicat filtre un ensemble de nœuds [...] pour produire un nouvel ensemble de nœuds. PredicateExpr est évalué pour chaque nœud à filtrer dans l'ensemble de nœuds à filtrer [...]; si PredicateExpr a la valeur true pour ce nœud, celui-ci est inclus dans le nouvel ensemble de nœuds. sinon, ce n'est pas inclus.

contains('haystack', 'needle') renvoie true si haystackcontientneedle:

Fonction: boolean contient (chaîne, chaîne)

La fonction contient renvoie true si la première chaîne d'argument contient la deuxième chaîne d'argument, sinon renvoie false.

Mais contains() prend une chaîne comme premier paramètre. Et c'est passé des noeuds. Pour traiter ce problème, chaque nœud ou ensemble de nœuds transmis en tant que premier paramètre est converti en chaîne par la fonction string():

Un argument est converti en chaîne comme en appelant la fonction chaîne.

La fonction string() renvoie string-value sur le premier noeud :

Un ensemble de nœuds est converti en une chaîne en renvoyant la valeur de chaîne du nœud dans l'ensemble de nœuds qui est le premier dans l'ordre du document. Si l'ensemble de nœuds est vide, une chaîne vide est renvoyée.

string-value d'un nœud d'élément :

La valeur de chaîne d'un nœud d'élément est la concaténation des valeurs de chaîne de tous les descendants de nœud de texte du nœud d'élément dans l'ordre du document.

string-value d'un noeud de texte :

La valeur de chaîne d'un nœud de texte correspond aux données de caractères.

Donc, fondamentalement, string-value représente tout le texte contenu dans un nœud (concaténation de tous les nœuds de texte descendants).

text() est un test de noeud qui correspond à tout noeud de texte:

Le texte de test du noeud () est vrai pour tout noeud de texte. Par exemple, child :: text () sélectionnera les enfants du noeud de texte du noeud contextuel.

Cela dit, //*[contains(text(), 'ABC')] correspond à n'importe quel élément (à l'exception du nœud racine), dont le premier nœud de texte contient ABC. Étant donné que text() renvoie un ensemble de noeuds contenant tous les noeuds de texte enfant du noeud de contexte (par rapport auquel une expression est évaluée). Mais contains() ne prend que le premier. Donc, pour le document ci-dessus, le chemin correspond à l'élément Street.

L'expression suivante //*[text()[contains(., 'ABC')]] correspond à n'importe quel élément (à l'exception du nœud racine) comportant au moins un nœud de texte enfant contenant ABC. . représente le nœud de contexte. Dans ce cas, il s'agit d'un nœud de texte enfant de n'importe quel élément, à l'exception du nœud racine. Ainsi, pour le document situé au-dessus, le chemin correspond aux éléments Street et Comment.

Maintenant, //*[contains(., 'ABC')] correspond à tout élément (sauf le nœud racine) contenant ABC (dans la concaténation des nœuds de texte descendants). Pour le document ci-dessus, il correspond aux éléments Home, Addr, Street et Comment. En tant que tel, //*[contains(., 'BLAH ABC')] correspond aux éléments Home, Addr et Comment.

0
x-yuri