http://cheeseshop.python.org/pypi/pyfo
Kann aus x-beliebig verschachtelten dicts und listen XML erzeugen... Leider aber nicht anders herrum

Kennt jemand auch ein kleines Modul, welches in beiden Richtungen Funktioniert???
Hi Jens!jens hat geschrieben:Kennt jemand auch ein kleines Modul, welches in beiden Richtungen Funktioniert???
Funktioniert bei mir spontan nicht:gerold hat geschrieben:XMarshaL
Braucht man noch ein zusätzliches Modul? Das hier: http://pyxml.sourceforge.net ?File "D:\temp\XMarshaL-0.46\XMarshaL.py", line 40, in ?
from xml.sax import saxlib, saxexts
ImportError: cannot import name saxlib
Hi Jens!
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
Das hab ich auf http://www-128.ibm.com/developerworks/l ... ers23.html gefunden...<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}
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 nichtgerold 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.
Hi Jens!jens hat geschrieben:Eine andere Alternativen ist xmlrpclib aus den built-ins...
Hi Jens!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
Kann ich nicht, weil ich nicht an die Sourcen komme: http://pyyaml.org/ticket/1gerold hat geschrieben:Bitte lass uns wissen, wie sich PyYAML 3000 geschlagen hat, falls du es testest.
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
['YAML', 'is', 'fun!', {'dict1': {'key3': 3, 'key2': 2, 'key1': 1}}, {'dict2': {'drei': 'value3', 'eins': 'value1', 'zwei': 'value2'}}]
0.0929999351501
Die Namen sind doch okay!? Kurz und beschreiben ganz gut worum es geht.gerold hat geschrieben:Ich verstehe nicht, warum die Entwickler von XMLRPC keine kürzeren Namen verwendet haben.
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>
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%
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...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.
Ich habe heute nebenbei mal was gebastelt. Ist nicht wirklich schön, ziemlich unterdokumentiert, aber scheint zu funktionieren:jens hat geschrieben: Aber ich kann nicht wirklich glauben, das es nicht schon sowas in der Art, irgendwo fertig rumschwirrt...
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()
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>
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)
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>
Ich werd's überleben.jens hat geschrieben:Wow... Nette arbeit, die du dir gemacht hat... Leider kann ich aber nur mekern![]()
ElementTree ist aber so schön einfach zu benutzen. Und es ist in Python geschrieben, sollte sich also auch als Benutzer installieren lassen.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 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.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...
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(" ")