Kapitel 26
XML
740
#6: Der Textknoten wird an den neuen Elementknoten ware gehängt. Dieser wiederum wird
zum Kind des Wurzelknotens
neu.
#7: Diese Stelle bedarf einer etwas ausführlicheren Erklärung. Mit der Funktion url-
lib.request.urlopen()
wird eine Datei (zum Lesen) geöffnet, die sich auf einem beliebi-
gen Rechner im Internet befinden kann. Das erste Argument gibt den URL dieser Datei an.
Das zweite Argument enthält Daten, die zusätzlich geschickt werden. Diese Daten dürfen
kein String sein, sondern müssen vom Typ
bytes sein. Nun ist in unserem Fall die geöffnete
Datei ein Python-Skript (
catserver.py), das wegen der magic line in der ersten Zeile sofort
ausgeführt wird. Die Zeichenkette im zweiten Argument gelangt in die Standardeingabe und
kann über eine
read()-Anweisung vom Server-Skript gelesen werden.
#8: Die Methode update() wird aufgerufen, sobald die Schaltfläche KATALOG AKTUALISIEREN
angeklickt worden ist. Sie entnimmt den Eingabe-Widgets die eingetragenen Werte
(Strings) und instanziiert damit ein Objekt namens
doc der Klasse NewItem. An dieses
Objekt wird der Auftrag geschickt, ein XML-Dokument mit dem neuen Katalogeintrag an
den Server zu schicken.
#9: Die Methode send() gibt die Antwort des Serverskriptes zurück. Wenn alles richtig
funktioniert hat, erscheint im Textfenster des Clients die Meldung –
Katalog wurde aktu-
alisiert -
. Da im Serverskript mit cgitb.enable() der Debugging-Modus eingeschaltet
wurde (siehe folgender Abschnitt), sieht man an Stelle dieser Mitteilung im Textfeld eine
Fehlermeldung, falls im Serverskript ein Laufzeitfehler auftritt.
26.8.3 Das Server-Programm
Das zweite Programm catserver.py wird im cgi-bin-Verzeichnis des HTTP-Servers gespei-
chert. Es hat folgende Aufgaben:
Lesen des gesendeten XML-Dokumentes
Ermitteln der Warengruppe, in die die Artikel-Beschreibung eingetragen werden soll
Aktualisieren des XML-Dokumentes, das den Katalog repräsentiert
Erzeugen einer neuen HTML-Seite, die den geänderten Katalog wiedergibt.
Wenn die öffentliche HTML-Seite erfolgreich aktualisiert worden ist, muss sie in unserem
Beispiel so aussehen wie in Abbildung 26.7.Das Skript enthält zwei Klassendefinitionen.
Die Klasse
Catalogue modelliert das XML-Dokument mit der Katalogdefinition. Die Klasse
CatUpdate definiert die Reaktion des Servers auf eine Anfrage und ist insbesondere für die
Erstellung der HTML-Seite zuständig.
Skript:
#! /Python35/python.exe
# catserver.py
XMLPATH = "katalog/katalog_1.xml" #1
HTMLPATH = "katalog/katalog.html"
HTML_PATTERN = """
<html>
<head>
741
26.8
Anwendungsbeispiel 2: Datenkommunikation mit XML
<title>{}</title>
<meta http-equiv="Content-Type" content="charset=utf-8" />
</head>
<body><h1> {} </h1>{}</body>
</html>"""
GROUP_PATTERN = """
<h2> {} </h2>
<table border="0" >
<tr bgcolor="#c0c0c0">
<th>Nr.</th><th>Artikelbezeichnung</th><th>Preis</th>
</tr>
{}
</table>"""
ROW_PATTERN="""
<tr bgcolor="#c0c0c0">
<td>{}</td><td>{}</td><td>{} EUR</td>
</tr>"""
import sys
from xml.dom import minidom
class Catalogue(object):
# Modelliert einen XML-basierten Online-Katalog
def __init__(self, path):
self.doc = minidom.parse(path)
self.path = path
def update(self, newItemXML):
# XML-Dokument des Katalogs aktualisieren
newItemDoc = minidom.parseString(newItemXML) #2
newItem = newItemDoc.documentElement
groupName = newItem.getAttribute("warengruppe")
new = newItem.getElementsByTagName("ware")[0] #3
self.__insert(new, groupName) #4
f = open(self.path, "w", encoding="utf-8") #5
f.write(self.doc.toxml())
f.close()
def __insert(self, new, groupName):
# neuen Artikel in DOM-Objekt einfügen
Kapitel 26
XML
742
groups= self.doc.getElementsByTagName("warengruppe")
for g in groups:
if g.getAttribute("name") == groupName:
g.appendChild(new)
r e turn
def getTitle(self):
# Liefert Titel des Katalogs
return self.doc.documentElement.getAttribute("titel")
def getGroupNames(self):
# Liefert Liste mit Namen der Warengruppen
groups= self.doc.getElementsByTagName("warengruppe")
return [g.getAttribute("name") for g in groups]
def getItems (self, groupName):
# Liefert Liste mit Artikelbeschreibungen als Tupel
# der Form (id, preis, beschreibung)
groups= self.doc.getElementsByTagName("warengruppe")
for g in groups:
if g.getAttribute("name") == groupName:
items = g.getElementsByTagName ("ware")
return [(i.getAttribute("id"),
i.getAttribute("preis"),
i.firstChild.data) for i in items] #6
class CatUpdate(object):
# Update einer HTML-Seite
def __init__(self):
self.catalogue = Catalogue(XMLPATH)
self.catalogue.update(sys.stdin.read()) #7
self.updatePresentation()
print("Content-type: text/html",
"\n\n- Katalog wurde aktualisiert -")
def makeHtmlGroupDescription(self, groupName):
items = self.catalogue.getItems(groupName) #8
rows = ""
for (ID, price, descr) in items:
rows += ROW_PATTERN.format(ID, descr, price)
return GROUP_PATTERN.format(groupName, rows)
743
26.8
Anwendungsbeispiel 2: Datenkommunikation mit XML
Abb. 26.7: Ansicht der aus einem XML-Dokument automatisch erzeugten HTML-Seite
Erläuterung:
#1: Die Pfade für die XML- und HTML-Dateien werden in »Konstanten« gespeichert.
Eigentlich sind es globale Variablen, die nirgendwo geändert werden sollen. Ihre Namen
bestehen üblicherweise aus lauter Großbuchstaben.
#2: Das empfangene XML-Dokument wird geparst und ein DOM-Objekt erzeugt.
#3: new ist ein Elementknoten mit dem Tag-Namen ware, das erste (und einzige) Element
der Liste aller Knoten mit diesem Tag-Namen.
#4: Die private Methode __insert() sorgt dafür, dass das neue ware-Element im Katalog in
der richtigen Warengruppe eingefügt wird.
def updatePresentation(self):
title = self.catalogue.getTitle()
htmlGroups = ""
for g in self.catalogue.getGroupNames():
htmlGroups += self.makeHtmlGroupDescription(g)
htmlAll = HTML_PATTERN.format(title,title,
ht m lGr o u ps) #9
f = open(HTMLPATH, "w", encoding="utf-8")
f.write(htmlAll)
f.close()
CatUpdate()

Get Python 3 - Lernen und professionell anwenden now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.