XML 문자열을 사전으로 변환하는 방법은 무엇입니까?


125

소켓에서 xml 문서를 읽는 프로그램이 있습니다. Django의 simplejson라이브러리 에서 수행되는 것과 동일한 방식으로 Python 사전으로 직접 변환하려는 문자열에 저장된 xml 문서가 있습니다.

예를 들어 :

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

그러면 다음 dic_xml과 같이 보일 것입니다.{'person' : { 'name' : 'john', 'age' : 20 } }


str에는 몇 가지 구문 오류가 있습니다. try : str = '<? xml version = "1.0"?> <person> <name> john </ name> <age> 20 </ age> </ person>'
Keir

답변:


58

이것은 누군가가 만든 훌륭한 모듈입니다. 나는 그것을 여러 번 사용했습니다. http://code.activestate.com/recipes/410469-xml-as-dictionary/

다음은 링크가 잘못 될 경우를 대비하여 웹 사이트의 코드입니다.

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

사용 예 :

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

// 또는 XML 문자열을 사용하려는 경우 :

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

4
U는 'xmltodict'를 대신 사용할 수 있습니다
mrash

7
나는 이것을 시도했고 xmltodict보다 훨씬 빠릅니다. 80MB xml 파일을 파싱하는 데 7 초가 걸렸고 xmltodict를 사용하면 90 초가 걸렸습니다
Eddy

1
확인했습니다. 모든 경우에 대해 테스트하지는 않았지만 다소 복잡하지 않은 XML 문자열의 경우 매우 빠릅니다 ( xmltodict라이브러리 보다 약 8 배 빠름 ). 단점은 프로젝트 내에서 직접 호스팅해야한다는 것입니다.
Dirk

10
안녕하세요,이 완벽하게 작동 찾을 수없는 사람들을 위해 스 니펫을 추가 할 것입니다 cElementTree단지에 첫 번째 줄을 변경 : from xml.etree import cElementTree as ElementTree
라파엘 아길라에게

2
특히 동일한 이름을 가진 여러 태그를 처리 할 때 아래에 더 나은 답변이 게시되어 있으므로 아래로 투표합니다.
Maksym

280

xmltodict (전체 공개 : 내가 썼습니다)는 정확히 다음과 같이합니다.

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
이것은 환상적인 모듈입니다.
zekel 2012-07-13

2
당신은 저에게 많은 노력을 절약했습니다. 내 하루를 만들었습니다.
LRE

3
또한 미래의 googlenauts를 위해-나는 이것을 App Engine에서 사용할 수 있었는데, 파이썬의 대부분의 xml 라이브러리에서 잘 작동하지 않는다고 믿었습니다.
LRE

2
u는 저장된 유니 코드 문자열임을 나타냅니다. 어떤 식 으로든 문자열의 값에 영향을주지 않습니다.
Joshua Olson

2
좋은. 그리고 예, @ypercube, 그 반대를위한 xmldict.unparse () 함수가 있습니다.
Duther 2014 년

47

다음 XML-to-Python-dict 스 니펫은 이 XML-to-JSON "사양"을 따르는 속성뿐만 아니라 엔티티를 구문 분석 합니다. XML의 모든 경우를 처리하는 가장 일반적인 솔루션입니다.

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

다음과 같이 사용됩니다.

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

이 예제의 출력 (위에 링크 된 "사양"에 따라)은 다음과 같아야합니다.

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

반드시 예쁘지는 않지만 모호하지 않으며 더 간단한 XML 입력으로 더 간단한 JSON이 생성됩니다. :)


최신 정보

당신이하고 싶은 경우 역을 , 방출 JSON / DICT에서 XML 문자열을 , 당신은 사용할 수 있습니다 :

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
이 코드에 대한 Thx! 추가 정보 : 파이썬 2.5를 사용하는 경우 사전 이해력을 사용할 수 없으므로 행 d = {t.tag: {k:v[0] if len(v) == 1 else v for k, v in dd.iteritems()}} 을 다음 으로 변경해야합니다 . d = { t.tag: dict( (k, v[0] if len(v) == 1 else v) for k, v in dd.iteritems() ) }
M--

2
나는 거의 10 개의 스 니펫 / 파이썬 모듈 등을 테스트했습니다. 이것은 내가 찾은 최고입니다. 내 테스트에 따르면, : 1) 훨씬 더 빨리보다 github.com/martinblech/xmltodict (XML의 SAX API) 2 기준)보다 나은 github.com/mcspring/XML2Dict 여러 아이들이 같은 이름 3이 몇 가지 작은 문제가 있습니다 ) 작은 문제도 있고 더 중요한 code.activestate.com/recipes/410469-xml-as-dictionary 보다 낫습니다 : 4) 이전의 모든 것보다 훨씬 짧은 코드! 감사합니다 @ K3 --- RNC
Basj

이것은 지금까지 가장 포괄적 인 답변이며 2.6 이상에서 작동하며 상당히 유연합니다. 내 유일한 문제는 텍스트가 속성이 있는지 여부에 따라 위치가 변경 될 수 있다는 것입니다.) 더 작고 더 단단한 솔루션도 게시했습니다.
Erik Aronesty

1
XML 파일에서 정렬 된 dict를
가져와야

이것은 또한 꽤 멋진 빠른 함께 사용할 때입니다 cElementTreelxml.etree. 파이썬 3를 사용하는 경우, 모든 것을 참고 .iteritems()있다가로 변경합니다 .items()(같은 동작하지만 3 파이썬이 변경 키워드).
Dirk

25

이 경량 버전은 구성 할 수 없지만 필요에 따라 조정하기가 매우 쉽고 오래된 파이썬에서 작동합니다. 또한 엄격합니다. 즉, 속성의 존재 여부에 관계없이 결과가 동일합니다.

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

그래서:

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

dictify(root)

결과 :

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

2
이 솔루션이 마음에 듭니다. 간단하고 외부 라이브러리가 필요하지 않습니다.
MattK

6

최신 버전의 PicklingTools 라이브러리 (1.3.0 및 1.3.1)는 XML에서 Python dict로 변환하는 도구를 지원합니다.

여기에서 다운로드 할 수 있습니다. PicklingTools 1.3.1

여기 에 변환기에 대한 문서가 많이 있습니다 . 문서는 XML과 Python 사전간에 변환 할 때 발생하는 모든 결정과 문제에 대해 자세히 설명합니다 (특성, 목록, 익명 목록, 익명의 여러 경우가 있습니다. 대부분의 변환기가 처리하지 않는 dicts, eval 등). 그러나 일반적으로 변환기는 사용하기 쉽습니다. 'example.xml'에 다음이 포함 된 경우 :

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

그런 다음 사전으로 변환하려면 :

>>> 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'}}

C ++와 Python 모두에서 변환하는 도구가 있습니다. C ++와 Python은 indentical 변환을 수행하지만 C ++는 약 60 배 더 빠릅니다.


물론 2 개의 a가 있으면 좋은 형식이 아닙니다.
Erik Aronesty 2015-06-18

1
흥미로워 보이지만 PicklingTools가 어떻게 사용되는지 아직 파악하지 못했습니다.이 파일은 내 작업에 적합한 파일을 찾은 다음 내 프로젝트에 복사해야하는 소스 코드 파일의 타르볼 일 뿐입니 까? 로드 할 모듈이 없거나 더 간단한 것이 있습니까?
Dirk

내가 얻을 :에 peekIntoNextNWSChar C = self.is .read (1) AttributeError : 'STR'개체가 어떤 속성이없는 '읽기'
sqp_125

5

lxml을 사용하면이 작업을 매우 쉽게 수행 할 수 있습니다. 먼저 설치하십시오.

[sudo] pip install lxml

여기에 내가 작성한 재귀 함수가 있습니다.

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)

아래 변형은 상위 키 / 요소를 유지합니다.

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

하위 트리 만 반환하고 dict로 변환하려는 경우 Element.find () 를 사용 하여 하위 트리를 가져온 다음 변환 할 수 있습니다.

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

여기 에서 lxml 문서를 참조 하십시오 . 이게 도움이 되길 바란다!


5

면책 조항 :이 수정 된 XML 파서는 Adam Clark에 의해 영감을 받았습니다 . 원래 XML 파서는 대부분의 간단한 경우에 작동합니다. 그러나 일부 복잡한 XML 파일에서는 작동하지 않았습니다. 코드를 한 줄씩 디버깅하고 마침내 몇 가지 문제를 해결했습니다. 버그를 발견하면 알려주세요. 나는 그것을 고쳐서 기쁘다.

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 용 XML 파서를 사용하는 가장 쉬운 방법은 ElementTree입니다 (2.5x 이상에서는 표준 라이브러리 xml.etree.ElementTree에 있음). 나는 당신이 상자에서 원하는 것을 정확히 수행하는 것이 없다고 생각합니다. ElementTree를 사용하여 원하는 작업을 수행하기 위해 무언가를 작성하는 것은 매우 사소한 일이지만 왜 사전으로 변환하고 ElementTree를 직접 사용하지 않는 이유는 무엇입니까?


2

http://code.activestate.com/recipes/410469-xml-as-dictionary/ 의 코드 는 잘 작동하지만 계층 구조의 지정된 위치에 동일한 요소가 여러 개 있으면 해당 요소를 무시합니다.

self.update () 전에 요소가 이미 존재하는지 확인하기 위해 그 사이에 shim을 추가했습니다. 그렇다면 기존 항목을 팝하고 기존 항목과 새 항목에서 목록을 만듭니다. 이후의 모든 중복 항목이 목록에 추가됩니다.

이것이 더 우아하게 처리 될 수 있는지 확실하지 않지만 작동합니다.

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 응답 (나에게 가장 적합 함)에서 XML 텍스트에서 OrderedDict를 가져 오기 위해 약간의 수정을 추가했습니다 (때로는 순서가 중요 함).

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 예제에 따라 사용할 수 있습니다.

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

도움이 되었기를 바랍니다;)


1

다음은 ActiveState 솔루션에 대한 링크 이며 다시 사라질 경우를 대비 한 코드입니다.

==================================================
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

네, 그렇습니다. 다시 갈 경우를 대비하여 여기에 코드를 재현했습니다.
제이미 불

0

한때 속성이없는 요소로만 구성된 XML을 구문 분석하고 작성해야했기 때문에 XML에서 dict 로의 1 : 1 매핑이 쉽게 가능했습니다. 이것은 다른 사람도 속성이 필요하지 않은 경우에 내놓은 것입니다.

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에 동일한 이름의 태그가 두 개 이상 있으면 솔루션이 작동하지 않습니다.

귀하의 생각에 따라 코드를 약간 수정하고 루트 대신 일반 노드에 대해 작성했습니다.

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

내 취향에 대한 답변 중 하나를 수정하고 동일한 태그로 여러 값으로 작업하기 위해 예를 들어 XML.xml 파일에 저장된 다음 xml 코드를 고려하십시오.

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

그리고 파이썬에서

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)

출력은

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

-2

lxml 요소에서 사전을 가져 오는 재귀 적 방법이 있습니다.

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

1
이 솔루션에는 가져 오기 및 설정과 같은 일부 코드가 없습니다. 나는 메시지 'STR'객체가 더 속성 '태그'가있어
크리스 닐슨
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.