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?


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()

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


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']

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.


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


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.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.