Используя XPath, как выбрать дядюшку / племянника в том же результате? - PullRequest
0 голосов
/ 04 мая 2020

Давайте предположим следующее XML:

<top>
  <head>
    <node address="some value"></node>
    <othernode key="some other value"></othernode>
    <lower>
      <deepnode key="some value">lorem ipsum dolor</deepnode>
      <evenlower>
        <evendeepernode text="blablabla"></evendeepernode>
      </evenlower>
    </lower>
  </head>
  <head>
    <node address="some value"></node>
    <othernode key="some other value"></othernode>
    <lower>
      <deepnode key="some value">lorem</deepnode>
      <evenlower>
        <evendeepernode text="blablabla"></evendeepernode>
      </evenlower>
    </lower>
  </head>
  <head>
    <node address="some value"></node>
    <othernode key="some other value"></othernode>
    <lower>
      <deepnode key="some value">lorem ipsum dolor</deepnode>
      <evenlower>
        <evendeepernode text="blablabla"></evendeepernode>
      </evenlower>
    </lower>
  </head>
</top>

Затем для каждого head я бы хотел выбрать и node, и deepnode, который содержит слово "ipsum". Меня интересуют только эти 2 узла, то есть я не хочу, чтобы evendeepernode s или othernode s также печатались.

Желаемый результат:

<results>
  <result>
    <node address="some value"></node>
    <lower>
      <deepnode key="some value">lorem ipsum dolor</deepnode>
    </lower>
  </result>
  <result>
    <node address="some value"></node>
    <lower>
      <deepnode key="some value">lorem ipsum dolor</deepnode>
    </lower>
  </result>
</results>

Можно ли это сделать? : -)

Я пробовал что-то подобное, но это не работает:

'/top/*[self::node and self::lower/deepnode[contains(@key="some value",'ipsum')]]'

Ответы [ 3 ]

3 голосов
/ 04 мая 2020

Можно ли это сделать?

Нет, не так, как вы себе это представляете.

XPath - это язык выбора . Он может только выбрать, что там. Например, этот

//node[following-sibling::*[contains(.//deepnode, 'ipsum')]]

выберет два соответствующих <node> элемента:

<node key="some value"></node>

<node key="some value"></node>

И этот

//deepnode[contains(., 'ipsum')]

выберет два соответствующих <deepnode> элемента

<deepnode key="some value">lorem ipsum dolor</deepnode>

<deepnode key="some value">lorem ipsum dolor</deepnode>

Вы даже можете объединить эти два выражения с оператором объединения (expr1|expr2), который будет возвращать четыре узла:

<node key="some value"></node>

<deepnode key="some value">lorem ipsum dolor</deepnode>

<node key="some value"></node>

<deepnode key="some value">lorem ipsum dolor</deepnode>

Но это все равно не похоже на вывод документ, который вы предлагаете. XPath не может создавать документы. Он может предоставить вам списки узлов, которые соответствуют определенным критериям.

То, что вы хотите - это преобразовать входные данные XML во что-то еще. Это можно сделать, например, с помощью XSLT или XQuery, или с помощью ручной сборки DOM на любом языке программирования хоста, который поддерживает XML.

1 голос
/ 04 мая 2020

Чтобы выбрать (только для выбора) ваши узлы, предполагая, что //head является вашим контекстным узлом, вы можете использовать:

.//*[name()="deepnode" and string(@key)='some value' and contains(.,"ipsum") or name()="node" and string(@key)='some value' and following::deepnode[1][contains(.,"ipsum")]]

или короче:

.//*[position()=1 and parent::head and following::deepnode[1][@key="some value" and contains(.,"ipsum")] or contains(text(),"ipsum")]

Выход: 4 узлы.

0 голосов
/ 04 мая 2020

Используя ваш пример:

//*[@key="some value" and contains(.,"ipsum")]

В вашем примере 'node' и 'deepnode' имеют один и тот же ключ, поэтому вы можете проверить, что ключ правильный, а затем проверить, что он содержит "ipsum".

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