XML 到/从 Python 字典
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3292973/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
XML to/from a Python dictionary
提问by Liam
I need to use Python 2.4.4 to convert XML to and from a Python dictionary. All I need are the node names and values, I'm not worried about attributes because the XML I'm parsing doesn't have any. I can't use ElementTreebecause that isn't available for 2.4.4, and I can't use 3rd party libraries due to my work environment. What's the easiest way for me to do this? Are there any good snippets?
我需要使用 Python 2.4.4 将 XML 与 Python 字典相互转换。我只需要节点名称和值,我不担心属性,因为我解析的 XML 没有任何属性。我无法使用,ElementTree因为它不适用于 2.4.4,并且由于我的工作环境,我无法使用 3rd 方库。对我来说最简单的方法是什么?有什么好的片段吗?
Also, if there isn't an easy way to do this, are there any alternative serialization formats that Python 2.4.4 has native support for?
另外,如果没有一种简单的方法可以做到这一点,那么 Python 2.4.4 是否有任何其他的序列化格式具有本机支持?
采纳答案by Grey Teardrop
Question Serialize Python dictionary to XMLlists some ways of XML serialization. As for alternative serialization formats, I guess picklemodule is a nice tool for it.
问题Serialize Python dictionary to XML列出了一些 XML 序列化的方法。至于替代序列化格式,我猜pickle模块是一个很好的工具。
回答by Aaron Altman
Grey's link includes some solutions that look pretty robust. If you want to roll your own though, you could use xml.dom.node's childNode member recursively, terminating when node.childNode = None.
Grey 的链接包括一些看起来非常强大的解决方案。如果你想推出你自己的,你可以递归地使用 xml.dom.node 的 childNode 成员,当 node.childNode = None 时终止。
回答by Doug F
I recently wrote some code to translate XML into a python data structure, although I did have to handle attributes. I used xml.dom.minidomrather than ElementTree, for a similar reason. I haven't actually tested this on Python 2.4.4, but I think it will work. I didn't write a reverse XML generator, though you can probably use the 'lispy_string' function I included to do this.
我最近编写了一些代码将 XML 转换为 python 数据结构,尽管我确实必须处理属性。出于类似的原因,我使用了xml.dom.minidom而不是ElementTree。我还没有在 Python 2.4.4 上实际测试过这个,但我认为它会起作用。我没有编写反向 XML 生成器,但您可能可以使用我包含的 'lispy_string' 函数来执行此操作。
I also included some shortcuts specific to the application I was writing (explained in the docstring), but you might find those shortcuts useful too, from the sounds of it. Essentially, an xml tree technically translates into a dictionary of lists of dictionaries of lists of dictionaries of lists, etc. I omit creating the intermediary lists unless they are necessary, so you can reference elements by dictname[element1][element2]rather than dictname[element1][0][element2][0]and so on.
我还包含了一些特定于我正在编写的应用程序的快捷方式(在文档字符串中进行了解释),但是您可能会发现这些快捷方式也很有用,从它的声音来看。从本质上讲,xml 树在技术上可以转换为列表词典列表词典列表等。除非必要,否则我省略了创建中间列表,因此您可以通过dictname[element1][element2]而不是dictname[element1][0][element2][0]等来引用元素。
Attribute handling is a little kludgy, I strongly recommend reading the code before doing anything with attributes.
属性处理有点笨拙,我强烈建议在对属性进行任何操作之前阅读代码。
import sys
from xml.dom import minidom
def dappend(dictionary, key, item):
"""Append item to dictionary at key. Only create a list if there is more than one item for the given key.
dictionary[key]=item if key doesn't exist.
dictionary[key].append(item) if key exists."""
if key in dictionary.keys():
if not isinstance(dictionary[key], list):
lst=[]
lst.append(dictionary[key])
lst.append(item)
dictionary[key]=lst
else:
dictionary[key].append(item)
else:
dictionary.setdefault(key, item)
def node_attributes(node):
"""Return an attribute dictionary """
if node.hasAttributes():
return dict([(str(attr), str(node.attributes[attr].value)) for attr in node.attributes.keys()])
else:
return None
def attr_str(node):
return "%s-attrs" % str(node.nodeName)
def hasAttributes(node):
if node.nodeType == node.ELEMENT_NODE:
if node.hasAttributes():
return True
return False
def with_attributes(node, values):
if hasAttributes(node):
if isinstance(values, dict):
dappend(values, '#attributes', node_attributes(node))
return { str(node.nodeName): values }
elif isinstance(values, str):
return { str(node.nodeName): values,
attr_str(node): node_attributes(node)}
else:
return { str(node.nodeName): values }
def xmldom2dict(node):
"""Given an xml dom node tree,
return a python dictionary corresponding to the tree structure of the XML.
This parser does not make lists unless they are needed. For example:
'<list><item>1</item><item>2</item></list>' becomes:
{ 'list' : { 'item' : ['1', '2'] } }
BUT
'<list><item>1</item></list>' would be:
{ 'list' : { 'item' : '1' } }
This is a shortcut for a particular problem and probably not a good long-term design.
"""
if not node.hasChildNodes():
if node.nodeType == node.TEXT_NODE:
if node.data.strip() != '':
return str(node.data.strip())
else:
return None
else:
return with_attributes(node, None)
else:
#recursively create the list of child nodes
childlist=[xmldom2dict(child) for child in node.childNodes if (xmldom2dict(child) != None and child.nodeType != child.COMMENT_NODE)]
if len(childlist)==1:
return with_attributes(node, childlist[0])
else:
#if False not in [isinstance(child, dict) for child in childlist]:
new_dict={}
for child in childlist:
if isinstance(child, dict):
for k in child:
dappend(new_dict, k, child[k])
elif isinstance(child, str):
dappend(new_dict, '#text', child)
else:
print "ERROR"
return with_attributes(node, new_dict)
def load(fname):
return xmldom2dict(minidom.parse(fname))
def lispy_string(node, lst=None, level=0):
if lst==None:
lst=[]
if not isinstance(node, dict) and not isinstance(node, list):
lst.append(' "%s"' % node)
elif isinstance(node, dict):
for key in node.keys():
lst.append("\n%s(%s" % (spaces(level), key))
lispy_print(node[key], lst, level+2)
lst.append(")")
elif isinstance(node, list):
lst.append(" [")
for item in node:
lispy_print(item, lst, level)
lst.append("]")
return lst
if __name__=='__main__':
data = minidom.parse(sys.argv[1])
d=xmldom2dict(data)
print d
回答by Dmitry Horonitel
Dicts in python are not ordered, remember this. I have a very basic code, which is small and does not require any external modules. Bad thing is that it does not support any kind of XML attributes, but you said
python 中的字典没有顺序,记住这一点。我有一个非常基本的代码,它很小,不需要任何外部模块。不好的是它不支持任何类型的 XML 属性,但是你说
I'm not worried about attributes
我不担心属性
,so here it is:
,所以这里是:
def d2x(d, root="root"):
op = lambda tag: '<' + tag + '>'
cl = lambda tag: '</' + tag + '>\n'
ml = lambda v,xml: xml + op(key) + str(v) + cl(key)
xml = op(root) + '\n' if root else ""
for key,vl in d.iteritems():
vtype = type(vl)
if vtype is list:
for v in vl:
xml = ml(v,xml)
if vtype is dict: xml = ml('\n' + d2x(vl,None),xml)
if vtype is not list and vtype is not dict: xml = ml(vl,xml)
xml += cl(root) if root else ""
return xml
Example of usage:
用法示例:
mydict = {
"boolean":False,
"integer":12,
"float":3.1,
"listitems":["item1","item2"],
"string":"Hello world",
"dictionary":{
"key1":1,
"key2":2,
"dictindict":{
"a":"aaa",
"b":"bbb"
}
}
}
print d2x (mydict,"superxml")
This will print:
这将打印:
<superxml>
<string>Hello world</string>
<dictionary>
<key2>2</key2>
<key1>1</key1>
<dictindict>
<a>aaa</a>
<b>bbb</b>
</dictindict>
</dictionary>
<float>3.1</float>
<listitems>item1</listitems>
<listitems>item2</listitems>
<boolean>False</boolean>
<integer>12</integer>
</superxml>
回答by thomaskonrad
For serializing a Python dict to XML, the following Python class works well for me. Over some other solutions, it has the advantage that it is quite simple and that it does proper XML encoding. The script is based on this answer. It has only one extension: By passing the list_mappingsdictionary to the constructor, you can specify how a single list item (a childinside the childrenattribute in the example below) is named.
为了将 Python dict 序列化为 XML,以下 Python 类对我来说效果很好。与其他一些解决方案相比,它的优势在于它非常简单并且可以进行正确的 XML 编码。该脚本基于此答案。它只有一个扩展:通过将list_mappings字典传递给构造函数,您可以指定单个列表项(下例中child的children属性内部)的命名方式。
from xml.dom.minidom import Document
class DictToXML(object):
default_list_item_name = "item"
def __init__(self, structure, list_mappings={}):
self.doc = Document()
if len(structure) == 1:
rootName = str(list(structure.keys())[0])
self.root = self.doc.createElement(rootName)
self.list_mappings = list_mappings
self.doc.appendChild(self.root)
self.build(self.root, structure[rootName])
def build(self, father, structure):
if type(structure) == dict:
for k in structure:
tag = self.doc.createElement(k)
father.appendChild(tag)
self.build(tag, structure[k])
elif type(structure) == list:
tag_name = self.default_list_item_name
if father.tagName in self.list_mappings:
tag_name = self.list_mappings[father.tagName]
for l in structure:
tag = self.doc.createElement(tag_name)
self.build(tag, l)
father.appendChild(tag)
else:
data = str(structure)
tag = self.doc.createTextNode(data)
father.appendChild(tag)
def display(self):
print(self.doc.toprettyxml(indent=" "))
def get_string(self):
return self.doc.toprettyxml(indent=" ")
if __name__ == '__main__':
example = {'sibling': {'couple': {'mother': 'mom', 'father': 'dad', 'children': [{'child': 'foo'},
{'child': 'bar'}]}}}
xml = DictToXML(example)
xml.display()
It gives the following output:
它提供以下输出:
<?xml version="1.0" ?>
<sibling>
<couple>
<children>
<child>
<name>foo</name>
</child>
<child>
<name>bar</name>
</child>
</children>
<father>dad</father>
<mother>mom</mother>
</couple>
</sibling>

