используя регулярное выражение с xml2?

Рассмотрим этот простой пример

example_xml <- '<?xml version="1.0" encoding="UTF-8"?>
<file>
<book>
<text>abracadabra</text>
<node></node>
</book>
<book>
<text>hello world</text>
<node></node>
</book>
</file>'

myxml <- xml2::read_xml(example_xml)

Теперь это работает, как и ожидалось.

> myxml %>% xml_find_all('//book')
{xml_nodeset (2)}
[1] <book>\n  <text>abracadabra</text>\n  <node/>\n</book>
[2] <book>\n  <text>hello world</text>\n  <node/>\n</book>

но поиск узлов, атрибут text которых содержит wor, не содержит.

> myxml %>% xml_find_all('//book[contains(@text, "wor")]')
{xml_nodeset (0)}

В чем проблема? Как я могу использовать регулярное выражение (или частичное сопоставление строк) с xml2?

Спасибо!


person ℕʘʘḆḽḘ    schedule 07.02.2018    source источник
comment
У вас нет текстовых атрибутов. У вас есть text узлов внутри book узлов. Попробуйте xml_find_all('//book/text[contains(., "wor")]')   -  person Wiktor Stribiżew    schedule 08.02.2018
comment
оооо спасибо, но что это за сумасшедший синтаксис [contains(. с точкой?   -  person ℕʘʘḆḽḘ    schedule 08.02.2018
comment
text — это узел, а не атрибут, поэтому @ не нужен.   -  person Parfait    schedule 08.02.2018
comment
См. этот ответ, чтобы узнать больше о разнице между text() и .. Кстати, может быть, вам нужно xml_find_all(myxml, '//book[contains(., "wor")]')? Результат равен [1] <book>\n <text>hello world</text>\n <node/>\n</book>, а решение для верхнего комментария дает [1] <text>hello world</text>.   -  person Wiktor Stribiżew    schedule 08.02.2018
comment
Я бы опубликовал это как ответ. это интересно еще раз спасибо!   -  person ℕʘʘḆḽḘ    schedule 08.02.2018


Ответы (1)


//book[contains(@text, "wor")] XPath находит book узлов, которые содержат атрибут text (@ указывает атрибут), которые содержат wor в своих значениях.

Ваш XML не содержит таких элементов, как <book text="Hello world">Title</book>, поэтому результатов нет.

Вы можете получить узлы книги, которые содержат wor в своих текстовых узлах, используя

> xml_find_all(myxml, '//book[contains(., "wor")]')
{xml_nodeset (1)}
[1] <book>\n  <text>hello world</text>\n  <node/>\n</book>

Если вас устраивает только text узлов в качестве возвращаемых значений, вы можете использовать

> xml_find_all(myxml, '//book/text[contains(., "wor")]')
{xml_nodeset (1)}
[1] <text>hello world</text>

Если вам нужно получить всех родителей book, содержащих любые дочерние узлы с текстом wor внутри, используйте

> xml_find_all(myxml, '//*[contains(., "wor")]/parent::book')
{xml_nodeset (1)}
[1] <book>\n  <text>hello world</text>\n  <node/>\n</book>

См. этот ответ, чтобы узнать больше о разнице между text() и .. Короче говоря, [contains(., "wor")] возвращает true, если строковое значение элемента содержит wor.

person Wiktor Stribiżew    schedule 07.02.2018
comment
удивительно. просто вопрос вдогонку. Как я могу получить все родительские узлы узлов, содержащих wor? - person ℕʘʘḆḽḘ; 08.02.2018
comment
@ℕʘʘḆḽḘ Ты имеешь в виду xml_find_all(myxml, '//*[contains(., "wor")]/parent::book')? Смотрите мою правку с тестом. - person Wiktor Stribiżew; 08.02.2018