Quiero utilizar el método de "findall" para localizar algunos elementos del archivo xml de origen en el módulo ElementTree.
Sin embargo, el archivo xml de origen (test.xml) tiene espacio de nombres. Trunco parte del archivo xml como muestra:
<?xml version="1.0" encoding="iso-8859-1"?>
<XML_HEADER xmlns="http://www.test.com">
<TYPE>Updates</TYPE>
<DATE>9/26/2012 10:30:34 AM</DATE>
<COPYRIGHT_NOTICE>All Rights Reserved.</COPYRIGHT_NOTICE>
<LICENSE>newlicense.htm</LICENSE>
<DEAL_LEVEL>
<PAID_OFF>N</PAID_OFF>
</DEAL_LEVEL>
</XML_HEADER>
El código de Python de muestra está abajo:
from xml.etree import ElementTree as ET
tree = ET.parse(r"test.xml")
el1 = tree.findall("DEAL_LEVEL/PAID_OFF") # Return None
el2 = tree.findall("{http://www.test.com}DEAL_LEVEL/{http://www.test.com}PAID_OFF") # Return <Element '{http://www.test.com}DEAL_LEVEL/PAID_OFF' at 0xb78b90>
Aunque puede funcionar, porque hay un espacio de nombres "{http://www.test.com}", es muy inconveniente agregar un espacio de nombres frente a cada etiqueta.
¿Cómo puedo ignorar el espacio de nombres cuando uso el método de "buscar", "findall", etc.
python
namespaces
find
elementtree
findall
KevinLeng
fuente
fuente
tree.findall("xmlns:DEAL_LEVEL/xmlns:PAID_OFF", namespaces={'xmlns': 'http://www.test.com'})
suficientemente conveniente?tree.findall("{0}DEAL_LEVEL/{0}PAID_OFF".format('{http://www.test.com}'))
Respuestas:
En lugar de modificar el documento XML en sí, es mejor analizarlo y luego modificar las etiquetas en el resultado. De esta manera puede manejar múltiples espacios de nombres y alias de espacios de nombres:
Esto se basa en la discusión aquí: http://bugs.python.org/issue18304
Actualización: en
rpartition
lugar departition
asegurarse de obtener el nombre de la etiquetapostfix
incluso si no hay espacio de nombres. Así podrías condensarlo:fuente
et.findall('{*}sometag')
. Y también está destruyendo el árbol de elementos en sí, no solo "realiza la búsqueda ignorando los espacios de nombres en este momento, sin volver a analizar el documento, etc., conservando la información del espacio de nombres". Bueno, para ese caso, es necesario que recorras el árbol y compruebes por ti mismo si el nodo coincide con tus deseos después de eliminar el espacio de nombres.Si elimina el atributo xmlns del xml antes de analizarlo, entonces no habrá un espacio de nombres antepuesto a cada etiqueta en el árbol.
fuente
=
signo igual.Las respuestas hasta ahora ponen explícitamente el valor del espacio de nombres en el script. Para una solución más genérica, prefiero extraer el espacio de nombres del xml:
Y úsalo en el método de búsqueda:
fuente
namespace
Aquí hay una extensión de la respuesta de nonagon, que también elimina los espacios de nombres de los atributos:
ACTUALIZACIÓN: agregado
list()
para que el iterador funcione (necesario para Python 3)fuente
Mejorando la respuesta de ericspod:
En lugar de cambiar el modo de análisis globalmente, podemos envolver esto en un objeto que soporte la construcción with.
Esto se puede usar de la siguiente manera
La belleza de esta manera es que no cambia ningún comportamiento para el código no relacionado fuera del bloque with. Terminé creando esto después de obtener errores en bibliotecas no relacionadas después de usar la versión de ericspod que también usaba expat.
fuente
xml.etree.ElementTree.XMLParser
alguna manera está optimizado y el parche de mono noexpat
tiene absolutamente ningún efecto.También puede usar la elegante construcción de formato de cadena:
o, si está seguro de que PAID_OFF solo aparece en un nivel en el árbol:
fuente
Si está utilizando
ElementTree
y nocElementTree
puede forzar a Expat a ignorar el procesamiento del espacio de nombres reemplazandoParserCreate()
:ElementTree
intenta usar Expat llamandoParserCreate()
pero no proporciona ninguna opción para no proporcionar una cadena de separación de espacio de nombres, el código anterior hará que se ignore pero se le advierte que esto podría romper otras cosas.fuente
ElementTree.fromstring(s, parser=None)
estoy tratando de pasarle un analizador.Podría llegar tarde a esto, pero no creo que
re.sub
sea una buena solución.Sin embargo, la reescritura
xml.parsers.expat
no funciona para las versiones de Python 3.x,El principal culpable es la
xml/etree/ElementTree.py
parte inferior del código fuente.Lo cual es un poco triste.
La solución es deshacerse de él primero.
Probado en Python 3.6.
La
try
declaración de prueba es útil en caso de que en algún lugar de su código vuelva a cargar o importe un módulo dos veces y obtenga errores extraños comoPor cierto, el código fuente de etree parece realmente desordenado.
fuente
Vamos a combinar la respuesta de nonagon con la respuesta de mzjn a una pregunta relacionada :
Usando esta función nosotros:
Cree un iterador para obtener espacios de nombres y un objeto de árbol analizado .
Itere sobre el iterador creado para obtener los espacios de nombres dictados que luego podemos pasar en cada uno
find()
ofindall()
llamar como lo sugiere iMom0 .Creo que este es el mejor enfoque en todos los aspectos, ya que no hay manipulación de un código fuente XML o de la
xml.etree.ElementTree
salida analizada resultante de ningún tipo.También me gustaría dar crédito a la respuesta de Barny al proporcionar una pieza esencial de este rompecabezas (que puede obtener la raíz analizada del iterador). Hasta ese momento, atravesé dos veces el árbol XML en mi aplicación (una vez para obtener espacios de nombres, la segunda para una raíz).
fuente
find()
yfindall()
. Simplemente alimente esos métodos con el dict de espacios de nombresparse_xml()
y use el prefijo del espacio de nombres en sus consultas. Por ejemplo:et_element.findall(".//some_ns_prefix:some_xml_tag", namespaces=xml_namespaces)