У меня есть следующий xml документ:
<node0>
<node1>
<node2 a1="x1"> ... </node2>
<node2 a1="x2"> ... </node2>
<node2 a1="x1"> ... </node2>
</node1>
</node0>
Я хочу отфильтровать node2
когда a1="x2"
. Пользователь обеспечивает xpath и значения атрибута, для которых нужно к протестированному и отфильтрованному. Я посмотрел на некоторые решения в Python как BeautifulSoup, но они являются слишком сложными и не сохраняют случай текста. Я хочу сохранить документ тем же как прежде с некоторым материалом отфильтрованный.
Можно ли рекомендовать простое и сжатое решение? Это не должно быть слишком сложно от взглядов его. Фактический xml документ не так прост как выше но идея является тем же.
Здесь используется 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
, которого нет в стандартной библиотеке, но есть более мощный синтаксис :
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>
Изменить: Если 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)