Jak wybrać węzeł za pomocą XPath, jeśli węzeł siostrzany ma określoną wartość?

88

Mam następujący dokument:

<a>
  <bb>abc</bb>
  <cc>ccc</cc>
  <dd>ddd</dd>
</a>
<a>
  <bb>zz</bb>
  <cc>1</cc>
  <dd>2</dd>
</a>

Jak mogę uzyskać korzyści z <cc>używania XPath, jeśli tak <bb>jest zz?

HOE SENGKIANG
źródło
1
Problem polega na tym, że wiem, jak uzyskać dostęp do określonego węzła, ale nie mam pojęcia, jak uzyskać dostęp do węzła, jeśli rodzeństwo ma określoną wartość. Czy może to być coś takiego / a / cc / zawiera (/ a / bb = 'zz')?
HOE SENGKIANG

Odpowiedzi:

100

Nie jesteś pewien, dlaczego wszyscy pytają o rodzeństwo, możesz również sprawdzić <bb/>-elementy pasujące do predykatu z <a/>predykatu:

//a[bb/text() = "zz"]/cc/text()
Jens Erat
źródło
24
„Nie wiem, dlaczego wszyscy pytają o rodzeństwo” : Być może dlatego, że pytanie dotyczyło rodzeństwa .. ;-)
hr_117
4
Wygląda na to, że nie przeczytałem tytułu. :) Odpowiedź i tak pozostaje aktualna.
Jens Erat
2
Twoja odpowiedź dotyczy również rodzeństwa. Po prostu nie użyłeś *-siblingosi. Jednak +1.
LarsH
To nie odpowiada na pytanie, ale odpowiada na moje rzeczywiste pytanie, które źle sformułowałem. Dziękuję Ci!
User9213
37

Potrzebujesz following-siblingosi XPath

//a/bb[text()="zz"]/following-sibling::cc[1]/text()

Przetestuj Xpath tutaj: http://www.xpathtester.com/obj/b55ec3ac-dfa4-4f44-81e8-f963ea4a0625

Stanley
źródło
4
@HOESENGKIANG: należy kliknąć znacznik wyboru, aby „zaakceptować” tę odpowiedź, lub taką, która Twoim zdaniem najlepiej odpowiada na pytanie.
LarsH
23

P: Jak wybrać węzeł za pomocą XPath, jeśli węzeł siostrzany ma określoną wartość?
Ponieważ istnieją tylko „osie XPath” dla następującego rodzeństwa i poprzedniego rodzeństwa, możesz użyć jednego z nich, jeśli pozycja jest ustalona.

Ale lepiej: poszukaj cc, czy rodzic ma dziecko bbz wartością 'zz':

//cc[../bb='zz']
hr_117
źródło
6
Albo to, albo //a[bb = 'zz']/cc.
Tomalak
Nie jestem pewien, co masz na myśli, mówiąc „tylko„ osie XPath ”dla podążającego i poprzedzającego rodzeństwa”. Czy masz na myśli fakt, że nie ma jednej osi dla całego rodzeństwa?
LarsH
@LarsH: Tak, przepraszam, (przepraszam za mój zły angielski :-() - to właśnie chciałem powiedzieć (ponieważ pytanie było dla rodzeństwa)
hr_117
6

Po pierwsze, twój przykład nie jest dobrze sformułowanym XML. Pomijając to i że nie opisałeś zbyt dobrze swoich zamiarów (co dokładnie chcesz wybrać, pod jakim warunkiem?), Zakładam, że chcesz to zrobić:

//cc[preceding-sibling::bb[text()="zz"]]/text()

To wybiera

TEXT VALUES OF ALL <CC> ELEMENTS
//cc                                    /text()
    THAT HAVE A PRECEDING SIBLING <BB>
    [preceding-sibling::bb             ]
                          THAT HAS TEXT VALUE EQUAL TO "zz"
                          [text()="zz"]

Możesz również napisać jako

//bb[text()="zz"]/following-sibling::cc/text()

Proszę spojrzeć na specyfikację , zawiera kilka bardzo czytelnych przykładów, z których wiele się nauczysz.

Petr Janeček
źródło
1
@LarsH Dzięki za poprawkę z „niepoprawny” na „niepoprawny”. Nauczyłem się dziś czegoś nowego.
Petr Janeček
4
//a/cc[../bb='zz']/text()

// a: wybiera wszystkie elementy „a” bez względu na to, gdzie się znajdują.

// a / cc: wybiera elementy „cc”, które są dziećmi elementu „a” (bez względu na to, gdzie jest).

..: Wybiera rodzica bieżącego węzła.

[../bb='zz ']: gdzie wartość siostrzanego elementu „bb” to zz.

Źródła: http://www.w3schools.com/xsl/xpath_syntax.asp

Bae Cheol Shin
źródło
4

Innym rozwiązaniem tego problemu jest

//bb[contains(.,'zz')]/../cc/text()

Objaśnienie : Każdy, bbktóry zawiera 'zz'ciąg we wszystkich węzłach potomnych, bba następnie przechodzi do węzła nadrzędnego tego bbza pomocą .., teraz, gdy możemy uzyskać dostęp do cctak zwracanego tekstu.

Mam nadzieję, że to wyjaśnienie nie jest skomplikowane.

Saleh Mahmood
źródło