我需要使用 Python 2.4.4 将 XML 与 Python 字典相互转换。我只需要节点名称和值,我不担心属性,因为我正在解析的 XML 没有任何属性。我不能使用ElementTree
,因为它不适用于 2.4.4,而且由于我的工作环境,我不能使用 3rd 方库。对我来说最简单的方法是什么?有什么好的片段吗?
此外,如果没有简单的方法来做到这一点,是否有 Python 2.4.4 原生支持的其他序列化格式?
我需要使用 Python 2.4.4 将 XML 与 Python 字典相互转换。我只需要节点名称和值,我不担心属性,因为我正在解析的 XML 没有任何属性。我不能使用ElementTree
,因为它不适用于 2.4.4,而且由于我的工作环境,我不能使用 3rd 方库。对我来说最简单的方法是什么?有什么好的片段吗?
此外,如果没有简单的方法来做到这一点,是否有 Python 2.4.4 原生支持的其他序列化格式?
我最近编写了一些代码来将 XML 转换为 python 数据结构,尽管我确实必须处理属性。出于类似的原因,我使用了xml.dom.minidom
而不是。ElementTree
我实际上还没有在 Python 2.4.4 上测试过这个,但我认为它会起作用。我没有编写反向 XML 生成器,尽管您可以使用我包含的 'lispy_string' 函数来执行此操作。
我还包含了一些特定于我正在编写的应用程序的快捷方式(在文档字符串中进行了解释),但是从听起来你可能会发现这些快捷方式也很有用。从本质上讲,xml 树在技术上转换为列表字典列表的字典列表等。除非必要,否则我省略创建中间列表,因此您可以通过dictname[element1][element2]
而不是dictname[element1][0][element2][0]
等方式引用元素。
属性处理有点笨拙,我强烈建议在对属性进行任何操作之前阅读代码。
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
问题Serialize Python dictionary to XML列出了一些 XML 序列化的方法。至于替代的序列化格式,我猜pickle
模块是一个很好的工具。
python中的字典没有顺序,记住这一点。我有一个非常基本的代码,它很小,不需要任何外部模块。不好的是它不支持任何类型的 XML 属性,但你说
我不担心属性
,所以这里是:
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
使用示例:
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")
这将打印:
<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>
为了将 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()
它提供以下输出:
<?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>
Grey 的链接包括一些看起来非常强大的解决方案。如果你想自己动手,你可以递归地使用 xml.dom.node 的 childNode 成员,当 node.childNode = None 时终止。