webentwicklung-frage-antwort-db.com.de

XPath, um das nächstgelegene Vorfahrenelement zu finden, das ein Element enthält, das ein Attribut mit einem bestimmten Wert hat

ancestor::foo[bar[@attr="val"]]

Ich dachte, das würde funktionieren, aber es ist nicht so. Ich muss das nächstgelegene foo-Element finden, das in der Baumstruktur aufsteigt und ein bar-untergeordnetes Element enthält, das wiederum das attr-Attribut von val hat.

18
Core Xii

Das sollte funktionieren:

//*[ancestor::foo[bar[@attr="val"]]]

oder alternativ

root/foo/bar[ancestor::foo[bar[@attr="val"]]]

stimmt mit dem zweiten <bar> Element überein

<root>
    <foo>
        <bar attr="xxx"></bar>
    </foo>
    <foo>
        <bar attr="val"></bar>
    </foo>
    <foo>
        <bar attr="zzz"></bar>
    </foo>
</root>
30
Gordon

Aktualisiert, um eine von OP beabsichtigte Lösung widerzuspiegeln.

Siehe @ Davids Antwort

Für eine Beispiel-XML unten

<root>
<foo id="0">
    <bar attr="val"/>
    <foo id="1">
        <bar attr="xxx"/>
    </foo>
    <foo id="2">
        <bar attr="val">
            <one>1</one>
            <two>
                <three>3</three>
            </two>
        </bar>
    </foo>
</foo>

ein gültiger xpath auf der umgekehrten Achse mit <drei> als Kontextknoten ist eine gültige Lösung

./ancestor::foo[bar[@attr='val']][position() = 1]

"./" es ist optional. position () = 1 ist nicht optional, da sonst auch der Vorgänger foo, der die Prädikate erfüllt, zurückgegeben wird.

Alte Antwort: ignorieren

Das ist eine alte Frage. aber wer interessiert ist, sollte das Folgende bekommen, was die ursprüngliche Frage beabsichtigte.

Achse umkehren

//bar[@attr='val']/ancestor::*[position()=1]

Vorwärtsachse

//*[child::bar[@attr='val']]
11
santon

Meiner Meinung nach wurde die beste Antwort von der Person gegeben, die die Frage gestellt hat. Seine Lösung sollte alle Ahnenfos zurückgeben. Er möchte nur den nächsten, der mit position () = 1 ist, daher muss sein Xpath-Ausdruck leicht geändert werden:

ancestor::foo[bar[@attr="val"] and position() = 1]

Wenn er schreibt, dass der ancestor::foo[bar[@attr="val"]] nichts zurückgegeben hat, hatte er ein anderes Problem in seiner XML-Datei oder in seiner Annahme über das aktuelle Element seines XPath-Evaluierungskontexts.

Die anderen Antworten (beginnend mit //) beantworten die Frage nicht wirklich und auch wenn sie zufällig auf jemanden gestoßen sind, sind sie nicht effizient: Sie wählen ALLE Elemente in der XML-Datei und wenden anschließend einen Filter an Während das, was der relative xpath, der von mir oder von der Person, die diese Frage gestellt hat, vorgeschlagen wurde, nur wenige Elemente durchsucht, angefangen vom aktuellen Knoten bis zum Elternteil und dessen Elternteil usw., ist dies selbst mit sehr effizient große XML-Dateien.

1
David L.

Wenn Sie eine Datei wie diese haben:

<root>                                                                                                             
<foo id="0">                                                                                                       
    <foo id="1">                                                                                                   
        <bar attr="xxx" />                                                                                         
    </foo>                                                                                                         
    <foo id="2">                                                                                                   
        <bar attr="val" />                                                                                         
    </foo>                                                                                                         
    <foo id="3">                                                                                                   
        <tar>                                                                                                      
            <bar attr="val" />                                                                                     
        </tar>                                                                                                     
    </foo>                                                                                                         
</foo>                                                                                                             
</root>

und Sie möchten, dass die foo-Knoten mit den IDs 2 und 3, d. h. die foos, die ihren bar-Nachkommen mit attr=val am nächsten ist, wie folgt funktionieren:

//foo[descendant::bar[@attr="val"] and not(descendant::foo)]

Wenn Sie and not(descendant::foo) weglassen, erhalten Sie zusätzlich das foo mit der ID 0.

Die anderen Antworten funktionierten für mich im allgemeinen Fall meines Beispiels nicht.

Sie können es in Python testen mit:

from lxml import etree
tree = etree.parse('example.xml')
foos = tree.xpath('//foo[descendant::bar[@attr="val"] and not(descendant::foo)]')
for foo in foos:
    print(foo.attrib)

welche druckt:

{'id': '2'}
{'id': '3'}

Beachten Sie, dass der verwendete xpath nicht effizient ist. Ich würde gerne eine effizientere lernen.

0
Ivan Ogai