XPath bevat (tekst (), ‘Sommige string’) werkt niet wanneer gebruikt met knooppunt met meer dan één tekst-subnode

Ik heb een klein probleem met XPath bevat met DOM4J …

Laten we zeggen dat mijn XML

is

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

Laten we zeggen dat ik alle knooppunten willen vinden die ABC in de tekst hebben gezien het root-element …

Dus de XPath die ik moest schrijven zou schrijven

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

Dit is echter niet wat Dom4j terugkeert …. Is dit een DOM4J-probleem of mijn begrip hoe XPath werkt. Omdat die query alleen het straatelement en niet het commentaarelement retourneert.

De DOM maakt het commentaarelement een composietelement met vier tags twee

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

Ik zou aannemen dat de query nog steeds het element moet retourneren, omdat het het element en de uitvoer erop moet vinden, maar het niet … …

De volgende zoekopdracht geeft het element terug, maar het geeft veel meer terug dan alleen het element, het retourneert de ouderelementen ook … die ongewenst is voor het probleem …

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

Kent iemand de XPath-query die alleen de elementen zou retourneren <Street/>en <Comment/>?


Antwoord 1, Autoriteit 100%

De <Comment>TAG bevat twee tekstknooppunten en twee <br>knooppunten als kinderen.

Uw XPath-expressie was

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

Om dit op te splitsen,

  1. *is een selector die overeenkomt met elk element (d.w.z. tag) — het retourneert een node-set.
  2. De []zijn een voorwaarde die werkt op elk afzonderlijk knooppunt in die knooppuntenset. Het komt overeen als een van de individuele knooppunten waarop het werkt, overeenkomt met de voorwaarden tussen de haakjes.
  3. text()is een selectordie overeenkomt met alle tekstknooppunten die kinderen zijn van het contextknooppunt — het retourneert een knooppuntenset.
  4. containsis een functie die op een string werkt. Als een knooppuntset wordt doorgegeven, wordt de knooppuntenset geconverteerd naar een tekenreeks door terug te keren de string-waarde van de node in de node-set die als eerste in documentvolgorde staat. Daarom kan het alleen overeenkomen met het eerste tekstknooppunt in uw <Comment>-element — namelijk BLAH BLAH BLAH. Aangezien dat niet overeenkomt, krijgt u geen <Comment>in uw resultaten.

U moet dit wijzigen in

//*[text()[contains(.,'ABC')]]
  1. *is een selector die overeenkomt met elk element (d.w.z. tag) — het retourneert een node-set.
  2. De buitenste []is een voorwaarde die werkt op elk afzonderlijk knooppunt in die knooppuntenset — hier werkt het op elk element in het document.
  3. text()is een selectordie overeenkomt met alle tekstknooppunten die kinderen zijn van het contextknooppunt — het retourneert een knooppuntenset.
  4. De binnenste []is een voorwaarde die werkt op elk knooppunt in die knooppuntenset — hier elk afzonderlijk tekstknooppunt. Elk afzonderlijk tekstknooppunt is het startpunt voor elk pad tussen haakjes en kan ook expliciet worden aangeduid als .tussen haakjes. Het komt overeen als een van de individuele knooppunten waarop het werkt, overeenkomt met de voorwaarden tussen de haakjes.
  5. containsis een functie die op een string werkt. Hier wordt een individueel tekstknooppunt (.) doorgegeven. Aangezien het het tweede tekstknooppunt in de tag <Comment>afzonderlijk wordt doorgegeven, ziet het de tekenreeks 'ABC'en kan het deze overeenkomen.

Antwoord 2, autoriteit 2%

Het XML-document:

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

De XPath-uitdrukking:

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

//*komt overeen met elk afstammelend elementvan het hoofdknooppunt. Dat wil zeggen, elk element behalve het hoofdknooppunt.

[...]is een predikaat, het filtert de node-set. Het retourneert knooppunten waarvoor ...trueis:

Een predikaat filtert een node-set […] om een nieuwe node-set te produceren. Voor elk knooppunt in de knooppuntset dat moet worden gefilterd, wordt de PredicateExpr geëvalueerd […]; als PredicateExpr evalueert naar waar voor dat knooppunt, wordt het knooppunt opgenomen in de nieuwe knooppuntenset; anders is het niet inbegrepen.

contains('haystack', 'needle')retourneert trueals haystackbevatneedle:

Functie: boolean bevat(string, string)

De functie bevat levert true op als de eerste argumentstring de tweede argumentstring bevat, en geeft anders false terug.

Maar contains()neemt een string als eerste parameter. En het heeft knooppunten gepasseerd. Om hiermee om te gaan is elke node of node-set die als eerste parameter wordt doorgegeven, omgezetnaar een string door de functie string():

Een argument wordt geconverteerd naar het type string alsof het de stringfunctie aanroept.

string()functie retourneert string-valuevan het eerste knooppunt:

Een node-set wordt geconverteerd naar een string door de string-waarde van de node in de node-set die als eerste in documentvolgorde staat te retourneren. Als de node-set leeg is, wordt een lege string geretourneerd.

string-valuevan een elementknooppunt:

De tekenreekswaarde van een elementknooppunt is de aaneenschakeling van de tekenreekswaarden van alle afstammelingen van het tekstknooppunt van het elementknooppunt in documentvolgorde.

string-valuevan een tekst knoop:

De tekenreekswaarde van een tekstknooppunt zijn de tekengegevens.

Dus in feite is string-valuealle tekst die in een knooppunt is opgenomen (aaneenschakeling van alle onderliggende tekstknooppunten).

text()is een knooppunttest die overeenkomt met een tekstknooppunt:

De knooppunttesttekst() is waar voor elk tekstknooppunt. Child::text() selecteert bijvoorbeeld de onderliggende tekstknooppunten van het contextknooppunt.

Dat gezegd hebbende, //*[contains(text(), 'ABC')]komt overeen met elk element (behalve het hoofdknooppunt), waarvan het eerste tekstknooppunt ABC. Aangezien text()een knooppuntenset retourneert die alle onderliggende tekstknooppunten van het contextknooppunt bevat (relatief ten opzichte waarvan een expressie wordt geëvalueerd). Maar contains()neemt alleen de eerste. Dus voor het document hierboven komt het pad overeen met het Streetelement.

De volgende uitdrukking //*[text()[contains(., 'ABC')]]komt overeen met elk element (behalve het hoofdknooppunt), dat ten minste één onderliggende tekstknooppunt heeft, die ABCbevat. .staat voor het contextknooppunt. In dit geval is het een onderliggend tekstknooppunt van elk element behalve het hoofdknooppunt. Dus voor het document hierboven komt het pad overeen met de Streeten de Commentelementen.

Nu dan, //*[contains(., 'ABC')]komt overeen met elk element (behalve het hoofdknooppunt) dat ABCbevat (in de aaneenschakeling van de onderliggende tekstknooppunten). Voor het bovenstaande document komt het overeen met de elementen Home, Addr, Streeten Comment. Als zodanig komt //*[contains(., 'BLAH ABC')]overeen met de Home, de Addren de Commentelementen.


Antwoord 3

[contains(text(),'')]geeft alleen waar of onwaar terug. Er worden geen elementresultaten geretourneerd.


Antwoord 4

Het geaccepteerde antwoord retourneert ook alle bovenliggende knooppunten. Om alleen de daadwerkelijke knooppunten met ABC te krijgen, zelfs als de tekenreeks na
komt:

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

Antwoord 5

//*[text()='ABC'] 

retouren

<street>ABC</street>
<comment>BLAH BLAH BLAH <br><br>ABC</comment>

Antwoord 6

Hier is een alternatieve manier om knooppunten te matchen die een bepaalde tekenreeks bevatten. Zoek eerst naar het tekstknooppunt zelf en haal vervolgens de ouder op:

//text()[contains(., "ABC")]/..

Voor mij is dit gemakkelijk te lezen en te begrijpen.


Antwoord 7

Het heeft even geduurd, maar ik heb het eindelijk door. Aangepast xpath met onderstaande tekst werkte perfect voor mij.

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

Other episodes