webentwicklung-frage-antwort-db.com.de

XPath enthält (text (), 'some string') funktioniert nicht, wenn ein Knoten mit mehr als einem Text-Unterknoten verwendet wird

Ich habe ein kleines problem mit xpath enthält mit dom4j ...

Nehmen wir an, mein XML ist

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

Nehmen wir an, ich möchte alle Knoten mit ABC im Text finden, wenn das Wurzelelement angegeben ist ...

Also wäre der xpath, den ich schreiben müsste

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

Dies ist jedoch nicht das, was Dom4j zurückgibt. Ist dies ein Dom4j-Problem oder mein Verständnis, wie xpath funktioniert? da diese Abfrage nur das Street-Element und nicht das Comment-Element zurückgibt.

Das DOM macht das Comment-Element zu einem zusammengesetzten Element mit vier Tags zwei

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

Ich würde annehmen, dass die Abfrage immer noch das Element zurückgeben sollte, da es das Element finden und ausführen sollte, das es enthält, aber nicht ... ...

die folgende Abfrage gibt das Element zurück, aber es gibt weit mehr zurück als nur das Element, es gibt auch die übergeordneten Elemente zurück ... was für das Problem unerwünscht ist ...

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

Kennt jemand die xpath-Abfrage, die nur die Elemente <Street/> und <Comment/> zurückgibt?

226
Mike Milkin

Das <Comment> -Tag enthält zwei Textknoten und zwei <br> -Knoten als untergeordnete Elemente.

Dein xpath Ausdruck war

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

Um dies zu brechen,

  1. * ist ein Selektor, der mit jedem Element (d. H. Tag) übereinstimmt - er gibt eine Knotenmenge zurück.
  2. Die [] sind eine Bedingung, die für jeden einzelnen Knoten in diesem Knotensatz gilt. Es stimmt überein, ob einer der einzelnen Knoten, mit denen es arbeitet, den Bedingungen in den Klammern entspricht.
  3. text() ist ein Selektor , der mit allen Textknoten übereinstimmt, die Kinder des Kontextknotens sind - er gibt eine Knotenmenge zurück.
  4. contains ist eine Funktion, die mit einem String arbeitet. Wenn ein Knotensatz übergeben wird, lautet der Knotensatz konvertiert in einen String, indem der String-Wert des Knotens im Knotensatz zurückgegeben wird, der sich zuerst in der Dokumentenreihenfolge befindet . Daher kann es nur mit dem ersten Textknoten in Ihrem <Comment> -Element übereinstimmen - nämlich BLAH BLAH BLAH. Da dies nicht übereinstimmt, erhalten Sie in Ihren Ergebnissen keinen <Comment>.

Sie müssen dies in ändern

//*[text()[contains(.,'ABC')]]
  1. * ist ein Selektor, der mit jedem Element (d. H. Tag) übereinstimmt - er gibt eine Knotenmenge zurück.
  2. Der äußere [] ist eine Bedingung, die für jeden einzelnen Knoten in diesem Knotensatz gilt - hier gilt sie für jedes Element im Dokument.
  3. text() ist ein Selektor , der mit allen Textknoten übereinstimmt, die Kinder des Kontextknotens sind - er gibt eine Knotenmenge zurück.
  4. Der innere [] ist eine Bedingung, die für jeden Knoten in diesem Knotensatz gilt - hier für jeden einzelnen Textknoten. Jeder einzelne Textknoten ist der Ausgangspunkt für jeden Pfad in den Klammern und kann innerhalb der Klammern auch explizit als . bezeichnet werden. Es stimmt überein, ob einer der einzelnen Knoten, mit denen es arbeitet, den Bedingungen in den Klammern entspricht.
  5. contains ist eine Funktion, die mit einem String arbeitet. Hier wird ein einzelner Textknoten übergeben (.). Da der zweite Textknoten im Tag <Comment> einzeln übergeben wird, wird die Zeichenfolge 'ABC' angezeigt und kann mit dieser übereinstimmen.
625
Ken Bloom

[contains(text(),'')] gibt nur true oder false zurück. Es werden keine Elementergebnisse zurückgegeben.

6
Ratna

Es hat eine Weile gedauert, aber endlich herausgefunden. Benutzerdefinierter xpath, der unten Text enthält, funktionierte perfekt für mich.

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

Das XML-Dokument:

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

Der XPath-Ausdruck:

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

//* entspricht einem beliebigen abgeleiteten Element des Wurzelknotens . Das heißt, jedes Element außer dem Wurzelknoten.

[...] ist ein - Prädikat , es filtert die Knotenmenge. Es gibt Knoten zurück, für die ...true ist:

Ein Prädikat filtert eine Knotenmenge, [...] um eine neue Knotenmenge zu erzeugen. Für jeden Knoten in der zu filternden Knotengruppe wird PredicateExpr ausgewertet [...]; Wenn PredicateExpr für diesen Knoten als true ausgewertet wird, wird der Knoten in die neue Knotengruppe aufgenommen. Andernfalls ist es nicht enthalten.

contains('haystack', 'needle') gibt true zurück, wenn haystackenthältneedle:

Funktion: Boolean enthält (String, String)

Die Funktion includes gibt true zurück, wenn die erste Argumentzeichenfolge die zweite Argumentzeichenfolge enthält, andernfalls false.

Aber contains() nimmt einen String als ersten Parameter. Und es ist Knoten übergeben. Um damit umzugehen, wird jeder Knoten oder jede Knotenmenge, die als erster Parameter übergeben wird, von der Funktion string()konvertiert in einen String:

Ein Argument wird wie durch Aufrufen der Funktion string in den Typ string konvertiert.

Die Funktion string() gibt string-value von the first node zurück:

Eine Knotenmenge wird in eine Zeichenfolge konvertiert, indem der Zeichenfolgenwert des Knotens in der Knotenmenge zurückgegeben wird, der sich in der Reihenfolge des Dokuments an erster Stelle befindet. Wenn der Knotensatz leer ist, wird eine leere Zeichenfolge zurückgegeben.

string-value eines Elementknotens :

Der String-Wert eines Elementknotens ist die Verkettung der String-Werte aller Textknotennachkommen des Elementknotens in Dokumentreihenfolge.

string-value eines Textknotens :

Der String-Wert eines Textknotens sind die Zeichendaten.

Grundsätzlich ist string-value der gesamte Text, der in einem Knoten enthalten ist (Verkettung aller untergeordneten Textknoten).

text() ist ein Knotentest, der mit einem beliebigen Textknoten übereinstimmt:

Der Knotentesttext () gilt für jeden Textknoten. Mit child :: text () werden beispielsweise die untergeordneten Textknoten des Kontextknotens ausgewählt.

Vor diesem Hintergrund stimmt //*[contains(text(), 'ABC')] mit jedem Element (außer dem Wurzelknoten) überein, dessen erster Textknoten ABC enthält. Since text() gibt eine Knotenmenge zurück, die alle untergeordneten Textknoten des Kontextknotens enthält (in Bezug auf die ein Ausdruck ausgewertet wird). Aber contains() nimmt nur die erste. Für das obige Dokument entspricht der Pfad dem Street -Element.

Der folgende Ausdruck //*[text()[contains(., 'ABC')]] entspricht einem beliebigen Element (außer dem Stammknoten) mit mindestens einem untergeordneten Textknoten, der ABC enthält. . repräsentiert den Kontextknoten. In diesem Fall handelt es sich um einen untergeordneten Textknoten eines beliebigen Elements außer dem Stammknoten. Für das Dokument oben entspricht der Pfad also den Elementen Street und Comment.

Dann stimmt //*[contains(., 'ABC')] mit jedem Element (außer dem Stammknoten) überein, das ABC enthält (in der Verkettung der untergeordneten Textknoten). Für das obige Dokument entspricht es den Elementen Home, Addr, Street und Comment. Als solches entspricht //*[contains(., 'BLAH ABC')] den Home, den Addr und den Comment Elementen.

0
x-yuri