read - xml etree python 3
¿Cómo puedo analizar XML en Python? (14)
xml.etree.ElementTree vs. lxml
Estos son algunos de los beneficios de las dos bibliotecas más usadas que me gustaría conocer antes de elegir entre ellas.
xml.etree.ElementTree:
- Desde la librería estándar : no hay necesidad de instalar ningún módulo.
lxml
- Escriba fácilmente la declaración XML : ¿necesita agregar, por ejemplo, standalone = "no"?
- Impresión bonita : puede tener un buen XML sangrado sin código adicional.
- Funcionalidad de Objectify : le permite usar XML como si estuviera tratando con una jerarquía normal de objetos de Python.
Tengo muchas filas en una base de datos que contiene xml y estoy tratando de escribir un script de Python que pase por esas filas y cuente cuántas instancias de un atributo de nodo en particular aparecen. Por ejemplo, mi árbol se ve como:
<foo>
<bar>
<type foobar="1"/>
<type foobar="2"/>
</bar>
</foo>
¿Cómo puedo acceder a los atributos 1 y 2 en el XML utilizando Python?
Aquí un código muy simple pero efectivo usando cElementTree
.
try:
import cElementTree as ET
except ImportError:
try:
# Python 2.5 need to import a different module
import xml.etree.cElementTree as ET
except ImportError:
exit_err("Failed to import cElementTree from any known place")
def find_in_tree(tree, node):
found = tree.find(node)
if found == None:
print "No %s in file" % node
found = []
return found
# Parse a xml file (specify the path)
def_file = "xml_file_name.xml"
try:
dom = ET.parse(open(def_file, "r"))
root = dom.getroot()
except:
exit_err("Unable to open and parse input definition file: " + def_file)
# Parse to find the child nodes list of node ''myNode''
fwdefs = find_in_tree(root,"myNode")
Fuente:
http://www.snip2code.com/Snippet/991/python-xml-parse?fromPage=1
Encuentro Python xml.dom y xml.dom.minidom bastante fáciles. Tenga en cuenta que DOM no es bueno para grandes cantidades de XML, pero si su entrada es bastante pequeña, esto funcionará bien.
Hay muchas opciones alla afuera. cElementTree ve excelente si la velocidad y el uso de la memoria son un problema. Tiene una sobrecarga muy pequeña en comparación con la simple lectura del archivo utilizando readlines
lectura.
Las métricas relevantes se pueden encontrar en la tabla a continuación, copiada del cElementTree web cElementTree :
library time space
xml.dom.minidom (Python 2.1) 6.3 s 80000K
gnosis.objectify 2.0 s 22000k
xml.dom.minidom (Python 2.4) 1.4 s 53000k
ElementTree 1.2 1.6 s 14500k
ElementTree 1.2.4/1.3 1.1 s 14500k
cDomlette (C extension) 0.540 s 20500k
PyRXPU (C extension) 0.175 s 10850k
libxml2 (C extension) 0.098 s 16000k
readlines (read as utf-8) 0.093 s 8850k
cElementTree (C extension) --> 0.047 s 4900K <--
readlines (read as ascii) 0.032 s 5050k
Como lo señaló @jfs , cElementTree
viene con Python:
- Python 2:
from xml.etree import cElementTree as ElementTree
. - Python 3:
from xml.etree import ElementTree
(la versión C acelerada se usa automáticamente).
Podría sugerir declxml .
Revelación completa: escribí esta biblioteca porque buscaba una forma de convertir estructuras de datos XML y Python sin necesidad de escribir docenas de líneas de código imperativo de análisis / serialización con ElementTree.
Con declxml, usas procesadores para definir de forma declarativa la estructura de tu documento XML y cómo mapear entre XML y las estructuras de datos de Python. Los procesadores se utilizan para la serialización y el análisis, así como para un nivel básico de validación.
El análisis en las estructuras de datos de Python es sencillo:
import declxml as xml
xml_string = """
<foo>
<bar>
<type foobar="1"/>
<type foobar="2"/>
</bar>
</foo>
"""
processor = xml.dictionary(''foo'', [
xml.dictionary(''bar'', [
xml.array(xml.integer(''type'', attribute=''foobar''))
])
])
xml.parse_from_string(processor, xml_string)
Lo que produce la salida:
{''bar'': {''foobar'': [1, 2]}}
También puede usar el mismo procesador para serializar datos a XML
data = {''bar'': {
''foobar'': [7, 3, 21, 16, 11]
}}
xml.serialize_to_string(processor, data, indent='' '')
Lo que produce la siguiente salida.
<?xml version="1.0" ?>
<foo>
<bar>
<type foobar="7"/>
<type foobar="3"/>
<type foobar="21"/>
<type foobar="16"/>
<type foobar="11"/>
</bar>
</foo>
Si desea trabajar con objetos en lugar de diccionarios, puede definir procesadores para transformar datos hacia y desde objetos también.
import declxml as xml
class Bar:
def __init__(self):
self.foobars = []
def __repr__(self):
return ''Bar(foobars={})''.format(self.foobars)
xml_string = """
<foo>
<bar>
<type foobar="1"/>
<type foobar="2"/>
</bar>
</foo>
"""
processor = xml.dictionary(''foo'', [
xml.user_object(''bar'', Bar, [
xml.array(xml.integer(''type'', attribute=''foobar''), alias=''foobars'')
])
])
xml.parse_from_string(processor, xml_string)
Lo que produce la siguiente salida.
{''bar'': Bar(foobars=[1, 2])}
Puedes usar BeautifulSoup
from bs4 import BeautifulSoup
x="""<foo>
<bar>
<type foobar="1"/>
<type foobar="2"/>
</bar>
</foo>"""
y=BeautifulSoup(x)
>>> y.foo.bar.type["foobar"]
u''1''
>>> y.foo.bar.findAll("type")
[<type foobar="1"></type>, <type foobar="2"></type>]
>>> y.foo.bar.findAll("type")[0]["foobar"]
u''1''
>>> y.foo.bar.findAll("type")[1]["foobar"]
u''2''
Python tiene una interfaz para el analizador xml expat.
xml.parsers.expat
Es un analizador que no valida, por lo que no se capturará el xml malo. Pero si sabe que su archivo es correcto, entonces esto es bastante bueno, y probablemente obtendrá la información exacta que desea y puede descartar el resto sobre la marcha.
stringofxml = """<foo>
<bar>
<type arg="value" />
<type arg="value" />
<type arg="value" />
</bar>
<bar>
<type arg="value" />
</bar>
</foo>"""
count = 0
def start(name, attr):
global count
if name == ''type'':
count += 1
p = expat.ParserCreate()
p.StartElementHandler = start
p.Parse(stringofxml)
print count # prints 4
Solo para agregar otra posibilidad, puedes usar Untangle , ya que es una simple biblioteca de objetos xml a python. Aquí tienes un ejemplo:
Instalación
pip install untangle
Uso
Tu archivo xml (un poco cambiado):
<foo>
<bar name="bar_name">
<type foobar="1"/>
</bar>
</foo>
accediendo a los atributos con desenredar :
import untangle
obj = untangle.parse(''/path_to_xml_file/file.xml'')
print obj.foo.bar[''name'']
print obj.foo.bar.type[''foobar'']
La salida será:
bar_name
1
Más información sobre desenredar se puede encontrar here .
También (si tienes curiosidad), puedes encontrar una lista de herramientas para trabajar con XML y Python here (también verás que las respuestas más comunes se mencionaron en las respuestas anteriores).
Sugiero ElementTree
. Hay otras implementaciones compatibles de la misma API, como lxml
y cElementTree
en la biblioteca estándar de Python; pero, en este contexto, lo que agregan principalmente es aún más velocidad: la facilidad de programación depende de la API, que define ElementTree
.
Después de crear una instancia de Element e
partir del XML, por ejemplo, con la función XML , o analizando un archivo con algo como
import xml.etree.ElementTree
e = xml.etree.ElementTree.parse(''thefile.xml'').getroot()
o cualquiera de las muchas otras formas mostradas en ElementTree
, simplemente haces algo como:
for atype in e.findall(''type''):
print(atype.get(''foobar''))
y similares, generalmente bastante simples, patrones de código.
Sugiero xmltodict por simplicidad.
Analiza su xml a un OrderedDict;
>>> e = ''<foo>
<bar>
<type foobar="1"/>
<type foobar="2"/>
</bar>
</foo> ''
>>> import xmltodict
>>> result = xmltodict.parse(e)
>>> result
OrderedDict([(u''foo'', OrderedDict([(u''bar'', OrderedDict([(u''type'', [OrderedDict([(u''@foobar'', u''1'')]), OrderedDict([(u''@foobar'', u''2'')])])]))]))])
>>> result[''foo'']
OrderedDict([(u''bar'', OrderedDict([(u''type'', [OrderedDict([(u''@foobar'', u''1'')]), OrderedDict([(u''@foobar'', u''2'')])])]))])
>>> result[''foo''][''bar'']
OrderedDict([(u''type'', [OrderedDict([(u''@foobar'', u''1'')]), OrderedDict([(u''@foobar'', u''2'')])])])
XML
<foo>
<bar>
<type foobar="1"/>
<type foobar="2"/>
</bar>
</foo>
PYTHON_CODE
import xml.etree.cElementTree as ET
tree = ET.parse("foo.xml")
root = tree.getroot()
root_tag = root.tag
print(root_tag)
for form in root.findall("./bar/type"):
x=(form.attrib)
z=list(x)
for i in z:
print(x[i])
SALIDA:
foo
1
2
lxml.objectify es realmente simple.
Tomando su texto de muestra:
from lxml import objectify
from collections import defaultdict
count = defaultdict(int)
root = objectify.fromstring(text)
for item in root.bar.type:
count[item.attrib.get("foobar")] += 1
print dict(count)
Salida:
{''1'': 1, ''2'': 1}
minidom
es el más rápido y sencillo.
XML:
<data>
<items>
<item name="item1"></item>
<item name="item2"></item>
<item name="item3"></item>
<item name="item4"></item>
</items>
</data>
PITÓN:
from xml.dom import minidom
xmldoc = minidom.parse(''items.xml'')
itemlist = xmldoc.getElementsByTagName(''item'')
print(len(itemlist))
print(itemlist[0].attributes[''name''].value)
for s in itemlist:
print(s.attributes[''name''].value)
SALIDA
4
item1
item1
item2
item3
item4
import xml.etree.ElementTree as ET
data = ''''''<foo>
<bar>
<type foobar="1"/>
<type foobar="2"/>
</bar>
</foo>''''''
tree = ET.fromstring(data)
lst = tree.findall(''bar/type'')
for item in lst:
print item.get(''foobar'')
Esto imprimirá el valor del atributo foobar.