2010-05-19 8 views
4

У меня есть следующий XML-документ:XML фильтрации с питоном

<node0> 
    <node1> 
     <node2 a1="x1"> ... </node2> 
     <node2 a1="x2"> ... </node2> 
     <node2 a1="x1"> ... </node2> 
    </node1> 
</node0> 

Я хочу, чтобы отфильтровать node2 при a1="x2". Пользователь предоставляет значения xpath и атрибуты, которые необходимо протестировать и отфильтровать. Я смотрел на некоторые решения в python, такие как BeautifulSoup, но они слишком сложны и не сохраняют случай с текстом. Я хочу сохранить документ таким же, как и раньше, с некоторыми фильтрами.

Можете ли вы порекомендовать простое и сжатое решение? Это не должно быть слишком сложным из-за его внешнего вида. Фактический XML-документ не так прост, как указано выше, но идея такая же.

+1

Ваш XML документ не хорошо сформирован. В нем отсутствуют некоторые символы «/». – BoltBait

ответ

6

Это использует xml.etree.ElementTree, который находится в стандартной библиотеке:

import xml.etree.ElementTree as xee 
data='''\ 
<node1> 
    <node2 a1="x1"> ... </node2> 
    <node2 a1="x2"> ... </node2> 
    <node2 a1="x1"> ... </node2> 
</node1> 
''' 
doc=xee.fromstring(data) 

for tag in doc.findall('node2'): 
    if tag.attrib['a1']=='x2': 
     doc.remove(tag) 
print(xee.tostring(doc)) 
# <node1> 
# <node2 a1="x1"> ... </node2> 
# <node2 a1="x1"> ... </node2> 
# </node1> 

Это использует lxml, который не находится в стандартной библиотеке, но имеет a more powerful syntax:

import lxml.etree 
data='''\ 
<node1> 
    <node2 a1="x1"> ... </node2> 
    <node2 a1="x2"> ... </node2> 
    <node2 a1="x1"> ... </node2> 
</node1> 
''' 
doc = lxml.etree.XML(data) 
e=doc.find('node2/[@a1="x2"]') 
doc.remove(e) 
print(lxml.etree.tostring(doc)) 

# <node1> 
# <node2 a1="x1"> ... </node2> 
# <node2 a1="x1"> ... </node2> 
# </node1> 

Edit: Если node2 более глубоко погружается в xml, затем вы можете проходить через все теги, проверять каждый родительский тег, чтобы увидеть, является ли элемент node2 одним из его дочерних элементов , И удалить его, если так:

Использование только xml.etree.ElementTree:

doc=xee.fromstring(data) 
for parent in doc.getiterator(): 
    for child in parent.findall('node2'): 
     if child.attrib['a1']=='x2': 
      parent.remove(child) 

Использование LXML:

doc = lxml.etree.XML(data) 
for parent in doc.iter('*'): 
    child=parent.find('node2/[@a1="x2"]') 
    if child is not None: 
     parent.remove(child) 
+0

Я понял, что это не сработает, когда node2 находится внутри. Я могу найти тег, используя doc.findAll ('node1/node2'), но я не могу удалить его из doc. Какие-либо предложения? – user236215

+0

@saminny, я добавил код, показывающий, как справиться с этой ситуацией. – unutbu

+0

Это работает отлично. Вы гений :) – user236215

Смежные вопросы