Converter XML para JSON usando Python?

Eu vi uma boa parte do código XML->JSON na web, e tendo interagido com os usuários do Stack por um tempo, estou convencido de que esta multidão pode ajudar mais do que as primeiras páginas dos resultados do Google podem.

Então, estamos a analisar uma fonte meteorológica, e precisamos de povoar widgets meteorológicos numa infinidade de sites. Estamos agora a investigar soluções baseadas em Python.

este público weather.com RSS feed é um bom exemplo do que estaríamos a analisar (o nosso real weather.com o alimento para animais contém informação adicional devido a uma parceria w / them .

em poucas palavras, como devemos converter XML para JSON usando Python?

Author: dreftymac, 2008-10-10

19 answers

Não há mapeamento" um-para-um " entre XML e JSON, por isso converter um para o outro requer necessariamente alguma compreensão do que você quer Fazer com os resultados.

Dito isto, a biblioteca padrão do Python tem vários módulos para processar XML (incluindo DOM, SAX e ElementTree). A partir do Python 2.6, o suporte para converter estruturas de dados Python de e para JSON está incluído no json módulo

Então a infra-estrutura é la.

 48
Author: Dan Lenski, 2014-09-07 21:36:10

O Xmltodict (divulgação completa: fui eu que o escrevi) pode ajudá-lo a converter o seu XML para uma estrutura dict+list+string, seguindo este "standard". É baseado em Expat , então é muito rápido e não precisa carregar toda a árvore XML em memória.

Uma vez que você tenha essa estrutura de dados, você pode serializá-la para JSON:
import xmltodict, json

o = xmltodict.parse('<e> <a>text</a> <a>text</a> </e>')
json.dumps(o) # '{"e": {"a": ["text", "text"]}}'
 236
Author: Martin Blech, 2012-04-18 01:06:05

Você pode usar a biblioteca xmljson para converter usando diferentes convenções XML JSON .

Por exemplo, Este XML:

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

Tradução através da Convenção de peixes texugos {[8] } para isto:

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

E através da Convenção de GData para isto (os atributos não são suportados):

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

... e através da Convenção Parker para isto (os atributos não são suportados):

{
  'p': 'text'
}
É possível converter de XML para JSON e de JSON a XML usando o mesmo convenções:
>>> 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>]

Divulgação: eu escrevi esta biblioteca. Espero que ajude futuros investigadores.

 13
Author: S Anand, 2015-09-20 07:37:54
Aqui está o código que construí para isso. Não há análise do conteúdo, apenas conversão simples.
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()
 6
Author: Paulo Vj, 2012-04-19 15:35:21

Existe um método para transportar a marcação baseada em XML como JSON que permite que ela seja convertida sem perdas de volta à sua forma original. Ver http://jsonml.org/.

É uma espécie de XSLT do JSON. Espero que o ache útil.
 5
Author: themihai, 2016-09-02 09:18:02

É melhor dar uma vista de olhos a http://designtheory.org/library/extrep/designdb-1.0.pdf . Este projecto começa com uma conversão XML para JSON de uma grande biblioteca de ficheiros XML. Houve muita pesquisa feita na conversão, e o mais simples mapeamento intuitivo XML -> JSON foi produzido (é descrito no início do documento). Em resumo, Converter tudo para um objeto JSON, e colocar blocos repetitivos como uma lista de objetos.

Objectos que significam pares de chaves / valores (dicionário em Python, hashmap em Java, objecto em JavaScript)

Não existe nenhum mapeamento de volta ao XML para obter um documento idêntico, a razão é que é Desconhecido se um par chave/valor era um atributo ou um <key>value</key>, portanto essa informação é perdida.

Se você me perguntar, os atributos são um hack para começar; então novamente eles funcionaram bem para HTML.

 4
Author: pykler, 2016-05-31 20:28:15

Bem, provavelmente a maneira mais simples é apenas processar o XML em dicionários e, em seguida, serializar isso com simplejson.

 3
Author: dguaraglia, 2008-10-10 14:30:59

Embora as bibliotecas incorporadas para o processamento de XML sejam bastante boas, eu sou parcial a lxml.

Mas para analisar os feeds RSS, eu recomendaria O analisador universal de Feed , que também pode processar o átomo. Sua principal vantagem é que ele pode digerir até mesmo a maioria dos feeds malformados.

O Python 2.6 já inclui um analisador JSON, mas uma versão mais recente com velocidade melhorada está disponível como simplejson.

Com estas ferramentas a construir a aplicação, não devia ser assim. dificil.
 2
Author: Luka Marinko, 2016-05-31 20:25:18
Sugiro que não se faça uma conversão directa. Converter XML para um objeto, em seguida, a partir do objeto para JSON. Na minha opinião, isto dá uma definição mais limpa de como o XML e o JSON correspondem.

É preciso tempo para acertar e você pode até mesmo escrever Ferramentas para ajudá-lo a gerar algum dele, mas seria mais ou menos assim:

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
Author: Michael Anderson, 2016-06-01 00:28:19

Quando faço qualquer coisa com XML em python, quase sempre uso o pacote lxml. Suspeito que a maioria das pessoas usa lxml. Você poderia usar xmltodict mas você terá que pagar a penalidade de processar o XML novamente.

Para converter XML para json com lxml você:

  1. processar o documento XML com lxml
  2. Converter lxml para um dict
  3. converter a lista para json
Uso a seguinte classe nos meus projectos. Usa o método toJson.
from lxml import etree 
import json


class Element:
    '''
    Wrapper on the etree.Element class.  Extends functionality to output element
    as a dictionary.
    '''

    def __init__(self, element):
        '''
        :param: element a normal etree.Element instance
        '''
        self.element = element

    def toDict(self):
        '''
        Returns the element as a dictionary.  This includes all child elements.
        '''
        rval = {
            self.element.tag: {
                'attributes': dict(self.element.items()),
            },
        }
        for child in self.element:
            rval[self.element.tag].update(Element(child).toDict())
        return rval


class XmlDocument:
    '''
    Wraps lxml to provide:
        - cleaner access to some common lxml.etree functions
        - converter from XML to dict
        - converter from XML to json
    '''
    def __init__(self, xml = '<empty/>', filename=None):
        '''
        There are two ways to initialize the XmlDocument contents:
            - String
            - File

        You don't have to initialize the XmlDocument during instantiation
        though.  You can do it later with the 'set' method.  If you choose to
        initialize later XmlDocument will be initialized with "<empty/>".

        :param: xml Set this argument if you want to parse from a string.
        :param: filename Set this argument if you want to parse from a file.
        '''
        self.set(xml, filename) 

    def set(self, xml=None, filename=None):
        '''
        Use this to set or reset the contents of the XmlDocument.

        :param: xml Set this argument if you want to parse from a string.
        :param: filename Set this argument if you want to parse from a file.
        '''
        if filename is not None:
            self.tree = etree.parse(filename)
            self.root = self.tree.getroot()
        else:
            self.root = etree.fromstring(xml)
            self.tree = etree.ElementTree(self.root)


    def dump(self):
        etree.dump(self.root)

    def getXml(self):
        '''
        return document as a string
        '''
        return etree.tostring(self.root)

    def xpath(self, xpath):
        '''
        Return elements that match the given xpath.

        :param: xpath
        '''
        return self.tree.xpath(xpath);

    def nodes(self):
        '''
        Return all elements
        '''
        return self.root.iter('*')

    def toDict(self):
        '''
        Convert to a python dictionary
        '''
        return Element(self.root).toDict()

    def toJson(self, indent=None):
        '''
        Convert to JSON
        '''
        return json.dumps(self.toDict(), indent=indent)


if __name__ == "__main__":
    xml='''<system>
    <product>
        <demod>
            <frequency value='2.215' units='MHz'>
                <blah value='1'/>
            </frequency>
        </demod>
    </product>
</system>
'''
    doc = XmlDocument(xml)
    print doc.toJson(indent=4)

A saída do construído em o principal é:

{
    "system": {
        "attributes": {}, 
        "product": {
            "attributes": {}, 
            "demod": {
                "attributes": {}, 
                "frequency": {
                    "attributes": {
                        "units": "MHz", 
                        "value": "2.215"
                    }, 
                    "blah": {
                        "attributes": {
                            "value": "1"
                        }
                    }
                }
            }
        }
    }
}

Que é uma transformação deste xml:

<system>
    <product>
        <demod>
            <frequency value='2.215' units='MHz'>
                <blah value='1'/>
            </frequency>
        </demod>
    </product>
</system>
 2
Author: shrewmouse, 2017-05-10 13:31:29
Para quem ainda precisar disto. Aqui está um código mais novo e simples para fazer esta conversão.
from xml.etree import ElementTree as ET

xml    = ET.parse('FILE_NAME.xml')
parsed = parseXmlToJson(xml)


def parseXmlToJson(xml):
  response = {}

  for child in list(xml):
    if len(list(child)) > 0:
      response[child.tag] = parseXmlToJson(child)
    else:
      response[child.tag] = child.text or ''

    # one-liner equivalent
    # response[child.tag] = parseXmlToJson(child) if len(list(child)) > 0 else child.text or ''

  return response
 2
Author: jnhustin, 2017-11-06 18:06:24

Se algum tempo você obter apenas o código de resposta em vez de todos os dados então erro como json parse vai estar lá então u precisa convertê - lo como texto

import xmltodict

data = requests.get(url)
xpars = xmltodict.parse(data.text)
json = json.dumps(xpars)
print json 
 2
Author: Akshay Kumbhar, 2018-05-12 08:17:18

Jsonpickle ou se estiver a utilizar o feedparser, pode tentar feed_parser_to_json.py

 1
Author: choonkeat, 2010-12-09 06:27:59

Encontrei para snips XML simples, usar a expressão regular iria salvar problemas. Por exemplo:

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

Para o fazer por análise XML, como @Dan disse, não existe uma solução única porque os dados são diferentes. A minha sugestão é usar lxml. Apesar de não ter terminado com o json, lxml.objectify dá bons resultados silenciosos:

>>> 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'
 1
Author: Andrew_1510, 2012-04-05 15:59:42

A Minha resposta endereços específicos (e um pouco comum) caso você não é realmente necessário para converter o xml inteiro json, mas o que você precisa fazer é atravessar/acesso a partes específicas do xml, e você precisa que ele seja rápido, e simples (usando json/dict-operações similares).

Aproximação

Para isso, é importante notar que processar um xml para o etree usando lxml é super rápido. A parte lenta na maioria das outras respostas é a segunda passagem: atravessando a estrutura etree (geralmente em python-land), convertendo-a para json.

O que me leva à abordagem que achei melhor para este caso: analisar o xml usando {[[2]}, e então enrolar os nós etree (preguiçosamente), fornecendo-lhes uma interface tipo dict.

Código

Aqui está o código:

from collections import Mapping
import lxml.etree

class ETreeDictWrapper(Mapping):

    def __init__(self, elem, attr_prefix = '@', list_tags = ()):
        self.elem = elem
        self.attr_prefix = attr_prefix
        self.list_tags = list_tags

    def _wrap(self, e):
        if isinstance(e, basestring):
            return e
        if len(e) == 0 and len(e.attrib) == 0:
            return e.text
        return type(self)(
            e,
            attr_prefix = self.attr_prefix,
            list_tags = self.list_tags,
        )

    def __getitem__(self, key):
        if key.startswith(self.attr_prefix):
            return self.elem.attrib[key[len(self.attr_prefix):]]
        else:
            subelems = [ e for e in self.elem.iterchildren() if e.tag == key ]
            if len(subelems) > 1 or key in self.list_tags:
                return [ self._wrap(x) for x in subelems ]
            elif len(subelems) == 1:
                return self._wrap(subelems[0])
            else:
                raise KeyError(key)

    def __iter__(self):
        return iter(set( k.tag for k in self.elem) |
                    set( self.attr_prefix + k for k in self.elem.attrib ))

    def __len__(self):
        return len(self.elem) + len(self.elem.attrib)

    # defining __contains__ is not necessary, but improves speed
    def __contains__(self, key):
        if key.startswith(self.attr_prefix):
            return key[len(self.attr_prefix):] in self.elem.attrib
        else:
            return any( e.tag == key for e in self.elem.iterchildren() )


def xml_to_dictlike(xmlstr, attr_prefix = '@', list_tags = ()):
    t = lxml.etree.fromstring(xmlstr)
    return ETreeDictWrapper(
        t,
        attr_prefix = '@',
        list_tags = set(list_tags),
    )

Esta implementação não está completa, por exemplo, não suporta de forma limpa os casos em que um elemento tem tanto texto e atributos, ou tanto texto e crianças (apenas porque eu não precisei dele quando o escrevi...) Deve ser fácil melhorá-lo, no entanto.

Velocidade

No meu caso de uso específico, onde eu precisava apenas processar elementos específicos do xml, esta abordagem deu uma aceleração surpreendente e impressionante por um fator de 70 (!) em comparação com o uso de @Martin Blech's xmltodict e depois atravessar o dict directamente.

Bónus

Como bónus, uma vez que a nossa estrutura já é parecida com a do dict, temos outra alternativa. execução gratuita de xml2json Só precisamos de passar a nossa estrutura parecida com o dict para json.dumps. Algo do género:
def xml_to_json(xmlstr, **kwargs):
    x = xml_to_dictlike(xmlstr, **kwargs)
    return json.dumps(x)
Se o seu xml incluir atributos, terá de utilizar alguns caracteres alfanuméricos (por exemplo, "ATTR_") para garantir que as chaves são chaves json válidas. Ainda não fiz a avaliação desta parte.
 1
Author: shx2, 2016-10-20 10:38:21

Este material aqui é mantido activamente e até agora é o meu favorito: xml2json em python

 1
Author: ifelsemonkey, 2017-02-09 16:43:09

Confira lxml2json (disclosure: I wrote it)

Https://github.com/rparelius/lxml2json

É muito rápido, leve (só requer lxml), e uma vantagem é que você tem o controle sobre se certos elementos são convertidos para listas ou dicts

 0
Author: Robert Parelius, 2018-09-12 01:21:51

Para representar os dados em JSON formato

name=John
age=20
gender=male
address=Sector 12 Greater Kailash, New Delhi
Jobs=Noida,Developer | Gurugram,Tester |Faridabad,Designer

Em JSON Nós repelimos um dado no formato chave e valor

{
    "name":"john",
    "age":20,
    "gender":"male",
    "address":["New kP college","Greater Kailash","New Delhi"],
    "jobs":[
               {"Place":"Noida","Title":"Developer "},
               {"Place":"Gurugram","Title":"Tester "},
               {"Place":"Faridabad","Title":"Designer"}
           ]
}

Para representar os dados em XML formato

<!-- In xml we write a code under a key you can take any key -->
<info> <!-- key open -->

<name> john </name> 
<age> 20 </age>
<gender> male </gender>

<address> 
<item> New kP college </item>
<item> Greater Kailash </item>
<item> New Delhi </item>
</address>

<jobs>
 <item>
  <title>Developer </title>
  <place>Noida</place>
 </item>

 <item>
  <title>Designer</title>
  <place>Gurugram</place>
 </item>
 
 <item>
  <title>Developer </title>
  <place>Faridabad</place>
 </item>
</jobs>

</info> <!-- key close-->
 0
Author: Anushree Anisha, 2018-09-27 05:47:41

Preparar dados em Python : Para criar JSON Primeiro você precisa preparar dados em python. Podemos usar lista e dicionário em Python para preparar os dados.

Python List JSON Array

Dicionário Python objecto JSON (Formato do valor da chave) Assinale isto para mais detalhes

Https://devstudioonline.com/article/create-json-and-xml-in-python

 0
Author: Anushree Anisha, 2018-09-27 06:08:47