• Keine Ergebnisse gefunden

Transformationen mit Hilfe von XML-APIs

Im Dokument Serielle Transformationen von XML (Seite 39-43)

3   Transformationsmethoden für XML   23

3.2 Transformationen mit Hilfe von XML-APIs

APIs sind Schnittstellen zu Modulen oder Code-Bibliotheken, die eine spezielle Funktionalität anbieten. Ein API besitzt abhängig von der verwendeten Programmier-sprache immer eine konkrete Ausprägung, beispielsweise in Form von Klassen und Funktionssignaturen.

Allen APIs für die XML-Verarbeitung ist gemeinsam, dass sie einen Parser beinhalten, der einen XML-Text analysiert und der Applikation den Zugriff auf die enthaltenen Daten ermöglicht. Sie unterscheiden sich jedoch in der konkreten Repräsentation dieser XML-Daten. Die Transformationsregeln selbst müssen vom Entwickler mit den Mitteln der verwendeten Programmiersprache realisiert werden.

Eine XML-Transformation auf dieser Ebene beinhaltet die folgenden Schritte:

1. Einlesen und Analysieren des XML-Textes (Parsen)

Dieser Vorgang erkennt XML-Markup in einem Text und zerlegt den Text in seine Bestandteile. Ein XML-Parser, der sich am XML-Infoset orientiert, löst bereits Entity-Referenzen auf und überliest irrelevante Informationen (wie z.B.

Leerraum innerhalb von Start-Tags).

2. Aufbau einer internen Repräsentation der XML-Daten

Die Applikation fügt die durch den XML-Parser im vorherigen Schritt gelieferten Daten in eine größere Struktur ein. In der Regel handelt es sich dabei um ein Objektmodell, das das XML-Dokument oder Teile davon repräsentiert.

3. Umwandlung dieser internen Repräsentation

Diesen Schritt könnte man auch als die eigentliche Transformation bezeichnen.

Der Transformationsalgorithmus arbeitet auf den in der internen Repräsentation vorliegenden Daten und erzeugt daraus ein Ergebnis, das in der Regel ebenfalls zunächst in Form von Datenstrukturen der verwendeten Programmiersprache repräsentiert ist.

4. Serialisierung des Ergebnisses

Als abschließender Schritt muss aus der internen Darstellung des Ergebnisses wieder XML-Text erzeugt werden. Dieser Schritt kann entfallen, wenn nachfol-gende Verarbeitungsschritte mit der internen XML-Repräsentation weiterarbeiten.

Abhängig davon, in welchem Umfang der zweite Schritt (Aufbau der internen Daten-repräsentation) durch das API durchgeführt wird, lassen sich drei prinzipielle Heran-gehensweisen identifizieren:

1. Bereitstellung eines Datenstroms ohne den Aufbau einer zusammenhängenden Struktur (streambasiert)

2. Aufbau einer generischen Struktur, die im weiteren Sinne dem Baum des Infoset entspricht (baumbasiert)

3. Aufbau einer spezifischen, meist durch ein Schema definierten Baumstruktur (schemabasiert)

Dissertation, Oliver Becker, 1. Juli 2004

3.2  Transformationen mit Hilfe von XML-APIs 27

3.2.1  Streambasierte Transformationen

Eine streambasierte XML-Transformation verarbeitet die durch einen XML-Parser oder eine XML-Applikation gelieferten XML-Daten als Strom. Die Transformations-logik kann dabei

passiv die Daten in Form von Events vom Parser entgegennehmen (Push-Modell) oder

aktiv die Daten vom Parser abfragen (Pull-Modell)

In beiden Fällen verarbeitet die Transformationslogik pro Schritt nur ein weiteres Stück des Dokuments. Der Aufbau größerer Datenstrukturen liegt im Verantwortungs-bereich des Entwicklers, der solche streambasierten APIs benutzt.

SAX Der bekannteste Vertreter des Push-Modells ist das Simple API for XML (SAX) [SAX].

SAX entstand als Open-Source-Entwicklung und unterliegt keinem Urheberrecht (public domain). Ursprünglich für Java entworfen, existieren mittlerweile Versionen für viele andere Programmiersprachen. Sun hat SAX in das Paket JAXP (Java API for XML Processing) aufgenommen, welches seit der Version 1.4 zur Java-Standard-ausgabe (J2SE) gehört.

Pull-Parser Die Entwicklung von APIs für das Pull-Modell begann erst nach der Veröffentlichung von SAX. Die gegenwärtige Arbeit konzentriert sich auf die Spezifikation eines standardisierten Java-API innerhalb des Java Specification Request 173 [JSR173], als dessen Vorläufer das XmlPull-API [XmlPull] angesehen werden kann.

Leider existiert in der Praxis keine eineindeutige Zuordnung der Informationseinheiten des XML-Infoset zu den durch die verschiedenen Parsertypen gemeldeten Informa-tionen. Beispielsweise meldet ein SAX-Parser nicht, in welcher Kodierung das XML-Dokument vorliegt, obwohl diese Information im Infoset vorgesehen ist. Demgegen-über werden CDATA-Abschnitte im XML-Infoset nicht repräsentiert, wohingegen ein SAX-Parser diese Information liefert.

Neuere Ideen gehen sogar soweit, möglichst jede Information auf lexikalischer Ebene einer Applikation zur Verfügung zu stellen, beispielsweise im Gorille-Projekt von Simon St. Laurent [StL03].

Eine XML-Transformation, die einen XML-Datenstrom verarbeitet, muss ein eigenes Modell für die XML-Daten aufbauen. Speicherung und Verarbeitung der Daten liegen im Verantwortungsbereich der Applikation. Sie bestimmt, wie umfangreich eine solche interne Datenstruktur ausfällt. Insbesondere kann eine solcherart programmierte Transformation dynamisch genau die Daten im Speicher halten, die für den aktuellen Transformationsschritt notwendig sind, und Speicher für nicht mehr benötigte Daten wieder freigeben.

Eine rein streambasierte Lösung ist dann sinnvoll, wenn für die auszuführende Transformation wenige Kontextinformationen, also Daten aus anderen Teilen des Eingabedokuments benötigt werden. Ein typischer Anwendungsfall dafür ist die einfache Umbenennung von bestimmten Elementen.

Serialisierung SAX ist ein reines Parser-API, das keine Funktionen zur Generierung von XML beinhaltet. Demzufolge gehört es zum Aufgabenbereich des Programmierers, korrektes XML im Ergebnis der Transformation auszugeben. Insbesondere erfordert die Mas-kierung der Zeichen < und & als &lt; bzw. &amp; erhöhte Aufmerksamkeit. Eine

Serielle Transformationen von XML. Probleme, Methoden, Lösungen.

28 3  Transformationsmethoden für XML

SAX-basierte Transformation, die das Ergebnis direkt selbst als Text ausgibt, gewährt keine Sicherheit, dass dieser Text fehlerfrei ist.

Eine Lösung ist die Benutzung ergänzender APIs, die den durch einen SAX-Parser gelieferten XML-Datenstrom wieder in einen XML-Text serialisieren. In diesem Fall muss der zu programmierende Transformationscode ebenfalls einen SAX-Datenstrom produzieren. Werden die transformierten Daten an eine Serialisierungskomponente gegeben, erzeugt diese daraus korrektes XML und kann bereits Verstöße gegen die Anforderungen der Wohlgeformtheit erkennen.

Bewertung Transformationen auf der Basis eines Stream-API sind prinzipiell für beliebig große

Dokumente möglich, da diese keine zusammenhängende Repräsentation des gelesenen XML-Dokumentes erzeugen. Es liegt allein in der Verantwortung des Programmierers, eigene Datenstrukturen für die zu speichernden XML-Daten aufzubauen und zu ver-walten. Dies bedeutet gleichzeitig einen generell erhöhten Programmieraufwand. Für nichttriviale Transformationen kann der zu erstellende Code leicht komplex und un-übersichtlich werden. Die XML-Daten selbst werden als Folge von Funktionsaufrufen repräsentiert und haben in dieser Form nichts mehr mit der XML-Syntax gemein.

Darüber hinaus handelt es sich hier um reine Parser-APIs, die den Aspekt der XML-Generierung nicht berücksichtigen und daher keine Unterstützung für die Erzeugung von korrektem XML bieten.

3.2.2  Baumbasierte Transformationen

Baumbasierte APIs stellen dem Entwickler eine Baumansicht der XML-Daten zur Verfügung. Im Gegensatz zu streambasierten APIs wird kein Datenstrom, sondern eine komplette Datenstruktur erzeugt. Diese repräsentiert das gesamte XML-Dokument entsprechend einer abstrakten Syntax und ermöglicht den freien Zugriff auf alle ent-haltenen Informationen.

Eine Transformation mit Hilfe eines baumbasierten API muss somit Änderungen an dem bereitgestellten Baum vornehmen. Es können neue Objekte erzeugt, andere entfernt oder Eigenschaften der Objekte geändert werden. Wenn sich das gewünschte Ergebnis strukturell sehr stark von den Eingangsdaten unterscheidet (etwa bei der Transformation in ein anderes Vokabular), kann es günstiger sein, eine neue Objekt-struktur für das Resultat der Transformation aufzubauen und die Eingangsdaten un-verändert zu lassen.

Das W3C hat mit dem Document Object Model (DOM) ein sprachunabhängiges XML-Datenmodell spezifiziert, das für mehrere Programmiersprachen in Form kon-kreter APIs verfügbar ist. Das DOM stellt das bekannteste baumbasierte API für XML dar. Wie bereits in Kapitel 2.4 erwähnt wurde, haben sich darüber hinaus alter-native APIs entwickelt, die effizienter und sprachspezifischer sind als DOM. Für Java sind hier JDOM [JDOM] und DOM4J [DOM4J] zu nennen. Eine XML-Transforma-tion bedeutet in jedem dieser APIs die ManipulaXML-Transforma-tion von Objektstrukturen mit den Mitteln der gewählten Programmiersprache. Die anschließende Erzeugung eines XML-Textes aus einer solchen Objektstruktur übernehmen in der Regel ebenfalls Funktionen des API.

Bewertung Die Repräsentation des gesamten XML-Dokuments als Objektstruktur hat zur Folge,

dass nur Dokumente mit begrenzter Größe auf diese Weise verarbeitet werden können.

In Abhängigkeit von der konkreten Implementation belegt der Objektbaum das fünf-bis zehnfache des Speicherplatzes, den das dazugehörige Textdokument benötigt.

Dissertation, Oliver Becker, 1. Juli 2004

3.2  Transformationen mit Hilfe von XML-APIs 29

Mögliche Auswege für dieses Problem sind APIs, die die Baumstruktur verzögert erst bei Bedarf erzeugen (z.B. deferred DOM im Xerces [ASFa]) oder den benötigten Speicher virtuell auf externen Speichermedien simulieren. Beides schlägt sich in einer geringeren Performance nieder.

Die Repräsentation von XML in Form von Objekten und deren Transformation mit den Mitteln einer objektorientierten Programmiersprache erschweren das Erkennen der XML-Daten und der implementierten Transformationsregeln. Allerdings können durch die Benutzung einer universellen Programmiersprache beliebig komplexe Be-rechnungen durchgeführt werden. Die Objektstruktur stellt eine gewisse Konsistenz der Daten sicher. So werden Fehler in dieser Struktur spätestens bei der Serialisierung durch das API gemeldet.

Seit der Entwicklung spezieller Transformationssprachen reduzierte sich der Anwen-dungsbereich für Transformationen in DOM erheblich. Dies gilt um so mehr, da in-zwischen ebenfalls Transformations-APIs existieren, denen ein DOM- oder JDOM-Baum übergeben werden kann, und die dann einen solchen JDOM-Baum mit den Mitteln einer speziellen Transformationssprache transformieren. Das für Java entwickelte Transformations-API TrAX wird in Kapitel 7.2 genauer vorgestellt.

3.2.3  Schemabasierte Transformationen

Während DOM und ähnliche APIs entsprechend den Informationseinheiten des Infoset einen generischen Baum modellieren, ermöglichen so genannte Data-Binding-Fra-meworks wie zum Beispiel Castor [Castor] die Erzeugung eines spezifischen, auf ein konkretes Vokabular zugeschnittenen Modells. Dieses lässt sich mit Hilfe eines Schemas automatisch generieren. In einem solchen Modell existiert anstelle des ge-nerischen Knotentyps Element für jeden XML-Elementtyp ein eigener Objekttyp.

Dieser Objekttyp lässt von vornherein nur solche Kindelemente oder Attribute zu, die auch im Schema beschrieben worden sind.

Die Programmierung auf dieser Ebene unterscheidet sich damit nur unwesentlich von der in Kapitel 3.2.2 beschriebenen. Allerdings muss bei Transformationen in ein an-deres Vokabular eine vollständig neue Baumstruktur aufgebaut werden. Die Manipu-lation des Eingabebaumes ist nur bei inhaltlichen Transformationen, d.h. bei Ände-rungen des Inhalt unter Beibehaltung der vorhandenen Struktur möglich. Der einfache Fall einer reinen Elementumbenennung ist bereits eine strukturelle Transformation, die damit den Aufbau eines vollständig neuen Ergebnisbaumes erfordert.

Schemabasierte Transformationen erfordern ein Schema für Eingabe- und Ausgabe-daten. Der Zugriff auf XML-Markup, das nicht durch ein Schema beschrieben wird, ist mit einem schemabasierten API nicht möglich. So können beispielsweise weder Kommentare noch Verarbeitungsanweisungen transformiert werden. Die Existenz eines Schemas hat des Weiteren zur Folge, dass im Ergebnis immer gültige XML-Dokumente erzeugt werden. Verstöße gegen das Schema können bereits durch das API gemeldet werden.

In der Praxis sind strukturelle Transformationen mit Hilfe schemabasierter APIs eher selten anzutreffen. Data-Binding-Frameworks sollen vor allem einen typisierten Zugriff auf XML-Daten ermöglichen. Für pure inhaltliche Transformationen eignet sich diese Transformationsmethode jedoch sehr gut.

Serielle Transformationen von XML. Probleme, Methoden, Lösungen.

30 3  Transformationsmethoden für XML

3.2.4  Funktionale Sprachen

In den vorherigen Kapiteln wurde vorausgesetzt, dass von prozeduralen und impera-tiven Sprachen die Rede ist. Tatsächlich verhindert insbesondere ein durch DOM suggerierter Objektcharakter von XML oftmals den unvoreingenommenen Blick auf alternative Möglichkeiten. Doch XML ist nicht per se objektorientiert. Gerade eine Vielzahl funktionaler Programmiersprachen harmoniert sehr gut mit XML. Diese sind häufig ebenso wie XML deklarativ. Sie bieten Datenstrukturen, die eine direkte Repräsentation der XML innewohnenden Baumstruktur erlaubt. Einen Überblick über verschiedene Ansätze gibt Parsia in [Par01].

Für die Sprache Haskell wurde beispielsweise eine Sammlung von Funktionen namens HaXml [HaXml] entwickelt. XML-Daten werden hier durch Haskell-eigene Typen beschrieben. Verschiedene Werkzeuge, wie z.B. ein Parser und ein Pretty-Printer er-möglichen die Ein- und Ausgabe von XML. Für die so repräsentierten XML-Daten können beliebige Funktionen in Haskell definiert und aufgerufen werden. Über die Kombination solcher Funktionen lassen sich mehrere Transformationsschritte hinter-einander ausführen. Dies fördert eine klare Struktur und die Wartbarkeit der beschrie-benen Transformation.

Darüber hinaus unterstützt HaXml den schemabasierten Ansatz, indem aus einer DTD spezifische Haskell-Typen generiert werden können. Damit ist es möglich, in Haskell ebenfalls typsichere Transformationen (bezogen auf den Dokumenttyp) zu program-mieren.

Haskell erfordert für den mit dem Konzept der funktionalen Programmierung uner-fahrenen Entwickler sicher einen hohen Lernaufwand. Hat man diesen jedoch bewäl-tigt, steht mit HaXml eine mächtiges Werkzeug für die Verarbeitung von XML-Daten bereit.

Der Nachteil des funktionalen Ansatzes besteht darin, dass ein solches Programm die zu verarbeitenden Daten in der Regel vollständig als Eingabe für die zu berechnende Funktion benötigt. Zwar existiert in vielen funktionalen Sprachen das Konzept der Bedarfsauswertung von Ausdrücken (lazy evaluation), das die Bewältigung theoretisch unendlich großer Datenstrukturen ermöglicht. Die Anwendung für den Bereich der Datentransformation3 ist jedoch derzeit noch Gegenstand der Forschung, siehe Gibbons in [Gib04]. Insbesondere erfordern solche speziellen Algorithmen neben der (bisher fehlenden) Unterstützung durch die XML-APIs einen durchdachten Entwurf der ei-genen Transformationslogik, da diese ansonsten ein inkrementelles Verarbeiten der XML-Daten verhindert.

Im Dokument Serielle Transformationen von XML (Seite 39-43)