如何在Python中将XML转换为JSON?

65

可能是重复问题:
如何使用Python将XML转换为JSON?

我正在开发App Engine,并且需要将从远程服务器检索的XML文档转换为等效的JSON对象。

我使用xml.dom.minidom解析urlfetch返回的XML数据。 我还尝试使用django.utils.simplejson将解析的XML文档转换为JSON。 我完全不知道如何将两者连接在一起。 下面是我正在尝试调试的代码:

from xml.dom import minidom
from django.utils import simplejson as json

#pseudo code that returns actual xml data as a string from remote server. 
result = urlfetch.fetch(url,'','get');

dom = minidom.parseString(result.content)
json = simplejson.load(dom)

self.response.out.write(json)

以前:https://dev59.com/f3VC5IYBdhLWcg3ww0Hr - RexE
看一下这个:https://github.com/aausch/filteringxmljsonifier - blueberryfields
7个回答

85

xmltodict(完全透明:我写过)可以帮助您将XML转换为字典+列表+字符串结构,并遵循此“标准”。它基于Expat,因此非常快速,并且不需要在内存中加载整个XML树。

一旦您拥有该数据结构,就可以将其序列化为JSON:

import xmltodict, json

o = xmltodict.parse('<e> <a>text</a> <a>text</a> </e>')
json.dumps(o) # '{"e": {"a": ["text", "text"]}}'

4
你写过它的反义词吗?我对这样的东西很感兴趣。 - zigg
我还没做过,但听起来并不太难。不过,我不知道该怎么处理“半结构化”的xml。像 <a>text <b>c</b> moretext</a> -> {'a': {'#text': 'text moretext', 'b': 'c'}} -> 然后呢? - Martin Blech
1
如果您严格按照Goessner的文章,实际上应该有{'a': 'text <b>c</b> moretext'},然后回路到<a>text &lt;b&gt;c&lt;/b&gt; moretext</a>... JSON和XML之间的不匹配使得这种情况非常尴尬。无论如何,我还是用ElementTree尝试了整个过程,因为我正在进行API工作。https://github.com/zigg/xon - zigg
1
@MartinBlech,xmltodict对我的eBay RSS阅读器项目非常完美,谢谢! - Haqa
6
xmltodict现在似乎有一个“unparse”方法,可以执行相反的操作。 - Rob Dennis
libexpat库存在一些问题,无法处理元素名称中的全角括号。 - Wei Qiu

27

Soviut对于lxml objectify的建议很好。使用一个特别子类化的simplejson,你可以将一个lxml objectify结果转换成json。

import simplejson as json
import lxml

class objectJSONEncoder(json.JSONEncoder):
  """A specialized JSON encoder that can handle simple lxml objectify types
      >>> from lxml import objectify
      >>> obj = objectify.fromstring("<Book><price>1.50</price><author>W. Shakespeare</author></Book>")       
      >>> objectJSONEncoder().encode(obj)
      '{"price": 1.5, "author": "W. Shakespeare"}'       
 """


    def default(self,o):
        if isinstance(o, lxml.objectify.IntElement):
            return int(o)
        if isinstance(o, lxml.objectify.NumberElement) or isinstance(o, lxml.objectify.FloatElement):
            return float(o)
        if isinstance(o, lxml.objectify.ObjectifiedDataElement):
            return str(o)
        if hasattr(o, '__dict__'):
            #For objects with a __dict__, return the encoding of the __dict__
            return o.__dict__
        return json.JSONEncoder.default(self, o)
请参阅文档字符串以获取使用示例,基本上您需要将lxml的 objectify 结果传递给 objectJSONEncoder 实例的encode方法。
请注意,Koen的观点在这里非常有效,上面的解决方案仅适用于简单嵌套的xml,并且不包括根元素的名称。这可以修复。
我在这里的gist中包含了这个类:http://gist.github.com/345559

2
如果我有一个标签,它有几个具有相同标签名称的子元素,该怎么办? - vittore
1
@vittore: 你可以将 return o.__dict__ 替换为 return [i.__dict__ for i in o],以处理多个子元素。 - weaver
@weaver,那几乎就是我所做的。 - vittore

15

我认为XML格式可以是如此多样化,以至于没有一个能够在没有非常严格定义的XML格式的情况下完成这个任务的代码。这是我的意思:

<persons>
    <person>
        <name>Koen Bok</name>
        <age>26</age>
    </person>
    <person>
        <name>Plutor Heidepeen</name>
        <age>33</age>
    </person>
</persons>

会变成什么?

{'persons': [
    {'name': 'Koen Bok', 'age': 26},
    {'name': 'Plutor Heidepeen', 'age': 33}]
}

但这会是什么:

<persons>
    <person name="Koen Bok">
        <locations name="defaults">
            <location long=123 lat=384 />
        </locations>
    </person>
</persons>

明白我的意思吗?

编辑:刚刚找到了这篇文章:http://www.xml.com/pub/a/2006/05/31/converting-between-xml-and-json.html


1
你找到的文章是关于JavaScript的。 - George Godik
10
这篇文章讨论的是XML和JSON往返转换的一般问题,与这个主题非常相关。不要被结尾的JavaScript代码吓到。 - zigg
1
@Koen,将会长这样。{ "persons": { "person": { "-name": "Koen Bok", "locations": { "-name": "defaults", "location": { "-long": "123", "-lat": "384" } } } } } - Hugo Prudente

8

Jacob Smullyan编写了一个名为pesterfish的实用程序,该程序使用effbot的ElementTree将XML转换为JSON。


1
使用pip安装似乎出现了问题:UnicodeDecodeError: 'utf8' codec can't decode byte 0x8b in position 1: invalid start byte - smci

4
一种可能的方法是使用来自 lxml 模块 的 Objectify 或 ElementTree。 旧版本的 ElementTree 也可以在 python xml.etree 模块中找到。 无论哪种方法,都会将您的 XML 转换为 Python 对象,然后您可以使用 simplejson 将对象序列化为 JSON。

虽然这可能看起来像是一个痛苦的中间步骤,但当您处理 XML 和普通 Python 对象时,它开始变得更有意义了。


1

这个链接已经失效了。如果脚本仍然存在,更新一下会很好。 - Alison R.
糟糕,我把脚本移动到了自己的存储库中。感谢您注意到了404错误! - Husky
谢谢,这很完美。需要注意的一件事是它需要安装simplejson:sudo easy_install simplejson - Suman
@srs2012 我没有尝试过这个具体的脚本,但我注意到pesterfish明确地引入了simplejson,而实际上使用标准库json也可以完成任务。有关详细信息,请参见https://dev59.com/wXRB5IYBdhLWcg3wH0SW#712799。 - zigg
-1 你的代码不起作用。a) 它忽略了标签的属性:xml2json.xml2json('<a href="111"> <b href="222" /> </a>', no_options) 删除了 href 属性,只返回了 '{"a": {"b": null}}' - smci
显示剩余2条评论

1
通常情况下,您希望将XML转换为您的语言的普通对象(因为通常有合理的工具来完成这个过程,而且这是更难的转换)。然后从普通对象生成JSON——也有相应的工具,这是一种非常简单的序列化方式(因为JSON是“对象表示法”,自然适合于序列化对象)。 我假设Python有其自己的一套工具。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接