2013-11-19 4 views
3

У меня есть xml;Найти родительский узел без корня, где дочерний элемент содержит текст

<root> 
    <parent> 
     <child>foo987654</child> 
    </parent> 
    <parent> 
     <child>bar15245</child> 
    </parent> 
    <parent> 
     <child>baz87742</child> 
    </parent> 
    <parent> 
     <child>foo123456</child> 
    </parent> 
</root> 

Я использую питон и модуль etree, и я хотел бы, чтобы выбрать все узлы <parent> которых ребенок начинает с «Foo». Я знаю, что у etree ограниченная поддержка xpath, но я новичок в xpath, поэтому я стараюсь приземлиться на лучшее решение. Я думаю, что что-то по этому поводу

parent[(contains(child,'foo'))] 

, но я хотел бы отказаться от родительских узлов, содержащих Foo, но не начинаются с Foo (т.е. <child>125456foo</child>), поэтому я не уверен, что это будет работать. Кроме того, я не уверен, что etree поддерживает этот уровень ... XPath

EDIT:

Другим приемлемым решением было бы выбрать родителей, чьи детские текст в списке. псевдо-код parent => child [text = "foo1" || "bar1" || "bar2"]

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

ответ

3

Это позволит получить то, что вы хотите:

[elem for elem in root.findall('parent') if elem.find('child').text.startswith('foo')] 

Смотреть в действии:

s = """<root> 
    <parent> 
     <child>foo987654</child> 
    </parent> 
    <parent> 
     <child>bar15245</child> 
    </parent> 
    <parent> 
     <child>baz87742</child> 
    </parent> 
    <parent> 
     <child>foo123456</child> 
    </parent> 
</root>""" 

import xml.etree.ElementTree as ET 

root = ET.fromstring(s) 
elems = [elem for elem in root.findall('parent') if elem.find('child').text.startswith('foo')] 

Проверка данных:

for elem in elems: 
    print elem.find('child').text 
>>> 
foo987654 
foo123456 
+0

NINJA! Я предполагаю, что это будет чувствительно к регистру, да? – Brad

+0

@Brad XML действительно чувствителен к регистру. –

+3

@Brad: Вы позвонили? –

0

Как вы можете видеть из xml.etree documentation, эта библиотека не поддерживает оператора от XPath. Мое предложение состояло в том, чтобы выбрать всех детей с XPath /parent, а затем итерации по каждому результату, чтобы удалить контент для детей, который не начинается с foo.

+0

Есть ли чистое решение xpath без необходимости делать дополнительные итерации и удалять узлы? – Brad

+0

Использование xml.etree? Конечно, не похоже. –

+0

Я бы предложил использовать библиотеку [lxml] (http://lxml.de/xpathxslt.html#xpath), если вы хотите выполнить это, используя чисто выражение XPath, без какой-либо другой операции. –

0

с XPath

import lxml.html 
doc = lxml.html.document_fromstring(s) 
for e in doc.xpath(".//child[starts-with(text(), 'foo')]"): 
    print e.text 
Смежные вопросы