Как выбрать узел с помощью XPath, если родственный узел имеет определенное значение?

88

У меня есть следующий документ:

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

Как я могу получить пользу от <cc>использования XPath, если <bb>это так zz?

HOE SENGKIANG
источник
1
проблема в том, что я знаю, как получить доступ к конкретному узлу, но я понятия не имею, как получить доступ к узлу, если у родного брата есть определенное значение. Может ли это быть что-то вроде этого / a / cc / contains (/ a / bb = 'zz')?
HOE SENGKIANG

Ответы:

100

Не уверен, почему все запрашивают братьев и сестер, вы также можете проверить <bb/>-элементы, соответствующие предикату из <a/>предиката:

//a[bb/text() = "zz"]/cc/text()
Йенс Эрат
источник
24
«Не уверен, почему все спрашивают братьев и сестер» : Возможно, потому что вопрос был к брату или
сестре
4
Кажется, я действительно не читал название. :) Ответ остается действительным.
Jens Erat
2
Ваши ответы на вопросы для братьев и сестер тоже. Вы просто не использовали *-siblingось. +1 хотя.
LarsH,
Это не отвечает на вопрос, но отвечает на мой вопрос, который я сформулировал неправильно. Спасибо!
User9213
37

Вам нужна following-siblingось XPath

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

Протестируйте Xpath здесь: http://www.xpathtester.com/obj/b55ec3ac-dfa4-4f44-81e8-f963ea4a0625

Стэнли
источник
4
@HOESENGKIANG: вы должны щелкнуть галочку, чтобы «принять» этот ответ, или тот, который, по вашему мнению, лучше всего отвечает на вопрос.
LarsH
23

Вопрос: Как выбрать узел с помощью XPath, если у родственного узла есть определенное значение?
Поскольку существуют только «оси XPath» для следующих и предшествующих братьев и сестер, вы можете использовать одну из них, если положение фиксировано.

Но лучше: посмотрите, есть ли ccу родителя дочерний элемент bbсо значением 'zz':

//cc[../bb='zz']
hr_117
источник
6
Либо так, либо //a[bb = 'zz']/cc.
Tomalak
Не уверен, что вы имеете в виду под «только« XPath Axes »для следующих и предыдущих братьев и сестер». Вы имеете в виду тот факт, что не существует единой оси для всех братьев и сестер?
LarsH
@LarsH: Да, извините, (извините за плохой английский :-() - это то, что я пытался сказать. (Потому что вопрос был для братьев и сестер.)
hr_117
6

Во-первых, ваш пример не является правильно сформированным XML. Не обращая внимания на это и на то, что вы не очень хорошо описали свои намерения (что именно вы хотите выбрать при каком условии?), Я предполагаю, что вы хотите сделать это:

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

Он выбирает

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

Вы могли бы написать также как

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

Пожалуйста, посмотрите на спецификацию , там есть несколько очень хорошо читаемых примеров, из которых вы многому научитесь.

Петр Янечек
источник
1
@LarsH Спасибо за исправление с "недействительно" на "не правильно сформировано". Сегодня я узнал кое-что новое.
Петр Янечек
4
//a/cc[../bb='zz']/text()

// a: выбирает все элементы 'a' независимо от того, где они находятся.

// a / cc: выбирает элементы 'cc', которые являются дочерними элементами элемента 'a' (независимо от того, где находится a).

..: Выбирает родителя текущего узла.

[../bb='zz ']: где значение родственного элемента' bb 'равно zz.

Ссылка: http://www.w3schools.com/xsl/xpath_syntax.asp

Пэ Чхоль Шин
источник
4

Другое решение этой проблемы -

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

Объяснение : Любой, bbкоторый содержит 'zz'строку во всех дочерних узлах, bbзатем переходит к родительскому узлу того, что bbиспользует .., теперь, когда мы можем получить доступ кcc так возвращаемому тексту.

Надеюсь, это объяснение несложно.

Салех Махмуд
источник