Frage Wie analysiere ich XML in Python?


Ich habe viele Zeilen in einer Datenbank, die XML enthält, und ich versuche ein Python-Skript zu schreiben, das diese Zeilen durchläuft und zählt, wie viele Instanzen eines bestimmten Knotenattributs angezeigt werden. Zum Beispiel sieht mein Baum so aus:

<foo>
   <bar>
      <type foobar="1"/>
      <type foobar="2"/>
   </bar>
</foo>

Wie kann ich mit Python auf die Attribute 1 und 2 im XML zugreifen?


760
2017-12-16 05:09


Ursprung


Antworten:


Ich schlage vor ElementTree. Es gibt andere kompatible Implementierungen der gleichen API, wie z lxml, und cElementTree in der Python-Standardbibliothek selbst; Aber in diesem Zusammenhang kommt vor allem noch mehr Geschwindigkeit hinzu - die Leichtigkeit des Programmierens hängt von der API ab, die ElementTree definiert.

Nach dem Erstellen einer Element-Instanz e aus dem XML, z.B. mit dem XML Funktion oder durch Parsing einer Datei mit etwas wie

import xml.etree.ElementTree
e = xml.etree.ElementTree.parse('thefile.xml').getroot()

oder irgendeine der vielen anderen Möglichkeiten, die gezeigt werden ElementTree, du machst einfach so etwas wie:

for atype in e.findall('type'):
    print(atype.get('foobar'))

und ähnliche, normalerweise ziemlich einfache Codemuster.


582
2017-12-16 05:21



minidom ist am schnellsten und schön geradlinig:

XML:

<data>
    <items>
        <item name="item1"></item>
        <item name="item2"></item>
        <item name="item3"></item>
        <item name="item4"></item>
    </items>
</data>

PYTHON:

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)

AUSGABE

4
item1
item1
item2
item3
item4

372
2017-12-16 05:30



Sie können verwenden BeautifulSuppe

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'

201
2017-12-16 05:12



Es gibt viele Möglichkeiten da draußen. cElementTree sieht gut aus, wenn Geschwindigkeit und Speichernutzung ein Problem darstellen. Es hat sehr wenig Overhead im Vergleich zum einfachen Einlesen der Datei mit readlines.

Die relevanten Metriken finden Sie in der folgenden Tabelle, kopiert von der cElementTree Webseite:

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   

Wie von @ Jfs, cElementTree kommt zusammen mit Python:

  • Python 2: from xml.etree import cElementTree as ElementTree.
  • Python 3: from xml.etree import ElementTree (Die beschleunigte C-Version wird automatisch verwendet).

76
2017-10-10 17:44



lxml.objectify ist wirklich einfach.

Nehmen Sie Ihren Beispieltext:

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)

Ausgabe:

{'1': 1, '2': 1}

36
2017-12-16 10:42



Ich schlage vor xmltodict der Einfachheit halber.

Es analysiert Ihr XML zu einem 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')])])])

30
2018-06-12 11:57



Python hat eine Schnittstelle zum Expat-XML-Parser.

xml.parsers.expat

Es ist ein nicht-validierender Parser, also wird kein fehlerhaftes XML abgefangen. Aber wenn Sie wissen, dass Ihre Datei korrekt ist, dann ist das ziemlich gut, und Sie werden es wahrscheinlich tun Holen Sie sich die genaue Information, die Sie wollen, und Sie können den Rest im laufenden Betrieb verwerfen.

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

17
2017-12-16 05:28



Hier ein sehr einfacher aber effektiver Code mit 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")

Quelle:

http://www.snip2code.com/Snippet/991/python-xml-parse?fromPage=1


8
2017-07-08 20:35