سؤال

أحتاج إلى الحصول على قائمة بقيم السمات من العناصر الفرعية في بايثون.

من الأسهل الشرح بمثال.

بالنظر إلى بعض XML مثل هذا:

<elements>
    <parent name="CategoryA">
        <child value="a1"/>
        <child value="a2"/>
        <child value="a3"/>
    </parent>
    <parent name="CategoryB">
        <child value="b1"/>
        <child value="b2"/>
        <child value="b3"/>
    </parent>
</elements>

أريد أن أكون قادرًا على القيام بشيء مثل:

>>> getValues("CategoryA")
['a1', 'a2', 'a3']
>>> getValues("CategoryB")
['b1', 'b2', 'b3']

يبدو أنها وظيفة لـ XPath لكنني منفتح على جميع التوصيات.أود أيضًا أن أسمع عن مكتبات Python XML المفضلة لديك.

هل كانت مفيدة؟

المحلول

أنا لست خبيرًا في لغة Python، ولكن إليك حل XPath باستخدام libxml2.

import libxml2

DOC = """<elements>
    <parent name="CategoryA">
        <child value="a1"/>
        <child value="a2"/>
        <child value="a3"/>
    </parent>
    <parent name="CategoryB">
        <child value="b1"/>
        <child value="b2"/>
        <child value="b3"/>
    </parent>
</elements>"""

doc = libxml2.parseDoc(DOC)

def getValues(cat):
    return [attr.content for attr in doc.xpathEval("/elements/parent[@name='%s']/child/@value" % (cat))]

print getValues("CategoryA")

بالنتيجة...

['a1', 'a2', 'a3']

نصائح أخرى

شجرة العنصر 1.3 (لسوء الحظ ليس 1.2 وهو المتضمن في بايثون) يدعم XPath مثله:

import elementtree.ElementTree as xml

def getValues(tree, category):
    parent = tree.find(".//parent[@name='%s']" % category)
    return [child.get('value') for child in parent]

ثم يمكنك أن تفعل

>>> tree = xml.parse('data.xml')
>>> getValues(tree, 'CategoryA')
['a1', 'a2', 'a3']
>>> getValues(tree, 'CategoryB')
['b1', 'b2', 'b3']

lxml.etree (الذي يوفر أيضًا واجهة ElementTree) سيعمل أيضًا بنفس الطريقة.

باستخدام W3 DOM قياسي مثل minidom stdlib أو pxdom:

def getValues(category):
    for parent in document.getElementsByTagName('parent'):
        if parent.getAttribute('name')==category:
            return [
                el.getAttribute('value')
                for el in parent.getElementsByTagName('child')
            ]
    raise ValueError('parent not found')

يجب أن أعترف أنني من محبي com.xmltramp بسبب سهولة استخدامه.

الوصول إلى ما سبق يصبح:

  import xmltramp

  values = xmltramp.parse('''...''')

  def getValues( values, category ):
    cat = [ parent for parent in values['parent':] if parent(name) == category ]
    cat_values = [ child(value) for child in parent['child':] for parent in cat ]
    return cat_values

  getValues( values, "CategoryA" )
  getValues( values, "CategoryB" )

يمكنك القيام بذلك مع حساء جميل

>>> from BeautifulSoup import BeautifulStoneSoup
>>> soup = BeautifulStoneSoup(xml)
>>> def getValues(name):
. . .      return [child['value'] for child in soup.find('parent', attrs={'name': name}).findAll('child')]

إذا كنت تعمل باستخدام HTML/XML، فإنني أنصحك بإلقاء نظرة على BeautifulSoup.إنها تشبه شجرة DOM ولكنها تحتوي على المزيد من الوظائف.

مكتبة python xml المفضلة لدي هي com.lxml ، الذي يلتف libxml2.
يبدو أن Xpath هو الحل الأمثل هنا، لذا سأكتب هذا كشيء مثل:

from lxml import etree

def getValues(xml, category):
    return [x.attrib['value'] for x in 
            xml.findall('/parent[@name="%s"]/*' % category)]

xml = etree.parse(open('filename.xml'))

>>> print getValues(xml, 'CategoryA')
['a1', 'a2', 'a3']
>>> print getValues(xml, 'CategoryB')
['b1', 'b2', 'b3]

في Python 3.x، يعد جلب قائمة السمات مهمة بسيطة لاستخدام العضو items()

باستخدام ElementTree, ، يوضح المقتطف أدناه طريقة للحصول على قائمة السمات.لاحظ أن هذا المثال لا يأخذ في الاعتبار مساحات الأسماء، والتي إذا كانت موجودة، فسوف تحتاج إلى أخذها في الاعتبار.

    import xml.etree.ElementTree as ET

    flName = 'test.xml'
    tree = ET.parse(flName)
    root = tree.getroot()
    for element in root.findall('<child-node-of-root>'):
        attrList = element.items()
        print(len(attrList), " : [", attrList, "]" )

مرجع:

العناصر ()
تُرجع سمات العنصر كسلسلة من أزواج (الاسم والقيمة).
يتم إرجاع السمات بترتيب تعسفي.

دليل بايثون

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top