2010-07-20 62 views
4

我需要使用Python 2.4.4将XML转换为Python字典和从Python字典转换。我所需要的只是节点名称和值,我并不担心属性,因为我解析的XML没有任何属性。我不能使用ElementTree,因为它不适用于2.4.4,并且由于我的工作环境,我无法使用第三方库。我做这件事最简单的方法是什么?有没有好的片段?来自Python字典的XML

另外,如果没有简单的方法来做到这一点,是否有Python 2.4.4原生支持的其他序列化格式?

回答

3

问题Serialize Python dictionary to XML列出了XML序列化的一些方法。至于替代序列化格式,我猜pickle模块是一个很好的工具。

+1

关于这一问题的的3/4是外部库,这是不是我的选择。最后一个编组XML文档,这不是我正在寻找的,但它似乎首先将其转换为字典,所以我会看看。 – Liam 2010-07-21 15:57:03

1

格雷的链接包括一些看起来非常健壮的解决方案。如果你想滚动你自己,你可以递归地使用xml.dom.node的childNode成员,当node.childNode = None时结束。

5

我最近写了一些代码来将XML转换成python数据结构,尽管我必须处理属性。出于类似的原因,我使用了xml.dom.minidom而不是ElementTree。我没有真正在Python 2.4.4上测试过,但我认为它会起作用。我没有编写一个反向XML生成器,尽管你可以使用我包含的'lispy_string'函数来完成此操作。

我还包含了一些特定于我正在编写的应用程序的快捷方式(在docstring中进行了解释),但是您可能会发现这些快捷方式也很有用,从它的声音中也是如此。从本质上讲,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 
+0

这是一个很好的例子。谢谢! – rsmoorthy 2013-08-22 04:31:14

+0

我稍微修改了这个以包含附加功能,它在http://pastebin.com/rtDQsR2j – rsmoorthy 2013-08-22 18:25:24

+0

真棒!谢谢! – 2016-05-03 06:04:58

2

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

对于将Python字典序列化为XML,以下Python类对我来说效果很好。在其他一些解决方案中,它具有非常简单的优点,并且它可以执行正确的XML编码。该脚本基于this answer。它只有一个扩展名:通过将list_mappings字典传递给构造函数,可以指定单个列表项(children属性在以下示例中为child)的命名方式。

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

已经有一个包[dicttoxml](https://pypi.python.org/pypi/dicttoxml)。我建议使用它,因为它已经在Python Package Index中列出并且有详细记录。 – philosopher 2017-05-09 11:27:54