Bir xml dizesi bir sözlüğe nasıl dönüştürülür?


125

Bir soketten bir xml belgesi okuyan bir programım var. Django simplejsonkütüphanesinde olduğu gibi, doğrudan bir Python sözlüğüne dönüştürmek istediğim bir dizede depolanan xml belgesine sahibim .

Örnek olarak alın:

str ="<?xml version="1.0" ?><person><name>john</name><age>20</age></person"
dic_xml = convert_to_dic(str)

Sonra dic_xmlbenzeyecekti{'person' : { 'name' : 'john', 'age' : 20 } }


str'de birkaç sözdizimi hatası var. deneyin: str = '<? xml version = "1.0"?> <person> <name> john </name> <age> 20 </age> </person>'
Keir

Yanıtlar:


58

Bu, birinin oluşturduğu harika bir modül. Birkaç kez kullandım. http://code.activestate.com/recipes/410469-xml-as-dictionary/

İşte web sitesindeki kod, bağlantının bozulma ihtimaline karşı.

from xml.etree import cElementTree as ElementTree

class XmlListConfig(list):
    def __init__(self, aList):
        for element in aList:
            if element:
                # treat like dict
                if len(element) == 1 or element[0].tag != element[1].tag:
                    self.append(XmlDictConfig(element))
                # treat like list
                elif element[0].tag == element[1].tag:
                    self.append(XmlListConfig(element))
            elif element.text:
                text = element.text.strip()
                if text:
                    self.append(text)


class XmlDictConfig(dict):
    '''
    Example usage:

    >>> tree = ElementTree.parse('your_file.xml')
    >>> root = tree.getroot()
    >>> xmldict = XmlDictConfig(root)

    Or, if you want to use an XML string:

    >>> root = ElementTree.XML(xml_string)
    >>> xmldict = XmlDictConfig(root)

    And then use xmldict for what it is... a dict.
    '''
    def __init__(self, parent_element):
        if parent_element.items():
            self.update(dict(parent_element.items()))
        for element in parent_element:
            if element:
                # treat like dict - we assume that if the first two tags
                # in a series are different, then they are all different.
                if len(element) == 1 or element[0].tag != element[1].tag:
                    aDict = XmlDictConfig(element)
                # treat like list - we assume that if the first two tags
                # in a series are the same, then the rest are the same.
                else:
                    # here, we put the list in dictionary; the key is the
                    # tag name the list elements all share in common, and
                    # the value is the list itself 
                    aDict = {element[0].tag: XmlListConfig(element)}
                # if the tag has attributes, add those to the dict
                if element.items():
                    aDict.update(dict(element.items()))
                self.update({element.tag: aDict})
            # this assumes that if you've got an attribute in a tag,
            # you won't be having any text. This may or may not be a 
            # good idea -- time will tell. It works for the way we are
            # currently doing XML configuration files...
            elif element.items():
                self.update({element.tag: dict(element.items())})
            # finally, if there are no child tags and no attributes, extract
            # the text
            else:
                self.update({element.tag: element.text})

Örnek kullanım:

tree = ElementTree.parse('your_file.xml')
root = tree.getroot()
xmldict = XmlDictConfig(root)

// Veya bir XML dizesi kullanmak istiyorsanız:

root = ElementTree.XML(xml_string)
xmldict = XmlDictConfig(root)

4
Alternatif olarak 'xmltodict' kullanabilirsiniz
mrash

7
Bunu denedim ve xmltodict'ten çok daha hızlı. 80MB xml dosyasını ayrıştırmak için 7 saniye, xmltodict ile 90 saniye sürdü
Eddy

1
Onaylandı ... Bunu her uç durum için test etmedim, ancak oldukça karmaşık olmayan XML dizelerim için bu oldukça hızlı ( xmltodictkitaplıktan yaklaşık 8 kat daha hızlı ). Dezavantajı, projenizde kendiniz barındırmanız gerektiğidir.
Dirk

10
Merhabalar, bu harika çalışıyor, bulamayanlar için sadece bir pasaj ekleyecek cElementTree, sadece ilk satırı şu şekilde değiştirin: from xml.etree import cElementTree as ElementTree
Rafael Aguilar

2
Aşağıda yayınlanan daha iyi yanıtlar olduğundan, özellikle aynı ada sahip birden çok etiketi ele alırken aşağı oylama.
Maksym

281

xmltodict (tam açıklama: ben yazdım) tam olarak şunu yapar:

xmltodict.parse("""
<?xml version="1.0" ?>
<person>
  <name>john</name>
  <age>20</age>
</person>""")
# {u'person': {u'age': u'20', u'name': u'john'}}

22
Bu harika bir modül.
zekel

2
Az önce bana büyük bir çaba harcadın. Günümü şenlendirdin.
LRE

3
ayrıca, gelecekteki googlenauts için - bunu App Engine'de kullanabildim, bunu Python'daki çoğu xml kitaplığıyla iyi oynamadığına inandırdım.
LRE

2
U, saklanan unicode dizesini gösterir. Dizenin değerini hiçbir şekilde etkilemez.
Joshua Olson

2
Güzel. Ve evet, @ypercube, tersi için bir xmldict.unparse () işlevi var.
Duther

47

Aşağıdaki XML-Python-dikt pasajı, varlıkları ve bu XML-JSON "spesifikasyonunu" izleyen öznitelikleri ayrıştırır . Tüm XML durumlarını ele alan en genel çözümdür.

from collections import defaultdict

def etree_to_dict(t):
    d = {t.tag: {} if t.attrib else None}
    children = list(t)
    if children:
        dd = defaultdict(list)
        for dc in map(etree_to_dict, children):
            for k, v in dc.items():
                dd[k].append(v)
        d = {t.tag: {k:v[0] if len(v) == 1 else v for k, v in dd.items()}}
    if t.attrib:
        d[t.tag].update(('@' + k, v) for k, v in t.attrib.items())
    if t.text:
        text = t.text.strip()
        if children or t.attrib:
            if text:
              d[t.tag]['#text'] = text
        else:
            d[t.tag] = text
    return d

Kullanılır:

from xml.etree import cElementTree as ET
e = ET.XML('''
<root>
  <e />
  <e>text</e>
  <e name="value" />
  <e name="value">text</e>
  <e> <a>text</a> <b>text</b> </e>
  <e> <a>text</a> <a>text</a> </e>
  <e> text <a>text</a> </e>
</root>
''')

from pprint import pprint
pprint(etree_to_dict(e))

Bu örneğin çıktısı (yukarıda bağlantılı "spesifikasyon" a göre) şöyle olmalıdır:

{'root': {'e': [None,
                'text',
                {'@name': 'value'},
                {'#text': 'text', '@name': 'value'},
                {'a': 'text', 'b': 'text'},
                {'a': ['text', 'text']},
                {'#text': 'text', 'a': 'text'}]}}

İlle de hoş değil, ancak belirsizdir ve daha basit XML girdileri daha basit JSON ile sonuçlanır. :)


Güncelleme

Eğer yapmak istiyorsanız ters bir yayarlar JSON / dict XML dizesi , şunları kullanabilirsiniz:

try:
  basestring
except NameError:  # python3
  basestring = str

def dict_to_etree(d):
    def _to_etree(d, root):
        if not d:
            pass
        elif isinstance(d, basestring):
            root.text = d
        elif isinstance(d, dict):
            for k,v in d.items():
                assert isinstance(k, basestring)
                if k.startswith('#'):
                    assert k == '#text' and isinstance(v, basestring)
                    root.text = v
                elif k.startswith('@'):
                    assert isinstance(v, basestring)
                    root.set(k[1:], v)
                elif isinstance(v, list):
                    for e in v:
                        _to_etree(e, ET.SubElement(root, k))
                else:
                    _to_etree(v, ET.SubElement(root, k))
        else:
            raise TypeError('invalid type: ' + str(type(d)))
    assert isinstance(d, dict) and len(d) == 1
    tag, body = next(iter(d.items()))
    node = ET.Element(tag)
    _to_etree(body, node)
    return ET.tostring(node)

pprint(dict_to_etree(d))

1
Bu kod için teşekkürler! Ek bilgi: Eğer piton 2.5 kullanıyorsanız çizgiyi değiştirmek zorunda böylece, sözlük anlama kullanamazsınız d = {t.tag: {k:v[0] if len(v) == 1 else v for k, v in dd.iteritems()}} için d = { t.tag: dict( (k, v[0] if len(v) == 1 else v) for k, v in dd.iteritems() ) }
M-

2
Bunun için yaklaşık 10 snippet / python modülü / vb. Test ettim. Bu bulduğum en iyisi. Testlerime göre: 1) github.com/martinblech/xmltodict'ten çok daha hızlı (XML SAX api'ye dayalı olarak) 2) github.com/mcspring/XML2Dict'ten daha iyi , birkaç çocuk aynı ada sahip olduğunda bazı küçük sorunlar yaşanıyor 3 ) küçük sorunları olan code.activestate.com/recipes/410469-xml-as-dictionary'den daha iyi ve daha da önemlisi: 4) öncekilerden çok daha kısa kod! Teşekkürler @ K3 --- rnc
Basj

Bu, açık ara en kapsamlı cevaptır ve> 2.6 üzerinde çalışır ve oldukça esnektir. Tek sorunum, metnin bir öznitelik olup olmadığına bağlı olarak bulunduğu yeri değiştirebilmesidir). daha da küçük ve daha katı bir çözüm yayınladım.
Erik Aronesty

1
Bir XML dosyasından sıralı bir söz almanız gerekiyorsa, lütfen aynı örneği birkaç değişiklikle kullanabilirsiniz (aşağıdaki
cevabıma

Bu aynı zamanda cElementTreeveya ile birlikte kullanıldığında oldukça şık ve hızlıdır lxml.etree. Python 3 kullanırken, hepsinin .iteritems()olarak değiştirilmesi gerektiğini unutmayın .items()(aynı davranış, ancak anahtar kelime Python 2'den 3'e değiştirildi).
Dirk

25

Bu hafif sürüm, yapılandırılabilir olmasa da, gerektiği gibi uyarlanması oldukça kolaydır ve eski pitonlarda çalışır. Ayrıca katıdır - yani sonuçlar, niteliklerin varlığına bakılmaksızın aynıdır.

import xml.etree.ElementTree as ET

from copy import copy

def dictify(r,root=True):
    if root:
        return {r.tag : dictify(r, False)}
    d=copy(r.attrib)
    if r.text:
        d["_text"]=r.text
    for x in r.findall("./*"):
        if x.tag not in d:
            d[x.tag]=[]
        d[x.tag].append(dictify(x,False))
    return d

Yani:

root = ET.fromstring("<erik><a x='1'>v</a><a y='2'>w</a></erik>")

dictify(root)

Sonuçlar:

{'erik': {'a': [{'x': '1', '_text': 'v'}, {'y': '2', '_text': 'w'}]}}

2
Bu çözümü beğendim. Basittir ve harici kitaplara ihtiyaç duymaz.
MattK

6

PicklingTools kitaplıklarının (1.3.0 ve 1.3.1) en son sürümleri, XML'den bir Python diktesine dönüştürmek için araçları destekler.

İndirmeye buradan ulaşabilirsiniz: PicklingTools 1.3.1

Burada dönüştürücüler için epeyce dokümantasyon var : dokümantasyon, XML ve Python sözlükleri arasında dönüştürme yaparken ortaya çıkacak tüm kararları ve sorunları ayrıntılı olarak açıklıyor (birkaç uç durum vardır: öznitelikler, listeler, anonim listeler, anonim çoğu dönüştürücünün işlemediği diktler, değerlendirmeler vb.). Genel olarak, dönüştürücülerin kullanımı kolaydır. Bir "example.xml" şunları içeriyorsa:

<top>
  <a>1</a>
  <b>2.2</b>
  <c>three</c>
</top>

Sonra onu bir sözlüğe dönüştürmek için:

>>> from xmlloader import *
>>> example = file('example.xml', 'r')   # A document containing XML
>>> xl = StreamXMLLoader(example, 0)     # 0 = all defaults on operation
>>> result = xl.expect XML()
>>> print result
{'top': {'a': '1', 'c': 'three', 'b': '2.2'}}

Hem C ++ hem de Python'da dönüştürmek için araçlar vardır: C ++ ve Python girintili dönüştürme yapar, ancak C ++ yaklaşık 60 kat daha hızlıdır


tabii ki, 2 a varsa, bu iyi bir format değil.
Erik Aronesty

1
İlginç görünüyor, ancak PicklingTools'un nasıl kullanılması gerektiğini henüz anlamadım - bu sadece işim için doğru olanları bulmam ve sonra bunları projeme kopyalamam gereken kaynak kod dosyalarının bir tarball'u mu? Yüklenecek modül yok mu veya daha basit bir şey mi var?
Dirk

Anladığım: peekIntoNextNWSChar c = self.is .read (1) AttributeError: 'str' nesnesinin 'okuma' özniteliği yok
sqp_125

5

Bunu lxml ile oldukça kolay bir şekilde yapabilirsiniz. Önce kurun:

[sudo] pip install lxml

İşte sizin için işin zor kısmını yapan, yazdığım yinelemeli bir işlev:

from lxml import objectify as xml_objectify


def xml_to_dict(xml_str):
    """ Convert xml to dict, using lxml v3.4.2 xml processing library """
    def xml_to_dict_recursion(xml_object):
        dict_object = xml_object.__dict__
        if not dict_object:
            return xml_object
        for key, value in dict_object.items():
            dict_object[key] = xml_to_dict_recursion(value)
        return dict_object
    return xml_to_dict_recursion(xml_objectify.fromstring(xml_str))

xml_string = """<?xml version="1.0" encoding="UTF-8"?><Response><NewOrderResp>
<IndustryType>Test</IndustryType><SomeData><SomeNestedData1>1234</SomeNestedData1>
<SomeNestedData2>3455</SomeNestedData2></SomeData></NewOrderResp></Response>"""

print xml_to_dict(xml_string)

Aşağıdaki varyant, ana anahtarı / öğeyi korur:

def xml_to_dict(xml_str):
    """ Convert xml to dict, using lxml v3.4.2 xml processing library, see http://lxml.de/ """
    def xml_to_dict_recursion(xml_object):
        dict_object = xml_object.__dict__
        if not dict_object:  # if empty dict returned
            return xml_object
        for key, value in dict_object.items():
            dict_object[key] = xml_to_dict_recursion(value)
        return dict_object
    xml_obj = objectify.fromstring(xml_str)
    return {xml_obj.tag: xml_to_dict_recursion(xml_obj)}

Yalnızca bir alt ağacı döndürmek ve onu dikteye dönüştürmek istiyorsanız, alt ağacı almak için Element.find () öğesini kullanabilir ve ardından onu dönüştürebilirsiniz:

xml_obj.find('.//')  # lxml.objectify.ObjectifiedElement instance

Lxml belgelerine buradan bakın . Umarım bu yardımcı olur!


5

Sorumluluk Reddi: Bu değiştirilmiş XML ayrıştırıcısı Adam Clark'tan esinlenmiştir . Orijinal XML ayrıştırıcı çoğu basit durumda çalışır. Ancak, bazı karmaşık XML dosyaları için işe yaramadı. Kod satırında hata ayıkladım ve sonunda bazı sorunları düzelttim. Bazı hata bulursanız lütfen bana bildirin. Düzeltmekten memnunum.

class XmlDictConfig(dict):  
    '''   
    Note: need to add a root into if no exising    
    Example usage:
    >>> tree = ElementTree.parse('your_file.xml')
    >>> root = tree.getroot()
    >>> xmldict = XmlDictConfig(root)
    Or, if you want to use an XML string:
    >>> root = ElementTree.XML(xml_string)
    >>> xmldict = XmlDictConfig(root)
    And then use xmldict for what it is... a dict.
    '''
    def __init__(self, parent_element):
        if parent_element.items():
            self.updateShim( dict(parent_element.items()) )
        for element in parent_element:
            if len(element):
                aDict = XmlDictConfig(element)
            #   if element.items():
            #   aDict.updateShim(dict(element.items()))
                self.updateShim({element.tag: aDict})
            elif element.items():    # items() is specialy for attribtes
                elementattrib= element.items()
                if element.text:           
                    elementattrib.append((element.tag,element.text ))     # add tag:text if there exist
                self.updateShim({element.tag: dict(elementattrib)})
            else:
                self.updateShim({element.tag: element.text})

    def updateShim (self, aDict ):
        for key in aDict.keys():   # keys() includes tag and attributes
            if key in self:
                value = self.pop(key)
                if type(value) is not list:
                    listOfDicts = []
                    listOfDicts.append(value)
                    listOfDicts.append(aDict[key])
                    self.update({key: listOfDicts})
                else:
                    value.append(aDict[key])
                    self.update({key: value})
            else:
                self.update({key:aDict[key]})  # it was self.update(aDict)    

3
def xml_to_dict(node):
    u''' 
    @param node:lxml_node
    @return: dict 
    '''

    return {'tag': node.tag, 'text': node.text, 'attrib': node.attrib, 'children': {child.tag: xml_to_dict(child) for child in node}}

2

Python için kullanımı en kolay XML ayrıştırıcı ElementTree'dir (2.5x ve üzeri itibariyle standart xml.etree.ElementTree kitaplığındadır). Kutudan tam olarak istediğinizi yapan bir şey olduğunu sanmıyorum. ElementTree kullanarak istediğiniz şeyi yapmak için bir şeyler yazmak oldukça önemsiz olurdu, ancak neden bir sözlüğe dönüştürün ve neden doğrudan ElementTree'yi kullanmıyorsunuz?


2

Http://code.activestate.com/recipes/410469-xml-as-dictionary/ adresindeki kod iyi çalışır, ancak hiyerarşide belirli bir yerde aynı olan birden fazla öğe varsa, bunları geçersiz kılar.

Self.update () 'den önce elemanın zaten var olup olmadığını görmek için arasına bir şim ekledim. Öyleyse, mevcut girişi açar ve mevcut ve yeniden bir liste oluşturur. Sonraki kopyalar listeye eklenir.

Bunun daha zarif bir şekilde ele alınabileceğinden emin değilim, ancak işe yarıyor:

import xml.etree.ElementTree as ElementTree

class XmlDictConfig(dict):
    def __init__(self, parent_element):
        if parent_element.items():
            self.updateShim(dict(parent_element.items()))
        for element in parent_element:
            if len(element):
                aDict = XmlDictConfig(element)
                if element.items():
                    aDict.updateShim(dict(element.items()))
                self.updateShim({element.tag: aDict})
            elif element.items():
                self.updateShim({element.tag: dict(element.items())})
            else:
                self.updateShim({element.tag: element.text.strip()})

    def updateShim (self, aDict ):
        for key in aDict.keys():
            if key in self:
                value = self.pop(key)
                if type(value) is not list:
                    listOfDicts = []
                    listOfDicts.append(value)
                    listOfDicts.append(aDict[key])
                    self.update({key: listOfDicts})

                else:
                    value.append(aDict[key])
                    self.update({key: value})
            else:
                self.update(aDict)

2

@ K3 --- rnc yanıtı (benim için en iyisi) Bir XML metninden OrderedDict almak için küçük değişiklikler ekledim (bazı zamanlarda sıra önemlidir):

def etree_to_ordereddict(t):
d = OrderedDict()
d[t.tag] = OrderedDict() if t.attrib else None
children = list(t)
if children:
    dd = OrderedDict()
    for dc in map(etree_to_ordereddict, children):
        for k, v in dc.iteritems():
            if k not in dd:
                dd[k] = list()
            dd[k].append(v)
    d = OrderedDict()
    d[t.tag] = OrderedDict()
    for k, v in dd.iteritems():
        if len(v) == 1:
            d[t.tag][k] = v[0]
        else:
            d[t.tag][k] = v
if t.attrib:
    d[t.tag].update(('@' + k, v) for k, v in t.attrib.iteritems())
if t.text:
    text = t.text.strip()
    if children or t.attrib:
        if text:
            d[t.tag]['#text'] = text
    else:
        d[t.tag] = text
return d

@ K3 --- rnc örneğini takiben, onu kullanabilirsiniz:

from xml.etree import cElementTree as ET
e = ET.XML('''
<root>
  <e />
  <e>text</e>
  <e name="value" />
  <e name="value">text</e>
  <e> <a>text</a> <b>text</b> </e>
  <e> <a>text</a> <a>text</a> </e>
  <e> text <a>text</a> </e>
</root>
''')

from pprint import pprint
pprint(etree_to_ordereddict(e))

Umarım yardımcı olur ;)


1

İşte bir ActiveState çözümüne bağlantı ve tekrar kaybolması durumunda kod.

==================================================
xmlreader.py:
==================================================
from xml.dom.minidom import parse


class NotTextNodeError:
    pass


def getTextFromNode(node):
    """
    scans through all children of node and gathers the
    text. if node has non-text child-nodes, then
    NotTextNodeError is raised.
    """
    t = ""
    for n in node.childNodes:
    if n.nodeType == n.TEXT_NODE:
        t += n.nodeValue
    else:
        raise NotTextNodeError
    return t


def nodeToDic(node):
    """
    nodeToDic() scans through the children of node and makes a
    dictionary from the content.
    three cases are differentiated:
    - if the node contains no other nodes, it is a text-node
    and {nodeName:text} is merged into the dictionary.
    - if the node has the attribute "method" set to "true",
    then it's children will be appended to a list and this
    list is merged to the dictionary in the form: {nodeName:list}.
    - else, nodeToDic() will call itself recursively on
    the nodes children (merging {nodeName:nodeToDic()} to
    the dictionary).
    """
    dic = {} 
    for n in node.childNodes:
    if n.nodeType != n.ELEMENT_NODE:
        continue
    if n.getAttribute("multiple") == "true":
        # node with multiple children:
        # put them in a list
        l = []
        for c in n.childNodes:
            if c.nodeType != n.ELEMENT_NODE:
            continue
        l.append(nodeToDic(c))
            dic.update({n.nodeName:l})
        continue

    try:
        text = getTextFromNode(n)
    except NotTextNodeError:
            # 'normal' node
            dic.update({n.nodeName:nodeToDic(n)})
            continue

        # text node
        dic.update({n.nodeName:text})
    continue
    return dic


def readConfig(filename):
    dom = parse(filename)
    return nodeToDic(dom)





def test():
    dic = readConfig("sample.xml")

    print dic["Config"]["Name"]
    print
    for item in dic["Config"]["Items"]:
    print "Item's Name:", item["Name"]
    print "Item's Value:", item["Value"]

test()



==================================================
sample.xml:
==================================================
<?xml version="1.0" encoding="UTF-8"?>

<Config>
    <Name>My Config File</Name>

    <Items multiple="true">
    <Item>
        <Name>First Item</Name>
        <Value>Value 1</Value>
    </Item>
    <Item>
        <Name>Second Item</Name>
        <Value>Value 2</Value>
    </Item>
    </Items>

</Config>



==================================================
output:
==================================================
My Config File

Item's Name: First Item
Item's Value: Value 1
Item's Name: Second Item
Item's Value: Value 2

Evet öyle. Tekrar gitme ihtimaline karşı kodu burada yeniden ürettiniz.
Jamie Bull

0

Bir noktada, yalnızca öznitelikleri olmayan öğelerden oluşan XML'i ayrıştırıp yazmak zorunda kaldım, böylece XML'den dikteye 1: 1 eşleme kolayca mümkün oldu. Başka birinin de niteliklere ihtiyaç duymaması durumunda bulduğum şey buydu:

def xmltodict(element):
    if not isinstance(element, ElementTree.Element):
        raise ValueError("must pass xml.etree.ElementTree.Element object")

    def xmltodict_handler(parent_element):
        result = dict()
        for element in parent_element:
            if len(element):
                obj = xmltodict_handler(element)
            else:
                obj = element.text

            if result.get(element.tag):
                if hasattr(result[element.tag], "append"):
                    result[element.tag].append(obj)
                else:
                    result[element.tag] = [result[element.tag], obj]
            else:
                result[element.tag] = obj
        return result

    return {element.tag: xmltodict_handler(element)}


def dicttoxml(element):
    if not isinstance(element, dict):
        raise ValueError("must pass dict type")
    if len(element) != 1:
        raise ValueError("dict must have exactly one root key")

    def dicttoxml_handler(result, key, value):
        if isinstance(value, list):
            for e in value:
                dicttoxml_handler(result, key, e)
        elif isinstance(value, basestring):
            elem = ElementTree.Element(key)
            elem.text = value
            result.append(elem)
        elif isinstance(value, int) or isinstance(value, float):
            elem = ElementTree.Element(key)
            elem.text = str(value)
            result.append(elem)
        elif value is None:
            result.append(ElementTree.Element(key))
        else:
            res = ElementTree.Element(key)
            for k, v in value.items():
                dicttoxml_handler(res, k, v)
            result.append(res)

    result = ElementTree.Element(element.keys()[0])
    for key, value in element[element.keys()[0]].items():
        dicttoxml_handler(result, key, value)
    return result

def xmlfiletodict(filename):
    return xmltodict(ElementTree.parse(filename).getroot())

def dicttoxmlfile(element, filename):
    ElementTree.ElementTree(dicttoxml(element)).write(filename)

def xmlstringtodict(xmlstring):
    return xmltodict(ElementTree.fromstring(xmlstring).getroot())

def dicttoxmlstring(element):
    return ElementTree.tostring(dicttoxml(element))

0

@dibrovsd: xml'de aynı ada sahip birden fazla etiket varsa çözüm çalışmayacaktır

Sizin düşüncenize göre, kodu biraz değiştirdim ve onu kök yerine genel düğüm için yazdım:

from collections import defaultdict
def xml2dict(node):
    d, count = defaultdict(list), 1
    for i in node:
        d[i.tag + "_" + str(count)]['text'] = i.findtext('.')[0]
        d[i.tag + "_" + str(count)]['attrib'] = i.attrib # attrib gives the list
        d[i.tag + "_" + str(count)]['children'] = xml2dict(i) # it gives dict
     return d

0

Zevkime verilen yanıtlardan birini değiştirdim ve aynı etikete sahip birden çok değerle çalışmak için örneğin XML.xml dosyasına kaydedilmiş aşağıdaki xml kodunu düşünün

     <A>
        <B>
            <BB>inAB</BB>
            <C>
                <D>
                    <E>
                        inABCDE
                    </E>
                    <E>value2</E>
                    <E>value3</E>
                </D>
                <inCout-ofD>123</inCout-ofD>
            </C>
        </B>
        <B>abc</B>
        <F>F</F>
    </A>

ve python'da

import xml.etree.ElementTree as ET




class XMLToDictionary(dict):
    def __init__(self, parentElement):
        self.parentElement = parentElement
        for child in list(parentElement):
            child.text = child.text if (child.text != None) else  ' '
            if len(child) == 0:
                self.update(self._addToDict(key= child.tag, value = child.text.strip(), dict = self))
            else:
                innerChild = XMLToDictionary(parentElement=child)
                self.update(self._addToDict(key=innerChild.parentElement.tag, value=innerChild, dict=self))

    def getDict(self):
        return {self.parentElement.tag: self}

    class _addToDict(dict):
        def __init__(self, key, value, dict):
            if not key in dict:
                self.update({key: value})
            else:
                identical = dict[key] if type(dict[key]) == list else [dict[key]]
                self.update({key: identical + [value]})


tree = ET.parse('./XML.xml')
root = tree.getroot()
parseredDict = XMLToDictionary(root).getDict()
print(parseredDict)

çıktı

{'A': {'B': [{'BB': 'inAB', 'C': {'D': {'E': ['inABCDE', 'value2', 'value3']}, 'inCout-ofD': '123'}}, 'abc'], 'F': 'F'}}

-2

Bir lxml öğesinden sözlük almak için yinelemeli bir yöntemim var

    def recursive_dict(element):
        return (element.tag.split('}')[1],
                dict(map(recursive_dict, element.getchildren()),
                     **element.attrib))

1
Bu çözümde, içe aktarma ve kurulum gibi bazı kodlar eksik. 'Str' nesnesinin 'etiketi' niteliği yok mesajını aldım
Chris Nielsen
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.