Создание XML из словаря Python

У меня есть словари Python со следующей структурой:

d={ 'cfdi:Emisor': {'rfc': u'ALF040329CX6', 'nombre': u'ALFATECH, S.A. DE C.V.', 
     'cfdi:RegimenFiscal': {'Regimen': u'Personas morales del r\xe9gimen general'}, 
      'cfdi:ExpedidoEn': {'calle': u'ING. INDUSTRIALES', 'localidad': u'MORELIA', 'pais':   u'M\xe9xico', 'noInterior': 'N/A', 'colonia': u'BUENAVISTA 1A ETAPA', 'noExterior': u'215', 'codigoPostal': u'58228', 'estado': u'Michoac\xe1n', 'municipio': u'MORELIA'}, 
       'cfdi:DomicilioFiscal': {'calle': u'ING. INDUSTRIALES', 'localidad': u'MORELIA', 'pais': u'M\xe9xico', 'noInterior': 'N/A', 'colonia': u'BUENAVISTA 1A ETAPA', 'noExterior': u'215', 'codigoPostal': u'58228', 'estado': u'Michoac\xe1n', 'municipio': u'MORELIA'}, 
        }}

Структура состоит из словарей внутри словаря. Мне нужно преобразовать его в XML, тогда я получил следующий код для этого:

def dict2xml(data_dict, node=False, doc=False):

    parent = False
    if node:
        parent = True

    for element, attribute in data_dict.iteritems():
        if not parent:
            doc = minidom.Document()
        if isinstance(attribute, dict):
            if not parent:
                node = doc.createElement(element)
                dict2xml(attribute, node, doc)
            else:
                child = doc.createElement(element)
                dict2xml(attribute, child, doc)
                node.appendChild(child)
        elif isinstance(attribute, list):
            child = doc.createElement(element)
            for attr in attribute:
                if isinstance(attr, dict):
                    dict2xml(attr, child, doc)
            node.appendChild(child)
        else:
            if isinstance(attribute, str) or isinstance(attribute, unicode):
                attribute = str(attribute)
            else:
                    attribute = str(attribute)
            node.setAttribute(element, attribute)
            # print "attribute",unicode( attribute, 'UTF-8')
    if not parent:
        doc.appendChild(node)
    print doc.toprettyxml(indent="     ", encoding='utf-8')
    return doc

Эта функция отлично работает с предыдущим словарем и возвращает это:

<cfdi:Emisor nombre="ALFATECH, S.A. DE C.V." rfc="ALF040329CX6">
    <cfdi:RegimenFiscal Regimen="Personas morales del régimen general"/>
    <cfdi:ExpedidoEn calle="ING. INDUSTRIALES" codigoPostal="58228" colonia="BUENAVISTA 1A ETAPA" estado="Michoacán" localidad="MORELIA" municipio="MORELIA" noExterior="215" noInterior="N/A" pais="México"/>
    <cfdi:DomicilioFiscal calle="ING. INDUSTRIALES" codigoPostal="58228" colonia="BUENAVISTA 1A ETAPA" estado="Michoacán" localidad="MORELIA" municipio="MORELIA" noExterior="215" noInterior="N/A" pais="México"/>
</cfdi:Emisor>

это то, чего я ждал, но теперь мне нужно сделать то же самое с этим словарем, который имеет в основном ту же структуру, но содержит другие элементы:

d3={ 'catalogocuentas:Catalogo': {'rfc': u'ALF040329CX6', 'xmlns:catalogocuentas':'"http://www.sat.gob.mx/catalogocuentas"', 'xmlns:xsi':'"http://www.w3.org/2001/XMLSchema-instance"', 'xsi:schemaLocation':'"http://www.sat.gob.mx//catalogocuentas"', 'Ano':'2014', 'Mes':'02', 'TotalCtas':'219','version':'1.0', 
     'catalogocuentas:Ctas': {'Natur': u'D', 'nivel':'2', 'SubCtaDe':'1110-000-000', 'Desc':'CAJA CHICA', 'NumCta':'1110-001-000', 'CodAgrup':'1.1'}, 
      'catalogocuentas:Ctas': {'Natur': u'D', 'nivel':'3', 'SubCtaDe':'1120-001-000', 'Desc':'Banamex 741107-1', 'NumCta':'1120-001-001', 'CodAgrup':'2.1'}, 
       'catalogocuentas:Ctas': {'Natur': u'D', 'nivel':'3', 'SubCtaDe':'1120-001-000', 'Desc':'Bancomer 12911256971', 'NumCta':'1120-001-002', 'CodAgrup':'2.1'} 
        }}

Вы, ребята, можете видеть, что основное отличие состоит в том, что этот словарь имеет ОДИНАКОВЫЙ ТЕГ для внутренних элементов (словарей), и я получил следующий результат:

<?xml version="1.0" encoding="utf-8"?>
   <catalogocuentas:Catalogo Ano="2014" Mes="02" TotalCtas="219" rfc="ALF040329CX6"     version="1.0" xmlns:catalogocuentas="&quot;http://www.sat.gob.mx/catalogocuentas&quot;" xmlns:xsi="&quot;http://www.w3.org/2001/XMLSchema-instance&quot;" xsi:schemaLocation="&quot;http://www.sat.gob.mx//catalogocuentas&quot;">
         <catalogocuentas:Ctas CodAgrup="2.1" Desc="Bancomer 12911256971" Natur="D" NumCta="1120-001-002" SubCtaDe="1120-001-000" nivel="3"/>
   </catalogocuentas:Catalogo>

Как видите, я получил только ПОСЛЕДНИЙ элемент (словарь) из d3, а не все.

Из этого могу сделать вывод, что проблема может быть в том, что в этом словаре у меня один и тот же тег для всех моих элементов.

Это реальная проблема?

Любые предложения будут высоко оценены!!!

Заранее спасибо.


person Diego Calzadilla    schedule 11.08.2014    source источник


Ответы (2)


От вашего форматирования кода у меня болят глаза. Вам поможет руководство по стилю форматирования Python. В частности, вы злоупотребляете максимальной длиной строки.

Если вы хотите отформатировать словари Python в XML, есть ряд стандартных опций. См. этот предыдущий вопрос для некоторых решений.

Словарь Python позволяет использовать только один элемент на основе одного и того же ключа, повторяющиеся записи перезаписывают предыдущие записи.

person Gary Walker    schedule 11.08.2014
comment
Спасибо, так что ... если python перезаписывает предыдущие записи ... это определенно невозможно сделать с помощью minidom ?? - person Diego Calzadilla; 12.08.2014
comment
Вы не можете создать словарь Python с повторяющимися ключами. Это не вопрос DOM или XML. Вы не строите словарь, о котором вы думали. Вы можете создать словарь Python, где одно значение ключа представляет собой список объектов, и сериализовать его в XML. - person Gary Walker; 12.08.2014

Для этого уже существуют библиотеки, одну из них я создал. Используя пакет xmler, вы можете взять свой словарь и довольно легко превратить его в следующий xml:

<?xml version="1.0" encoding="UTF-8"?><?xml version="1.0" ?>
<cfdi:Emisor xmlns:cfdi="www.sat.gob.mx/cfd/3">
    <cfdi:DomicilioFiscal>
        <pais>Mexico</pais>
        <localidad>MORELIA</localidad>
        <estado>Michoacán</estado>
        <noExterior>215</noExterior>
        <municipio>MORELIA</municipio>
        <calle>ING. INDUSTRIALES</calle>
        <noInterior>N/A</noInterior>
        <codigoPostal>58228</codigoPostal>
        <colonia>BUENAVISTA 1A ETAPA</colonia>
    </cfdi:DomicilioFiscal>
    <nombre>ALFATECH, S.A. DE C.V.</nombre>
    <cfdi:ExpedidoEn>
        <pais>Mexico</pais>
        <localidad>MORELIA</localidad>
        <estado>Michoacán</estado>
        <noExterior>215</noExterior>
        <municipio>MORELIA</municipio>
        <calle>ING. INDUSTRIALES</calle>
        <noInterior>N/A</noInterior>
        <codigoPostal>58228</codigoPostal>
        <colonia>BUENAVISTA 1A ETAPA</colonia>
    </cfdi:ExpedidoEn>
    <rfc>ALF040329CX6</rfc>
    <cfdi:RegimenFiscal>
        <Regimen>Personas morales del régimen general</Regimen>
    </cfdi:RegimenFiscal>
</cfdi:Emisor>

Чтобы получить эту XML-структуру и правильно ее напечатать, вам придется немного изменить свой словарь, поскольку в настоящее время вы не определяете пространства имен xml для cfdi. Я использовал следующий словарь:

d = {
    "cfdi:Emisor": {
        "@attrs": {
            "xmlns:cfdi": "www.sat.gob.mx/cfd/3"
        },
        "rfc": "ALF040329CX6",
        "nombre": "ALFATECH, S.A. DE C.V.",
        "cfdi:RegimenFiscal": {
            "Regimen": "Personas morales del r\xe9gimen general"
        },
        "cfdi:ExpedidoEn": {
            "calle": "ING. INDUSTRIALES",
            "localidad": "MORELIA",
            "pais": "Mexico",
            "noInterior": "N/A",
            "colonia": "BUENAVISTA 1A ETAPA",
            "noExterior": "215",
            "codigoPostal": "58228",
            "estado": "Michoac\xe1n",
            "municipio": "MORELIA"
        },
        "cfdi:DomicilioFiscal": {
            "calle": "ING. INDUSTRIALES",
            "localidad": "MORELIA",
            "pais": "Mexico",
            "noInterior": "N/A",
            "colonia": "BUENAVISTA 1A ETAPA",
            "noExterior": "215",
            "codigoPostal": "58228",
            "estado": "Michoac\xe1n",
            "municipio": "MORELIA"
        }
    }
}

а потом побежал

print(xmler(d, customRoot=None, pretty=True))

Обратите внимание на ключ @attrs в словаре. Он добавляет атрибуты к элементу. Вы также можете использовать здесь клавишу @ns, чтобы установить пространства имен, а не использовать строку, разделенную двоеточием.

person watzon    schedule 10.08.2016