Python string,dict,list und Co. <-> XML

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Ich hab mal meines weiter gebaut, aber nun häng ich an einem Fehler und komm nicht weiter:

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: UTF-8 -*-

import sys, time

t = [
    "beispiel", 123, 23j, #u'hällø',
    {"1": None, "2": True, "3": False},
    {'status':'GM', 'rating':2700},
    {
        "eins": {"a":1, "b":2},
        "zwei": {"c":2, "d":3},
    },
    {'foo': {"bar":("jup","jap","schnupp")}}
]


class XMLPickle:
    def __init__(self):

        self.encodingMap = {
            dict: self.encode_dict,
            list: self.encode_iter,
            tuple: self.encode_iter,
            unicode: self.encode_unicode,

            str: str,

            int: str,
            long: str,
            complex: str,
        }

    def encode_dict(self, data):
        result = ""
        for k,v in data.iteritems():
            result += self.to_xml(v, key=k)
        return result

    def encode_iter(self, data):
        result = ""
        for e in iter(data):
            result += self.to_xml(e)
        return result

    def encode_unicode(self, data):
        try:
            return data.decode('ascii')
        except UnicodeError:
            return data.encode(
                sys.stdout.encoding or sys.getfilesystemencoding()
            )

    def encodeData(self, data):
        # Quick: type()-Mapping
        try:
            return self.encodingMap[type(data)](data)
        except KeyError:
            # slow Fallback: isinstance()-Mapping
            for encodeType, method in self.encodingMap.iteritems():
                if isinstance(data, encodeType):
                    return method(data)

            try:
                return encode_iter(e)
            except:
                return str(data)


    def to_xml(self, data, **attributes):
        result = ""
        typ = data.__class__.__name__

        if type(data) in (None,True,False,):
            return "<%s></%s>" % (data,data)

        if attributes:
            startTag = [typ]
            for a in attributes.iteritems():
                startTag.append('%s="%s"' % a)
            startTag = " ".join(startTag)
        else:
            startTag = typ

        return "<%s>%s</%s>" % (
            startTag, self.encodeData(data), typ
        )

    def dumps(self, dataString):
        return self.to_xml(dataString)



def durationTest():
    start_time = time.time()
    xml = XMLPickle()
    for i in xrange(10000):
        xml.dumps(t)
    print "duration: %.2fsec" % (time.time()- start_time)

#~ durationTest()

xml = XMLPickle()
xmlData = xml.dumps(t)
xmlData = "<data>%s</data>" % xmlData

#~ xmlData = xmlData.replace(">",">\n")
#~ xmlData = xmlData.strip()
#~ for e in enumerate(xmlData.split("\n")):
    #~ print "%3s - %s" % e

#~ print xmlData

from xml.dom import minidom

# Formatieren und ausgeben
dom = minidom.parseString(xmlData)
print dom.toprettyxml("    ")
Ausgabe:

Code: Alles auswählen

<?xml version="1.0" ?>
<data>
    <list>
        <str>
            beispiel
        </str>
        <int>
            123
        </int>
        <complex>
            23j
        </complex>
        <dict>
            <NoneType key="1">
                None
            </NoneType>
            <bool key="3">
                False
            </bool>
            <bool key="2">
                True
            </bool>
        </dict>
        <dict>
            <str key="status">
                GM
            </str>
            <int key="rating">
                2700
            </int>
        </dict>
        <dict>
            <dict key="eins">
                <int key="a">
                    1
                </int>
                <int key="b">
                    2
                </int>
            </dict>
            <dict key="zwei">
                <int key="c">
                    2
                </int>
                <int key="d">
                    3
                </int>
            </dict>
        </dict>
        <dict>
            <dict key="foo">
                <tuple key="bar">
                    <str>
                        jup
                    </str>
                    <str>
                        jap
                    </str>
                    <str>
                        schnupp
                    </str>
                </tuple>
            </dict>
        </dict>
    </list>
</data>
EDIT: Fehler gefunden... (Ich dummie hab alle Tags nicht geschlossen ;)

Außerdem wüßte ich gern, wie man am besten mit unicode umgehen könnte... Aber das kommt wahrscheinlich auf die Art der Verwendung an, was?

Nun müßte ich mir mal überlegen, wie man das wieder zurück wandeln kann... *schau auf BlackJack's Lösung* :lol:

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
mitsuhiko
User
Beiträge: 1790
Registriert: Donnerstag 28. Oktober 2004, 16:33
Wohnort: Graz, Steiermark - Österreich
Kontaktdaten:

Leonidas hat geschrieben:Ich werf jetzt noch neben YAML auch noch JSON rein, zusammen mit JSON-RPC ;)
Wollte ich auch gerade vorschlagen. Nutzt pocoo für den AJAX transport :)
TUFKAB – the user formerly known as blackbird
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Hab mir gerade simplejson angeschaut... Sieht nett aus:

Code: Alles auswählen

import simplejson

t = [
    "beispiel", 123, 23, #u'hällø',
    {"1": None, "2": True, "3": False},
    {'status':'GM', 'rating':2700},
    {
        "eins": {"a":1, "b":2},
        "zwei": {"c":2, "d":3},
    },
    {'foo': {"bar":("jup","jap","schnupp")}}
]

data = simplejson.dumps(t)
print data
print type(data)


data = simplejson.loads(data)
print data
print type(data)
Ist kaum ein unterschied zur Python-Version auszumachen:

Code: Alles auswählen

["beispiel", 123, 23, {"1":null, "3":false, "2":true}, {"status":"GM", "rating":2700}, {"eins":{"a":1, "b":2}, "zwei":{"c":2, "d":3}}, {"foo":{"bar":["jup", "jap", "schnupp"]}}]
<type 'str'>
[u'beispiel', 123, 23, {u'1': None, u'3': False, u'2': True}, {u'status': u'GM', u'rating': 2700}, {u'eins': {u'a': 1, u'b': 2}, u'zwei': {u'c': 2, u'd': 3}}, {u'foo': {u'bar': [u'jup', u'jap', u'schnupp']}}]
<type 'list'>
IMHO hätten die sich dann auch gleich alle Leerzeichen sparen können...


Aber ich weiß nicht, es ist nicht so super gut lesbar, weil die Formatierung, in einer Zeile, recht unübersichtlich ist. Da kann ich gleich pickle nehmen...

Die Sourcen sind mit 26KB vertretbar klein...

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
XT@ngel
User
Beiträge: 255
Registriert: Dienstag 6. August 2002, 14:36
Kontaktdaten:

HI, ich hab jetzt nicht alles gelesen aber schau dir dochmal Dookies PyXO an.
http://www.boa3d.de/python/modules/PyXO.php die Seite ist noch online.

MfG
Andreas
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Dookies PyXO hatte ich mir heute schon öfters mal angesehen. Aber IMHO kann man damit nicht wirklich ein verschachteltes dict/liste/tuple zu XML konvertieren... oder ich hab es noch nicht richtig verstanden :oops:

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
XT@ngel
User
Beiträge: 255
Registriert: Dienstag 6. August 2002, 14:36
Kontaktdaten:

Logisch gehts das ;)

Am Beispiel t = []

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: UTF-8 -*-

import PyXO

xmlfile = "PyXO_demo.xml"

t = [
    "beispiel", 123, 23, #u'hällø',
    {"1": None, "2": True, "3": False},
    {'status':'GM', 'rating':2700},
    {
        "eins": {"a":1, "b":2},
        "zwei": {"c":2, "d":3},
    },
    {'foo': {"bar":("jup","jap","schnupp")}}
] 

PyXO.Object.save(xmlfile, t)
Ergebnis

Code: Alles auswählen

<?xml version="1.0" encoding="utf-8"?>
<PyXO del_root="true" id="Root_001" name="PyXO_demo.xml" python_module="PyXO">
  <list>
    <str>beispiel</str>
    <int>123</int>
    <int>23</int>
    <dict>
      <str>1</str>
        <NoneType>None</NoneType>
      <str>3</str>
        <bool>False</bool>
      <str>2</str>
        <bool>True</bool>
    </dict>
    <dict>
      <str>status</str>
        <str>GM</str>
      <str>rating</str>
        <int>2700</int>
    </dict>
    <dict>
      <str>eins</str>
        <dict>
          <str>a</str>
            <int>1</int>
          <str>b</str>
            <int>2</int>
        </dict>
      <str>zwei</str>
        <dict>
          <str>c</str>
            <int>2</int>
          <str>d</str>
            <int>3</int>
        </dict>
    </dict>
    <dict>
      <str>foo</str>
        <dict>
          <str>bar</str>
            <tuple>
              <str>jup</str>
              <str>jap</str>
              <str>schnupp</str>
            </tuple>
        </dict>
    </dict>
  </list>
</PyXO>
Es gibt nichts besseres als PyXO

MfG
Andreas :wink:
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

XT@ngel hat geschrieben:Es gibt nichts besseres als PyXO
Wow, das geht ja doch... Ich hatte auf die schnelle kein Beispiel gefunden...

Ich würde allerdings gern eine dumpString() und loadString() Methode einbauen... Aber ich check einfach nicht, wie PyXO funktioniert... Kannst du mir helfen?

EDIT: Ich hab PyXO mal in meinem SVN aufgenommen: http://www.python-forum.de/viewtopic.php?p=33275#33275

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
modelnine
User
Beiträge: 670
Registriert: Sonntag 15. Januar 2006, 18:42
Wohnort: Celle
Kontaktdaten:

Bah, PyXO ist nicht mal auf irgendeine geartete Weise transparent wie das pickle ist. Eines der schlimmsten Hacks die ich bisher gesehen habe. Wenn Du wirklich xml-Pickling willst, dann guck Dir mal gnosis.xml.* an, die haben ein pickle(-ähnliches) Serialisierungsprotokoll (sprich __savestate__ und __loadstate__ und Verwandte), und geben auch brauchbares XML aus (was ohne XML-Tags in Text wie bei PyXO auskommt, *brrrrr*^5, siehe Beispiel auf der Webseite zu Base64). Alles andere wie der __init__(**kwargs)-Hack bei PyXO ist Scheiße.

Edit: natürlich gehts bei meiner Kritik um Serialisierung von eigenen Objekten. Dass PyXO normale Standard-Python-Objektbäume transparent serialisiert, davon bin ich einfach mal so ausgegangen...
--- Heiko.
XT@ngel
User
Beiträge: 255
Registriert: Dienstag 6. August 2002, 14:36
Kontaktdaten:

Hie Jens,
jens hat geschrieben: Ich würde allerdings gern eine dumpString() und loadString() Methode einbauen... Aber ich check einfach nicht, wie PyXO funktioniert... Kannst du mir helfen?
Kannst du mir erklären was du darunter verstehst? Ich schau dann mal ob ich dir helfen kann.

@modeline
Alles eine Frage des Blickwinkels, mich interessiert nicht wie ein Modul funktioniert. Wichtig ist, dass es funktioniert und seinen Zweck erfüllt.
Immer diese Kritiker.........


MfG
Andreas
modelnine
User
Beiträge: 670
Registriert: Sonntag 15. Januar 2006, 18:42
Wohnort: Celle
Kontaktdaten:

Immer diese Kritiker.........
Das iss nicht böse gemeint, und ich weiß dass der Entwickler von PyXO auch hier im Forum ist. Nur find ich das Design von PyXO absolut unsauber und unpythonisch, deswegen würde ich einen riesengroßen Bogen drum machen. Da ist gnosis.xml.pickle erheblich besser, weil's eben pickle vom Interface her nachbaut (und was eben ein ziemlich pythonisches Interface hat, für allgemeine Inhalte von "pythonisch"), bloß eine XML-Ausgabe produziert, ähnlich wie PyXO auch.

Aber: hört nicht auf mich, vielleicht bin ich auch einfach zu sehr Perfektionist... ;-)
--- Heiko.
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

modelnine hat geschrieben:Das iss nicht böse gemeint, und ich weiß dass der Entwickler von PyXO auch hier im Forum ist. Nur find ich das Design von PyXO absolut unsauber und unpythonisch, deswegen würde ich einen riesengroßen Bogen drum machen.
Der Entwickler von PyXO ist nicht mehr in diesem Forum, das ist auch die letzte Version von PyXO gewesen :(

Derweil werf ich noch EaseXML ein, vielleicht mag sich das auch noch jemand ansehen.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
modelnine
User
Beiträge: 670
Registriert: Sonntag 15. Januar 2006, 18:42
Wohnort: Celle
Kontaktdaten:

Der Entwickler von PyXO ist nicht mehr in diesem Forum, das ist auch die letzte Version von PyXO gewesen
Okay, blackbird hat mich gerade aufgeklärt, und ich habs dann auch irgendwann geschnallt, langsam wie ich bin (damals gehörte ich noch nicht zum Python-Forum). Vielleicht wärs an der Zeit dass jemand PyXO aufgreift?
--- Heiko.
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

modelnine hat geschrieben:Vielleicht wärs an der Zeit dass jemand PyXO aufgreift?
Tut jens das nicht schon?
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
modelnine
User
Beiträge: 670
Registriert: Sonntag 15. Januar 2006, 18:42
Wohnort: Celle
Kontaktdaten:

Ja und nein. Soweit ich das verstehe checkt er's ja nur in subversion ein. Ich habs nicht so verstanden dass er ab jetzt Maintainer dafür sein will. Aber, okay, vielleicht hab ich ihn auch falsch verstanden... bzw. sollte jens sich vielleicht mal dazu äußern... Wenn's um ein Binärformat geht hab ich selbt auch schon einen serializer geschrieben, wenn bedarf besteht kann ich die Quellen auch mal gerne posten.
--- Heiko.
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Tja, ob ich jetzt der "Maintainer" von PyXO werden will, weiß ich nicht. Kommt darauf an, ob ich das Skript überhaupt verstehen werde. Ich hab z.B. mit Metaclassen bisher nix gemacht.
modelnine hat geschrieben:Da ist gnosis.xml.pickle erheblich besser
Das mag sein, aber erstens ist die Webseite von dem, was für'n Ar*** und zweitens ist das gesammte Paket 918KB groß, wärend PyXO eine Datei mit 22,4KB ist...
Aber gut, ich hab mir das mal angesehen und man kann gnosis.xml.pickle etwas abspecken, zumindest auf 28 Dateien und 134KB. Ist aber im Verhältnis noch immer sehr schlecht!

Leider verstehe ich PyXO noch nicht wirklich, aber ich denke schon, das ich ihm das pickle Interface bei bringen kann...

Ich möchte doch nur eine dumpString() und loadString() Methode einpflanzen. Dabei produziert dumpString() die XML-Daten und liefert sie als String zurück und loadString() erstellt aus einem XML-String wieder das Python Objekt.

EDIT: Beim studieren der Doku von EaseXML hab ich nichts gefunden, was so funktionieren kann, wie ein XML-pickle...

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
modelnine
User
Beiträge: 670
Registriert: Sonntag 15. Januar 2006, 18:42
Wohnort: Celle
Kontaktdaten:

Mir geht's nicht prinzipiell um das pickle-Interface, was ich nicht umbedingt das beste von Welt finde. Mir geht's schlicht und ergreifend darum dass ein neues Objekt die serialisierten Daten als __init__(**kwargs) kriegt, das ist grausam, und verkompliziert die Logik in __init__ nur absolut unnötig.

Vielleicht, als kleine Anregung, kann ich Dich mal auf ein altes Projekt von mir verweisen (Flatten), welches ein pickle-ähnliches Protokoll implementiert um Daten zu serialisieren, aber ein Binärformat draus macht (was ja eben nicht das ist was Du willst). Warum Du Dir das mal vielleicht angucken solltest ist die Art und Weise wie Daten serialisiert werden:

http://switch.dl.sourceforge.net/source ... .1.tar.bz2

Das Protokoll was es eben für die Serialisierung einer Klasse implementiert ist vielleicht nicht das schönste, aber sehr, sehr sauber, zumindest in meinen Augen...

Das ganze kann noch ein bissel mehr (wie zum Beispiel klassenunabhängige Serialisierung über Registrierung von Klassen mit Namen, Serialisierung von Klassenbäumen, wo jede Basisklasse unabhängig serialisiert und geladen wird, und Signierung/Verschlüsselung von Teilen des Pickles, weiß aber nicht ob die Version die auf SF steht das kann, wenn nicht dann muß ich noch mal graben), aber das ist ja nicht umbedingt das was Du brauchst. Vielleicht aber trotzdem interessant mal zu vergleichen mit PyXO.
--- Heiko.
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

modelnine hat geschrieben:Mir geht's schlicht und ergreifend darum dass ein neues Objekt die serialisierten Daten als __init__(**kwargs) kriegt, das ist grausam, und verkompliziert die Logik in __init__ nur absolut unnötig.
Ich weiß zwar nicht genau was du damit meinst, aber ich glaube das ist ein Teil von PyXO den ich eigentlich überhaupt nicht nutzten möchte. In der readme ist ganz unten das mit dem Vector(PyXO.Object). Es ist ja irgendwie eine eigene Daten-Klasse, wie die buildins dict, tuple und Co.

Ich wüßte allerdings nicht, warum ich eigene Datenklasse in der Form erzeugen sollte. Das liegt wohl daran, das ich generell solche Dinge nicht wirklich mache. Das höchste der Gefühle ist es bei mir, wenn ich von dict Ableite und so meine eigene Datenklasse baue. Wobei das wahrscheinlich nicht gerade der pyothischste Weg ist, nehme ich an...

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

jens hat geschrieben:Ich möchte doch nur eine dumpString() und loadString() Methode einpflanzen. Dabei produziert dumpString() die XML-Daten und liefert sie als String zurück und loadString() erstellt aus einem XML-String wieder das Python Objekt.
Bitte die Namen dumps() und loads() benutzen, dann ist das auch pickle-kompatibel.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Antworten