Domanda

Ho un documento XML seguente:

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

Voglio filtrare node2 quando a1="x2". L'utente fornisce i valori di attributo XPath e che devono testato e filtrati. Ho guardato alcune soluzioni in pitone come BeautifulSoup ma sono troppo complicate e non lo conservo caso del testo. Voglio mantenere il documento stesso di prima con alcune cose filtrato.

Mi può consigliare un semplice e la soluzione succinta? Questo non dovrebbe essere troppo complicato dagli sguardi di esso. Il documento XML reale non è così semplice come sopra ma l'idea è la stessa.

È stato utile?

Soluzione

Questa usi xml.etree.ElementTree che si trova nella libreria standard:

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>

Questa usi lxml, che non è nella libreria standard, ma ha un più potente sintassi :

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>

Modifica Se node2 è sepolto più profondamente nel xml, quindi è possibile scorrere tutte le etichette, controllare ogni tag principale per vedere se l'elemento node2 è uno dei suoi figli, e la rimozione se così:

Utilizzando solo 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)

Utilizzando 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)
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top