XML_Objects - Tester und Kritiker gesucht

Stellt hier eure Projekte vor.
Internetseiten, Skripte, und alles andere bzgl. Python.
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]
XT@ngel
User
Beiträge: 255
Registriert: Dienstag 6. August 2002, 14:36
Kontaktdaten:

Danke,
hab nicht mitbekommen das es eine neue Version gibt. Da Du das am anfang immer in diesen Thread geschrieben hast.
Aber super, läuft jetzt einwandfrei.
eigentlich müssen laut XML-Spezifikation die Attribute von Elementen schon bekannt sein
Gut meine Darstellung war vieleicht schon etwas übertrieben.
Es geht um OPML.

In der DTD steht:

Code: Alles auswählen

text CDATA #IMPLIED
type CDATA #IMPLIED
isComment (true|false) false
isBreakpoint (true|false) false
%OtherAttributes;
:mrgreen:


Auf jedenfall Danke, funktioniert jetzt wie sein muss!

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

So hab mal wieder ein Update gemacht, neben kleinen Codesäuberungen hab ich jetzt die Lizenz von "free" nach "Python license" geändert.
Hier nochmal der Link zu PyXO:
http://www.boa3d.de/python/modules/PyXO.php


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:

Damit PyXO nicht evtl. von der Bildfläche verschwindet, gab ich es inkl. readme in meinem SVN Server übernommen:

PyXO.py - Sourcecode | Revision Log | readme

Als erste aktion hab ich mal "cls" nach "self" umbenannt... Hatte mich ganz verwirrt, was "cls" bedeutet.

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:Als erste aktion hab ich mal "cls" nach "self" umbenannt... Hatte mich ganz verwirrt, was "cls" bedeutet.
cls ist die Namenskonvention, wenn man Metaclassen verwendet. Die Änderung würde ich rückgängig machen.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Dann muß ich wohl bisher nie über Metaclassen gestolpert sein. Denn cls hatte ich noch niergendwo gesehen:

Ich war ertmal nur verwirrt, was dieses cls ist und wo es her kommt. Erst als ich gesehen hab, das es in der Zeile, wo Methoden definiert werden, an der Stelle steht wo normalerweise self steht, ist mir ein Licht aufgegangen...

Ich find's aber als Erklärung zu wenig, warum man bei Metaclassen statt self cls nehmen sollte. Die Funktion ist doch die selbe, oder?

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

Jein. cls ist im Endeffekt wie selbst, nur macht man indem man cls nimmt noch mal explizit deutlich dass man es mit einem Klassen-Objekt (also einer Instanz des Typs type oder abgeleiteten Typs), und nicht mit einem Daten-Objekt (also einer Instanz des Typs object oder abgeleiteten Typs) zu tun hat.

Ich find die Konvention zwar in Metaklassen selbst auch unsinnig, da man mit dem self der Metaklasse spielt (bzw. die Methode eben das self der Metaklasse, was zwar ein Klassen-Objekt, aber eben eine Instanz der Klasse in der die Methode steckt ist), wo sie aber nicht unsinnig ist ist zum Beispiel bei __new__ einer Klasse, da man da wirklich das eigentliche Klassenobjekt bekommt.
--- Heiko.
Antworten