Seite 1 von 2

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

Verfasst: Mittwoch 15. März 2006, 07:45
von jens
Gerade bei "Daily Python-URL" gesehen:
http://cheeseshop.python.org/pypi/pyfo

Kann aus x-beliebig verschachtelten dicts und listen XML erzeugen... Leider aber nicht anders herrum :( Das wäre aber ideal für Fälle in dem man normalerweise Pickle nehmen könnte...

Kennt jemand auch ein kleines Modul, welches in beiden Richtungen Funktioniert???

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

Verfasst: Mittwoch 15. März 2006, 08:25
von gerold
jens hat geschrieben:Kennt jemand auch ein kleines Modul, welches in beiden Richtungen Funktioniert???
Hi Jens!

Ich habe XMarshaL für solche Fälle im Einsatz. Es ist aber nicht unbedingt ein *kleines* Modul, da es auch von pyXML abhängt. Aber es erfüllt seinen Zweck.

lg
Gerold
:-)

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

Verfasst: Mittwoch 15. März 2006, 08:41
von jens
gerold hat geschrieben:XMarshaL
Funktioniert bei mir spontan nicht:
File "D:\temp\XMarshaL-0.46\XMarshaL.py", line 40, in ?
from xml.sax import saxlib, saxexts
ImportError: cannot import name saxlib
Braucht man noch ein zusätzliches Modul? Das hier: http://pyxml.sourceforge.net ?
OK, das wäre wirklich etwas sehr groß :(

EDIT: Das was ich suche ist wohl xml.pickle aus http://freshmeat.net/projects/gnosisxml/ Allerdings ist das auch sehr groß :(

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

Verfasst: Mittwoch 15. März 2006, 09:08
von gerold
jens hat geschrieben:Das hier: http://pyxml.sourceforge.net ?
OK, das wäre wirklich etwas sehr groß :(
Hi Jens!

Ja, man braucht dazu pyXML. Aber ich kenne keine akzeptable Alternative, wenn man auf XML angewiesen ist.

Meine persönliche Alternative zu XML ist YAML. Dafür verwende ich PySyck. Leider ist der Server für "Syck" die letzten Tage nicht erreichbar.

lg
Gerold
:-)

Verfasst: Mittwoch 15. März 2006, 09:19
von jens
Eine andere Alternativen ist xmlrpclib aus den built-ins... Aber es produziert nicht wirklich XML, aber irgendwie was ähnliches:

Code: Alles auswählen

import xmlrpclib

t = [
  {'status':'GM', 'rating':2700},
  {'status':'Computer', 'rating':2700},
  {'status':'Amateur', 'rating':1400},
]


dump = xmlrpclib.dumps(tuple(t))
print dump

load = xmlrpclib.loads(dump)[0]
for item in load:
    print item
Ausgabe:
<params>
<param>
<value><struct>
<member>
<name>status</name>
<value><string>GM</string></value>
</member>
<member>
<name>rating</name>
<value><int>2700</int></value>
</member>
</struct></value>
</param>
<param>
<value><struct>
<member>
<name>status</name>
<value><string>Computer</string></value>
</member>
<member>
<name>rating</name>
<value><int>2700</int></value>
</member>
</struct></value>
</param>
<param>
<value><struct>
<member>
<name>status</name>
<value><string>Amateur</string></value>
</member>
<member>
<name>rating</name>
<value><int>1400</int></value>
</member>
</struct></value>
</param>
</params>

{'status': 'GM', 'rating': 2700}
{'status': 'Computer', 'rating': 2700}
{'status': 'Amateur', 'rating': 1400}
Das hab ich auf http://www-128.ibm.com/developerworks/l ... ers23.html gefunden...

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

Verfasst: Mittwoch 15. März 2006, 09:45
von jens
gerold hat geschrieben:Meine persönliche Alternative zu XML ist YAML. Dafür verwende ich PySyck. Leider ist der Server für "Syck" die letzten Tage nicht erreichbar.
Während PySyck auf Syck als binarie aufsetzt ist http://pyyaml.org/wiki/PyYAML vielleicht das richtige für mich... Es ist YAML in pure Python. Allerdings wohl noch in der Entwicklung... Leider funktioniert gerade der SVN checkout nicht :(

Verfasst: Mittwoch 15. März 2006, 09:48
von gerold
jens hat geschrieben:Eine andere Alternativen ist xmlrpclib aus den built-ins...
Hi Jens!

Sieht wirklich nicht schlecht aus. Allerdings weiß ich jetzt auch, warum XMLRPC bei großen Datenmengen so langsam ist. Der Overhead ist enorm. Ich verstehe nicht, warum die Entwickler von XMLRPC keine kürzeren Namen verwendet haben. :?

lg
Gerold
:-)

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

Verfasst: Mittwoch 15. März 2006, 10:06
von gerold
jens hat geschrieben:http://pyyaml.org/wiki/PyYAML vielleicht das richtige für mich... Es ist YAML in pure Python. Allerdings wohl noch in der Entwicklung... Leider funktioniert gerade der SVN checkout nicht :(
Hi Jens!

Danke für den Hinweis. PyYAML 3000 kannte ich noch nicht. Allerdings kenne ich dessen Vorgänger zu genüge.

PyYAML (nennt sich jetzt anscheinend PyYAMLLegacy) hätte mich fast ein Projekt gekostet. PyYAML war so mit Fehlern vollgestopft, dass mich das Ausbügeln dieser Fehler einige Tage kostete. Als ich schon fast auf XML umsteigen wollte, bin ich auf PySyck gestoßen. Seitdem läuft alles wie am Schnürchen. Auch PySyck hatte mal Probleme, aber diese sind längst ausgebessert und seit dem läuft PySyck richtig gut.

Der Vorteil einer kleinen Lösung ohne große Abhängigkeiten ist aber nicht von der Hand zu weisen. Bitte lass uns wissen, wie sich PyYAML 3000 geschlagen hat, falls du es testest.

lg
Gerold
:-)

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

Verfasst: Mittwoch 15. März 2006, 10:19
von jens
gerold hat geschrieben:Bitte lass uns wissen, wie sich PyYAML 3000 geschlagen hat, falls du es testest.
Kann ich nicht, weil ich nicht an die Sourcen komme: http://pyyaml.org/ticket/1

Und ich hab keine Lust die Dateien per Hand aus Trac zu kopieren...

Verfasst: Mittwoch 15. März 2006, 13:11
von jens
SVN geht wieder...

Anscheinend geht es mit YAML3000 aber nur in einer Richtung... Von YAML -> Python, aber nicht anders herrum. Zumindest hab ich keine dump-Methode gefunden und das ist wohl mit There in no YAML emitter yet. gemeint, was?

Ansonsten geht es:

Code: Alles auswählen

import time

start_time = time.time()
import yaml

data = """
 - YAML
 - is
 - fun!
 - dict1:
    key1: 1
    key2: 2
    key3: 3
 - dict2:
    eins: value1
    zwei: value2
    drei: value3
"""

data = yaml.load_document(data)
duration = time.time() - start_time

print data
print duration
Ausgabe:
['YAML', 'is', 'fun!', {'dict1': {'key3': 3, 'key2': 2, 'key1': 1}}, {'dict2': {'drei': 'value3', 'eins': 'value1', 'zwei': 'value2'}}]
0.0929999351501

Verfasst: Mittwoch 15. März 2006, 22:19
von BlackJack
gerold hat geschrieben:Ich verstehe nicht, warum die Entwickler von XMLRPC keine kürzeren Namen verwendet haben.
Die Namen sind doch okay!? Kurz und beschreiben ganz gut worum es geht.

Verfasst: Donnerstag 16. März 2006, 07:28
von jens
Ich denke gerold meint wohl ehr, die vielen zusätzlichen, leeren Namen... Ist schon ganz schön aufgebläht...

Hier mal ein gegenvorschlagt, wie sowas aussehen kann:

Code: Alles auswählen

t = [
    "beispiel", 123, "noch was",
    {'status':'GM', 'rating':2700},
    {'status':'Computer', 'rating':2700},
    {'status':'Amateur', 'rating':1400},
    {
        "eins": {"a":1, "b":2},
        "zwei": {"c":2, "d":3},
    },
]


<list>
    <string>beispiel</string>
    <int>123</int>
    <string>noch was</string>
    <dict>
        <string key="status">GM</string>
        <int key="rating">2700</int>
    </dict>
    <dict>
        <string key="status">Computer</string>
        <int key="rating">2700</int>
    </dict>
    <dict>
        <string key="status">Amateur</string>
        <int key="rating">1400</int>
    </dict>
    <dict>
        <dict key="eins">
            <dict>
                <int key="a">1</int>
                <int key="b">2</int>
            </dict>
        </dict>
        <dict key="zwei">
            <dict>
                <int key="c">2</int>
                <int key="d">3</int>
            </dict>
        </dict>
    </dict>
</list>
Wobei mir jetzt schon auffällt, das ein Key in einem dict, nicht mit einem Typen angegeben ist...

Aber ich kann nicht wirklich glauben, das es nicht schon sowas in der Art, irgendwo fertig rumschwirrt...

EDIT: btw. pyfo kann man vergessen, funktioniert nicht wirklich gut :(

Verfasst: Donnerstag 16. März 2006, 09:24
von gerold
Hi!

XMLRPC muss ja nicht menschenlesbar sein. Es dient dem Übertragen von Daten von einem Programm zum anderen oder von einem Computer zum anderen. Ich wäre in diesem Fall sogar noch weiter als Jens gegangen.

Code: Alles auswählen

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

import xmlrpclib

tags = (
    ("param", "p"),
    ("value", "v"),
    ("struct", "d"),
    ("member", "m"),
    ("name", "n"),
    ("int", "i"),
    ("string", "s"),
    ("double", "f"),
    ("data", "dat"),
)

def verkleinern(xml):
    for old, new in tags:
        xml = xml.replace("<%s>" % old, "<%s>" % new)
        xml = xml.replace("</%s>" % old, "</%s>" % new)
    return xml

def vergroessern(xml):
    for new, old in tags:
        xml = xml.replace("<%s>" % old, "<%s>" % new)
        xml = xml.replace("</%s>" % old, "</%s>" % new)
    return xml

t = (
    {"Vorname": "Martin", "Nachname": "Thompson", "Alter": 10},
    {"Vorname": "Maria", "Nachname": "Thompson", "Alter": 11},
    {"Vorname": "Mustermann", "Nachname": "Thompson", "Alter": 12.5},
    {"Vorname": "Manuela", "Nachname": "Schuepfli", "Alter": 13.6},
    {"Vorname": "Kartoffel", "Nachname": "Puffer", "Alter": 14},
    {"Vorname": "Sagenhaft", "Nachname": "Imbett", "Alter": 30},
)

dumpgross = xmlrpclib.dumps(tuple(t))
dumpklein = verkleinern(dumpgross)

len_dumpgross = len(dumpgross)
len_dumpklein = len(dumpklein)
len_eingespart = len_dumpgross - len_dumpklein
print "Vorher:     %10i Byte  100.00%%" % len_dumpgross
print "Nachher:    %10i Byte  %6.2f%%" % (
    len_dumpklein,
    (100.0 / len_dumpgross * len_dumpklein)
)
print "Eingespart: %10i Byte  %6.2f%%" % (
    len_eingespart, 
    (100.0 / len_dumpgross * len_eingespart)
)

dumpgross = vergroessern(dumpklein)
load = xmlrpclib.loads(dumpgross)[0]

Code: Alles auswählen

Vorher:           1716 Byte  100.00%
Nachher:           972 Byte   56.64%
Eingespart:        744 Byte   43.36%
Das fürfte das Datenaufkommen bei Datenbankabfragen erheblich vermindern und dadurch beschleunigen.

lg
Gerold
:-)

Verfasst: Donnerstag 16. März 2006, 09:45
von jens
gerold hat geschrieben:XMLRPC muss ja nicht menschenlesbar sein. Es dient dem Übertragen von Daten von einem Programm zum anderen oder von einem Computer zum anderen.
Naja, mir geht es aber darum, das es Menschenlesbar ist... Halt im Prinzip der YAML Ansatz, nur halt in XML... z.B. für Config-Dateien, wo man nicht immer INI nehmen kann, weil es zu komplex wird...

Und mit XMLRPC ist es nicht wirklich lesbar, ob nun in der Original Version, oder in deiner "komprimierten" variante. Das liegt zum einen an dem fehlenden Einrückung und zum anderen in den unoptimalem Aufbau. Der ist wahrscheinlich dazu da, mehr als nur Strings, Dicts, Listen usw. unterzubringen, was?

Wenn man es nur zur kommunikation zwischen Programmen braucht, frag ich mich, warum man dann nicht besser pickle nimmt (zumindest, wenn auf beiden Seiten Python ist)...

Verfasst: Donnerstag 16. März 2006, 23:07
von Leonidas
Ich werf jetzt noch neben YAML auch noch JSON rein, zusammen mit JSON-RPC ;)

Verfasst: Donnerstag 16. März 2006, 23:30
von BlackJack
jens hat geschrieben: Aber ich kann nicht wirklich glauben, das es nicht schon sowas in der Art, irgendwo fertig rumschwirrt...
Ich habe heute nebenbei mal was gebastelt. Ist nicht wirklich schön, ziemlich unterdokumentiert, aber scheint zu funktionieren:

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: UTF-8 -*-
"""XML objects.

The following types can be converted to XML and back:

* None, True and False
* int, long and float
* str
* unicode (as long as it contains only printable characters below U+0020)
* tuple, list, set, frozenset and dict

The container types must not contain cycles and if an object is referenced
more than once it's contend will be expanded for every occurence.

  >>> import xmlobjects
  >>> a = (1, 2, 3)
  >>> b = [a, a]
  >>> xml = xmlobjects.encode(b)
  >>> print xml
  <objects version="0">
    <object type="list">
      <object type="tuple">
        <object type="int">1</object>
        <object type="int">2</object>
        <object type="int">3</object>
      </object>
      <object type="tuple">
        <object type="int">1</object>
        <object type="int">2</object>
        <object type="int">3</object>
      </object>
    </object>
  </objects>

If that XML is decoded, both elements of the list are different objects:

  >>> c = xmlobjects.decode(xml)
  >>> c
  [(1, 2, 3), (1, 2, 3)]
  >>> c[0] is c[1]
  False

"""
from __future__ import division
from itertools import imap
from elementtree.ElementTree import TreeBuilder, XML, tostring

__author__ = "Marc 'BlackJack' Rintsch"
__version__ = '0.0.1'
__date__ = '$Date: 2006-03-16 21:02:28 +0100 (Thu, 16 Mar 2006) $'
__revision__ = '$Rev: 825 $'

OBJECT = 'object'
OBJECTS = 'objects'

encoders = dict()
decoders = dict()


def encode_none(builder, obj):
    builder.start_object('None')
    builder.end_object()


def encode_bool(builder, obj):
    builder.start_object('bool')
    builder.data(str(obj))
    builder.end_object()

def decode_bool(decoder, element):
    try:
        return {'True': True, 'False': False}[element.text]
    except KeyError:
        raise Exception('expected True or False, got %r instead' % element.text)


def encode_complex(builder, obj):
    builder.start_object('complex')
    builder.feed(obj.real)
    builder.feed(obj.imag)
    builder.end_object()

def decode_complex(decoder, element):
    return complex(decoder.dispatch(element[0]), decoder.dispatch(element[1]))


def encode_str(builder, obj):
    try:
        value = obj.decode('ascii')
        typename = 'str'
        small_values = set(char for char in value if char < ' ')
        small_values -= set('\t\r\n')
        if small_values:
            value = obj.encode('base64')
            typename = 'binstr'
    except UnicodeDecodeError:
        value = obj.encode('base64')
        typename = 'binstr'
    builder.start_object(typename)
    builder.data(value)
    builder.end_object()

def decode_str(decoder, element):
    return str(element.text)

def decode_binstr(decoder, element):
    return element.text.decode('base64')


def make_encode_object(typename, encode_func):
    def encode_object(builder, obj):
        builder.start_object(typename)
        builder.data(encode_func(obj))
        builder.end_object()
    return encode_object


def make_decode_object(decode_func):
    def decode_object(decoder, element):
        return decode_func(element.text)
    return decode_object


def make_iterable_encoder(typename):
    def encode_iterable(builder, obj):
        builder.encode_iterable(typename, obj)
    return encode_iterable


def make_iterable_decoder(type_):
    def decode_iterable(decoder, element):
        return type_(imap(decoder.dispatch, element))
    return decode_iterable


def register(type_, encode_func, decode_func, serialized_name=None):
    typename = type_.__name__
    if not serialized_name:
        serialized_name = typename
    encoders[typename] = encode_func
    decoders[serialized_name] = decode_func


def _register_default_types():
    register(type(None), encode_none, lambda d, e: None, 'None')
    
    for type_ in (bool, complex, str):
        typename = type_.__name__
        register(type_,
                 globals()['encode_' + typename],
                 globals()['decode_' + typename])
    decoders['binstr'] = decode_binstr
    
    for type_, encode_func in ((int, str),
                               (float, repr),
                               (unicode, unicode)):
        typename = type_.__name__
        register(type_,
                 make_encode_object(typename, encode_func),
                 make_decode_object(type_))
    
    for type_ in (list, tuple, set, frozenset, dict):
        typename = type_.__name__
        register(type_,
                 make_iterable_encoder(typename),
                 make_iterable_decoder(type_))
    encoders['dict'] = lambda b, o: b.encode_iterable('dict', o.iteritems())
    
    for coders in (encoders, decoders):
        coders['long'] = coders['int']

_register_default_types()


class ObjectTreeBuilder(TreeBuilder):
    def __init__(self):
        TreeBuilder.__init__(self)
        self.start(OBJECTS, {'version': '0'})
        self.encoders = encoders
    
    def feed(self, obj):
        typename = obj.__class__.__name__
        try:
            encode_func = self.encoders[typename]
        except KeyError:
            raise Exception('unknown type %r' % typename)
        encode_func(self, obj)
    
    def close(self):
        self.end(OBJECTS)
        return TreeBuilder.close(self)
    
    def start_object(self, typename):
        self.start(OBJECT, {'type': typename})
    
    def end_object(self):
        self.end(OBJECT)
    
    def encode_iterable(self, typename, iterable):
        self.start_object(typename)
        for item in iterable:
            self.feed(item)
        self.end_object()


class Decoder(object):
    def __init__(self, source):
        self.elements = iter(XML(source))
        self.decoders = decoders
    
    def dispatch(self, element):
        typename = element.attrib['type']
        try:
            decode_func = self.decoders[typename]
        except KeyError:
            raise Exception('unknown type %r' % typename)
        return decode_func(self, element)
    
    def read(self):
        return self.dispatch(self.elements.next())


def indent(element, level=0):
    if not element.tail:
        element.tail = '\n' + ('  ' * level)
    if not element.text and len(element):
        element.text = '\n' + ('  ' * (level + 1))
    for child in element:
        indent(child, level + 1)
    if element:
        element[-1].tail = '\n' + ('  ' * level)


def encode(obj, encoding='utf-8', pretty_print=True):
    otb = ObjectTreeBuilder()
    otb.feed(obj)
    tree = otb.close()
    if pretty_print:
        indent(tree)
    return tostring(tree, encoding)


def decode(text):
    return Decoder(text).read()


def test():
    objects = ([None, True, False, (1, 0.1, (42+23j)), '<test>', u'hällø'],
               {'name': 'Methusalem', 'age': 1000000000000000000000},
               set('Mississippi'),
               frozenset('Mississippi'))

    xml_string = encode(objects)
    print xml_string
    print decode(xml_string)


if __name__ == '__main__':
    test()
Dein Beispiel sieht dann so aus:

Code: Alles auswählen

In [527]:t = [
   .527.:    "beispiel", 123, "noch was",
   .527.:    {'status':'GM', 'rating':2700},
   .527.:    {'status':'Computer', 'rating':2700},
   .527.:    {'status':'Amateur', 'rating':1400},
   .527.:    {
   .527.:        "eins": {"a":1, "b":2},
   .527.:        "zwei": {"c":2, "d":3},
   .527.:    },
   .527.:]

In [528]:print xmlobjects.encode(t)
<objects version="0">
  <object type="list">
    <object type="str">beispiel</object>
    <object type="int">123</object>
    <object type="str">noch was</object>
    <object type="dict">
      <object type="tuple">
        <object type="str">status</object>
        <object type="str">GM</object>
      </object>
      <object type="tuple">
        <object type="str">rating</object>
        <object type="int">2700</object>
      </object>
    </object>
    <object type="dict">
      <object type="tuple">
        <object type="str">status</object>
        <object type="str">Computer</object>
      </object>
      <object type="tuple">
        <object type="str">rating</object>
        <object type="int">2700</object>
      </object>
    </object>
    <object type="dict">
      <object type="tuple">
        <object type="str">status</object>
        <object type="str">Amateur</object>
      </object>
      <object type="tuple">
        <object type="str">rating</object>
        <object type="int">1400</object>
      </object>
    </object>
    <object type="dict">
      <object type="tuple">
        <object type="str">eins</object>
        <object type="dict">
          <object type="tuple">
            <object type="str">a</object>
            <object type="int">1</object>
          </object>
          <object type="tuple">
            <object type="str">b</object>
            <object type="int">2</object>
          </object>
        </object>
      </object>
      <object type="tuple">
        <object type="str">zwei</object>
        <object type="dict">
          <object type="tuple">
            <object type="str">c</object>
            <object type="int">2</object>
          </object>
          <object type="tuple">
            <object type="str">d</object>
            <object type="int">3</object>
          </object>
        </object>
      </object>
    </object>
  </object>
</objects>
Man kann natürlich sagen, dass es auch ein wenig aufgebläht ist, weil ich nur ein Tag verwende, aber ich wollte es erstmal einfach halten und erweiterbar, so dass man auch Typnamen verwenden kann die keine gültigen Tagnamen sind.

Man kann auch (De)Kodierfunktionen für andere Datentypen registrieren.

Wenn Zeichenketten "binäre" Daten enthalten, dann werden sie in Base64 kodiert gespeichert.

Und das ganze kommt nicht mit zyklischen Datenstrukturen klar und Referenzen auf das gleiche Objekt werden jedesmal neu kodiert und beim wiedereinlesen hat man dann zwei gleiche Objekte, die aber nicht die selben sind.

Verfasst: Freitag 17. März 2006, 07:43
von jens
Wow... Nette arbeit, die du dir gemacht hat... Leider kann ich aber nur mekern :lol:

Du hast das externe Modul ElementTree genutzt, das ist nicht nur schlecht, weil ich es nicht installiert hab, sondern generell blöd weil man es installieren muß ;)
Laut http://effbot.org/zone/element-index.htm wird zwar wohl in Python 2.5 mit an Board sein, aber solange auf Shared-Hosting-Server ein uralt Python installiert ist, bringt das erstmal auch nix...

Wie du schon richtig festgestellt hat, ist deine gewählte Datenstruktur leider auch sehr aufgebläht. Aber immerhin wesendlich besser als XMLRPC das macht, weil es viel lesbarer ist...

Verfasst: Freitag 17. März 2006, 08:56
von jens
Frisch aus der Maillingliste, gibt es was:

Code: Alles auswählen

import sys

t = [
    "beispiel", 123, "noch was",
    {'status':'GM', 'rating':2700},
    {'status':'Computer', 'rating':2700},
    {'status':'Amateur', 'rating':1400},
    {
        "eins": {"a":1, "b":2},
        "zwei": {"c":2, "d":3},
    },
]

def to_xml(data, out, deep=0, **attributes):
    typ = data.__class__.__name__

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

    out.write(
        "%s<%s>" % ("\t"*deep, attr)
    )

    if isinstance(data, dict):
        out.write("\n")
        for k,v in data.iteritems():
            to_xml(v, out, deep+1, key=k)
        out.write("\t"*deep)

    elif isinstance(data, list) or \
        isinstance(data, tuple):
        out.write("\n")
        for e in data:
            to_xml(e, out, deep+1)
        out.write("\t"*deep)

    else:
        out.write(repr(data))

    out.write("</%s>\n" % typ)

to_xml(t, out=sys.stdout)

print "-"*79
t = {'foo': {"bar":("jup","jap","schnupp")}}
to_xml(t, out=sys.stdout)
Erzeugt:

Code: Alles auswählen

<list>
	<str>'beispiel'</str>
	<int>123</int>
	<str>'noch was'</str>
	<dict>
		<str key="status">'GM'</str>
		<int key="rating">2700</int>
	</dict>
	<dict>
		<str key="status">'Computer'</str>
		<int key="rating">2700</int>
	</dict>
	<dict>
		<str key="status">'Amateur'</str>
		<int key="rating">1400</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>
</list>
-------------------------------------------------------------------------------
<dict>
	<dict key="foo">
		<tuple key="bar">
			<str>'jup'</str>
			<str>'jap'</str>
			<str>'schnupp'</str>
		</tuple>
	</dict>
</dict>
EDIT: So, nun hab ich auch die TABs besser erzeugt....

EDIT2: man sieht allerdings das es mit komplizierten Kombinationen probleme gibt, bei <tuple key="bar">

Verfasst: Freitag 17. März 2006, 10:39
von BlackJack
jens hat geschrieben:Wow... Nette arbeit, die du dir gemacht hat... Leider kann ich aber nur mekern :lol:
Ich werd's überleben. :-)
Du hast das externe Modul ElementTree genutzt, das ist nicht nur schlecht, weil ich es nicht installiert hab, sondern generell blöd weil man es installieren muß ;)
Laut http://effbot.org/zone/element-index.htm wird zwar wohl in Python 2.5 mit an Board sein, aber solange auf Shared-Hosting-Server ein uralt Python installiert ist, bringt das erstmal auch nix...
ElementTree ist aber so schön einfach zu benutzen. Und es ist in Python geschrieben, sollte sich also auch als Benutzer installieren lassen.
Wie du schon richtig festgestellt hat, ist deine gewählte Datenstruktur leider auch sehr aufgebläht. Aber immerhin wesendlich besser als XMLRPC das macht, weil es viel lesbarer ist...
Wie gesagt ich wollt's erstmal möglichst generell halten. Aber ich habe in der ToDo stehen, dass ich es mal mit eigenen Tags für die Grundtypen probieren will. Und zyklische Datenstrukturen wären auch ganz nett, damit man auch "Graphen" speichern kann.

Verfasst: Freitag 17. März 2006, 11:11
von jens
Ein kleines Update... Nun kümmere ich mich nicht mehr um die Formatierung, denn die kann man anschließend von minidom machen lassen:

Code: Alles auswählen

import sys

t = [
    "beispiel", 123, "noch was",
    {'status':'GM', 'rating':2700},
    {
        "eins": {"a":1, "b":2},
        "zwei": {"c":2, "d":3},
    },
    {'foo': {"bar":("jup","jap","schnupp")}}
]

def to_xml(data, out, **attributes):
    typ = data.__class__.__name__

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

    out.write("<%s>" % attr)

    if isinstance(data, dict):
        for k,v in data.iteritems():
            to_xml(v, out, key=k)

    elif isinstance(data, list) or \
        isinstance(data, tuple):
        for e in data:
            to_xml(e, out)

    else:
        out.write(str(data))

    out.write("</%s>" % typ)

class buffer:
    def __init__(self):
        self.data = ""
    def write(self, s):
        self.data += s


b = buffer()

to_xml(t, out=b)
data = b.data
print data


from xml.dom import minidom
# Formatieren und ausgeben
dom = minidom.parseString(data)
print dom.toprettyxml("    ")