Frage

Ich habe einen fairen Anteil an ungainly XML-> JSON-Code auf der Web zu sehen ist, und mit Stapel Nutzer für ein bisschen interagierten zu haben, ich bin überzeugt, dass diese Menge mehr als die ersten paar Seiten von Google Ergebnissen helfen kann .

Also, wir Parsen ein Wetter-Feed, und wir müssen Wetter Widgets auf dem eine Vielzahl von Web-Sites füllen. Wir suchen jetzt in Python-basierten Lösungen.

Dieses öffentliche weather.com RSS-Feed ein gutes Beispiel dafür, was würden wir werden das Parsen ( unser tatsächlicher weather.com Feed enthält zusätzliche Informationen aufgrund einer Partnerschaft w / sie ).

Auf den Punkt gebracht, wie wir XML zu JSON mit Python konvertieren sollte?

War es hilfreich?

Lösung

Es gibt keine "one-to-one" Mapping zwischen XML und JSON, so eine Umwandlung in die andere erfordert notwendigerweise ein gewisses Verständnis von dem, was Sie wollen tun mit den Ergebnissen.

aber sagen, dass Python-Standardbibliothek hat mehrere Module für das Parsen von XML ( einschließlich DOM, SAX und ElementTree). Ab Python 2.6, Unterstützung zu Python Datenstrukturen und zum Umwandeln von JSON ist in dem json Modul enthält .

So ist die Infrastruktur ist da.

Andere Tipps

xmltodict (vollständige Offenlegung: Ich schrieb es) kann Ihnen helfen, Ihre XML in eine dict + Liste konvertieren + String-Struktur, im Anschluss an diese “ Standard ". Es ist Expat -Basis, also ist es sehr schnell und braucht nicht das ganze zu laden XML-Struktur im Speicher.

Wenn Sie diese Datenstruktur haben, können Sie es zu JSON serialisiert:

import xmltodict, json

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

Sie können die xmljson Bibliothek mit verschiedenem XML-JSON Konventionen .

Zum Beispiel dieses XML:

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

übersetzt über die BadgerFish Konvention in diesen:

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

und über die GData Konvention in diese (Attribute werden nicht unterstützt):

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

... und über die Parker Konvention in diese (Attribute werden nicht unterstützt):

{
  'p': 'text'
}

Es ist möglich, von XML zu JSON und von JSON in XML zu konvertieren, die diese verwenden Konventionen:

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

Disclosure: Ich diese Bibliothek geschrieben. Hoffe, dass es künftig Suchenden hilft.

Hier ist der Code, den ich dafür gebaut. Es gibt keinen Parsing der Inhalte, einfach nur Konvertierung.

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

Wenn einige Zeit erhalten Sie nur Antwortcode , also nicht alle Daten dann Fehler wie json Parse wird es so u konvertieren müssen es als Text

import xmltodict

data = requests.get(url)
xpars = xmltodict.parse(data.text)
json = json.dumps(xpars)
print json 

Es ist eine Methode, XML-basierte Markup als JSON zu transportieren, die es verlustlos wieder in seine ursprüngliche Form umgewandelt werden können. Siehe http://jsonml.org/ .

Es ist eine Art von XSLT von JSON. Ich hoffe, Sie finden es hilfreich,

Sie können einen Blick auf http://designtheory.org/library/ haben wollen extrep / Designdb-1.0.pdf . Das Projekt beginnt mit einer XML zu JSON Konvertierung von einer großen Bibliothek von XML-Dateien ab. Es gab viel Forschung in der Konvertierung durchgeführt, und die einfachste intuitive XML -> JSON-Mapping wurde hergestellt (es früh in dem Dokument beschrieben wird). Zusammenfassend alles auf ein JSON-Objekt konvertieren, und als eine Liste von Objekten zu wiederholen Blöcke setzen.

Objekte bedeuten, Schlüssel / Wert-Paare (Wörterbuch in Python, hashmap in Java, Objekt in JavaScript)

Es gibt keine Zuordnung zu XML zurück ein identisches Dokument zu erhalten, ist der Grund, es ist nicht bekannt, ob ein Schlüssel / Wert-Paar war ein Attribut oder ein <key>value</key> daher, dass Informationen verloren gehen.

Wenn Sie mich fragen, sind Attribute ein Hack zu beginnen; dann wieder arbeitete sie auch für HTML.

Nun, wahrscheinlich der einfachste Weg ist nur das XML in Wörterbücher analysiert und dann die Serialisierung mit simplejson.

Ich würde vorschlagen, nicht für eine direkte Umwandlung gehen. Konvertieren von XML in ein Objekt, dann von dem Objekt zu JSON.

Meiner Meinung nach ist dies gibt eine sauberere Definition, wie die XML und JSON entsprechen.

Es braucht Zeit, richtig zu machen und Sie können sogar Werkzeuge schreiben, Ihnen zu helfen mit etwas davon zu erzeugen, aber es wäre in etwa wie folgt aussehen:

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 ):
    ...

fand ich für eine einfache XML snips verwenden regulären Ausdruck Schwierigkeiten retten würde. Zum Beispiel:

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

Um es durch XML-Analyse zu tun, wie @ Dan sagte, gibt es nicht ein-for-all-Lösung, da die Daten unterschiedlich ist. Mein Vorschlag ist, lxml zu verwenden. Obwohl nicht auf json abgeschlossen, lxml.objectify geben ruhig gute Ergebnisse:

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

Während der Einbau-Libs für das Parsen von XML ist recht gut ich bin teilweise zu lxml .

Aber für RSS-Feeds Parsen, würde ich empfehlen Universal-Feed-Parser , die auch analysieren Atom. Sein Hauptvorteil ist, dass es sogar die meisten malformed Feeds verdauen kann.

Python 2.6 enthält bereits einen JSON-Parser, aber eine neuere Version mit verbesserter Geschwindigkeit ist als simplejson .

Mit diesen Tools, um Ihren App Aufbau sollte nicht so schwierig sein.

Wenn ich etwas tun mit XML in Python fast immer ich das lxml Paket verwenden. Ich vermute, dass die meisten Menschen lxml verwenden. Sie könnten xmltodict verwenden, aber Sie werden wieder die Strafe der Parsen der XML bezahlen.

Zur Umwandlung von XML zu JSON mit lxml Sie:

  1. Parse XML-Dokument mit lxml
  2. Konvertieren lxml zu einem dict
  3. Konvertieren Liste json

Ich verwende die folgende Klasse in meinen Projekten. Verwenden Sie die toJson Methode.

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)

Die Ausgabe von dem eingebauten Haupt ist:

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

Welche ist eine Transformation dieser xml:

<system>
    <product>
        <demod>
            <frequency value='2.215' units='MHz'>
                <blah value='1'/>
            </frequency>
        </demod>
    </product>
</system>

jsonpickle oder wenn Sie feedparser verwenden, können Sie versuchen, feed_parser_to_json.py

Meine Antwort auf die spezifischen (und etwas gemeinsam) Fall, in dem Sie auf nicht wirklich das gesamte XML konvertieren müssen zu json, aber was Sie brauchen, ist / Zugriff bestimmte Teile des xml zu durchqueren , und Sie müssen es schnell und einfach (unter Verwendung von json / dict-ähnlichen Behandlungen) sein.

Ansatz

Dabei ist es wichtig zu beachten, dass ein XML-Parsing etree lxml Verwendung ist super schnell. Der langsame Teil in den meisten anderen Antworten ist den zweiten Durchgang. Die etree Struktur durchquert (in der Regel in Python-Land), um es zu json Umwandlung

Was mich zu dem Ansatz führt ich am besten für diesen Fall gefunden. Parsen der XML-lxml verwenden und Einwickeln dann die etree Knoten (träge), so dass sie mit einer dict-ähnlicher Oberfläche bietet

Code

Hier ist der 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),
    )

Diese Implementierung ist nicht vollständig, zum Beispiel, ist es nicht sauber Fälle unterstützen, in denen ein Element sowohl Text hat und Attribut oder Text und Kinder (nur, weil ich es nicht brauchte, als ich es geschrieben hätte ...) Es leicht zu verbessern, sollte es aber.

Geschwindigkeit

In meinem speziellen Anwendungsfall, wo ich nur prozessspezifische Elemente des XML benötigt, gab diesen Ansatz eine überraschende und auffallend Speedup um den Faktor 70 (!) im Vergleich zu @ Martin Blech ist mit xmltodict und dann die dict direkt durchquert.

Bonus

Als Bonus, da unsere Struktur bereits dict-like ist, bekommen wir eine weitere alternative Implementierung von xml2json kostenlos. Wir müssen nur unsere dict artige Struktur zu übergeben json.dumps. So etwas wie:

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

Wenn Sie Ihre XML-Attribut enthält, müssen Sie einige alphanumerischen attr_prefix (beispielsweise „ATTR_“) verwenden, um sicherzustellen, ist die Schlüssel gültig json Tasten.

Ich habe diesen Teil nicht gebenchmarkt.

hier Dieses Zeug ist aktiv gepflegt und so weit ist mein Favorit: xml2json in Python

Für jeden, der diese noch benötigen. Hier ist ein neuer, einfacher Code, um diese Umwandlung zu tun.

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

Besuche lxml2json (Offenlegung: Ich habe es geschrieben)

https://github.com/rparelius/lxml2json

es ist sehr schnell, leicht (nur erfordert lxml), und ein Vorteil ist, dass Sie die Kontrolle darüber haben, ob bestimmte Elemente in Listen oder dicts umgewandelt werden

Sie können declxml verwenden. Es verfügt über erweiterte Funktionen wie Multi-Attribute und komplex verschachtelte Unterstützung. Sie brauchen nur einen einfachen Prozessor für sie zu schreiben. Auch mit dem gleichen Code, können Sie konvertieren und zu JSON zurück. Es ist recht einfach und die Dokumentation ist genial.

Link: https://declxml.readthedocs.io/en/latest/index .html

Bereiten Sie Daten in Python : So erstellen Sie JSON zuerst müssen Sie Daten in Python vorzubereiten. Wir können Liste und Wörterbuch in Python verwenden, um die Daten vor.

Python List <==> JSON Array

Python Wörterbuch <==> JSON Object (Key Value Format) Aktivieren Sie diese Option, um weitere Informationen

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

Für die Darstellung von Daten in JSON Format

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

json wir Daten in Schlüssel repesent und Wert-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"}
           ]
}

Für die Darstellung von Daten in 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-->

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top