XPath для выбора нескольких тегов - PullRequest
115 голосов
/ 06 апреля 2009

Учитывая этот упрощенный формат данных:

<a>
    <b>
        <c>C1</c>
        <d>D1</d>
        <e>E1</e>
        <f>don't select this one</f>
    </b>
    <b>
        <c>C2</c>
        <d>D2</d>
        <e>E1</e>
        <g>don't select me</g>
    </b>
    <c>not this one</c>
    <d>nor this one</d>
    <e>definitely not this one</e>
</a>

Как бы вы выбрали все C s, D s и E s, которые являются дочерними элементами B элементов?

В основном, что-то вроде:

a/b/(c|d|e)

В моей собственной ситуации вместо a/b/ запрос, ведущий к выбору этих C, D, E узлов, на самом деле довольно сложный, поэтому я бы хотел избежать этого:

a/b/c|a/b/d|a/b/e

Возможно ли это?

Ответы [ 4 ]

187 голосов
/ 06 апреля 2009

Один правильный ответ: :

/a/b/*[self::c or self::d or self::e]

Обратите внимание, что это

a/b/*[local-name()='c' or local-name()='d' or local-name()='e']

слишком длинный и неправильный . Это выражение XPath выберет такие узлы, как:

OhMy:c

NotWanted:d 

QuiteDifferent:e
42 голосов
/ 06 апреля 2009

Вы можете избежать повторения с помощью атрибута test вместо:

a/b/*[local-name()='c' or local-name()='d' or local-name()='e']

Вопреки антагонистическому мнению Димитра, вышеприведенное не является неправильным в вакууме, когда OP не определил взаимодействие с пространствами имен. Ось self:: ограничивает пространство имен, local-name() - нет. Если OP намерен захватить c|d|e независимо от пространства имен (что я бы даже предположил, это вероятный сценарий, учитывая природу проблемы ИЛИ), то это «другой ответ, у которого все еще есть положительные голоса», что неверно.

Вы не можете быть окончательным без определения, хотя я очень рад исключить мой ответ как действительно неправильный, если ОП разъясняет его вопрос так, что я ошибаюсь.

13 голосов
/ 30 марта 2011

Почему бы не a/b/(c|d|e)? Я только что попробовал с Saxon XML-библиотеку (хорошо завернутую с некоторой добротой Clojure), и это, похоже, работает. abc.xml - документ, описанный ОП.

(require '[saxon :as xml])
(def abc-doc (xml/compile-xml (slurp "abc.xml")))
(xml/query "a/b/(c|d|e)" abc-doc)
=> (#<XdmNode <c>C1</c>>
    #<XdmNode <d>D1</d>>
    #<XdmNode <e>E1</e>>
    #<XdmNode <c>C2</c>>
    #<XdmNode <d>D2</d>>
    #<XdmNode <e>E1</e>>)
0 голосов
/ 06 апреля 2009

Не уверен, что это поможет, но с XSL я бы сделал что-то вроде:

<xsl:for-each select="a/b">
    <xsl:value-of select="c"/>
    <xsl:value-of select="d"/>
    <xsl:value-of select="e"/>
</xsl:for-each>

и этот XPath не выберет все дочерние элементы узлов B:

a/b/*
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...