Преобразование XML в JSON с использованием Python? - PullRequest
142 голосов
/ 10 октября 2008

Я видел немалую долю неуклюжего кода XML-> JSON в Интернете, и, немного пообщавшись с пользователями Stack, я убежден, что эта толпа может помочь больше, чем первые несколько страниц результатов Google. .

Итак, мы анализируем фид погоды, и нам нужно заполнить виджеты погоды на множестве веб-сайтов. Сейчас мы ищем решения на основе Python.

Этот общедоступный RSS-канал weather.com является хорошим примером того, что мы будем анализировать ( наш фактический фид weather.com содержит дополнительную информацию благодаря партнерству с ними ).

В двух словах, как мы должны конвертировать XML в JSON, используя Python?

Ответы [ 20 ]

253 голосов
/ 18 апреля 2012

xmltodict (полное раскрытие: я написал) может помочь вам преобразовать ваш XML в структуру dict + list + string, следуя этому «стандартному» . Он основан на Expat , поэтому он очень быстрый и не требует загрузки всего дерева XML в память.

Получив эту структуру данных, вы можете сериализовать ее в JSON:

import xmltodict, json

o = xmltodict.parse('<e> <a>text</a> <a>text</a> </e>')
json.dumps(o) # '{"e": {"a": ["text", "text"]}}'
50 голосов
/ 10 октября 2008

Между XML и JSON нет сопоставления «один к одному», поэтому преобразование одного в другое обязательно требует некоторого понимания того, что вы хотите делать с результатами.

При этом стандартная библиотека Python имеет несколько модулей для анализа XML (включая DOM, SAX и ElementTree). Начиная с Python 2.6, поддержка преобразования структур данных Python в JSON и обратно включена в модуль json .

Итак, инфраструктура есть.

18 голосов
/ 20 сентября 2015

Вы можете использовать библиотеку xmljson для преобразования с использованием различных XML JSON соглашений .

Например, этот XML:

<p id="1">text</p>

переводится через соглашение BadgerFish в это:

{
  'p': {
    '@id': 1,
    '$': 'text'
  }
}

и через соглашение GData в это (атрибуты не поддерживаются):

{
  'p': {
    '$t': 'text'
  }
}

... и через соглашение Паркера в это (атрибуты не поддерживаются):

{
  'p': 'text'
}

Можно конвертировать из XML в JSON и из JSON в XML, используя один и тот же условные обозначения:

>>> import json, xmljson
>>> from lxml.etree import fromstring, tostring
>>> xml = fromstring('<p id="1">text</p>')
>>> json.dumps(xmljson.badgerfish.data(xml))
'{"p": {"@id": 1, "$": "text"}}'
>>> xmljson.parker.etree({'ul': {'li': [1, 2]}})
# Creates [<ul><li>1</li><li>2</li></ul>]

Раскрытие: я написал эту библиотеку. Надеюсь, это поможет будущим искателям.

7 голосов
/ 19 апреля 2012

Вот код, который я построил для этого. Там нет анализа содержимого, просто преобразование.

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()
7 голосов
/ 12 мая 2018

Если через какое-то время вы получите только код ответа вместо всех данных, тогда будет ошибка, такая как json parse , поэтому вам нужно преобразовать ее в текст

import xmltodict

data = requests.get(url)
xpars = xmltodict.parse(data.text)
json = json.dumps(xpars)
print json 
6 голосов
/ 10 июня 2011

Существует метод для переноса разметки на основе XML в виде JSON, который позволяет преобразовать ее без потерь обратно в исходную форму. Смотри http://jsonml.org/.

Это своего рода XSLT из JSON. Я надеюсь, что вы найдете это полезным

5 голосов
/ 07 октября 2010

Возможно, вы захотите взглянуть на http://designtheory.org/library/extrep/designdb-1.0.pdf. Этот проект начинается с преобразования XML в JSON большой библиотеки файлов XML. Было проведено много исследований в области преобразования, и было создано самое простое интуитивно понятное отображение XML -> JSON (оно описано в начале документа). Таким образом, преобразуйте все в объект JSON и поместите повторяющиеся блоки в список объектов.

объекты, означающие пары ключ / значение (словарь на Python, hashmap на Java, объект на JavaScript)

Не существует сопоставления с XML для получения идентичного документа, причина в том, что неизвестно, была ли пара ключ / значение атрибутом или <key>value</key>, поэтому эта информация теряется.

Если вы спросите меня, атрибуты - это взлом для начала; опять же, они хорошо работали для HTML.

4 голосов
/ 10 октября 2008

Ну, наверное, самый простой способ - просто разобрать XML в словари и затем сериализовать это с simplejson.

3 голосов
/ 18 апреля 2012

Я бы предложил не идти на прямое преобразование. Преобразуйте 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 ):
    ...
2 голосов
/ 10 октября 2008

Хотя встроенные библиотеки для разбора XML довольно хороши, я неравнодушен к lxml .

Но для разбора RSS-каналов я бы порекомендовал Универсальный анализатор каналов , который также может анализировать Atom. Его главное преимущество заключается в том, что он может переваривать даже самые плохо сформированные корма.

Python 2.6 уже включает в себя анализатор JSON, но более новая версия с улучшенной скоростью доступна как simplejson .

С этими инструментами создание вашего приложения не должно быть таким сложным.

...