Convertir XML en JSON en utilisant Python?

j'ai vu une bonne part de code XML->JSON ungainly sur le web, et ayant interagi avec les utilisateurs de Stack pour un peu, je suis convaincu que cette foule peut aider plus que les premières pages de résultats de Google peuvent.

donc, nous analysons un flux météo, et nous avons besoin de peupler widgets météorologiques sur une multitude de sites web. Nous étudions actuellement des solutions basées sur Python.

ce public weather.com flux RSS est un bon exemple de ce que nous analyserions ( weather.com feed contient des informations supplémentaires en raison d'un partenariat avec them ).

en bref, comment convertir XML en JSON en utilisant Python?

129
demandé sur dreftymac 2008-10-10 18:19:44

19 réponses

il n'y a pas de correspondance" un-à-un "entre XML et JSON, donc la conversion de L'un à l'autre exige nécessairement une certaine compréhension de ce que vous voulez faire avec les résultats.

cela étant dit, la bibliothèque standard de Python a plusieurs modules pour analyser XML (y compris DOM, SAX et ElementTree). À partir de Python 2.6, le support pour convertir les structures de données Python en et à partir de JSON est inclus dans le json module .

donc l'infrastructure est là.

48
répondu Dan Lenski 2014-09-07 21:36:10

xmltodict (divulgation complète: je l'ai écrit) peut vous aider à convertir votre XML à une structure dict+list+string, en suivant ce "standard . Il est basé sur Expat , donc il est très rapide et n'a pas besoin de charger toute l'arborescence XML en mémoire.

une fois que vous avez cette structure de données, vous pouvez la sérialiser à JSON:

import xmltodict, json

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

vous pouvez utiliser la bibliothèque xmljson pour convertir en utilisant différentes conventions XML JSON .

par exemple, ce XML:

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

se traduit par Convention BadgerFish en ceci:

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

et via la convention GData dans ceci (les attributs ne sont pas supportés):

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

... et via la Convention Parker dans ceci (les attributs ne sont pas supportés):

{
  'p': 'text'
}

il est possible de passer de XML à JSON et de JSON à XML en utilisant le même conventions:

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

Divulgation: j'ai écrit cette bibliothèque. Espérons qu'il aidera les futurs chercheurs.

13
répondu S Anand 2015-09-20 07:37:54

voici le code que j'ai construit pour ça. Il n'y a pas d'analyse du contenu, Juste une simple conversion.

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
répondu Paulo Vj 2012-04-19 15:35:21

il y a une méthode pour transporter le balisage basé sur XML comme JSON qui lui permet d'être converti sans perte de nouveau à sa forme originale. Voir http://jsonml.org / .

c'est une sorte de XSLT de JSON. J'espère que vous le trouverez utile

5
répondu themihai 2016-09-02 09:18:02

vous pouvez jeter un oeil à http://designtheory.org/library/extrep/designdb-1.0.pdf . Ce projet commence avec une conversion XML en JSON d'une grande bibliothèque de fichiers XML. Il y a eu beaucoup de recherches dans la conversion, et la cartographie intuitive XML -> JSON la plus simple a été produite (elle est décrite au début du document). En résumé, convertissez tout en objet JSON, et mettez des blocs répétitifs comme une liste d'objets.

objets signification des couples clé/valeur (dictionnaire en Python, hashmap en Java, objet en JavaScript)

il n'y a pas de retour vers XML pour obtenir un document identique, la raison en est qu'on ne sait pas si une paire clé/valeur était un attribut ou un <key>value</key> , donc cette information est perdue.

si vous me demandez, les attributs sont un hack pour démarrer; puis ils ont bien fonctionné pour HTML.

4
répondu pykler 2016-05-31 20:28:15

Eh bien, probablement le moyen le plus simple est de simplement analyser le XML en dictionnaires et ensuite sérialiser cela avec simplejson.

3
répondu dguaraglia 2008-10-10 14:30:59

bien que les libs intégrées pour le parsing XML soient assez bonnes, je suis une partie de lxml .

mais pour l'analyse des flux RSS, je recommande Analyseur universel D'alimentation , qui peut aussi analyser atome. Son principal avantage est qu'il peut digérer même la plupart des aliments malformés.

Python 2.6 inclut déjà un analyseur JSON, mais une nouvelle version avec une vitesse améliorée est disponible en tant que simplejson .

avec ces outils construire votre application ne devrait pas être si difficile.

2
répondu Luka Marinko 2016-05-31 20:25:18

je suggère de ne pas aller pour une conversion directe. Convertissez XML en objet, puis de l'objet à JSON.

à mon avis, cela donne une définition plus claire de la façon dont le XML et le JSON correspondent.

il faut du temps pour bien faire et vous pouvez même écrire des outils pour vous aider à générer une partie de celui-ci, mais il semblerait à peu près comme ceci:

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
répondu Michael Anderson 2016-06-01 00:28:19

quand je fais quelque chose avec XML en python, j'utilise presque toujours le paquet lxml. Je soupçonne que la plupart des gens utilisent lxml. Vous pouvez utiliser xmltodict mais vous devrez payer la pénalité de l'analyse du XML à nouveau.

pour convertir XML en json avec lxml vous:

  1. Parse XML document with lxml
  2. convertir lxml en dict
  3. Convertir les listes en json

j'utilise le suivant la classe dans mes projets. Utilisez la méthode 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)

la sortie du Construit dans principal est:

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

qui est une transformation de ce xml:

<system>
    <product>
        <demod>
            <frequency value='2.215' units='MHz'>
                <blah value='1'/>
            </frequency>
        </demod>
    </product>
</system>
2
répondu shrewmouse 2017-05-10 13:31:29

à toute personne qui pourrait encore en avoir besoin. Voici un nouveau code simple pour faire cette conversion.

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
répondu jnhustin 2017-11-06 18:06:24

si un certain temps vous obtenez seulement code de réponse au lieu de toutes les données alors erreur comme JSON parse sera là donc u besoin de le convertir en texte

import xmltodict

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

jsonpickle ou si vous utilisez feedparser, vous pouvez essayer feed_parser_to_json.py

1
répondu choonkeat 2010-12-09 06:27:59

j'ai trouvé que pour les snips XML simples, utiliser l'expression regular sauverait les problèmes. Par exemple:

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

pour le faire par parsing XML, comme @Dan l'a dit, il n'y a pas de solution unique parce que les données sont différentes. Ma suggestion est d'utiliser lxml. Bien que pas terminé à json, lxml.objectify donner de bons résultats silencieux:

>>> 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
répondu Andrew_1510 2012-04-05 15:59:42

ma réponse traite du cas particulier (et assez courant) où vous n'avez pas vraiment besoin de convertir le xml entier en json, mais ce que vous avez besoin est de parcourir/accéder à des parties spécifiques du xml, et vous avez besoin qu'il soit rapide , et simple (en utilisant des opérations JSON/dict-like).

approche

pour cela, il est important de noter que le parsing d'un xml à etree en utilisant lxml est super rapide. La partie lente dans la plupart des autres réponses est le second passage: traverser la structure etree (généralement en python-land), La convertir en json.

ce qui m'amène à l'approche que j'ai trouvé la meilleure pour ce cas: analyser le xml en utilisant lxml , puis envelopper les noeuds etree (paresseusement), leur fournissant une interface de type dict.

Code

voici le code:

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),
    )

cette implémentation n'est pas complète, par exemple, elle ne supporte pas clairement les cas où un élément a à la fois du texte et des attributs, ou à la fois du texte et des enfants (seulement parce que je n'en avais pas besoin quand je l'ai écrit...) Il devrait être facile de l'améliorer.

vitesse

dans mon cas d'utilisation spécifique, où je n'avais besoin que de traiter des éléments spécifiques du xml, cette approche a donné une accélération surprenante et frappante de par un facteur de 70 (!) comparé à l'utilisation de xmltodict de @Martin Blech et puis traversant directement le dict.

Bonus

en prime, puisque notre structure est déjà dict-like, nous obtenons une autre implémentation alternative de xml2json gratuitement. Nous avons juste besoin de passer notre structure de type dict à json.dumps . Quelque chose comme:

def xml_to_json(xmlstr, **kwargs):
    x = xml_to_dictlike(xmlstr, **kwargs)
    return json.dumps(x)

si votre xml comprend des attributs, vous devez utiliser certains alphanumérique attr_prefix (par exemple" ATTR_"), pour s'assurer que les clés sont des clés JSON valides.

Je n'ai pas marqué cette partie.

1
répondu shx2 2016-10-20 10:38:21

ce truc ici est activement maintenu et jusqu'à présent est mon préféré: xml2json en python

1
répondu ifelsemonkey 2017-02-09 16:43:09

découvrez lxml2json (divulgation: je l'ai écrit)

https://github.com/rparelius/lxml2json

c'est très rapide, léger (ne nécessite que lxml), et un avantage est que vous avez le contrôle sur si certains éléments sont convertis en listes ou dicts

0
répondu Robert Parelius 2018-09-12 01:21:51

pour représenter les données dans JSON format

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

Dans json nous repesent de données dans une clé et une valeur de format

{
    "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"}
           ]
}

pour représenter les données dans XML format

<!-- 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
répondu Anushree Anisha 2018-09-27 05:47:41

Préparer les données dans Python : Pour créer JSON vous devez d'abord préparer des données en python. Nous pouvons utiliser la liste et le dictionnaire en Python pour préparer les données.

Python List < = = > JSON Array

Python Dictionnaire <==> JSON de l'Objet (Valeur de la Clé de Format) Vérifiez ceci pour plus de détails

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

0
répondu Anushree Anisha 2018-09-27 06:08:47