2009-05-21 25 views
9

Ich habe in dieser Frage sah: Select first instance only with XPath?erste Ergebnis in XPath

Aber wenn ich einen Knoten-Set haben wie folgt aus:


<container value=""> 
    <data id="1"></data> 
    <data id="2">test</data> 
    <container> 
    <data id="1">test</data> 
    <data id="3">test</data> 
    </container> 
</container> 

Jetzt ist mein Szenario, dass dieser Knoten-Set ist tief in einem Dokument, und ich habe einen Zeiger auf den inneren Container. Also muss ich meinen XPath mit "/ container/container" voranstellen (der Pfad ist eigentlich länger, aber für dieses Beispiel sollte das genügen).

EDIT: Was ich will ist ein "Daten" -Knoten mit einer ID von 1, die von der niedrigsten Knoten zuerst oder der nächste Vorfahren kommen sollte. Also, wenn ich es nicht auf dem "aktuellen" (/ container/container) finde, sollte ich mir die Vorfahren anschauen und den nächsten bekommen (oder am Ende nichts finden). Ich habe dies versucht:

/Behälter/Container/Vorfahr-or-self :: Behälter/data [@ id = "1"]

, die ein Ergebnis mit zwei Knoten gesetzt zurück bringt. Ich dachte, ich könnte last() benutzen, um den tiefsten zu bekommen, also habe ich das am Ende geheftet, aber ohne Erfolg.

+0

die Beschreibung mit mehr Klarheit tun könnte. Sie möchten den Datenknoten? Der Datenknoten muss eine ID von 1 haben. Bilden Sie den ursprünglichen Container, wenn der Datenknoten nicht die ID 1 hat. Sie möchten das Dokument in einen übergeordneten Container verschieben, um zu sehen, ob es einen Datenknoten mit der ID 1 hat. Wenn nicht, fahren Sie bis zum Datenknoten mit einer ID fort von 1 wird gefunden. Beschreibt es das? – AnthonyWJones

+0

Ich habe versucht zu beschreiben, was ich gesucht habe, obwohl einige es erraten haben. Es tut uns leid! –

Antwort

5

Wie haben Sie versuchen Anheften auf last()? Ich denke, das sollte funktionieren:

/container/container/ancestor-or-self::container/data[@id="1"][last()] 

EDIT:

natürlich recht, ich habe vergessen, die Klammern:

(/container/container/ancestor-or-self::container/data[@id="1"])[last()] 

Welche dies macht das gleiche wie einer der anderen Antworten; aber, wie das ursprüngliche Plakat weist darauf hin, schlägt dieser Ausdruck auf:

<container value=""> 
    <container> 
    <data id="1">a3</data> 
    <data id="3">a4</data> 
    </container> 
    <data id="1">a1</data> 
    <data id="2">a2</data> 
</container> 

Getreu den Geist der Stackoverflow, ich aber meine Antwort mit einem der anderen Antworten kombinieren und etwas, das in allen Fällen funktioniert:

Übrigens, wenn es mehrere @ id-is-1 < Daten> Kinder von einem Container gibt, wird dies alle zurückgeben.Um wieder nur die erste derartige < Daten> Element:

(/container/container/ancestor-or-self::container[data[@id="1"]])[last()]/data[@id="1"][1] 
+0

Wenn meine hier auf dem gewünschten Ergebnis liest (groß, wenn) das wird nicht funktionieren, weil die letzte() wird auf beiden Zweigen von Vorfahren oder selbst übereinstimmen - das ist die echtes Problem, also müssen Sie die Ergebnismenge entweder früh (wie ich) oder spät (wie Dave) schneiden. – annakata

+0

Dieser tut es. Vielen Dank (alle auch)! –

1

Ich bin nicht 100% klar auf, was Sie fragen, aber wenn ich das richtig gelesen vielleicht wollen Sie nur:

/container/container/ancestor-or-self::container[1]/data[@id='1'] 

Ton der "[1]"

Edit: darüber nachgedacht, ein wenig mehr, und die unten für mich funktioniert für alle bisher Fälle für @ id = $ N genau dort

/container/container/ancestor-or-self::container[data[@id=$N]][1]/data[@id=$N] 

Ziemlich extremen xpathing suchen. Grundsätzlich ist es so, dass der Knotensatz von Ahnen-oder-Selbst die niedrigste Reihenfolge an Position 1 zurückgibt - das ist die gewünschte - aber Sie müssen eine zweite Bedingung setzen, dass der Knoten auch einen Datenknoten hat, an dem Sie interessiert sind. Sobald Sie diese Bedingungen erfüllt haben, haben Sie den richtigen Knoten, jetzt wollen Sie nur weiter zu den eigentlichen Daten tunneln.

99% der Zeit XPath wird einfacher, wenn Sie es auseinander und betrachten Sie es als ein Algorithmus nehmen :)

+0

Ich habe das versucht, aber das deckt nicht jeden Fall ab. Was ist, wenn ich stattdessen nach @ id = '2' suche? Ich möchte die Ergebnisse aus dem aktuellen Knoten vor den Vorfahren bevorzugen, aber in der Lage sein, zurückzufallen. –

+0

Siehe Bearbeiten: Ich glaube, dass deckt alle aufgeführten Fälle – annakata

0

Statt

@id="1" 

haben Sie versucht:

position() == 1 
+0

Wenn position() == 1 funktionieren würde, dann lösche einfach den Ahnen-oder-Selbst :: alle zusammen. Ich denke, die Anforderung ist nicht für irgendeinen ersten Datenknoten, sondern für einen Datenknoten mit einer ID von 1. Die Frage ist nicht so klar wie sie sein könnte. – AnthonyWJones

11

Achten Sie darauf, die last() richtig scoped ist. Versuchen:

(/container/container/ancestor-or-self::container/data[@id="1"])[last()] 

Ähnlich:

//container[last()] 

und:

(//container)[last()] 

sind nicht dasselbe. Der erste gibt den letzten Container-Knoten auf jeder Hierarchieebene zurück - mehrere Übereinstimmungen - und der zweite gibt den letzten gefundenen Container-Knoten zurück - eine Übereinstimmung.

+0

Aha, das hat funktioniert! Vielen Dank. –

+0

Tatsächlich habe ich festgestellt, dass dies nicht funktioniert, wenn der untergeordnete Containerknoten vor einem übereinstimmenden Datenelement angegeben wird. –

+0

@Nick Spacek - Ich habe meine Antwort unten verbessert, und jetzt deckt es sogar diesen Eckfall ab –

0

versuchen [position() = 1]

ab.

/Behälter/Behälter/Vorfahr-or-self :: Container/data [position() = 1]