it-swarm.com.de

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?

907
randombits

Ich schlage vor ElementTree . Es gibt andere kompatible Implementierungen derselben API, z. B. lxml und cElementTree in der Standardbibliothek Python. In diesem Zusammenhang ist das, was sie hauptsächlich hinzufügen, noch mehr Geschwindigkeit - die Leichtigkeit des Programmierteils hängt von der API ab, die ElementTree definiert.

Erstellen Sie zunächst eine Elementinstanz root aus dem XML-Code, z. mit der Funktion XML oder durch Parsen einer Datei mit etwas wie:

import xml.etree.ElementTree as ET
root = ET.parse('thefile.xml').getroot()

Oder eine der vielen anderen unter ElementTree gezeigten Möglichkeiten. Dann mache etwas wie:

for type_tag in root.findall('bar/type'):
    value = type_tag.get('foobar')
    print(value)

Und ähnliche, normalerweise recht einfache Codemuster.

700
Alex Martelli

minidom ist die schnellste und einfachste Methode:

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
412

Sie können BeautifulSoup verwenden

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'
226
YOU

Es gibt viele Möglichkeiten da draußen. cElementTree sieht ausgezeichnet aus, wenn Geschwindigkeit und Speichernutzung eine Rolle spielen. Es hat sehr wenig Aufwand im Vergleich zum einfachen Einlesen der Datei mit readlines.

Die relevanten Metriken finden Sie in der folgenden Tabelle, die von der Website cElementTree kopiert wurde:

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 hervorgehoben, wird cElementTree mit Python gebündelt geliefert:

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

Der Einfachheit halber empfehle ich xmltodict .

Es analysiert Ihre 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')])])])
41
myildirim

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}
37
Ryan Ginstrom

Python verfügt über eine Schnittstelle zum XML-Parser expat.

xml.parsers.expat

Es handelt sich um einen nicht validierenden Parser, sodass fehlerhafte XML-Dateien nicht abgefangen werden. Aber wenn Sie wissen, dass Ihre Datei korrekt ist, ist dies ziemlich gut und Sie werden wahrscheinlich erhalten Sie die genauen Informationen, die Sie möchten, und Sie können den Rest sofort 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
19
Tor Valamo

Um eine weitere Möglichkeit hinzuzufügen, können Sie untangle verwenden, da es sich um eine einfache XML-zu-Python-Objektbibliothek handelt. Hier haben Sie ein Beispiel:

Installation

pip install untangle

Verwendung

Ihre XML-Datei (etwas geändert):

<foo>
   <bar name="bar_name">
      <type foobar="1"/>
   </bar>
</foo>

zugriff auf die Attribute mit entwirren :

import untangle

obj = untangle.parse('/path_to_xml_file/file.xml')

print obj.foo.bar['name']
print obj.foo.bar.type['foobar']

die Ausgabe wird sein:

bar_name
1

Weitere Informationen zu untangle finden Sie hier .
Auch (wenn Sie neugierig sind), finden Sie eine Liste von Werkzeugen für die Arbeit mit XML und Python hier (Sie werden auch sehen, dass die häufigsten wurden in früheren Antworten erwähnt).

13
jchanger

Ich könnte vorschlagen declxml .

Vollständige Offenlegung: Ich habe diese Bibliothek geschrieben, weil ich nach einer Möglichkeit gesucht habe, zwischen XML- und Python -Datenstrukturen zu konvertieren, ohne mit ElementTree Dutzende Zeilen imperativen Parsing-/Serialisierungscodes schreiben zu müssen.

Mit declxml verwenden Sie Prozessoren , um die Struktur Ihres XML-Dokuments deklarativ zu definieren und um zu bestimmen, wie XML- und Python -Datenstrukturen zugeordnet werden. Prozessoren werden sowohl für die Serialisierung und das Parsen als auch für eine grundlegende Validierungsstufe verwendet.

Das Parsen in Python Datenstrukturen ist einfach:

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)

Welches erzeugt die Ausgabe:

{'bar': {'foobar': [1, 2]}}

Sie können denselben Prozessor auch zum Serialisieren von Daten in XML verwenden

data = {'bar': {
    'foobar': [7, 3, 21, 16, 11]
}}

xml.serialize_to_string(processor, data, indent='    ')

Welches erzeugt die folgende Ausgabe

<?xml version="1.0" ?>
<foo>
    <bar>
        <type foobar="7"/>
        <type foobar="3"/>
        <type foobar="21"/>
        <type foobar="16"/>
        <type foobar="11"/>
    </bar>
</foo>

Wenn Sie mit Objekten anstelle von Wörterbüchern arbeiten möchten, können Sie Prozessoren definieren, um Daten auch in und von Objekten zu transformieren.

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)

Welches erzeugt die folgende Ausgabe

{'bar': Bar(foobars=[1, 2])}
11
gatkin

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

10
Jan Kohila

Ich finde die Python xml.dom und xml.dom.minidom ganz einfach. Beachten Sie, dass DOM nicht für große XML-Mengen geeignet ist. Wenn Ihre Eingabe jedoch recht klein ist, funktioniert dies problemlos.

6
EMP
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')

Dies gibt den Wert des Attributs foobar aus.

5
Souvik Dey

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])

AUSGABE:

foo
1
2
4
Ahito

xml.etree.ElementTree vs. lxml

Dies sind einige Vorteile der beiden am häufigsten genutzten Bibliotheken, die ich kennen lernen sollte, bevor ich mich für sie entscheide.

xml.etree.ElementTree:

  1. Aus der Standardbibliothek: Es muss kein Modul installiert werden

lxml

  1. Schreiben Sie einfach XML-Deklaration: Müssen Sie beispielsweise standalone="no" hinzufügen?
  2. Hübsches Drucken: Sie können ein Nizza eingerückt XML ohne zusätzlichen Code haben.
  3. Objectify Funktionalität: Sie können XML so verwenden, als ob Sie es mit einer normalen Python Objekthierarchie.node zu tun hätten.
2
G M