مكتبة - كيف يمكنني تحليل XML في Python؟




مكتبة اكواد بايثون (8)

أجد بيثون xml.dom و xml.dom.minidom سهلة للغاية. ضع في اعتبارك أن DOM ليس جيدًا لكميات كبيرة من XML ، ولكن إذا كانت المدخلات الخاصة بك صغيرة إلى حد ما ، فسيكون ذلك جيدًا.

لدي العديد من الصفوف في قاعدة بيانات تحتوي على xml وأحاول كتابة نص برمجي Python الذي سينتقل عبر هذه الصفوف ويحسب عدد مثيلات سمة سمة معينة تظهر. على سبيل المثال ، تبدو شجاعتي كما يلي:

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

كيف يمكنني الوصول إلى الصفتين 1 و 2 في XML باستخدام Python؟


أقترح ElementTree . هناك تطبيقات متوافقة أخرى لنفس API ، مثل lxml ، و cElementTree في مكتبة Python القياسية نفسها ؛ ولكن في هذا السياق ، فإن ما يضيفونه بشكل أساسي هو أكثر سرعة - يعتمد جزء سهولة البرمجة على واجهة برمجة التطبيقات (API) ، التي تعرفها ElementTree .

بعد إنشاء مثال e element من XML ، على سبيل المثال باستخدام وظيفة XML ، أو عن طريق تحليل ملف يحتوي على شيء ما

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

أو أي من الطرق الأخرى العديدة التي تظهر في ElementTree ، يمكنك فعل شيء مثل:

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

وما شابه ذلك ، وعادة ما تكون بسيطة جدا ، وأنماط التعليمات البرمجية.


فقط لإضافة إمكانية أخرى ، يمكنك استخدام untangle ، كما هي مكتبة كائنات xml-to-python بسيطة. هنا لديك مثال على ذلك:

التركيب

pip install untangle

استعمال

ملف xml الخاص بك (تغير قليلا):

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

الوصول إلى السمات مع فك التشفير :

import untangle

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

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

سيكون الناتج:

bar_name
1

يمكن العثور على مزيد من المعلومات حول فك التشفير here .
أيضا (إذا كنت فضوليا) ، يمكنك العثور على قائمة من الأدوات للعمل مع XML و Python here (سترى أيضا أن أكثرها شيوعا ذكرتها الإجابات السابقة).


قد أقترح declxml .

الإفصاح الكامل: لقد كتبت هذه المكتبة لأنني كنت أبحث عن طريقة للتحويل بين تراكيب بيانات XML و Python دون الحاجة إلى كتابة عشرات الأسطر من شفرة التحليل / التسلسل الحتمية مع ElementTree.

باستخدام declxml ، يمكنك استخدام المعالجات لتعريف بنية مستند XML بشكل تفصيلي وكيفية التعيين بين هياكل بيانات XML و Python. تُستخدم المعالجات في كل من التسلسل والتحليل ، بالإضافة إلى مستوى أساسي من التحقق.

التحليل في بنيات بيانات Python أمر بسيط:

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)

الذي ينتج الإخراج:

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

يمكنك أيضًا استخدام نفس المعالج لإجراء تسلسل البيانات إلى XML

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

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

الذي ينتج الإخراج التالي

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

إذا كنت ترغب في العمل مع الكائنات بدلاً من القواميس ، فيمكنك تعريف المعالجات لتحويل البيانات من وإلى الكائنات أيضًا.

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)

الذي ينتج الإخراج التالي

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

هنا رمز بسيط جدا لكنها فعالة باستخدام 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")

مصدر:

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


هناك العديد من الخيارات بالخارج. cElementTree تبدو ممتازة إذا كانت السرعة واستخدام الذاكرة هي القضية. لديها القليل جدا من النفقات العامة مقارنة ببساطة في الملف باستخدام readlines .

يمكن العثور على المقاييس ذات الصلة في الجدول أدناه ، ونسخها من الموقع الإلكتروني 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   

كما أشار بواسطة @jfs ، تأتي cElementTree مرفقة مع Python:

  • Python 2: from xml.etree import cElementTree as ElementTree .
  • Python 3: from xml.etree import ElementTree (يتم استخدام الإصدار C المتسارع تلقائيًا).

lxml.objectify بسيط للغاية.

أخذ نص عينتك:

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)

انتاج:

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

minidom هو أسرع وأسرع للأمام:

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)

انتاج

4
item1
item1
item2
item3
item4




xml