Pythonmania

Script Different!

Suchen in:
Suche:
In Partnerschaft mit Amazon.de
Startseite | Schockwellenreiter | Impressum
Anzeigen


Python und XML - Teil 1

Ein Mini-Weblog-Tool mit Python und XML

Python & XML Book Cover [Python & XML] (statt einer Besprechung): Das Buch Python & XML von Christopher A. Jones und Fred L. Drake, Jr. ist wunderbar. Doch statt einer ultimativen Lobhudelei möchte ich zwei Scripte veröffentlichen, die ich -- inspiriert durch die Beispiele in Kapitel 4 des Buches -- geschrieben habe. Sie folgen in weiten Teilen dem Buch, sind aber so abgewandelt, daß sie als Grundlage für ein Mini-Weblog-Tool auf XML-Basis benutzt werden können.

[Die Klasse Artikel]: Die Klasse Artikel ist ein kleine Klasse. Sie exportiert nur zwei Methoden, eine Methode, die aus einem Artikel eine XML-Representation erstellt, und eine Methode, die umgekehrt aus einer XML-Representation wieder einen String generiert. Diese Methode arbeitet mit minidom. Die DOM-Implementierung ist Teil der Python-Standard-Distribution.

import xml.dom.minidom
from xml.sax.saxutils import escape

class Article:
""" Ein Artikel und seine Metadaten. """

   def __init__(self):
   """ Alles zurücksetzen. """
      self.reset()

   def reset(self):
      self.title = ""
      self.source = ""
      self.size = 0
      self.when = ""
      self.description = ""
      # self.categories = ""
   def getXML(self):
   """ Generiert das XML für den Artikel. """

      attr = ''
      if self.title:
         attr = ' title="%s"' % escape(self.title)
      s = '<?xml version="1.0"?>\n<item%s>\n' % attr
      if self.source:
         s = '%s\t<source url="%s" />\n' % (s, escape(self.source))
      if self.description:
         s = '%s\t<description>\n%s\n\t</description>\n' % (s, escape(self.description))
      return s + '</item>\n'

   def fromXML(self, data):
   """ data ist ein XML-Dokument, das als String übergeben wird. """
      self.reset()
      dom = xml.dom.minidom.parseString(data)
      self.title = get_attribute(dom, "item", "title")
      self.source = get_attribute(dom, "source", "url")
      self.size = int(get_attribute(dom, "size", "bytes") or 0)
      self.when = get_attribute(dom, "when", "stime")
      nodelist = dom.getElementsByTagName("description")
      if nodelist:
         assert len(nodelist) == 1
         description = nodelist[0]
         description.normalize()
         if description.childNodes:
            self.description = description.firstChild.data.strip()

# Hilfsfunktionen:

def get_attribute(dom, tagname, attrname):
   """ Gibt den Wert eines Attributs zurück, falls vorhanden. """
   nodelist = dom.getElementsByTagName(tagname)
   if nodelist:
      assert len(nodelist) == 1
      node = nodelist[0]
      return node.getAttribute(attrname).strip()
   else:
      return ""

Wir machen hier massiv Gebrauch von Pythons string formatting expressions, die ähnlich funktionieren, wie das von C bekannte sprintf. Dabei werden links vom % stehende %s durch die rechts vom % stehende Strings ersetzt.

Beachtet außerdem die escape-Funktion (aus xml.sax.saxutils), die dafür sorgt, daß eventuelle Zeichen, die in XML maskiert werden müssen, auch maskiert werden.

Die fromXML-Methode benutzt das DOM um die benötigten Informationen aus dem XML herauszuklauben.

Jetzt kann man schon einmal testweise im Interpreter eingeben:

>>> from article import Article
>>> art = Article()
>>> art.title = "Erstes Posting"
>>> art.description = "Dies ist mein erstes Posting."
>>> print art.getXML()
<?xml version="1.0"?>
<item title="Erstes Posting">
   <description>
Dies ist mein erstes Posting.
   </description>
</item>

[Die Klasse Storage]: Jetzt benötigen wir als nächstes eine Klasse, die die generierten XML-Strings als Datei ins Filesystem schreibt und die XML-Dateien lesen und für die weitere Bearbeitung aufbereiten kann. Auch diese Klasse ist wieder sehr klein.

from article import Article
import string, os

class Storage:
""" Speichert und lädt Artikel-Objekte als XML-Files.
    -- sollte einfach für eine Datenbank zu adaptieren sein. """

   def save(self, article):
   """ Speichert als <article.title>.xml. Entfernt vorher alle
       Leerzeichen aus dem Titel. """

      # Einen einigermaßen sicheren Dateinamen aus dem Titel konstruieren:
      sf = string.replace(article.title, " ", "")
      sf = string.replace(sf, os.sep, "")
      sf = string.replace(sf, ".", "")
      sf = sf[:25]
      sf += ".xml"
      fd = open(sf, "w")

      # Schreibt die Daten via getXML() auf die Platte:
      fd.write(article.getXML())
      fd.close()

   def load(self, sName):
      """ sName in der Form *.xml. Gibt ein
          Article Object zurück. """
      fd = open(sName, "r")
      sxml = fd.read()

      # Erzeuge eine Article Instance:
      art = Article()

      # Erzeuge ein Article Object via fromXML():
      art.fromXML(sxml)
      fd.close()

      return art

Beide Methoden sind eigentlich trivial und tun exakt das, was ihr Name sagt: load lädt eine XML-Datei und generiert eine Instanz der Klasse Article und save schreibt eine Instanz der Klasse Article als XML-Datei auf die Festplatte.

Die umständliche Generierung eines Dateinamens aus dem Titel ist aus zweierlei Hinsicht eigentlich unnötig. Einmal wird man bei einer ernsthaften Anwendung sicher nicht einen Dateinamen aus dem Titel generieren, sondern sich irgendetwas anderes -- z.B. eine fortlaufende Numerierung -- überlegen und zweitens erinnere ich mich, irgendwo in der Dokumentation einmal eine Methode in irgendeinem Modul gefunden zu haben, die einen sicheren Dateinamen konstruiert. Nur -- ich konnte diese Methode nicht wiederfinden...

Diese beiden Klassen können auch ohne CGI-Modul lokal auf dem Rechner getestet werden. Sie sind völlig unabhängig von der geplanten Anwendung und daher vielleicht auch anderswo nützlich. Dies ist einer der Vorteile der Objektorientierung, wie Python sie bietet.

In der Fortsetzung dieser kleinen Artikelreihe werden wir ein CGI-Skript entwickeln, das diese beiden Methoden benutzt und mit Hilfe meiner kleinen Template-Engine ein Mini-Weblog-Tool daraus basteln.

Zum Schluß möchte ich noch einmal auf Python & XML hinweisen, das mich zu diesem Artikelchen inspiriert hat und woraus ich auch sehr viel Code geborgt habe. Es ist absolut lesenswert und ein must have für jeden, der sich mit Python und XML beschäftigt oder beschäftigen will.

Wie immer gibt es bei O'Reilly ein Probekapitel online. Diesmal das erste Kapitel Python and XML, das eine kleine Übersicht über XML, SAX, DOM und die Tools, die in Python für die Bearbeitung von XML zur Verfügung stehen, gibt.






Werbung: