XML_Objects - Tester und Kritiker gesucht

Stellt hier eure Projekte vor.
Internetseiten, Skripte, und alles andere bzgl. Python.
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Ahh, schon wieder was gelernt :) Mit new-style Klassen hatte ich schon immer Probleme...

Aber ist es nicht möglich irgendwelche Klassen mit PyXO zu serialisieren, oder müssen sie dann von PyXO.Object erben? In PyXO_Base64.py zeigst du das das auch mit einer Klasse geht die von str erbt möglich ist, diese aber to_xml() implementieren muss. Heist das also das man damit nur Newstyle Klassen serialisieren kann die to_xml() implementieren (oder eben von PyXO.Object erben)?

Wie schaut es mit der Performance aus, unter http://dezentral.de/soft/XMarshaL/ ist ein Benchmark, in dem PyXO leider fehlt. Ich würde PyXO gerne zum speichern eines mini-VFS nutzen, das wäre ein Dictionary, das alle möglichen Daten enthalten kann (Python Objekte, newstyle, oldstyle). Dazu könnte ich zwar pickle verwenden, aber es als XML abzuspeichern würde mir viel mehr gefallen.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Dookie
Python-Forum Veteran
Beiträge: 2010
Registriert: Freitag 11. Oktober 2002, 18:00
Wohnort: Salzburg
Kontaktdaten:

PyXO ist ursprünglich nicht als Serialisierer für irgendwelche Objekte gedacht gewesen. Es ist eher dazu gedacht hierarchische Datenstrukturen in XML zu speichern z.B. Szenen für ein 3D-Programm. Du kannst auch beliebige Oldstyle Objekte speichern, dann musst du aber die Klasse erst bei PyXO registrieren lassen mit einer Funktion die dann das Objekt in XML umwandelt und mit einer Funktion die aus den Daten, die xml liefert wieder ein Objekt erzeugt. Dies ist allerdings nur für besondere Fälle gedacht, wo man eben nicht mit eigenen Klassen arbeitet.

Die Performace dürfte wohl im Bereich von gnosis liegen.


Gruß

Dookie
[code]#!/usr/bin/env python
import this[/code]
Dookie
Python-Forum Veteran
Beiträge: 2010
Registriert: Freitag 11. Oktober 2002, 18:00
Wohnort: Salzburg
Kontaktdaten:

zum Testen der Performace kannst du ja wie auf der xmarshal Seite gemacht mit a = xrange(100000) eine Liste mit 100000 Integers erzeugen und die mit PyXO.Object.save("test.xml", a) speichern lassen. Das machste dann auch mit den anderen tools und hast so einen einfachen Benchmark.

Dookie
[code]#!/usr/bin/env python
import this[/code]
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Dookie hat geschrieben:zum Testen der Performace kannst du ja wie auf der xmarshal Seite gemacht mit a = xrange(100000) eine Liste mit 100000 Integers erzeugen und die mit PyXO.Object.save("test.xml", a) speichern lassen. Das machste dann auch mit den anderen tools und hast so einen einfachen Benchmark.
Für den Benchmark Trick ist PyXO viel zu schlau, es pickelt nämlich so:

Code: Alles auswählen

<?xml version="1.0" encoding="utf-8"?>
<PyXO del_root="true" id="Root_001" name="xrange.xml" python_module="PyXO">
  <xrange>xrange(100000)</xrange>
</PyXO>
Das geht zweifellos sehr schnell *g*, XMarshaL kann xrange überhaupt nicht pickeln. Ich werde das mal mit time und range versuchen.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Dookie
Python-Forum Veteran
Beiträge: 2010
Registriert: Freitag 11. Oktober 2002, 18:00
Wohnort: Salzburg
Kontaktdaten:

:oops: meinte eh range statt xrange, nur beim tippen hab ich xrange schon so verinnerlicht :D


Gruß

Dookie
[code]#!/usr/bin/env python
import this[/code]
Dookie
Python-Forum Veteran
Beiträge: 2010
Registriert: Freitag 11. Oktober 2002, 18:00
Wohnort: Salzburg
Kontaktdaten:

Wiedermal ein Update,

PyXO kann jetzt auch xrange-Objekte richtig speichern und dann wieder laden. Sehr praktisch falls man eine Folge von Integerwerten mit festgelegter Schrittweite sehr effizient speichern will.


Gruß

Dookie
[code]#!/usr/bin/env python
import this[/code]
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Ich frage mich gerade, ob man dein PyXO nicht auch dazu nutzen könnte eine Konfigdatei zu verwalten...

Im Prinzip könnte auch dein file_to_dict reichen, wenn es auch ein dem entsprechendes dict_to_file gibt...

Allerdings hat man bei XML mehr Möglichkeiten...

Kannst du vielleicht mal ein keines Beispiel zeigen, wie man folgendes abspeichern kann:
SQLcfg={
"host" : "localhost",
"user" : "root",
"passwd" : "",
"db" : "cddb",
"cds_table" : "cds",
"titles_table" : "titles"
}
EDIT: OK, die einfachste Weise ist wohl die hier:

Code: Alles auswählen

import sys, os, PyXO

filename = "PyXO_Object_test.xml"

SQLcfg={
"host"          : "localhost",
"user"          : "root",
"passwd"        : "",
"db"            : "cddb",
"cds_table"     : "cds",
"titles_table"  : "titles"
}

CFG = PyXO.Root(name = "SQLcfg")
CFG.append(SQLcfg)
CFG.save(filename)
Nur dann ist das XML-File nicht so einfach von Hand editierbar:

Code: Alles auswählen

<?xml version="1.0" encoding="utf-8"?>
<PyXO del_root="false" id="Root_001" name="SQLcfg" python_module="PyXO">
  <dict>
    <str>passwd</str>
      <str></str>
    <str>db</str>
      <str>cddb</str>
    <str>titles_table</str>
      <str>titles</str>
    <str>cds_table</str>
      <str>cds</str>
    <str>host</str>
      <str>localhost</str>
    <str>user</str>
      <str>root</str>
  </dict>
</PyXO>
Dookie
Python-Forum Veteran
Beiträge: 2010
Registriert: Freitag 11. Oktober 2002, 18:00
Wohnort: Salzburg
Kontaktdaten:

Hi jens,

es gibt auch ein entsprechendes dict_to_file in dem Thread:
http://python.sandtner.org/viewtopic.php?t=1785
Ansonst könntest du auch eine Klasse von dict ableiten mit der Möglichkeit durch eine Methode to_xml die Einträge als xml zu speichern und durch eine entsprechende __init__ Methode wieder zu laden.


Gruß

Dookie
[code]#!/usr/bin/env python
import this[/code]
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Dookie hat geschrieben:es gibt auch ein entsprechendes dict_to_file in dem Thread:
Ups :oops: das hab ich doch glatt übersehen... Peinlich...

Hmmm.... Jetzt weiß ich nicht genau, welches ich einsetzten soll... die dict_to_file() und file_to_dict() Version ist extrem schlank... Jedoch ist dein PyXO viel flexibler...

Naja, mal sehen ;)
XT@ngel
User
Beiträge: 255
Registriert: Dienstag 6. August 2002, 14:36
Kontaktdaten:

Hallo,
PyXO ist echt super!
Ich spiele seit gestern Nacht damit.
Aber es hat in manchen Situationen ein "komisches" Verhalten.
Wenn ich eigene Klassen/Obj von str ableite.

wird das so geschrieben.

Code: Alles auswählen

<meinObj>
    <str>H</str>
    <str>a</str>
    <str>l</str>
    <str>l</str>
    <str>o</str>
</meinObj>

Ist zwar logisch, aber schöner wäre doch

Code: Alles auswählen

<meinObj type="str">Hallo</meinObj>
da

Code: Alles auswählen

<str>Hallo</str>
Oder ist das möglich und ich hab das nur übersehen?
Auch wäre eine Klasse super die mit PCDATA was anfangen kann.

MfG
Andreas
Dookie
Python-Forum Veteran
Beiträge: 2010
Registriert: Freitag 11. Oktober 2002, 18:00
Wohnort: Salzburg
Kontaktdaten:

Hi XT@ngel,

Es sollte klappen, wenn du in deiner, von str abgeleiteten Klasse eine Methode to_xml definierst, die dann das Ausgeben als xml erledigt. Schau dir dazu das Beispiel im 2 mit der Base64-Stringklasse an ->
http://www.boa3d.de/python/modules/PyXO_Base64.py

Es gibt auch eine Klasse PyXO.CData.


Gruß

Dookie
[code]#!/usr/bin/env python
import this[/code]
rayo
User
Beiträge: 773
Registriert: Mittwoch 5. November 2003, 18:06
Wohnort: Schweiz
Kontaktdaten:

Hi Dookie

Kannst du noch ein Beispiel machen in dem es verschachtelte Objects hat?
Mein Ziel ist es einen Baum zu speichern, jedoch hab ich es noch nicht geschafft, dass er die Container im Container richtig speichert.

Hier mal mein kleines Beispiel mit dem Problem:

Code: Alles auswählen

class cWidget(PyXO.Object):
    __slots__ = ['parent','name','events','widgetClass','options','widget',
                 'childs','tree']
Von diesen Elementen sollen nicht alle gespeichert werden, z.B. parent, name würde ich gerne als Attribut speichern (hab ich mit xml_attrs = {'parent':str, 'name':str}.

Jetzt sollen aber die Options, welches ein Dict ist, als unterelemente gespeichert werden und die childs sind auch wieder cWidgets.

Code: Alles auswählen

<cWidget name="..." parent="...">
    <dict name="options">
    </dict>
    <childs>
      <cWidget name="..." parent="...">
      ...
      </cWidget>
    </childs>
</cWidget>
Hoffe das hat man nun verstanden :). Wie bekomm ich ca. so eine XML-Struktur?

Gruss und schöne Weihnachten
XT@ngel
User
Beiträge: 255
Registriert: Dienstag 6. August 2002, 14:36
Kontaktdaten:

Hi,
ich hab das mit den Unterelementen so gelöst.
ich weiss nicht ob sich Dookie die Verwendung so vorgestellt hat.

Code: Alles auswählen

#!d:/Program Files/Python23/python.exe -u
#-*- coding: Latin-1 -*-"

import PyXO
import os, sys, re 



class Title(PyXO.Object):
    __slots__ = ["Value"]

    def __init__(self, Value, **kw):
        super(Title, self).__init__(**kw)
        self.Value = Value
        self.xml_write_python_module

    def __str__(self):
        return self.Value[0]



class CreationDate(PyXO.Object):
    __slots__ = ["Value"]

    def __init__(self, Value, **kw):
        super(CreationDate, self).__init__(**kw)
        self.Value = Value
        self.xml_write_python_module

    def __str__(self):
        return self.Value[0]



class Language(PyXO.Object):
    __slots__ = ["Value"]

    def __init__(self, Value, **kw):
        super(Language, self).__init__(**kw)
        self.Value = Value
        self.xml_write_python_module

    def __str__(self):
        return self.Value[0]




class DocumentMeta(PyXO.Container):
    __slots__ = ["Title",
                 "CreationDate",
                 "Language"]

    def __init__(self, *args, **kw):
        self.name = "DocumentMeta"
        super(DocumentMeta, self).__init__(**kw)

        if args:
            self.Title = args[0][0]
            self.CreationDate = args[0][1]
            self.Language = args[0][2]
        else:
            pass
            

    def to_xml(self, indent=0, indstr=PyXO.indstr, stream=None):
        snip = """<DocumentMeta>
           <Title>%s</Title>
           <CreationDate>%s</CreationDate>
           <Language>%s</Language>
        </DocumentMeta>""" % (self.Title, self.CreationDate, self.Language)
    
        if stream is not None:
            stream.write(snip)
        else:
            return snip
        
    





class Chapter(PyXO.Container):
    __slots__ =  {"Nr": int ,
                  "Title": str
                  }

    def __init__(self, *args, **kw):      
        super(Chapter, self).__init__(**kw)
        self.name = "Chapter"

        print args
        
        if kw.has_key("Nr"):
            self.Nr = kw.pop("Nr")
        else:
            self.Nr = args[0]

        if kw.has_key("Title"):
            self.Title= kw.pop("Title")
        else:
            self.Title = args[1]


    def GetContent(self):
        pass








class PyBook(PyXO.Root):
    __slots__ = ["DocumentMeta", "Chapter"]

    def __init__(self, *args, **kw):
        super(PyBook, self).__init__(*args, **kw)
    
        self.DocumentMeta = None
        self.Chapter = {}

        for Children in self.children:
            if Children.__class__.__name__ == "DocumentMeta":
                self.DocumentMeta = Children
            elif Children.__class__.__name__ == "Chapter":
                self.Chapter[Children.Nr] = Children
                #self.Chapter.append(Children)
            else:
                print "Unknow Element"


    def GetIndex(self):
        return self.Chapter
            

    
        
        




File = "test.xml"

if os.path.exists(File):
    Book = PyXO.Object.load(File)
    #print """"Das Buch: %s wurde erstellt am %s""" % (Book.DocumentMeta.Title,
    #                                                  Book.DocumentMeta.CreationDate
    #                                                  )

    #print Book.GetIndex()
   
else:
    Book = PyBook()

    Meta = DocumentMeta()
    Meta.Title        = "Documentation PyBook"
    Meta.CreationDate = 100203230
    Meta.Language     = "de_DE"

    Book.append(Meta)
   
    MyChapter = Chapter(1, "Das ist ein Test")
    MyChapter.append(PyXO.CData("Das ist ein Inhalt"))
    Book.append(MyChapter)
    Book.save(File)

 
MfG
Andreas
Dookie
Python-Forum Veteran
Beiträge: 2010
Registriert: Freitag 11. Oktober 2002, 18:00
Wohnort: Salzburg
Kontaktdaten:

Hi,

bis auf die to_xml-Methode von DocumentMeta passt das, ich würde sie so schreiben:

Code: Alles auswählen

    def to_xml(self, indent=0, indstr=PyXO.indstr, stream=None):
        snip = """<DocumentMeta>
  <Title>%s</Title>
  <CreationDate>%s</CreationDate>
  <Language>%s</Language>
</DocumentMeta>""" % (self.Title, self.CreationDate, self.Language)
        snip = (indstr*indent)+snip.replace("\n", "\n"+indstr*indent)+"\n"
        if stream is not None:
            stream.write(snip)
        else:
            return snip
dann passen die Einrückungen im XML. Ich werd da wohl noch eine Formatierfunktion in PyXO einbauen.


Gruß

Dookie
[code]#!/usr/bin/env python
import this[/code]
Dookie
Python-Forum Veteran
Beiträge: 2010
Registriert: Freitag 11. Oktober 2002, 18:00
Wohnort: Salzburg
Kontaktdaten:

@ XT@ngel:

hab mir dein Beispiel nochmal zur Brust genommen.

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: UTF-8 -*-
"""
    Modul:          XmlBook
    Description:    Beschreibung
    Version:        0.1
    Copyright:      2004 by Fritz Cizmarov fritz@sol.at
    Created:        24. Dez. 2004
    Last modified:  25. Dez. 2004
    License:        free
    Requirements:   Python2.3
    Exports:        Classes and Functions to export
"""

import PyXO
import os, sys, re


class SimpleData(PyXO.Object):
    __slots__ = ["Value"]
    xml_attrs = {}

    def __init__(self, value, **kw):
        super(SimpleData, self).__init__(**kw)
        if isinstance(value, list):
            if value:
                value = value[0]
            else:
                value = ""
        self.Value = value

    def __str__(self):
        return self.Value

    def to_xml(self, indent=0, indstr=PyXO.indstr, stream=None):
        myind = indstr*indent
        fmt = '%s<%s python_module=\"%s\">%s</%s>\n'
        xml = fmt % (myind, self.__class__.__name__, 
                     os.path.basename(__file__), self.Value,
                     self.__class__.__name__)
        if stream:
            stream.write(xml)
        else:
            return xml

class Title(SimpleData):
    pass


class CreationDate(SimpleData):
    pass


class Language(SimpleData):
    pass


class DocumentMeta(PyXO.Container):

    def get_child_by_type(self, the_type):
        return [child for child in self.children if type(child) is the_type]
    
    def __get_Title(self):
        return self.get_child_by_type(Title)[0].Value

    def __set_Title(self, value):
        t = self.get_child_by_type(Title)
        if t:
            t[0].Value = value
        else:
            self.append(Title(value))

    Title = property(__get_Title, __set_Title)


    def __get_CreationDate(self):
        return int(self.get_child_by_type(CreationDate)[0].Value)

    def __set_CreationDate(self, value):
        t = self.get_child_by_type(CreationDate)
        if t:
            t[0].Value = str(value)
        else:
            self.append(CreationDate(str(value)))

    CreationDate = property(__get_CreationDate, __set_CreationDate)
    
    
    def __get_Language(self):
        return self.get_child_by_type(Language)[0].Value

    def __set_Language(self, value):
        t = self.get_child_by_type(Language)
        if t:
            t[0].Value = value
        else:
            self.append(Language(value))

    Language = property(__get_Language, __set_Language) 
    

    
class Chapter(PyXO.Container):
    __slots__ =  {"Nr": int ,
                  "Title": str
                  }
    name = "Chapter"
    def __init__(self, *args, **kw):     
        args = list(args)
        if kw.has_key("Nr"):
            self.Nr = kw.pop("Nr")
        elif args and isinstance(args[0], int):
            self.Nr = args.pop(0)
        else:
            self.Nr = 0
        if kw.has_key("Title"):
            self.Title= kw.pop("Title")
        elif args > 1 and isinstance(args[0], basestring):
            self.Title = args.pop(0)
        else:
            self.Title = "Unknown"
        super(Chapter, self).__init__(*args, **kw)


    def GetContent(self):
        pass



class PyBook(PyXO.Root):
    __slots__ = ["DocumentMeta", "Chapter"]

    def __init__(self, *args, **kw):
        super(PyBook, self).__init__(*args, **kw)
   
        self.DocumentMeta = None
        self.Chapter = {}

        for Children in self.children:
            if Children.__class__.__name__ == "DocumentMeta":
                self.DocumentMeta = Children
            elif Children.__class__.__name__ == "Chapter":
                self.Chapter[Children.Nr] = Children
                #self.Chapter.append(Children)
            else:
                print "Unknow Element"


    def GetIndex(self):
        return self.Chapter
           
   
File = "test.xml"

if os.path.exists(File):
    Book = PyXO.Object.load(File)
    #print """"Das Buch: %s wurde erstellt am %s""" % (Book.DocumentMeta.Title,
    #                                                  Book.DocumentMeta.CreationDate
    #                                                  )

    #print Book.GetIndex()
    Book.save(sys.stdout)
else:
    Book = PyBook()

    Meta = DocumentMeta()
    Meta.Title        = "Documentation PyBook"
    Meta.CreationDate = 100203230
    Meta.Language     = "de_DE"

    Book.append(Meta)
   
    MyChapter = Chapter(1, "Das ist ein Test")
    MyChapter.append(PyXO.CData("Das ist ein Inhalt"))
    Book.append(MyChapter)
    Book.save(File)

so als kleines Weihnachtsgeschenk.

Dookie
[code]#!/usr/bin/env python
import this[/code]
rayo
User
Beiträge: 773
Registriert: Mittwoch 5. November 2003, 18:06
Wohnort: Schweiz
Kontaktdaten:

Hi

Ich hab eine Frage oder vielleicht ist es ein Vorschlag.

Wenn ich einen Container hab kann ich ja mit .append() neue Elemente hinzufügen. Könnte man diesen Elementen nicht gleich einen Namen zuweisenen.


Also ich möchte in einem Container direkt die __slots__ variabeln speichern können, wie bei xml_attrs = {'name':int} in ein dict schreiben. Geht sowas schon oder kann man das hinzufügen? Beim Laden natürlich gleich wieder zuweisen.


Ich denke so könnte dein PyXO noch einfacher werden.

Code: Alles auswählen

class test(PyXO.Container):
    __slots__ = ['name','childs']
    xml_attrs = {'name':int}
    xml_container = ['childs']
childs ist bei mir jetzt wieder ein PyXO.Container.

Sowas in der Art, jetzt mach ich einfach in __init__ alle die ich drin haben möchte append(var)

Gruss
Dookie
Python-Forum Veteran
Beiträge: 2010
Registriert: Freitag 11. Oktober 2002, 18:00
Wohnort: Salzburg
Kontaktdaten:

Hi rayo,

da muss man bei xml etwas vorsichtig sein, da ein Attrubut name oft synonym für eine ID eines Objektes steht. PyXO.Container hat z.B. schon ein Attribut "name". Wenn gewünscht oder erforderlich, wird auch ein verstecktes Attribut "id" an die Objekte in der XML-Datei vergeben. Du kannst dann in deinen Eigenen Containern, wenn jedes enthaltene Objekt ein name-attribut hat auch eine Methode "get_child_by_name(self, the_name)" erstellen:

Code: Alles auswählen

    def get_child_by_name(self, the_name):
        for child in self.children:
            if child.name == the_name:
                return child
        return None
Gruß

Dookie
[code]#!/usr/bin/env python
import this[/code]
XT@ngel
User
Beiträge: 255
Registriert: Dienstag 6. August 2002, 14:36
Kontaktdaten:

Danke für dein Weihnachtsgeschenk, Dookie!
Bin jetzt erst aus Mattighofen gekommen (wirst sicher kennen)
MfG
Andreas
XT@ngel
User
Beiträge: 255
Registriert: Dienstag 6. August 2002, 14:36
Kontaktdaten:

Hallo Dookie,
ich hab nochmal eine Frage.

Ich hab ein XML Element das beliebig viele Attribute in unterschiedlichen Kombination haben kann. Zur zeit 21 Stück die mir bekannt sind.
Das Problem ist jetzt, das jeder Autor diesem Element beliebig Attribute hinzufügen kann da die Spezifikation nicht genauer regelt welche Attribute das Element haben darf.

Zur Zeit regele ich das so, das ich jedes einzelne der mir bekannten Attribute in __slots__ und xml_attrs schreibe und in der Init Methode jedes Attribut abfrage und entferne um das zurückschreiben von nicht vorhandenen Attributen zu verhindern setzte ich diese dann auf None.

Das funktioniert zwar, ist aber unflexibel.
Ich weiss das __slots__verhindert das ich einfach so Attribute hinzufügen kann. Und genau das ist mein Problem?
Wie muss ein PyXO.Object ausschauen damit ich das umgehen kann?

MfG und danke
Andreas
Zuletzt geändert von XT@ngel am Freitag 14. Januar 2005, 19:12, insgesamt 1-mal geändert.
Dookie
Python-Forum Veteran
Beiträge: 2010
Registriert: Freitag 11. Oktober 2002, 18:00
Wohnort: Salzburg
Kontaktdaten:

Hi XT@ngel,

hmm eigentlich müssen laut XML-Spezifikation die Attribute von Elementen schon bekannt sein, insbesondere wenn du eine DTD oder XMLScheme als Beschreibung des Formates definieren willst.

__slots__ ist seit dem letzten Update nur noch optional, also du musst __slots__ nicht mehr verwenden. Zum Schreiben von eigenen Attributen müsstest du, in einer von PyXO.Object abgeleiteten Klasse attrs_to_xml redefinieren.

Ich habe gerade eine neue Version von PyXO hochgeladen, welche auch unbekannte Attribute aus der XML-Datei lesen kann, dann wird als Typ automatisch str verwendet und ein Warning ausgegeben. Das Ausgeben des Warnings kannst Du über einen Filter in warnings bei Bedarf abschalten oder in eine Exception umleiten.


Gruß

Dookie
[code]#!/usr/bin/env python
import this[/code]
Antworten