我在网上看到过相当多笨拙的XML->JSON代码,并与Stack的用户进行了一些互动,我相信这群人能比谷歌结果的前几页提供更多的帮助。

因此,我们正在解析一个天气提要,我们需要在许多网站上填充天气小部件。我们现在正在研究基于python的解决方案。

这个公共weather.com RSS提要是我们将要解析的内容的一个很好的例子(我们实际的weather.com提要包含额外的信息,因为与他们有合作关系)。

简而言之,如何使用Python将XML转换为JSON ?


当前回答

这里的东西是主动维护的,到目前为止是我最喜欢的:python中的xml2json

其他回答

我建议不要直接转换。将XML转换为对象,然后从对象转换为JSON。

在我看来,这为XML和JSON如何对应提供了一个更清晰的定义。

这需要时间来调整,你甚至可以编写工具来帮助你生成一些内容,但它大致如下所示:

class Channel:
  def __init__(self)
    self.items = []
    self.title = ""

  def from_xml( self, xml_node ):
    self.title = xml_node.xpath("title/text()")[0]
    for x in xml_node.xpath("item"):
      item = Item()
      item.from_xml( x )
      self.items.append( item )

  def to_json( self ):
    retval = {}
    retval['title'] = title
    retval['items'] = []
    for x in items:
      retval.append( x.to_json() )
    return retval

class Item:
  def __init__(self):
    ...

  def from_xml( self, xml_node ):
    ...

  def to_json( self ):
    ...

虽然用于XML解析的内置库非常好,但我更倾向于lxml。

但是对于解析RSS提要,我推荐Universal Feed Parser,它也可以解析Atom。 它的主要优点是它甚至可以消化大多数畸形的饲料。

Python 2.6已经包含了一个JSON解析器,但是速度有所提高的新版本是simplejson。

有了这些工具,构建你的应用应该不会那么困难。

这是我为此编写的代码。没有对内容进行解析,只是简单的转换。

from xml.dom import minidom
import simplejson as json
def parse_element(element):
    dict_data = dict()
    if element.nodeType == element.TEXT_NODE:
        dict_data['data'] = element.data
    if element.nodeType not in [element.TEXT_NODE, element.DOCUMENT_NODE, 
                                element.DOCUMENT_TYPE_NODE]:
        for item in element.attributes.items():
            dict_data[item[0]] = item[1]
    if element.nodeType not in [element.TEXT_NODE, element.DOCUMENT_TYPE_NODE]:
        for child in element.childNodes:
            child_name, child_dict = parse_element(child)
            if child_name in dict_data:
                try:
                    dict_data[child_name].append(child_dict)
                except AttributeError:
                    dict_data[child_name] = [dict_data[child_name], child_dict]
            else:
                dict_data[child_name] = child_dict 
    return element.nodeName, dict_data

if __name__ == '__main__':
    dom = minidom.parse('data.xml')
    f = open('data.json', 'w')
    f.write(json.dumps(parse_element(dom), sort_keys=True, indent=4))
    f.close()

你可能想看看http://designtheory.org/library/extrep/designdb-1.0.pdf。这个项目从一个大型XML文件库的XML到JSON转换开始。在转换过程中进行了大量研究,并生成了最简单直观的XML -> JSON映射(在本文前面有描述)。总之,将所有内容转换为JSON对象,并将重复块作为对象列表。

表示键/值对的对象(Python中的字典,Java中的hashmap, JavaScript中的对象)

没有映射回XML以获得相同的文档,原因是,键/值对是属性还是<key>value</key>,因此该信息丢失。

如果你问我,我会说属性是一个入门;但它们在HTML上也很好用。

我发现对于简单的XML片段,使用正则表达式会省事。例如:

# <user><name>Happy Man</name>...</user>
import re
names = re.findall(r'<name>(\w+)<\/name>', xml_string)
# do some thing to names

正如@Dan所说,要通过XML解析来做到这一点,并没有万能的解决方案,因为数据是不同的。我的建议是使用lxml。虽然没有完成json, lxml。物化的效果很好:

>>> from lxml import objectify
>>> root = objectify.fromstring("""
... <root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
...   <a attr1="foo" attr2="bar">1</a>
...   <a>1.2</a>
...   <b>1</b>
...   <b>true</b>
...   <c>what?</c>
...   <d xsi:nil="true"/>
... </root>
... """)

>>> print(str(root))
root = None [ObjectifiedElement]
    a = 1 [IntElement]
      * attr1 = 'foo'
      * attr2 = 'bar'
    a = 1.2 [FloatElement]
    b = 1 [IntElement]
    b = True [BoolElement]
    c = 'what?' [StringElement]
    d = None [NoneElement]
      * xsi:nil = 'true'