Pertanyaan Bagaimana cara menguraikan XML dengan Python?


Saya memiliki banyak baris dalam database yang berisi xml dan saya mencoba menulis skrip Python yang akan melalui baris tersebut dan menghitung berapa banyak contoh atribut node tertentu yang muncul. Misalnya, pohon saya terlihat seperti:

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

Bagaimana saya bisa mengakses atribut 1 dan 2 dalam XML menggunakan Python?


760
2017-12-16 05:09


asal


Jawaban:


saya menyarankan ElementTree. Ada implementasi kompatibel lain dari API yang sama, seperti lxml, dan cElementTree di pustaka standar Python itu sendiri; tetapi, dalam konteks ini, apa yang terutama mereka tambahkan adalah kecepatan lebih - kemudahan bagian pemrograman tergantung pada API, yang ElementTree mendefinisikan.

Setelah membangun contoh Elemen e dari XML, mis. dengan XML berfungsi, atau dengan mengurai file dengan sesuatu seperti

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

atau salah satu dari banyak cara lain yang ditampilkan ElementTree, Anda hanya melakukan sesuatu seperti:

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

dan pola kode yang serupa, biasanya cukup sederhana.


582
2017-12-16 05:21



minidom adalah yang tercepat dan cukup lurus ke depan:

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)

KELUARAN

4
item1
item1
item2
item3
item4

372
2017-12-16 05:30



Kamu dapat memakai 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'

201
2017-12-16 05:12



Ada banyak pilihan di luar sana. cElementTree terlihat sangat baik jika kecepatan dan penggunaan memori menjadi masalah. Ini memiliki overhead yang sangat sedikit dibandingkan dengan hanya membaca dalam file menggunakan readlines.

Metrik yang relevan dapat ditemukan dalam tabel di bawah ini, disalin dari cElementTree situs web:

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   

Seperti yang ditunjukkan oleh @jfs, cElementTree datang dibundel dengan Python:

  • Python 2: from xml.etree import cElementTree as ElementTree.
  • Python 3: from xml.etree import ElementTree (Versi C yang dipercepat digunakan secara otomatis).

76
2017-10-10 17:44



lxml.objectify sangat sederhana.

Mengambil contoh teks Anda:

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)

Keluaran:

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

36
2017-12-16 10:42



saya menyarankan xmltodict untuk kesederhanaan.

Ini mem-parsing xml Anda ke 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 memiliki antarmuka ke parser xml expat.

xml.parsers.expat

Ini adalah parser yang tidak valid, sehingga xml yang buruk tidak akan tertangkap. Tetapi jika Anda tahu file Anda benar, maka ini cukup bagus, dan Anda mungkin akan melakukannya dapatkan info pasti yang Anda inginkan dan Anda dapat membuang sisanya dengan cepat.

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