从Python字典生成XML
我有一些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=""http://www.sat.gob.mx/catalogocuentas"" xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xsi:schemaLocation=""http://www.sat.gob.mx//catalogocuentas"">
<catalogocuentas:Ctas CodAgrup="2.1" Desc="Bancomer 12911256971" Natur="D" NumCta="1120-001-002" SubCtaDe="1120-001-000" nivel="3"/>
</catalogocuentas:Catalogo>
如你所见,我只得到了d3中的最后一个元素(字典),而不是所有的元素。
由此我可以推测,问题可能是因为在这个字典中,我的所有元素都使用了相同的标签。
这真的是问题所在吗?
任何建议都将非常感谢!!!
提前谢谢大家。
2 个回答
0
现在已经有一些现成的库可以用来做这个事情,其中一个是我自己创建的。使用这个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结构,并且让它正确地格式化,你需要稍微修改一下你的字典,因为你现在还没有为cfdi
定义XML的命名空间。我使用了以下这个字典:
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
这个键来设置命名空间,而不是使用带冒号的字符串。
1
你的代码格式让我看得很不舒服。Python有一个格式规范指南,可以帮助你。特别是,你的代码行太长了,违反了这个规范。
如果你想把Python字典格式化成XML,有很多标准的方法可以选择。可以看看这个之前的问题,里面有一些解决方案。
Python字典中同一个键只能有一个元素,如果你重复添加同样的键,后面的会覆盖前面的。