ElementTree XPath - Seleccionar elemento basado en atributo
-
03-07-2019 - |
Pregunta
Tengo problemas para usar el atributo XPath Selector en ElementTree, que debería poder hacer de acuerdo con Documentación
Aquí hay un código de muestra
XML
<root>
<target name="1">
<a></a>
<b></b>
</target>
<target name="2">
<a></a>
<b></b>
</target>
</root>
Python
def parse(document):
root = et.parse(document)
for target in root.findall("//target[@name='a']"):
print target._children
Recibo la siguiente excepción:
expected path separator ([)
Solución
La sintaxis que está intentando usar es nueva en ElementTree 1.3 .
Dicha versión se envía con Python 2.7 o superior. Si tiene Python 2.6 o menos, todavía tiene ElementTree 1.2.6 o menos.
Otros consejos
Hay varios problemas en este código.
-
El buildT ElementTree (ET para abreviar) de Python no tiene soporte XPATH real; solo un subconjunto limitado Por ejemplo, no admite expresiones find-from-root como
// target
.Aviso: la documentación menciona " // " ;, pero solo para niños: una expresión como
.//target
es válido;// ...
no lo esHay una implementación alternativa: lxml , que es más rica. Parece que se usa documentación para el código incorporado. Eso no coincide / funciona.
-
La notación
@name
selecciona xml- atributos ; la expresiónkey = value
dentro de una etiqueta xml.Entonces, ese nombre-valor debe ser 1 o 2 para seleccionar algo en el documento dado. O bien, uno puede buscar objetivos con un elemento secundario 'a' :
target [a]
(no @).
Para el documento dado, analizado con el ElementTree incorporado (v1.3) a la raíz, el siguiente código es correcto y funciona:
-
root.findall (" .// target ")
Encuentra ambos objetivos -
root.findall (" .// target / a ")
Encuentra dos elementos a -
root.findall (" .// target [a] ")
Esto vuelve a encontrar ambos elementos de destino, ya que ambos tienen un elemento a -
root.findall (" .// target [@ name = '1'] ")
Encuentre solo el first target. Observe que se necesitan las comillas alrededor de 1; de lo contrario, se genera un SyntaxError -
root.findall (" .// target [a] [@ name = '1'] ")
También válido; para encontrar ese objetivo -
root.findall (" .// target [@ name = '1'] / a ")
Encuentra solo un elemento a; ...