Filtrado de Python Elementtree por XPath

Sep 04 2020

imagina que tengo un XML como este:

<root>
  <elements>
    <element> foo </element>
    <element is="false"> foo </element>
    <element is="false"> bli </element>
    <element is="false"> bla </element>
  </elements>
</root>

Cómo puedo hacer esto:

import xml.etree.ElementTree as ET

root = ET.fromstring(XmlFromAbove)
res_a  = root.findall("element[@is='false']")) ##<- This gives me all elements with the specific attribute
res_b  = root.findall("element[not@is='false']")) ##<- This would be nice to give me all elements without that specific attribute (`<element> foo </element>` in this case)

Ahora, sé que res_bno funcionará, pero supongo que este es un problema común, por lo que alguien tiene una idea de cuál es la solución alternativa.

Para señalarlo un poco más (copiado de los comentarios)

Podría encontrar el elemento que contiene "foo" con seguridad, pero lo que quiero saber es si hay una manera de encontrar cualquier elemento que NO contenga el atributo es = "falso".

Respuestas

2 balderman Sep 04 2020 at 17:10

vea abajo

import xml.etree.ElementTree as ET

xml = '''<root>
  <elements>
    <element> foo </element>
    <element is="false"> foo </element>
    <element is="false"> bli </element>
    <element is="false"> bla </element>
    <element please="false"> no_is </element>
    <element is="true"> with_true_is </element>
  </elements>
</root>'''

root = ET.fromstring(xml)

no_is_lst = [e for e in root.findall('.//element') if 'is' not in e.attrib]
for e in no_is_lst:
    print(e.text)

salida

 foo 
 no_is 
deadshot Sep 04 2020 at 16:59

Puedes usar lxml

from lxml import etree

root = etree.fromstring(data)
res = root.xpath(".//element[not(@is)]")

print(res[0].text) #foo