Konzeption und Implementation eines XPath-Moduls für - FH Wedel

Konzeption und Implementation eines XPath-Moduls für - FH Wedel

Fachhochschule Wedel (University of Applied Sciences Wedel) Diplomarbeit im Fachbereich Wirtschaftsinformatik Konzeption und Implementation eines XP...

354KB Sizes 0 Downloads 5 Views

Fachhochschule Wedel (University of Applied Sciences Wedel)

Diplomarbeit im Fachbereich Wirtschaftsinformatik

Konzeption und Implementation eines XPath-Moduls fu ¨r die Haskell XML Toolbox

20.02.2003

Eingereicht von: Torben Kuseler Kroonhorst 80 D-22549 Hamburg EMail: [email protected]

Betreuer:

Prof. Dr. Uwe Schmidt Fachhochschule Wedel Feldstrasse 143 D-22880 Wedel EMail: [email protected]

dedicated to all friends who helped me in times of need...

Inhaltsverzeichnis

Inhaltsverzeichnis

3

Abbildungsverzeichnis

5

Tabellenverzeichnis

6

1 Einleitung

7

2 Funktionale Programmierung 2.1 Programmierparadigma . . . . . . . . 2.2 Funktionen . . . . . . . . . . . . . . . 2.2.1 Funktionen h¨oherer Ordnung . 2.2.2 Funktionskomposition . . . . . 2.2.3 Kombinatoren . . . . . . . . . 2.3 Typen . . . . . . . . . . . . . . . . . . 2.3.1 Basis-Typen, Listen und Tupel 2.3.2 Algebraische Typen . . . . . . 2.3.3 Typ-Synonyme . . . . . . . . . 2.4 Pattern Matching . . . . . . . . . . . . 2.5 Guards . . . . . . . . . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

3 Das XPath-Datenmodell 3.1 Repr¨asentation eines XML-Dokumentes . . . . . 3.1.1 Knotentypen . . . . . . . . . . . . . . . . 3.1.2 Dokumentordnung . . . . . . . . . . . . . 3.2 Parsen von Ausdr¨ ucken . . . . . . . . . . . . . . 3.3 Boolsche und arithmetische Ausdr¨ ucke . . . . . . 3.4 Zahlen und Zeichenketten . . . . . . . . . . . . . 3.5 Variablen und Funktionen . . . . . . . . . . . . . 3.6 Lokalisierungspfade . . . . . . . . . . . . . . . . . 3.6.1 Achsen . . . . . . . . . . . . . . . . . . . 3.6.2 Knotentests . . . . . . . . . . . . . . . . . 3.6.3 Pr¨adikate . . . . . . . . . . . . . . . . . . 3.6.4 Filter-Ausdr¨ ucke . . . . . . . . . . . . . . 3.6.5 Relative und absolute Lokalisierungspfade 3.6.6 Abk¨ urzungen . . . . . . . . . . . . . . . . 3.7 Darstellung eines geparsten Ausdruckes . . . . . 4 Auswertung eines Ausdruckes 4.1 Kontext . . . . . . . . . . . . . 4.1.1 Variablen . . . . . . . . 4.1.2 Funktionsbibliothek . . 4.1.3 Funktionsverarbeitung . 4.1.4 Namensraumdeklaration

. . . . .

. . . . .

. . . . .

3

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . . . . . . . .

. . . . . . . . . . . . . . .

. . . . .

. . . . . . . . . . .

. . . . . . . . . . . . . . .

. . . . .

. . . . . . . . . . .

. . . . . . . . . . . . . . .

. . . . .

. . . . . . . . . . .

. . . . . . . . . . . . . . .

. . . . .

. . . . . . . . . . .

. . . . . . . . . . . . . . .

. . . . .

. . . . . . . . . . .

. . . . . . . . . . . . . . .

. . . . .

. . . . . . . . . . .

. . . . . . . . . . . . . . .

. . . . .

. . . . . . . . . . .

. . . . . . . . . . . . . . .

. . . . .

. . . . . . . . . . .

. . . . . . . . . . . . . . .

. . . . .

. . . . . . . . . . .

. . . . . . . . . . . . . . .

. . . . .

. . . . . . . . . . .

. . . . . . . . . . . . . . .

. . . . .

. . . . . . . . . . .

. . . . . . . . . . . . . . .

. . . . .

. . . . . . . . . . .

. . . . . . . . . . . . . . .

. . . . .

. . . . . . . . . . .

. . . . . . . . . . . . . . .

. . . . .

. . . . . . . . . . .

. . . . . . . . . . . . . . .

. . . . .

. . . . . . . . . . .

9 9 9 9 10 10 10 10 11 11 11 12

. . . . . . . . . . . . . . .

13 13 14 16 16 17 19 20 21 21 25 26 26 26 27 28

. . . . .

30 31 32 32 34 36

4.2 4.3 4.4 4.5 4.6

XPathFilter . . . . . . . . . . . . . . . . . Boolsche Ausdr¨ ucke . . . . . . . . . . . . Numerische Ausdr¨ ucke . . . . . . . . . . . Un¨arer Ausdruck . . . . . . . . . . . . . . Relationale Ausdr¨ ucke . . . . . . . . . . . 4.6.1 Knotenmengen Vergleiche . . . . . 4.6.2 Numerische Vergleiche . . . . . . . 4.7 Lokalisierungspfade . . . . . . . . . . . . . 4.7.1 Navigierbare B¨aume . . . . . . . . 4.7.2 Relativer und absoluter Pfad . . . 4.7.3 Lokalisierungsschritte . . . . . . . 4.7.4 Knotentests . . . . . . . . . . . . . 4.7.5 Pr¨adikate . . . . . . . . . . . . . . 4.7.6 Entfernen doppelter Teilb¨aume . . 4.8 Filter-Ausdr¨ ucke und Mengenvereinigung 4.9 Darstellung eines Ergebnisses . . . . . . . 4.10 Modul-Hierarchie . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . .

36 38 38 39 39 39 40 40 41 42 42 43 43 44 45 46 46

5 Schlussbetrachtung 5.1 Erreichtes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.2 Konformit¨at . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.3 Ausblick . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

47 47 47 48

Literaturverzeichnis

49

Weitere Quellen

50

Eidesstattliche Erkl¨ arung

51

4

. . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . .

Abbildungsverzeichnis

3.1 3.2 3.3 3.4 3.5 3.6 3.7 3.8 3.9 3.10 3.11 3.12 3.13 3.14

XML-Dokument als Baum-Repr¨asentation Dokumentordnung . . . . . . . . . . . . . ancestor-Achse . . . . . . . . . . . . . . . ancestor-or-self-Achse . . . . . . . . . . . child-Achse . . . . . . . . . . . . . . . . . parent-Achse . . . . . . . . . . . . . . . . descendant-Achse . . . . . . . . . . . . . . descendant-or-self-Achse . . . . . . . . . . following-sibling-Achse . . . . . . . . . . . following-Achse . . . . . . . . . . . . . . . preceding-sibling-Achse . . . . . . . . . . preceding-Achse . . . . . . . . . . . . . . . self-Achse . . . . . . . . . . . . . . . . . . Zusammenwirken der Achsen . . . . . . .

. . . . . . . . . . . . . .

14 16 22 22 22 22 23 23 23 23 23 23 24 24

4.1 4.2

Doppelte Teilb¨aume . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Modul-Hierarchie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

45 46

5

. . . . . . . . . . . . . .

. . . . . . . . . . . . . .

. . . . . . . . . . . . . .

. . . . . . . . . . . . . .

. . . . . . . . . . . . . .

. . . . . . . . . . . . . .

. . . . . . . . . . . . . .

. . . . . . . . . . . . . .

. . . . . . . . . . . . . .

. . . . . . . . . . . . . .

. . . . . . . . . . . . . .

. . . . . . . . . . . . . .

. . . . . . . . . . . . . .

. . . . . . . . . . . . . .

. . . . . . . . . . . . . .

. . . . . . . . . . . . . .

. . . . . . . . . . . . . .

. . . . . . . . . . . . . .

. . . . . . . . . . . . . .

Tabellenverzeichnis

3.1 3.2 3.3 3.4

Boolsche und arithmetische Operatoren Zahlenwerte im IEEE-754-Standard . . . XPath-Achsen . . . . . . . . . . . . . . . XPath-Abk¨ urzungen . . . . . . . . . . .

. . . .

17 19 22 27

4.1 4.2

Ergebnis-Grundtypen einer Auswertung . . . . . . . . . . . . . . . . . . . . . Auswertungsfunktionen f¨ ur Teilausdr¨ ucke . . . . . . . . . . . . . . . . . . . .

30 37

6

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

1 Einleitung Die Sprache XPath (XML Path Language) dient zur Adressierung einzelner Teile eines XML-Dokumentes. XPath bildet damit die Grundlage f¨ ur XSLT und XPointer [W3C 99].

Im Umfeld einer st¨andig wachsenden Popularit¨at von XML ist das Selektieren bestimmter Elemente eines XML-Dokumentes eine der zentralen Aufgaben. Das World Wide Web Consortium (W3C) spezifizierte hierf¨ ur im November 1999 die XML Path Language (XPath), Version 1.0. Der Entwurf einer eigenen Empfehlung (W3C Recommendation) f¨ ur das Adressieren von Dokumentenbestandteilen resultiert daraus, dass sowohl f¨ ur XSLT als auch f¨ ur XPointer ein Adressierungsmechanismus gebraucht wird, der in weiten Teilen identisch ist. XPointer dienen einerseits zur Vernetzung unterschiedlicher Bereiche desselben XMLDokumentes, andererseits k¨onnen mit ihnen auch Verweise zwischen verschiedenen XML-Dokumenten erstellt werden. XSLT verwendet den XPath-Adressierungsmechanismus, um eine Teilmenge des XML-Dokumentes f¨ ur eine Weiterverarbeitung (zur Transformation) auszuw¨ahlen. Neben der Adressierung von Teilen eines Dokumentes erm¨oglicht XPath den Test eines Elementes auf ein bestimmtes Muster. Diese nat¨ urliche Teilmenge von XPath wird Pattern Matching genannt und haupts¨achlich von XSLT verwendet. Außerdem stellt XPath M¨oglichkeiten der Manipulation von Zeichenketten und der Berechnung einfacher arithmetischer und boolscher Ausdr¨ ucke zur Verf¨ ugung. ¨ Diese Arbeit bezieht sich auf die kommentierte deutsche Ubersetzung der W3C-Spezifikation ¨ f¨ ur XPath von Oliver Becker [Becker 02]. Bei nicht eindeutigen Abschnitten der Ubersetzung wird die normative englische Version [W3C 99] als einzig g¨ ultige Spezifikation von XPath verwendet. Der aktuelle W3C Working Draft f¨ ur die Spezifikation der XML Path Language, Version 2.0 wird nicht Gegenstand dieser Arbeit sein und im Weiteren auch nicht n¨aher betrachtet.

Die Haskell XML Toolbox [Toolbox 02] ist eine Sammlung von Werkzeugen f¨ ur die Verarbeitung von XML-Dokumenten. Die Toolbox ist in Haskell geschrieben und wurde an der Fachhochschule Wedel von Prof. Dr. Uwe Schmidt ins Leben gerufen. Sie umfasst in der aktuellen Version einen Parser sowie ein Modul zum Validieren von XML-Dokumenten. Ein Programm zum Ableiten von Java-Klassen aus DTDs wird zurzeit von einem Studenten der Fachhochschule Wedel entwickelt. Mit der Haskell XML Toolbox ist es derzeit m¨oglich, ein XML-Dokument einzulesen und auf seine G¨ ultigkeit zu pr¨ ufen. Ebenso k¨onnen einzelne XML-Elemente durch die Haskell XML Toolbox ver¨andert oder gel¨oscht werden. Das bearbeitete XML-Dokument kann abschließend wieder ausgegeben und gesichert werden. Die R¨ uckgabe einer ausgew¨ahlten Menge von Elementen eines Dokumentes ist hingegen nicht m¨oglich.

7

Das Ziel dieser Arbeit besteht in der Analyse der grundlegenden Arbeitsweise von XPath sowie in der Umsetzung der Spezifikation in ein XPath-Modul f¨ ur die Haskell XML Toolbox. Das Design und die Implementation des Moduls erfolgt dabei auf der Grundlage der Datenstrukturen und Verarbeitungstechniken der Haskell XML Toolbox. In Kapitel zwei wird zun¨achst auf die funktionale Programmiersprache Haskell eingegangen. Es werden kurz die wichtigsten Paradigmen der funktionalen Programmierung dargelegt, und einige Spracheigenschaften von Haskell erl¨autert. Dieses Kapitel legt die Grundlagen f¨ ur das Verst¨andnis der weiteren Abschnitte. Alle verwendeten Datenstrukturen und Beispiele des XPath-Moduls werden im Folgenden in der Sprache Haskell dargestellt. Das dritte Kapitel dient zur Analyse der XPath-Spezifikation. Parallel zur Betrachtung der verschiedenen Elemente von XPath wird ein Parser f¨ ur die Grammatik entwickelt. Die einzelnen Regeln der Grammatik werden hierf¨ ur schrittweise in ein Datenmodell u uhrt, das in der Lage ist, einen beliebigen XPath-Ausdruck abzubilden. ¨berf¨ Kapitel vier beschreibt die Umsetzung eines geparsten Ausdruckes in ein XPath-Ergebnis. Es wird hierbei herausgearbeitet, wie die verschiedenen Teilausdr¨ ucke von XPath bez¨ uglich eines XML-Dokumentes durch das Modul ausgewertet werden. Die zu ber¨ ucksichtigen Randbedingungen der XPath-Spezifikation sind ebenso Inhalt dieses Kapitels, wie die Entwicklung eines Datenmodells f¨ ur die unterschiedlichen Ergebnistypen eines Ausdruckes. Das letzte Kapitel beinhaltet die Schlussbetrachtungen dieser Arbeit. Es wird dabei auf die erreichten Ziele und die auf dem Weg zu u ¨berwindenden Probleme eingegangen. Ein weiterer Abschnitt besch¨aftigt sich mit der Konformit¨at von XPath zu umgebenen Prozessoren. Abschließend werden m¨ogliche Einsatzgebiete und Erweiterungen, die sich aus dieser Arbeit ergeben, diskutiert.

8

2 Funktionale Programmierung Dieses Kapitel beschreibt die wichtigsten Eigenschaften einer funktionalen Programmiersprache am Beispiel von Haskell [Haskell 02]. Es soll dabei keine vollst¨andige Sprachreferenz gebildet, sondern nur die Basis f¨ ur das Verst¨andnis der folgenden Kapitel gelegt werden. F¨ ur weitere Informationen wird das Buch “Haskell“ von Simon Thompson [Thompson 99] empfohlen. Leser, die mit den Methoden der funktionalen Programmierung vertraut sind, k¨onnen dieses Kapitel u ¨berspringen.

2.1 Programmierparadigma Im Gegensatz zu imperativen Programmiersprachen, wie beispielsweise der Sprache C oder Pascal, besitzen funktionale Sprachen keine Zuweisungen, Schleifen oder Prozeduren und somit auch keine Zustandstransformationen. Der ermittelte Wert eines Ausdruckes wird nicht in einer Speicherzelle abgelegt (Variablenzuweisung), sondern dient direkt als Eingabe f¨ ur eine folgende Funktion. Bei funktionalen Sprachen steht im Mittelpunkt der Betrachtung WAS berechnet werden soll und nicht WIE die Berechnung erfolgt.

2.2 Funktionen Funktionen und ihre Definition sind der zentrale Aspekt der funktionalen Programmierung. Eine formale Funktionsdefinition besteht aus einer Typdefinition und einem Funktionsk¨orper. ¨ Der Typ einer Funktion wird vollst¨andig statisch (zur Ubersetzungszeit) bestimmt. Die Auswertung des Funktionsk¨orpers bildet den R¨ uckgabewert der Funktion. Beispiel: (Funktionsdefinition ohne Argumente) aNumber :: Int (Typdefinition) aNumber = 6 * (9 - 2) (Funktionsk¨orper) Eine Typdefinition kann entweder aus einem einzigen Typ (dem R¨ uckgabetyp der Funktion) oder einer beliebigen Anzahl von Argumenttypen, gefolgt vom R¨ uckgabetyp, bestehen. Beispiel: (Funktionsdefinition mit einem Argument) doubleInteger :: Int → Int doubleInteger arg = 2 * arg

2.2.1 Funktionen h¨ oherer Ordnung Haskell erm¨oglicht als Typen nicht nur einfache Basis-Typen (Int, Char, usw.), sondern auch Funktionen zu verwenden. Kommt eine Funktion als Argument bzw. als R¨ uckgabetyp vor, so spricht man von einer “Funktion h¨oherer Ordnung“. Beispiel: (Funktionsdefinition h¨oherer Ordnung) twice :: (Int → Int) → Int → Int twice fct arg = fct ( fct arg )

9

Die Funktion fct wird zweimal auf das Argument arg angewendet: twice doubleIntegers 4 doubleIntegers (doubleIntegers 4) doubleIntegers 8 16

2.2.2 Funktionskomposition Das Zusammensetzen von Funktionen, die Funktionskomposition, erlaubt eine sehr kompakte Notation schwieriger Algorithmen. Sie existiert nicht in klassischen imperativen Programmiersprachen. Eine Funktion f berechnet aus einer Menge von Eingaben einen R¨ uckgabewert, der als Eingabe f¨ ur eine zweite Funktion g verwendet wird. Dies entspricht dem mathematischen Ausdruck g◦f und wird in Haskell als g.f notiert. Die Komposition kann beliebig mit weiteren Funktionen fortgesetzt werden.

2.2.3 Kombinatoren Kombinatoren nutzen die Eigenschaft der Funktionskomposition um einfache, elementare Funktionen zu komplexeren zusammenzusetzen. Der R¨ uckgabetyp eines Kombinators ist eine Funktion. Beispiel: (Definition eines Kombinators) newFct :: (Int → Int) → (Int → Int) → (Int → Int) newFct f g = (g.f)

2.3 Typen Haskell unterscheidet eine Reihe von Typen: - Basis-Typen - Listen und Tupel - Algebraische Typen - Abstrakte Typen - Typ Klassen ¨ Die folgenden Abschnitte geben einen kurzen Uberblick u ur diese Arbeit wichtigsten ¨ber die f¨ Typen.

2.3.1 Basis-Typen, Listen und Tupel Zu den einfachen Basis-Typen z¨ahlen Int, Float, Bool und Char. Listen und Tupel setzen Typen zu umfangreicheren Strukturen zusammen. Die Elemente einer Liste sind dabei immer vom selben Typ. Tupel erm¨oglichen das Zusammenfassen unterschiedlicher Typen. Beispiel: (Definition und Initialisierung einer Liste und eines Tupels) myList :: [Int] myList = [1,21,42]

10

myTupel :: (Int, Char, Bool) myTupel = (42, ’c’, True)

2.3.2 Algebraische Typen F¨ ur die Definition komplexerer Datenstrukturen als Listen und Tupel stellt Haskell die algebraischen Typen zur Verf¨ ugung. Der senkrechte Strich | trennt die verschiedenen Optionen, die f¨ ur den Typ m¨oglich sind. Beispiel: (Typdefinition eines Aufz¨ahlungstypen) data Season = Spring | Summer | Autumn | Winter Ein algebraischer Typ kann auch rekursiv definiert werden und eignet sich so beispielsweise f¨ ur eine Baumstruktur. Beispiel: (Typdefinition eines bin¨aren Baumes) data BinTree Int = Leaf Int | Branch (BinTree Int) (BinTree Int) Die Definition beginnt mit dem Schl¨ usselwort data, gefolgt von dem Namen des Typen und den Typkonstruktoren. Algebraische Typen, die neben ihren Typkonstruktoren noch weitere Komponenten besitzen, folglich keine Aufz¨ahlungstypen sind, werden auch Produkttypen genannt. Der Baum (ein Produkttyp) kann entweder ein Blatt oder ein Ast sein, wobei der Ast wiederum zwei (Teil-)B¨aume enth¨alt. BinTree speichert als Information in den Bl¨attern allerdings nur Werte vom Typ Int. Das Speichern von Zeichen ist in diesem Baum nicht m¨oglich. Polymorphismus Um beliebige Typen speichern und einheitlich verarbeiten zu k¨onnen, ist die Definition einer polymorphen Baumstruktur notwendig. Beispiel: (Typdefinition eines bin¨aren polymorphen Baumes) data BinTree1 a = Leaf a | Branch (BinTree1 a) (BinTree1 a) BinTree1 kann als Information in den Bl¨attern einen beliebigen Typ a enthalten. Listen (siehe Abschnitt 2.3.1) sind ebenfalls polymorph, so dass alle u ¨ber sie definierten Funktionen f¨ ur jede Art von Listen g¨ ultig sind.

2.3.3 Typ-Synonyme Typ-Synonyme erh¨ohen die Lesbarkeit und somit die Wartbarkeit eines Haskell Programms. Ein Synonym ist kein neuer Typ, sondern gibt einem bestehenden einen neuen Namen. Beispiel: (String ist ein Synonym f¨ ur eine Liste von Zeichen) type String = [Char]

2.4 Pattern Matching Funktionen k¨onnen viele unterschiedliche Werte als aktuelle Parameter besitzen. Das Pattern Matching erm¨oglicht eine sehr m¨achtige Art der Verarbeitung der verschiedenen F¨alle. Eine

11

Funktion wird hierbei mehrfach deklariert, wobei jede Deklaration einen anderen Fall der Eingabewerte abdeckt. Die erste Zeile mit einem erfolgreichen Mustervergleich wird f¨ ur die Berechnung des Funktionswertes verwendet. Beispiel: (Berechnung der L¨ange einer Liste) length :: [a] -> Int length [] = 0 length (x:xs) = 1 + length xs Die Funktion length erh¨alt eine Liste als Argument. Der erste Fall tritt ein, wenn die u ¨bergebene Liste leer [] ist. Enth¨alt die Liste mindestens ein Element, so bestimmt die zweite Definition die weitere Verarbeitung. x enth¨alt dabei den Kopf der Liste, xs den gesamten Rest. Da der Wert des Kopfelementes in diesem Fall nicht relevant ist, kann statt des x auch der Unterstrich als Platzhalter angegeben werden. Beispiel: (Pattern Matching mit Platzhalter) length ( :xs) = 1 + length xs Pattern Matching ist auch f¨ ur algebraische Typen (siehe Abschnitt 2.3.2) m¨oglich. Haskell f¨ uhrt hier einen Test des aktuell u ¨bergebenen Typkonstruktors gegen die verschiedenen definierten F¨alle durch. Beispiel: (Addition aller Werte eines Baumes) addTreeValues :: Bintree Int -> Int addTreeValues (Leaf x) = x addTreeValues (Branch t1 t2) = addTreeValues t1 + addTreeValues t2

As-Pattern Um auf ein, aus mehreren Teilen bestehendes, Muster zugreifen zu k¨onnen, existiert der Operator @. Beispiel: (Restliste ab dem Wert 42 bestimmen) getFrom42 :: [Int] -> [Int] getFrom42 [] = [] getFrom42 [email protected](x:xs) = if x == 42 then list else getFrom42 xs Wenn der Wert des Listenkopfes 42 betr¨agt, soll die Liste inklusive des Kopfes zur¨ uckgegeben werden. Ohne die Verwendung des @-Operators m¨ usste die Ergebnisliste neu konstruiert werden (x:xs), das Nutzen eines As-Pattern erspart diese erneute Berechnung.

2.5 Guards Guards erm¨oglichen boolsche Tests auf den Argumenten einer Funktion. Die erste erf¨ ullte Bedingung bestimmt dabei den Wert der Funktion. Das Schl¨ usselwort otherwise f¨ uhrt immer zu einem erfolgreichen Test. Beispiel: (Bestimmen des Minimums zweier Zahlen) min :: Int -> Int -> Int min x y | x <= y = x | otherwise = y

12

3 Das XPath-Datenmodell Die Sprache XPath dient zur Adressierung von Teilen eines XML-Dokumentes. Sie nutzt eine kompakte Nicht-XML-Syntax, um die Verwendung von XPath-Ausdr¨ ucken innerhalb von URIs1 und XML-Attributen zu erm¨oglichen. Die Nicht-XML-Syntax wird vor allem in den Implementationen von XSLT2 und XPointer ben¨otigt, f¨ ur die XPath entworfen wurde. Aber auch weitere Spezifikationen k¨ onnen die zur Verf¨ ugung gestellte Adressierungstechnik nutzen. Der Name XPath leitet sich von einer, auch in URLs3 genutzten, Pfad-Notation (path) ab, mit der sich durch die hierarchische Struktur eines XML-Dokumentes navigieren l¨asst.

3.1 Repr¨ asentation eines XML-Dokumentes XPath operiert auf der logischen Struktur eines XML-Dokumentes, nicht auf seiner ¨außerlichen Syntax. Ein Dokument wird als Baum mit verschiedenen Knotentypen repr¨asentiert. Beispiel: (XML-Dokument mit der entsprechenden XPath-Baumstruktur [Becker 02]) 200g Mehl Zuerst nehmen Sie das Mehl und mischen es mit ... Die f¨ ur die Verarbeitung eines XML-Dokumentes ben¨otigte Baumstruktur (siehe Abbildung 3.1) wird bereits durch die Haskell XML Toolbox bereitgestellt und ist nicht Gegenstand dieser Arbeit.

Hinweis:

Die grundlegenden Datenstrukturen und Verarbeitungstechniken der Haskell XML Toolbox werden in der Master Thesis von Martin Schmidt [Schmidt 02] beschrieben. Die folgenden Abschnitte beziehen sich auf diese Strukturen, so dass sich ein Blick in die Thesis empfiehlt.

1

Uniform Resource Identifier: generische Menge aller Benennungs- und Adressierungsarten von Ressourcen eXtensible Stylesheet Language Transformations 3 Uniform Resource Locator: vereinheitlichte, explizite Zugriffsanweisung zu einer Ressource im Internet 2

13

Abbildung 3.1: XML-Dokument als Baum-Repr¨asentation

3.1.1 Knotentypen Die XPath-Spezifikation unterscheidet 7 Knotentypen: - Wurzelknoten - Elementknoten - Attributknoten - Namensraumknoten - Processing-Instruction-Knoten - Kommentarknoten - Textknoten Elemente der Document Type Definition (DTD) sowie die XML-Deklaration geh¨oren nicht zum XPath-Datenmodell. Es kann durch einen XPath-Ausdruck auch nicht auf diese Informationen zugegriffen werden. Die entsprechenden XNodes: XDTD und XPi (mit dem Attribut version) werden vor der Verarbeitung, durch die Funktion canonicalizeForXPath, aus dem Baum entfernt. Jeder Knotentyp besitzt einen Zeichenkettenwert. Bei einigen Knotentypen ist er Teil des Knotens, bei anderen wird er aus den Zeichenkettenwerten der Nachkommen berechnet. Wurzelknoten Der Wurzelknoten ist die Wurzel des Baumes und kommt genau einmal im Baum vor. Er besitzt neben Processing-Instruction- und Kommentarknoten, die im Prolog oder Epilog des XML-Dokumentes auftreten k¨onnen, exakt einen weiteren Kindknoten, den Elementknoten f¨ ur das Dokumentelement. Der Wurzelknoten wird durch keine eigene XNode abgebildet, sondern entspricht einem XTag mit dem Tagnamen /. Der Zeichenkettenwert des Wurzelknotens ist die Verkettung der Zeichenkettenwerte aller nachfolgenden Textknoten.

14

Elementknoten Elementknoten haben ihre Entsprechung in den XML-Elementen eines Dokumentes. Sie k¨onnen weitere Element- sowie Namensraum-, Processing-Instruction-, Kommentar- oder Textknoten als Kinder haben. Attribute sind hingegen keine Kinder eines Elementes. Ein Elementknoten wird in der Haskell XML Toolbox durch einen XTag dargestellt und kann einen eindeutigen Bezeichner (ID) als Attribut besitzen. Bei der Verarbeitung von IDs hat das Vorhandensein einer DTD somit Einfluss auf das Ergebnis eines XPath-Ausdruckes. Aus diesem Grund m¨ ussen XPath-Implementationen, vor dem Reduzieren des Baumes um die DTD, die ben¨otigten Information extrahieren (siehe Abschnitt 4.1.3). Der Zeichenkettenwert eines Elementknotens ergibt sich aus der Verkettung der Zeichenkettenwerte aller Textknoten, die Nachkommen des Elementknotens in Dokumentordnung sind. Attributknoten Jeder Elementknoten besitzt eine Menge mit ihm verbundener Attributknoten. Der Elementknoten ist Elternknoten des Attributes, das Attribut selbst aber nicht Kindknoten. Ein Attribut besitzt keine weiteren Kinder oder Attribute und wird durch ein XAttr Knoten in der Haskell XML Toolbox dargestellt. Der Zeichenkettenwert ist der normalisierte Attributwert. Namensraumknoten Jedes Element hat assoziierte Namensraumknoten. Sie entstehen durch die Namensraumdeklaration mit den Attributen xmlns oder xmlns:praefix, in deren Sichtbarkeitsbereich sich das Element befindet. Der Zeichenkettenwert ist der Namensraum-URI. Namensraumknoten werden in der Haskell XML Toolbox nicht durch einen eigenst¨andigen Knotentyp repr¨asentiert. Processing-Instruction-Knoten F¨ ur jede Processing-Instruction (im Folgenden als PI bezeichnet), die außerhalb der DTD definiert wurde, existiert ein PI-Knoten (XPi). Die XML-Deklaration ist keine PI, so dass f¨ ur sie auch kein entsprechender Knoten vorhanden ist. Der Zeichenkettenwert eines PI-Knotens ist der Teil, der nach dem Ziel und s¨ amtlichem Leerraum folgt, jedoch ohne das abschließende ?>. Kommentarknoten Kommentare, die nicht innerhalb der DTD auftreten, werden im XPath-Baum als Kommentarknoten (XCmt) abgebildet. Der Zeichenkettenwert ist der Inhalt des Kommentars ohne die o¨ffnenden . Textknoten Die Schriftzeichen eines XML-Dokumentes werden in Textknoten zusammengefasst. Ein Textknoten (XText) besitzt niemals einen weiteren Textknoten als direkten Vorg¨anger oder Nachfolger und enth¨alt mindestens ein Zeichen. Der Zeichenkettenwert besteht aus den Schriftzeichen des Knotens. Textknoten verwalten keine Information dar¨ uber, wie die Zeichen im Dokument dargestellt wurden. Das Textknoten-Zeichen A kann als Zeichen A, aber auch als A oder A im XML-Dokument vorkommen.

15

Textknoten, die nur Leerraumzeichen enthalten, sind m¨oglich. Die XPath-Spezifikation u ¨berl¨asst es der Anwendung, die sie verwendet, ob Leerraumzeichen durch einen Textknoten repr¨asentiert werden sollen oder nicht. Die Haskell XML Toolbox legt eigene Textknoten f¨ ur Leerraumzeichen an, was dem Standardverhalten bei der Verarbeitung von Dokumenten durch XSLT entspricht.

3.1.2 Dokumentordnung Innerhalb des entstehenden Baumes herrscht eine Ordnung, die Dokumentordnung. Sie korrespondiert zu der Anordnung der Elemente im XML-Dokument. Der Wurzelknoten ist der erste Knoten des Baumes. Elementknoten werden in der Reihenfolge ihrer Start-Tags im XML-Dokument angeordnet. Die Attribut- und Namensraumknoten eines Elementes stehen vor den Kindern des Elementes, wobei Namensraumknoten vor den Attributknoten erscheinen. Die relative Ordnung innerhalb der Namensraum- und Attributknoten ist implementationsabh¨angig und wird im konkreten Fall durch die Haskell XML Toolbox bestimmt. Die XPath-Spezifikation verwendet den Begriff Menge abweichend von seiner mathematischen Bedeutung. Innerhalb einer Knotenmenge liegt in XPath eine Ordnung vor, so dass die Berechnung der Position eines Elementes in der Menge m¨oglich ist.

Abbildung 3.2: Dokumentordnung

3.2 Parsen von Ausdr¨ ucken Der Ausdruck ist das prim¨are syntaktische Konstrukt von XPath. Er kann aus boolschen Operatoren, arithmetischen Ausdr¨ ucken, Variablenreferenzen, Zeichenketten (Strings), Zahlen, Lokalisierungspfaden (Locationpaths) oder aus Funktionen der Funktionsbibliothek (Core-Functions) bestehen. Zum Parsen von Ausdr¨ ucken wird, wie bereits f¨ ur das Parsen von XML-Dokumenten durch die Haskell XML Toolbox, Parsec [Parsec 00] verwendet. Parsec ist eine auf Monads basierende Parser-Kombinatoren-Bibliothek f¨ ur Haskell und wurde von Daan Leijen entwickelt. Die einfache Grammatik von XPath erlaubt es, auf ein Zerlegen des Ausdruckes in lexikalische Einheiten (Token) zu verzichten. Es ist kein separater Scanner notwendig, so dass ein Ausdruck direkt geparst werden kann. Die Repr¨asentation eines geparsten XPath-Ausdruckes erfolgt unabh¨angig von dem Datenmodell der Haskell XML Toolbox. Durch die NICHT-XML-Syntax (siehe Abschnitt: 3) ist es notwendig, ein eigenes Modell f¨ ur die Abbildung eines Ausdruckes zu entwickeln.

16

Der algebraische Typ Expr ist der zentrale Punkt des Datenmodells. Er bildet die m¨oglichen, unterschiedlichen Arten eines Ausdruckes ab. Zu ihnen z¨ahlen die boolschen/arithmetischen Ausdr¨ ucke; aber auch Lokalisierungspfade und Variablen werden im Modell als Ausdr¨ ucke angesehen.

3.3 Boolsche und arithmetische Ausdr¨ ucke Die boolschen und arithmetischen Ausdr¨ ucke werden zu einem Ausdruckstyp zusammengefasst, da ihre Verarbeitung konzeptionell identisch ist. Priorit¨at 1 2 3 3 4 4 4 4 5 5 6 6 6 7

Operator or and = != < <= > >= + * div mod -

Bedeutung logisches oder logisches und gleich ungleich kleiner kleiner oder gleich gr¨osser gr¨osser oder gleich plus minus multiplikation division modulo un¨ares minus

Name im Modell Or And Eq NEq Less LessEq Greater GreaterEq Plus Minus Mult Div Mod Unary

Tabelle 3.1: Boolsche und arithmetische Operatoren (1 = niedrigste Priorit¨at)

Aus den Operatoren leitet sich der erste Ansatz f¨ ur den Datentyp Expr ab. Beispiel: (Erster Ansatz f¨ ur den Datentyp Expr) data Expr = OrExpr Expr Expr | AndExpr Expr Expr | PlusExpr Expr Expr | EqExpr Expr Expr | ... Jedem Operator wird ein Typkonstruktor zugeordnet, der jeweils zwei Werte vom Typ Expr beinhaltet. Sie entsprechen der linken bzw. rechten Seite des Ausdruckes. Beispiel: (Darstellung eines additiven Ausdruckes) 1 + 2 + 3 = 6 (1 + 2 + 3) = 6 (implizite Klammerung der h¨oheren Priorit¨at) EqExpr (PlusExpr 1 (PlusExpr 2 3) 6)4 Dieser Ansatz besitzt allerdings zwei gravierende Schw¨achen: 1. F¨ ur jeden zweistelligen Ausdruck wird ein eigenes Element erzeugt. 2. Die Links-Assoziativit¨at der Operatoren gleicher Priorit¨at wird nicht ber¨ ucksichtigt. 4

der Datentyp f¨ ur Zahlen wird sp¨ ater betrachtet und kann an dieser Stelle vernachl¨ assigt werden

17

Obwohl derselbe Operator + auf die drei Werte angewendet wird, m¨ ussen zwei Elemente des Typen PlusExpr erzeugt werden. Dies ergibt vor allem bei l¨angeren Ausdr¨ ucken einen zus¨atzlichen Verwaltungsaufwand, der zu vermeiden ist. Operatoren gleicher Priorit¨at sind in XPath links-assoziativ zu klammern. Der obige Ansatz klammert allerdings rechts-assoziativ ((1 + (2 + 3)) = 6), was bei relationalen Ausdr¨ ucken zu Fehlern f¨ uhrt. Beispiel: (Assoziativit¨at) 1 < 2 < 3 1 < (2 < 3) → Falsch (rechts-assoziativ)5 (1 < 2) < 3 → Richtig (links-assoziativ) Durch die Verwendung einer Liste von Expressions, anstatt der beiden getrennten Teilausdr¨ ucke, lassen sich diese Nachteile beheben. Beispiel: (Datentyp Expr) data Expr = OrExpr [Expr] | AndExpr [Expr] | PlusExpr [Expr] | EqExpr [Expr] | ... Die Elemente der Liste k¨onnen sequentiell verarbeitet werden (links-assoziativ), und es existiert f¨ ur einen beliebig langen Ausdruck gleicher Operatoren genau ein Typkonstruktor. Beispiel: (Darstellung der Operanden als Liste) 1 + 2 + 3 = 6 EqExpr (PlusExpr 1 2 3) 6) Die 15 Operatoren, die im Sprachumfang von XPath vorhanden sind, f¨ uhren im jetzigen Modell zu 15 Produkttypen (siehe Abschnitt: 2.3.2), die jeweils eine Liste von Expressions enthalten. An dieser Stelle bietet sich die Verwendung eines Aufz¨ahlungstypen Op f¨ ur die Operatoren an, so dass nur noch ein allgemeiner Produkttyp GenExpr im Modell vorhanden ist6 . Beispiel: (Operatoren im Datenmodell von XPath) data Op = Or | And | Eq | NEq | GreaterEq | Greater | LessEq | Less |Plus | Minus | Div | Mod | Mult| Unary | Union data Expr = GenExpr Op [Expr] Un¨ ares Minus Der Operator Unary berechnet das un¨are Minus eines Wertes. Obwohl das un¨are Minus eine einstellige Funktion ist, alle anderen Operatoren entsprechen zweistelligen Funktionen, kann es einfach durch das Datenmodell dargestellt werden. Die Liste von Ausdr¨ ucken besteht in diesem Fall aus genau einem Wert. Die zweifache Anwendung des Operators auf einen Wert ergibt zwei Unary-Elemente. Beispiel: (Doppelte Negation) --42 UnaryExpr (UnaryExpr 42) Ein Ausdruck kann nicht durch das Entfernen eines doppelten Minus-Zeichens, w¨ahrend des 5 6

es erfolgt eine Konversion des boolschen Zwischenergebnisses in eine Zahl (False 7→ 0, True 7→ 1) der Union-Operator vereinigt Knotenmengen (siehe Abschnitt 3.6.5)

18

Parsens, vereinfacht werden. Hierbei kann ein Fehler auftreten, wenn der zu negierende Wert der kleinsten darstellbaren Zahl entspricht.

3.4 Zahlen und Zeichenketten Im n¨achsten Schritt soll das Datenmodell um Typen f¨ ur Zahlen und Zeichenketten erg¨anzt werden. Zeichenketten (Literale) k¨onnen innerhalb der Haskell XML Toolbox aus Zeichen des gesamten Unicode Bereiches bestehen und werden durch den Haskell Datentyp String dargestellt. type Literal = String Einige Funktionen der Funktionsbibliothek, die auf Zeichenketten operieren, wie beispielsweise string-length oder translate arbeiten noch nicht mit beliebigen Unicode-Zeichen. Sobald die zurzeit noch fehlende Funktionalit¨at durch das Modul Unicode der Haskell XML Toolbox bereitgestellt wird, ist aber der Einsatz beliebiger Zeichen innerhalb von XPath m¨oglich. Zahlen k¨onnen jeden Gleitkommawert nach dem IEEE-754-Standard [IEEE 00] annehmen. Dieser beinhaltet einige besondere Werte, die in der folgenden Tabelle dargestellt sind. Zahlenwert normale Fließkommazahl negativ Unendlich positiv Unendlich negativ Null positiv Null Not-a-Number

Name im Modell Float f NegInf PosInf Neg0 Pos0 NaN

Tabelle 3.2: Zahlenwerte im IEEE-754-Standard Es ist allerdings nicht erlaubt, die speziellen Werte direkt in einem Ausdruck anzugeben. Sie k¨onnen nur berechnet werden. 1 div 0 7→ PosInf ¨ Bei Berechnungen in XPath treten keine Fehler, Ausnahmen oder Uberl¨ aufe auf. Ist die Berechnung eines Ausdruckes nicht m¨oglich, weil es sich bei einem Operanden beispielsweise um eine Zeichenkette handelt, wird der Wert NaN als Ergebnis geliefert. Beispiel: (Datentyp f¨ ur Zahlen und Zeichenketten) data XPNumber = Float Float | NaN | NegInf | Neg0 | Pos0 | PosInf Expr = GenExpr Op [Expr] | LiteralExpr Literal | NumberExpr XPNumber

19

Zahlendarstellung Eine Zahl kann nicht in Exponentialdarstellung (2.99792E+08) angegeben werden. Es existiert weder ein spezieller Typ f¨ ur ganzzahlige Werte, noch f¨ ur besondere Darstellungen, die eine Zahl als Oktal- oder Hexadezimalzahl interpretieren. Ein Wert kann ein negatives Vorzeichen besitzen. Die Angabe eines expliziten positiven Vorzeichens ist jedoch nicht erlaubt. Der Parser normalisiert alle syntaktisch korrekten Eingaben f¨ ur Zahlen in die Form a.b7 , um eine einheitliche Verarbeitung zu gew¨ahrleisten. Beispiel: (Normalisieren von Zahlen durch den Parser) 21. 7→ 21.0 42 7→ 42.0 .1 7→ 0.1 number :: Parser String number = do tokenParser (symbol ".") d <- many1 digit return ("0." ++ d) <|> do d <- many1 digit d1 <- option "" ( do tokenParser (symbol ".") d2 <- option "0" (many1 digit) return ("." ++ d2) ) return (d ++ d1) "number"

3.5 Variablen und Funktionen ¨ Uber Variablen lassen sich Informationen aus der Umgebung in die Verarbeitung eines XPath-Ausdruckes integrieren. Variablen besitzen einen Namen, u ¨ber den sie eindeutig identifiziert werden. Beispiel: (Datentyp f¨ ur einen Variablennamen) type VarName = String W¨ahrend des Parsens wird jeder syntaktisch korrekte Variablenname als Variable erkannt. Es wird zu diesem Zeitpunkt noch nicht u uft, ob eine Variable mit diesem ¨berpr¨ Namen existiert. Funktionen Funktion besitzen wie Variablen einen eindeutigen Namen und zus¨atzlich eine durch Kommata getrennte Liste von Argumenten, f¨ ur die ein beliebiger Ausdruck zugelassen ist. 7

a und b entsprechen einer beliebigen Ziffernfolge ≥ 1

20

Beispiel: (Darstellung einer Funktion im Modell) type FctName = String type FctArguments = [Expr] Eine Kontrolle der Eingabe erfolgt auch hier nur auf syntaktischer Ebene. Alle weite¨ ren Uberpr¨ ufungen8 finden erst w¨ahrend der Auswertung (siehe Abschnitt 4.1.2) statt. Hierdurch wird eine strikte Trennung der syntaktischen (Parsen) von der inhaltlichen ¨ Uberpr¨ ufung (Auswertung) erreicht. Beispiel: (Datentyp Expr inkl. der beiden Produkttypen VarExpr und FctExpr) data Expr = GenExpr Op [Expr] | LiteralExpr Literal | NumberExpr XPNumber | VarExpr VarName | FctExpr FctName FctArguments

3.6 Lokalisierungspfade Lokalisierungspfade sind die wichtigsten Teilausdr¨ ucke von XPath. Sie erlauben das Navigieren in einem XML-Baum u ber Achsen. Ein Lokalisierungspfad besteht aus einer Liste von ¨ Lokalisierungsschritten, die nacheinander auf einen Baum angewendet werden. Jeder Lokalisierungsschritt selektiert dabei eine Teilmenge des aktuellen Baumes. Diese resultierende Teilmenge ist Ausgangsmenge f¨ ur den n¨achsten Lokalisierungsschritt. Ein Schritt besteht aus drei Teilen: 1. aus einer Achse, die die Beziehung, zwischen den durch den Lokalisierungsschritt ausgew¨ ahlten Knoten und dem Kontextknoten, innerhalb des Baumes spezifiziert. 2. aus einem Knotentest, der den Knotentyp und den erweiterten Namen der durch den Lokalisierungsschritt ausgew¨ahlten Knoten spezifiziert. 3. aus null oder mehr Pr¨adikaten, die mittels beliebiger Ausdr¨ ucke die durch eine Achse und anschließendem Knotentest ausgew¨ahlte Teilmenge weiter verfeinern k¨onnen.

3.6.1 Achsen Achsen filtern die Knoten eines Baumes bez¨ uglich einer Richtung. Eine vorw¨arts gerichtete Achse enth¨alt immer nur den aktuellen Knoten (Kontextknoten) oder Knoten, die nach dem Kontextknoten im Dokument (siehe Abschnitt: 3.1.2) auftreten. Die Position eines Knotens in der resultierenden Menge, welche in Dokumentordnung vorliegt, wird als N¨aheposition bezeichnet. Eine r¨ uckw¨arts gerichtete Achse umfasst entsprechend den Kontextknoten und Knoten, die vor ihm auftreten. Die N¨aheposition wird anhand der umgekehrten Dokumentordnung bestimmt. Die self-Achse enth¨alt immer nur einen Knoten (den Kontextknoten), sie kann daher als vorw¨arts bzw. r¨ uckw¨arts gerichtet angesehen werden. Die attribute- und namespace-Achsen haben keine Richtung, da die relative Ordnung der Attribut- bzw. Namensraumknoten nicht durch XPath festgelegt wird, sondern implementationsabh¨angig ist. Die folgenden Abbildungen [Becker 02] verdeutlichen die durch die jeweilige Achse selektierten Knoten. Der grau hinterlegte Knoten entspricht dem aktuellen Kontextknoten. 8

Funktion mit dem Namen vorhanden, Anzahl und Art der Argumente

21

Achsenname ancestor ancestor-or-self attribute child descendant descendant-or-self following following-sibling namespace parent preceding preceding-sibling self

Name im Modell Ancestor AncestorOrSelf Attribute Child Descendant DescendantOrSelf Following FollowingSibling Namespace Parent Preceding PrecedingSibling Self

Richtung r¨ uckw¨arts gerichtet r¨ uckw¨arts gerichtet keine Richtung vorw¨arts gerichtet vorw¨arts gerichtet vorw¨arts gerichtet vorw¨arts gerichtet vorw¨arts gerichtet keine Richtung vorw¨arts gerichtet r¨ uckw¨arts gerichtet r¨ uckw¨arts gerichtet vorw¨arts/r¨ uckw¨arts gerichtet

Tabelle 3.3: XPath-Achsen Die Ziffern geben die N¨aheposition in der resultierenden Menge an. Es handelt sich bei den dargestellten Knoten um keine speziellen Knotentypen (siehe Abschnitt: 3.1.1): Es k¨onnen Element-, Text-, Kommentar- oder Processing-Instruction-Knoten sein. Sie repr¨asentieren allerdings niemals Attribut- oder Namensraumknoten, da diese nur u ur ¨ber eigens daf¨ definierte Achsen erreicht werden k¨onnen.

Abbildung 3.3: ancestor-Achse

Abbildung 3.4: ancestor-or-self-Achse

Die ancestor-Achse enth¨alt die Vorfahren des Kontextknotens. Die Vorfahren bestehen aus dem Elternknoten des Kontextknotens, dessen Elternknoten usw. Sie enth¨alt somit immer den Wurzelknoten, es sei denn, der Kontextknoten selbst ist der Wurzelknoten. Die ancestor-or-self-Achse beinhaltet neben den Vorfahren noch den Kontextknoten selbst.

Abbildung 3.5: child-Achse

Abbildung 3.6: parent-Achse

22

Die Achse child enth¨alt die Kinder, die parent-Achse den Elternknoten des Kontextknotens. Ist der Kontextknoten die Wurzel, selektiert die parent-Achse keine Elemente.

Abbildung 3.7: descendant-Achse

Abbildung 3.8: descendant-or-self-Achse

Die Achse descendant beinhaltet die Nachkommen des Kontextknotens. Ein Nachkomme ist ein Kind oder ein Kind eines Kindes usw. Die descendant-or-self-Achse enth¨alt zus¨atzlich den Kontextknoten.

Abbildung 3.9: following-sibling-Achse

Abbildung 3.10: following-Achse

Die following-sibling-Achse umfasst alle nachfolgenden Geschwister des Kontextknotens. Ist der Kontextknoten ein Attribut- oder Namensraumknoten, ist diese Achse leer. Die following-Achse selektiert alle Knoten, die nach dem Kontextknoten in Dokumentordnung auftreten, und zwar ohne seine Nachkommen, Attribut- und Namensraumknoten.

Abbildung 3.11: preceding-sibling-Achse

Abbildung 3.12: preceding-Achse

Die Achse preceding-sibling enth¨alt alle vorhergehenden Geschwister des Kontextknotens. Die preceding-Achse umfasst alle Knoten, die vor dem Kontextknoten in Dokumentordnung auftreten, ohne seine Vorfahren, Attribut- und Namensraumknoten.

23

Abbildung 3.13: self-Achse Die Achse self beinhaltet nur den Kontextknoten selbst.

Die attribute- bzw. namespace-Achse selektiert die entsprechenden Knotentypen des Kontextknotens. Diese Achsen sind leer, es sei denn, der Kontextknoten ist ein Elementknoten.

Abbildung 3.14: Zusammenwirken der Achsen Die Achsen ancestor, descendant, following, preceding und self erreichen zusammen alle Knoten des Dokumentes9 und u ¨berschneiden sich dabei nicht. Das Datenmodell f¨ ur einen Lokalisierungspfad Ein Lokalisierungspfad l¨asst sich auf die folgende Weise in Haskell modellieren: data LocationPath = LocPath [XStep] XStep entspricht einem Lokalisierungsschritt. Jeder Konstruktor von XStep bildet eine der XPath-Achsen ab.10 Beispiel: (Datentyp f¨ ur eine Lokalisierungsschritt) data XStep = XAncestor NodeTest Predicates | XChild NodeTest Predicates | XParent NodeTest Predicates | XSelf NodeTest Predicates | .. 9 10

Attribut- und Namensraumknoten werden hierbei nicht betrachtet die Datentypen f¨ ur NodeTest und Predicates werden in den n¨ achsten Abschnitten entwickelt

24

Auch an dieser Stelle wird das Datenmodell durch einen Aufz¨ahlungstypen f¨ ur die Achsen vereinfacht (siehe Abschnitt: 3.3). Beispiel: (Abbildung eines Lokalisierungspfades) data LocationPath = LocPath [XStep] data XStep = Step AxisSpec NodeTest Predicates data AxisSpec = Ancestor | AncestorOrSelf | Attribute | Child | Descendant | DescendantOrSelf | Following | FollowingSibling | Namespace | Parent | Preceding | PrecedingSibling | Self

3.6.2 Knotentests Knotentests schr¨anken die durch eine Achse selektierten Knoten um einen bestimmten Typ (siehe Abschnitt: 3.1.1) ein. Erf¨ ullt ein Knoten den Test, wird er in die Resultatmenge aufgenommen. Jede Achse besitzt hierf¨ ur einen Hauptknotentyp. Der Hauptknotentyp f¨ ur die attribute-Achse ist der Attributtyp, f¨ ur die namespace-Achse der Namensraumtyp. Alle anderen Achsen haben den Elementtyp als Hauptknotentyp. XPath unterscheidet zwei Arten von Knotentests, den Namenstest und den Typtest. Namenstest Ein Namenstest ist f¨ ur einen Knoten erfolgreich, wenn der Knotentyp mit dem Hauptknotentyp der Achse u ¨bereinstimmt und sein Name dem Namenstest entspricht. Beispiel: (Ausw¨ahlen aller Kinder, die den Namen para besitzen) child::para Der Namenstest * ist f¨ ur alle Knoten des Hauptknotentyps, unabh¨angig von ihrem Namen, erf¨ ullt. attribute::* w¨ahlt alle Attribute eines Elementtyps, child::* entsprechend alle Kinder. Typtest Ein Typtest ist f¨ ur einen Knoten erfolgreich, wenn sein Knotentyp dem geforderten Typ entspricht. Der Test comment() selektiert alle Knoten des Typen Kommentar, text() alle Textknoten. Processing-Instruction-Knoten k¨onnen u ¨ber processing-instruction() ausgew¨ahlt werden. Bei PI-Knotentests ist noch die Angabe einer zus¨atzlichen Zeichenkette m¨oglich: child::processing-instruction(’xml-stylesheet’) In diesem Beispiel werden alle Kinder ausgew¨ahlt, die vom Typ Processing-Instruction sind und zus¨atzlich den Namen xml-stylesheet besitzen. Der Test node() erm¨oglicht es, jeden Knoten, unabh¨angig von seinem Typ, in die Resultatmenge aufzunehmen. Beispiel: (Modell f¨ ur einen Typtest) data XPathNode = XPNode | XPCommentNode | XPPINode | XPTextNode Der resultierende Datentyp f¨ ur einen Typtest enth¨alt vier Konstruktoren; sie entsprechen jeweils einem Test auf einen Knotentyp. Der Konstruktor XPPINode bildet einen

25

PI-Test, ohne die Angabe einer zus¨atzlichen Zeichenkette, ab. Um eine einheitliche Verarbeitung zu erreichen, wird ein PI-Knoten inklusive eines Namensvergleiches nicht mit in den Datentypen XPathNode aufgenommen. Bei der Auswertung von XPathNode soll nur auf den Typ, nicht aber auf den Namen getestet werden. Die beiden Knotentests, die einen Namensvergleich fordern, werden als eigenst¨andige Konstruktoren mit dem zu testenden Namen als Wert modelliert. F¨ ur den allgemeinen Knotentest ergibt sich der folgende Datentyp. Beispiel: (Allgemeiner Knotentest) type Name = String data NodeTest = NameTest Name | PI Name | TypeTest XPathNode

3.6.3 Pr¨ adikate Die durch eine Achse und einen Knotentest bestimmte Menge von Elementen kann durch eine Liste von Pr¨adikaten weiter gefiltert werden. Ein Pr¨adikat kann ein beliebiger XPathAusdruck sein, der auf eine Knotenmenge angewendet wird. Die Ergebnismenge des ersten Pr¨adikats ist Ausgangsmenge f¨ ur das zweite Pr¨adikat usw. Die Verarbeitung wird detailliert im Abschnitt 4.7.5 beschrieben.

3.6.4 Filter-Ausdr¨ ucke Die im vorherigen Abschnitt beschriebenen Pr¨adikate beziehen sich auf einen Lokalisierungsschritt und werden im Kontext der Achse ausgewertet. XPath erm¨oglicht auch, das Ergebnis eines gesamten Lokalisierungspfades durch ein Pr¨adikat zu filtern. Wird ein Pr¨adikat auf einen allgemeinen Ausdruck angewendet, der eine Knotenmenge liefert, so spricht man von einem Filter-Ausdruck. Ein Filter-Ausdruck kann eine Liste von beliebigen Ausdr¨ ucken sein. Beispiel: (Filter-Ausdruck mit 2 Pr¨adikaten) (preceding-sibling::image)[@type=’item’][42] Filter-Ausdr¨ ucke k¨onnen nur auf Knotenmengen angewendet werden, das Filtern einer Zeichenkette w¨ urde einen Fehler verursachen. Da das XPath-Modul eine strikte Trennung zwischen dem Parsen und der Verarbeitung macht, wird jeder syntaktisch korrekte Ausdruck durch den Parser erkannt. Das Identifizieren eines Fehlers erfolgt erst bei der Auswertung des Ausdruckes. Beispiel: (Filter-Ausdruck im Datentyp Expr) data Expr = FilterExpr [Expr] -- NodeSet ++ [predicate] | ...

3.6.5 Relative und absolute Lokalisierungspfade Es gibt zwei Arten von Lokalisierungspfaden, relative und absolute. Ein relativer Pfad ist, wie in den vorhergehenden Abs¨atzen beschrieben, eine Liste von Lokalisierungsschritten, die durch den Schr¨agstrich / getrennt sind. Ein absoluter Pfad beginnt mit einem Schr¨agstrich, gefolgt von einem relativen Lokalisierungspfad. Durch den einleitenden Schr¨agstrich wird die Auswertung des Pfades nicht am aktuellen Kontextknoten, sondern an der Wurzel begonnen. Beispiel: (relativer und absoluter Lokalisierungspfad) child::chapter/descendant::para (relativer Pfad) /child::item/child::text() (absoluter Pfad)

26

Im obigen Beispiel w¨ahlt der relative Pfad alle para-Elemente aus, die Nachkommen der chapter-Kindelemente des Kontextknotens sind. Der absolute Pfad selektiert alle Textknoten, die ein item-Vaterelement besitzen, das Kind der Dokumentenwurzel ist. Das Modell f¨ ur einen Lokalisierungspfad wird um die Art des Pfades erweitert. Beispiel: (Vollst¨andige Darstellung eines Lokalisierungspfades) data LocationPath = LocPath Path [XStep] data Path = Rel | Abs data XStep = Step AxisSpec NodeTest [Expr] Ein Lokalisierungspfad kann u ¨ber den Schr¨agstrich / bzw. den doppelten Schr¨agstrich // mit einem Ausdruck verbunden werden. So ist die Anwendung eines Lokalisierungspfades auf einen Filter-Ausdruck m¨oglich. Die Schr¨agstriche haben dieselbe Bedeutung wie bei Lokalisierungsschritten. Beispiel: (Verbinden eines Filter-Ausdruckes mit einem Lokalisierungspfad) (preceding-sibling::image)[@type=’item’][42]/parent::text() Allgemeiner Pfad Ein allgemeiner Pfad kann aus einem optionalen Ausdruck und einem optionalen Lokalisierungspfad bestehen. Einer der beiden Teile muss vorhanden sein, beide Teile k¨onnen vorhanden sein. Das Ergebnis eines allgemeinen Pfades ist immer eine Knotenmenge. Beispiel: (Darstellung eines allgemeinen Pfades) data Expr = PathExpr (Maybe Expr) (Maybe LocationPath) | ... Vereinigung von Knotenmengen Die durch einen allgemeinen Pfad ausgew¨ahlte Knotenmenge kann mit einer weiteren Knotenmenge durch den Operator | vereinigt werden. Er entspricht der mathematischen Mengenvereinigung. Der Vereinigungsoperator wird im Modell den boolschen und arithmetischen Operatoren (siehe Abschnitt 3.3) zugeordnet, da die Verarbeitung konzeptionell identisch ist.

3.6.6 Abk¨ urzungen Einige Elemente von Lokalisierungspfaden lassen sich durch Abk¨ urzungen beschreiben. Abk¨ urzung

Langform child::

.

self::node()

..

parent::node()

// @

/descendant-or-self::node()/ attribute::

Beschreibung die child-Achse kann weggelassen werden, sie entspricht der Standardachse von XPath der einfache Punkt ist ein Alias f¨ ur die selfAchse durch zwei Punkte l¨aßt sich die parent-Achse darstellen Abk¨ urzung der descendant-or-self-Achse Kurzform der attribute-Achse

Tabelle 3.4: XPath-Abk¨ urzungen

27

Das folgende Beispiel stellt die Verwendung aller Abk¨ urzungen dar. Der resultierende Lokalisierungspfad entspricht keinem sinnvollen XPath-Ausdruck. Beispiel: (Abgek¨ urzte Syntax in einem Lokalisierungspfad) item[@para=’elem’]//./../text() child::item[attribute::para=’elem’]/descandent-or-self::node() /self::node()/parent::node()/child::text() Parsen von Abk¨ urzungen Abk¨ urzungen k¨onnen beim Parsen prinzipiell auf zwei Arten verarbeitet werden. In der ersten Variante durchl¨auft ein zus¨atzlicher Parser den Ausdruck und ersetzt alle Abk¨ urzungen durch ihre Normalformen. Der eigentliche Parser arbeitet anschließend auf einer normalisierten Form des Ausdruckes. Bei der zweiten Version werden die Abk¨ urzungen direkt durch den Ausdrucksparser interpretiert und verarbeitet. Da XPath nur wenige einfache Abk¨ urzungsm¨oglichkeiten bietet, arbeitet der Haskell XML Toolbox Parser mit der zweiten Variante. Er bildet die Kurzformen direkt auf die entsprechenden Lokalisierungsschritte ab. Ein eigener Datentyp f¨ ur Abk¨ urzungen wird folglich nicht gebraucht. Beispiel: (Parser f¨ ur die parent- und self-Achse) abbrStep :: Parser XStep abbrStep = do tokenParser (symbol "..") return (Step Parent (TypeTest XPNode) []) <|> do tokenParser (symbol ".") return (Step Self (TypeTest XPNode) []) "abbrStep"

3.7 Darstellung eines geparsten Ausdruckes Jeder XPath-Ausdruck l¨asst sich durch das folgende Datenmodell modellieren. Beispiel: (Vollst¨andiges Datenmodell f¨ ur einen Ausdruck) data Expr = GenExpr Op [Expr] | PathExpr (Maybe Expr) (Maybe LocationPath) | FilterExpr [Expr] -- NodeSet ++ [predicate] | VarExpr VarName | LiteralExpr Literal | NumberExpr XPNumber | FctExpr FctName FctArguments Mit der Funktion expr2XPathTree aus dem Modul XPathToString ist es m¨oglich, einen geparsten Ausdruck als Baum darzustellen. Die Funktion konvertiert dabei das XPathDatenmodell f¨ ur einen Ausdruck (Expr) in das Modell f¨ ur einen allgemeinen Baum (NTree).

28

Beispiel: (Funktion expr2XPathTree) type XPathTree = NTree String expr2XPathTree expr2XPathTree expr2XPathTree expr2XPathTree expr2XPathTree expr2XPathTree

(GenExpr op ex) (NumberExpr f) (LiteralExpr s) (VarExpr name) (FctExpr n arg)

:: Expr = NTree = NTree = NTree = NTree = NTree

-> XPathTree (show op) (map expr2XPathTree ex) (show f) [] s [] ("Var: " ++ name) [] ("Fct: " ++ n) (map expr2XPathTree arg)

Alle weiteren Funktionen zur Formatierung des NTree-Baumes werden durch die Haskell XML Toolbox zur Verf¨ ugung gestellt. Beispiel: (Darstellung eines XPath-Ausdruckes als Baum) parent::text()[42] - round(’str’) - (/self::item)[$varName] ---Minus | +---RelLocationPath | | | +---Parent | | | +---TypeTest: text() | | | +---Predicates | | | +---42.0 | +---Fct: round | | | +---str | +---FilterExpr | +---AbsLocationPath | | | +---Self | | | +---NameTest: "item" | +---Predicates | +---Var: varName

29

4 Auswertung eines Ausdruckes Dieses Kapitel beschreibt, wie ein, durch die im vorherigen Kapitel dargelegten Techniken, geparster Ausdruck ausgewertet wird. Das Ergebnis der Auswertung ist ein XPath-Objekt. XPath definiert vier Grundtypen, die bei jeder Implementierung enthalten sein m¨ ussen. Auf 1 XPath aufbauende Spezifikationen k¨ onnen weitere Objekttypen definieren, um das Ergebnis eines XPath-Ausdruckes ihrem Arbeitskontext anzupassen. Ergebnistyp node-set boolean number string

Beschreibung eine Knotenmenge ohne Duplikate ein Wahrheitswert (wahr oder falsch) eine Gleitkommazahl nach IEEE 754 eine Zeichenkette bestehend aus UCS-Zeichen

Name im Modell XPVNode NodeSet XPVBool Bool XPVNumber XPNumber XPVString String

Tabelle 4.1: Ergebnis-Grundtypen einer Auswertung Es existiert innerhalb von XPath kein Objekt, das einen Knoten repr¨asentiert. Ein einzelner Knoten kann aber als Knotenmenge (node-set) mit nur einem Element verstanden werden. Eine Knotenmenge wird durch eine Liste von navigierbaren B¨aumen (siehe Abschnitt 4.7.1) dargestellt. Beispiel: (Typdefinition f¨ ur eine Knotenmenge) type NavXmlTrees = [NavXmlTree] type NodeSet = NavXmlTrees Die Objekte f¨ ur Zahlen (number) und Zeichenketten (string) entsprechen den Typen, die im Kapitel 3.4 beschrieben wurden. Die Haskell XML Toolbox Implementation von XPath erweitert die Grundtypen um einen Typ f¨ ur den Fehlerfall. Beispiel: (Ergebnistypen der Haskell XML Toolbox) data XPathValue = XPVNode NodeSet | XPVBool Bool | XPVNumber XPNumber | XPVString String | XPVError String Der Wert des Typkonstruktors XPVError wird verwendet, um detaillierte Fehlermeldungen an den Nutzer der Haskell XML Toolbox zu u ¨bermitteln. Einerseits werden dabei Fehler abgedeckt, die aus einer falschen Eingabe des Benutzers resultieren. Andererseits dient XPVError auch dazu, bei internen, nicht durch den Nutzer verursachten Fehlern, den Ablauf mit einer sinnvollen Fehlermeldung zu beenden. 1

Die XSLT-1.0-Spezifikation enth¨ alt beispielsweise den neuen Typ Ergebnisteilbaum (result tree fragment)

30

Beispiel: (ein durch den Nutzer verursachter Fehler) evalFct :: FctName -> Env -> Context -> [XPathValue] -> XPathValue evalFct name env cont args = case (lookup name fctTable) of Nothing -> XPVError ("Call to undefined function: "++ name) Just (fct, checkArgCount) -> ... Die Haskell XML Toolbox findet im obigen Beispiel eine durch den Anwender angegebene Funktion nicht und beendet die Verarbeitung des Ausdruckes mit der entsprechenden Fehlermeldung. Beispiel: (ein interner Fehler der Haskell XML Toolbox) xround’ :: XFct xround’ _ _ [XPVNumber (Float f)] = ... xround’ _ _ [XPVNumber a] = XPVNumber a xround’ _ _ _ = XPVError "Call to xround’ without a number" Die Funktion xround’ wurde mit einem falschen Argument aufgerufen. Dieser Fehler kann nicht aus einer falschen Eingabe des Anwenders resultieren, da Argumente automatisch in den richtigen Typ konvertiert werden. Eine sinnvolle Fortf¨ uhrung des Programms ist nach der fehlgeschlagenen Konvertierung allerdings nicht mehr m¨oglich, so dass die Haskell XML Toolbox an dieser Stelle mit einer Fehlermeldung abbricht.

4.1 Kontext Ein Ausdruck wird in XPath innerhalb eines Kontextes berechnet. Die Auswertungsumgebung besteht dabei aus den folgenden Elementen: - einem Knoten (dem Kontextknoten) - einem Paar von positiven ganzen Zahlen ungleich null (der Kontextposition und der Kontextgr¨oße) - einer Menge von Variablenbelegungen - einer Funktionsbibliothek - der Namensraumdeklaration, in deren G¨ ultigkeitsbereich der Ausdruck liegt Der Kontextknoten ist der aktuell zu verarbeitende Knoten. Die Kontextgr¨oße entspricht der Anzahl aller zu verarbeitenden Elemente. Die Kontextposition stellt die Position des Kontextknotens in der Liste der gesamten Knoten dar und ist somit immer kleiner oder gleich der Kontextgr¨oße. Die Werte dieser Parameter ver¨andern sich bei der Verarbeitung eines Ausdruckes entsprechend des aktuellen Verarbeitungsabschnittes. Es gibt mehrere Arten von Ausdr¨ ucken, die den Kontextknoten ¨andern k¨onnen. Die Kontextposition und die Kontextgr¨oße werden allerdings nur durch Pr¨adikate (siehe Abschnitt: 4.7.5) ver¨andert. Die Variablenbelegung, die Funktionsbibliothek und die Namensraumdeklaration ¨andern sich hingegen, w¨ahrend der Berechnung eines Teilausdruckes, nicht. Es handelt sich bei ihnen um Parameter, die dem XPath-Auswertungsmechanismus von außen2 mitgeteilt werden. Im Modell der Haskell XML Toolbox werden sie daher nicht direkt dem Datentyp Context zugeordnet, sondern durch eigenst¨andige Datentypen repr¨asentiert. 2

beispielsweise Variablen, die in einem Stylesheet eines XSLT-Prozessors definiert sind

31

Beispiel: (Datentyp f¨ ur den Kontext eines Ausdruckes) type Context = (ConPos, ConLen, ConNode) type ConPos = Int type ConLen = Int type ConNode = NavXmlTree

4.1.1 Variablen Einem Variablennamen wird ein Variablenwert zugeordnet. Als Wert ist neben den vier Grundtypen jedes Objekt m¨oglich, das Resultat eines Ausdruckes sein kann. Im Datenmodell entspricht eine Variable einem Tupel bestehend aus Name und Wert. Beispiel: (Datentyp f¨ ur Variablen und einige Variablendeklarationen) type VarName = String type Env = [(VarName, XPathValue)] varEnv varEnv

:: Env = [ ("numberStr", XPVString "3.4") , ("five", XPVNumber (Float 5)) , ("inf", XPVNumber PosInf) , ("true", XPVBool True) , ("nodeSet", XPVNode aNodeSet) ] Alle Variablen des Kontextes werden u ¨ber den Datentyp Env zusammengefasst. Wird, w¨ahrend der Auswertung eines Ausdruckes, eine Variable referenziert, sucht die Funktion getVariable den passenden Namen in der Umgebung und liefert den entsprechenden Wert zur¨ uck. Durch den Parser werden alle syntaktisch korrekten Variablennamen erkannt. Es ist jedoch m¨ oglich, dass eine referenzierte Variable nicht in der Umgebung existiert. In diesem Fall wird das Programm mit einer Fehlermeldung beendet. Beispiel: (Abbruch des Programmes mit einer Fehlermeldung) getVariable :: VarName -> XPathValue getVariable name = case lookup name varEnv of Nothing -> XPVError ("Variable: " ++ name ++ " not found") Just v -> v Das Definieren von Variablen ist Aufgabe des XPath nutzenden Prozessors. Innerhalb von XPath k¨onnen Variablen nur verwendet, aber nicht erzeugt werden.

4.1.2 Funktionsbibliothek XPath spezifiziert, neben den Grundtypen f¨ ur das Ergebnis eines Ausdruckes, eine Reihe von Funktionen, die bei jeder Implementierung enthalten sein m¨ ussen. Diese Bibliothek der Grundfunktionen besteht aus der Abbildung eines Funktionsnamens auf eine Funktion. Die m¨oglichen Argumente sowie das Ergebnis einer Grundfunktion, geh¨oren den vier Grundtypen an. XPath nutzende Spezifikationen k¨onnen zus¨atzliche Funktionen definieren, die auf weiteren Typen operieren. Die Schnittstellenbeschreibung, die in den folgenden Abschnitten f¨ ur die Funktionen verwendet wird, entspricht der XPath-Spezifikation. Das Fragezeichen ? kennzeichnet hierbei ein optionales Argument. Ein Argument mit dem Stern * darf keinmal, einmal oder mehrmals auftreten. Der Argumenttyp object steht f¨ ur einen beliebigen Typ.

32

Hinweis:

Die Funktionen werden der Vollst¨andigkeit halber an dieser Stelle aufgef¨ uhrt, wobei nicht alle zu beachtenden Sonderf¨alle angesprochen werden. Weiterf¨ uhrende Informationen sind in der XPath-Spezifikation [W3C 99] nachzulesen.

Funktionen auf Knotenmengen - number last() Die Funktion last gibt die Kontextgr¨oße des Auswertungskontextes zur¨ uck. - number position() Die Funktion position liefert die aktuelle Kontextposition des Auswertungskontextes. - number count(node-set) Die Funktion count berechnet die Anzahl der Elemente einer Knotenmenge. - node-set id(object) Die Funktion id liefert eine Knotenmenge, die aus den Elementen besteht, deren ID mit dem Wert aus object u ¨bereinstimmt. - string local-name(node-set?) Die Funktion local-name liefert den lokalen Namen des Knotens, der in der Knotenmenge an erster Position steht. Ist das Argument nicht vorhanden, wird der lokale Name des Kontextknotens zur¨ uckgegeben. - string namespace-uri(node-set?) Die Funktion namespace-uri gibt den Namespace-URI des expandierten Namens des ersten Knotens in der Knotenmenge zur¨ uck. Wird das Argument weggelassen, so wird der Kontextknoten verwendet. - string name(node-set?) Die Funktion name ermittelt den qualifizierten Namen des ersten Knotens der Knotenmenge. Ist das Argument nicht vorhanden, wird der Kontextknoten verwendet. Zeichenkettenfunktionen - string string(object) Die Funktion string berechnet den Zeichenkettenwert eines Objektes. - string concat(string s1, string s2, string sn*) Die Funktion concat verkn¨ upft ihre Argumente. - boolean starts-with(string s1, string s2) Die Funktion starts-with liefert den Wert wahr, wenn die Zeichenkette s1 mit der Zeichenkette s2 beginnt. - boolean contains(string s1, string s2) Die Funktion contains liefert den Wert wahr, wenn die Zeichenkette s1 die Zeichenkette s2 an einer beliebigen Position enth¨alt. - string substring-before(string s1, string s2) Die Funktion substring-before berechnet die Zeichenkette von s1 vor dem ersten Auftreten von s2 innerhalb von s1. Ist s2 nicht in s1 enthalten, wird die leere Zeichenkette geliefert. - string substring-after(string s1, string s2) Die Funktion substring-after liefert die Zeichenkette von s1 nach dem ersten Auftreten von s2 innerhalb von s1. Ist s2 nicht in s1 enthalten, wird die leere Zeichenkette geliefert.

33

- string substring(string s1, number p, number n?) Die Funktion substring liefert die Teil-Zeichenkette von s1 ab der Position p3 , und zwar n Zeichen lang oder alle Zeichen ab der Position p, wenn n nicht angegeben wurde. - number string-length(string s1?) Die Funktion string-length ermittelt die L¨ange der Zeichenkette s1. Ist kein Argument angegeben, wird der Zeichenkettenwert des Kontextknotens verwendet. - string translate(string s1, string s2, string s3) Die Funktion translate ersetzt alle Zeichen in s1, die in s2 vorkommen, durch das Zeichen aus s3, das an der Stelle des Zeichens in s2 steht. Gibt es kein Zeichen in s3 an der Stelle des Zeichens in s2, wird das betrachtete Zeichen in s1 entfernt. Boolsche Funktionen - boolean boolean(object) Die Funktion boolean konvertiert ihr Argument in einen Wahrheitswert. - boolean not(boolean b) Die Funktion not negiert b. - boolean true() Die Funktion true liefert immer den Wert wahr. - boolean false() Die Funktion false liefert immer den Wert falsch. - boolean lang(string lng) Die Funktion lang gibt den Wert wahr zur¨ uck, wenn sich der Kontextknoten innerhalb der Sprache lng befindet. Numerische Funktionen - number number(object?) Die Funktion number konvertiert ihr Argument in eine Zahl. - number sum(node-set) Die Funktion sum berechnet die Summe der Zahlenwerte aller Knoten in der Knotenmenge. Dabei wird jeder Knoten durch die number-Funktion in eine Zahl konvertiert. - number ceiling(number) Die Funktion ceiling liefert die kleinste Zahl, die nicht kleiner als das Argument und eine ganze Zahl ist. - number floor(number) Die Funktion floor liefert die gr¨oßte Zahl, die nicht gr¨oßter als das Argument und eine ganze Zahl ist. - number round(number) Die Funktion round rundet ihr Argument zur n¨achsten ganzen Zahl.

4.1.3 Funktionsverarbeitung Der erste Ansatz f¨ ur das Auswerten einer Funktion fctEval besteht darin, u ¨ber das Pattern Matching die richtige Funktion zu einem geparsten Namen zu w¨ahlen. Ist die Funktion vorhanden, wird der Funktionsrumpf ausgewertet und das Ergebnis zur¨ uckgegeben. Kann 3

die Z¨ ahlung der Zeichen beginnt bei eins

34

eine Funktion nicht in der Bibliothek gefunden werden, bricht das Programm mit einer Fehlermeldung ab. Beispiel: (Erster Ansatz f¨ ur die Funktionsverarbeitung) fctEval :: String -> [Expr] -> XPathValue fctEval "number" args = ... fctEval "round" args = ... ... fctEval f _ = XPVError ("Call to unknown function: " ++ f) Dieser Ansatz l¨asst die Erweiterung der Bibliothek um zus¨atzliche Funktionen allerdings nur schwerlich zu. Die Zuordnung eines Namens zu einer Funktion wird nicht zentral verwaltet. Der Einsatz einer Funktionstabelle behebt dieses Problem und erlaubt das einfache Hinzuf¨ ugen von Funktionen. Beispiel: (Datenmodell der Funktionstabelle) type XFct = (Context -> Env -> [XPathValue] -> XPathValue) type FctName = String type FctTable = [(FctName, XFct)] fctTable :: FctTable fctTable = [ ("number", xnumber) , ("round", xround) , ... ] Alle Funktionen besitzen in der Implementation der Haskell XML Toolbox die einheitliche Typdefinition XFct. Spezifikationen, die die Menge der Grundfunktionen erweitern wollen, m¨ ussen ebenfalls dieser Schnittstelle gen¨ ugen. Jede Funktion kann null oder mehr Argumente vom Typ XPathValue besitzen. Die Anzahl, der im Ausdruck u ¨bergebenen Argumente, muss mit der, durch die Funktion geforderten Anzahl, korrespondieren. Ist dies nicht der Fall, handelt es sich um einen Fehler. Das Datenmodell wird hierf¨ ur um die Typen CheckArgCount erweitert. Beispiel: (Datenmodell f¨ ur das Pr¨ ufen der Argumentanzahl) type CheckArgCount = ([XPathValue] -> Bool) zero, zeroOrOne, one :: CheckArgCount zero ex = length ex == 0 zeroOrOne ex = length ex == 0 || length ex == 1 one ex = length ex == 1 type FctTableElem = (XFct, CheckArgCount) type FctTable = [(FctName, FctTableElem)] fctTable = [ ("number", (xnumber, zeroOrOne)) , ("round", (xround, one)) , ... ] Zu jedem Funktionsnamen wird jetzt neben der Funktion auch die Anzahl der erwarteten Argumente gespeichert. Der Wert einer Funktion wird bestimmt, indem erst alle Werte der Argumente berechnet und diese in den erwarteten Typ konvertiert werden. Anschließend erfolgt die Auswertung des Funktionsrumpfes. Die Konvertierung eines Argumentes in den Typ string erfolgt u ¨ber den Aufruf der Funktion string. Die Funktionen number bzw. boolean erzeugen die entsprechenden Typen. Ein Argument kann nicht in den Typ node-set konvertiert werden. Erwartet eine Funktion eine Knotenmenge, muss das Argument von diesem Typ sein. Anderenfalls wird die Auswertung mit einer Fehlermeldung abgebrochen.

35

Beispiel: (Konvertierung der Argumente einer Funktion) -- Funktion: string concat(string, string, string*) xconcat :: XFct xconcat c e args = XPVString (foldr (\(XPVString s) ->(s++)) [] (toXValue xstring c e args)) Die Funktion concat erwartet zwei oder mehr Argumente vom Typ string. Die Argumente werden erst u ¨ber den Aufruf von toXValue xstring in den ben¨otigten Typ konvertiert. Im Anschluss erfolgt die Berechnung des Ergebnisses und die R¨ uckgabe als XPVString. id-Funktion Die id-Funktion ben¨otigt f¨ ur die Auswertung Informationen der DTD. Dies ist einer der wenigen F¨alle, in denen das Ergebnis eines XPath-Ausdruckes von der Kenntnis der DTD des Dokumentes abh¨angt. Die Funktion getIdAttr extrahiert die ben¨otigten Informationen vor der Reduzierung des XML-Baumes um die DTD. Sie liefert eine durch Leerzeichen getrennte Zeichenkette, die alle ID-Attribute der DTD enth¨alt. Die Zeichenkette wird unter dem Variablennamen idAttr in der Liste der Variablen gespeichert. Die id-Funktion referenziert bei der Auswertung die ben¨otigte Variable. Beispiel: (Extrahieren der ID-Attribute aus der Variablenumgebung) getIds :: Env -> [String] getIds env = words $ (\ (XPVString str) -> str) . fromJust $ lookup "idAttr" env

4.1.4 Namensraumdeklaration Das letzte ben¨otigte Element f¨ ur den Kontext eines Ausdruckes ist die Namensraumdeklaration. Namensr¨aume werden von der Haskell XML Toolbox in der aktuellen Version jedoch nicht unterst¨ utzt, so dass auch innerhalb von XPath nicht mit ihnen gearbeitet werden kann. Alle Funktionen und Module, die auf Namensr¨aume zugreifen, sind aber f¨ ur die Verwendung vorbereitet und entsprechend gekennzeichnet. Sobald die Haskell XML Toolbox Namensr¨ aume unterst¨ utzt, ist auch der Einsatz im XPath-Modul m¨oglich. Beispiel: (Vorbereitung des XPath-Moduls f¨ ur Namensr¨aume) -- | -- evaluate a single XPath step -- namespace-axis is not supported evalStep :: Env -> XPathValue -> XStep -> XPathValue evalStep _ _ (Step Namespace _ _) = XPVError "namespace-axis not supported" evalStep env ns (Step axisSpec nt pr) = evalStep’ env pr nt (getAxisNodes axisSpec ns)

4.2 XPathFilter Alle Funktionen, die einen Teilausdruck berechnen, sind als XPathFilter implementiert. Der Einsatz von Filtern bildet die Grundlage f¨ ur die Verarbeitung von XML-Dokumenten (XmlFilter) in der Haskell XML Toolbox und wurde f¨ ur das XPath-Modul u ¨bernommen. Da, im Gegensatz zur Verarbeitung von XML, als Ergebnis eines XPath-Ausdruckes nicht nur Knotenmengen m¨oglich sind, war der Ansatz type XPathFilter = NodeSet -> NodeSet nicht ausreichend.

36

Ein XPathFilter muss jeden Ergebnistyp von XPath verarbeiten k¨onnen: type XPathFilter = XPathValue -> XPathValue Der Typ XPathValue erlaubt die Konversion zwischen beliebigen Ergebnistypen, beispielsweise die Umwandlung einer Knotenmenge in eine Zeichenkette. Er enth¨alt alle m¨oglichen Resultattypen eines Teilausdruckes. Funktionen, die einen Teilausdruck berechnen, k¨onnen somit u ¨ber die Funktionskomposition verkettet werden. Dies erm¨oglicht vor allem im Bereich der Auswertung von Lokalisierungspfaden (siehe Abschnitt 4.7) eine sehr kompakte Implementation von Knotentests und Pr¨adikaten. evalExpr Die Funktion evalExpr ist der zentrale XPathFilter. evalExpr :: Env -> Context -> Expr -> XPathFilter Sie enth¨alt neben den notwendigen Umgebungsinformationen Env und Context den aktuell zu verarbeitenden Teilausdruck Expr. Durch das Pattern Matching werden die unterschiedlichen Teilausdr¨ ucke (GenExpr, FctExpr, usw.) den entsprechenden Verarbeitungsfunktionen zugeordnet. Beispiel: (Ausschnitt aus der Funktion evalExpr) evalExpr env cont (GenExpr Or ex) = boolEval env cont Or ex evalExpr env cont (GenExpr And ex) = boolEval env cont And ex ... evalExpr env cont (FctExpr name args) = fctEval env cont name args Die folgende Tabelle stellt alle Teilausdr¨ ucke von XPath dar. Ihnen wird der entsprechende Datentyp des Modells f¨ ur einen Ausdruck sowie die f¨ ur die Auswertung verantwortliche Funktion zugeordnet. Ausdrucksart boolscher Ausdruck relationaler Ausdruck un¨arer Ausdruck numerischer Ausdruck Mengenvereinigung Funktion Lokalisierungspfad Filter-Ausdruck spezielle Ausdr¨ ucke

Typkonstruktor von Expr GenExpr mit den Operatoren Or, And GenExpr mit den Operatoren NEq, Eq, Less, LessEq, Greater, GreaterEq GenExpr mit dem Operator Unary GenExpr mit den Operatoren Plus, Minus, Div, Mod, Mult GenExpr mit dem Operator Union FctExpr PathExpr FilterExpr NumberExpr, LiteralExpr, VarExpr

Verarbeitende Funktion boolEval relEqEval xPathUnary numEval unionEval fctEval locPathEval filterEval evalSpezExpr

Tabelle 4.2: Auswertungsfunktionen f¨ ur Teilausdr¨ ucke Die speziellen Ausdr¨ ucke transformieren keinen Eingabewert in einen Ausgabewert. Sie liefern lediglich einen XPathValue zur¨ uck. Aus Gr¨ unden der einheitlichen Verarbeitung werden aber auch die speziellen Ausdr¨ ucke als XPathFilter implementiert.

37

Beispiel: (Ausschnitt aus der Funktion evalSpezExpr) evalSpezExpr :: Expr -> XPathFilter evalSpezExpr (LiteralExpr s) _ = XPVString s ... Die n¨achsten Abschnitte beschreiben, wie die unterschiedlichen Teilausdr¨ ucke durch die Haskell XML Toolbox ausgewertet werden und welche Bedingungen der XPath-Spezifikation dabei zu ber¨ ucksichtigen sind.

4.3 Boolsche Ausdr¨ ucke Analog zur Strategie von funktionalen Programmiersprachen wird ein boolscher Ausdruck auch in XPath nicht strikt ausgewertet. Beispiel: (Auswertung eines Oder-Ausdruckes) boolEval :: Env -> Context -> Op -> [Expr] -> XPathFilter ... boolEval env cont Or (x:xs) ns = case xboolean cont env [evalExpr env cont x ns] of [email protected](XPVError _) -> e XPVBool True -> XPVBool True _ -> boolEval env cont Or xs ns Wenn das Argument x u ¨ber die Funktion evalExpr zu dem Wert wahr ausgewertet wird, oder zu einem Fehler f¨ uhrt, steht das Ergebnis des Oder-Ausdruckes fest und die Berechnung wird beendet. Es treten keine Seiteneffekte bei der Berechnung auf.

4.4 Numerische Ausdr¨ ucke Die Berechnung eines numerischen Ausdruckes erfolgt nach den Regeln des IEEE 754 [IEEE 00] f¨ ur die Operatoren Plus, Minus, Div und Mult. Der Mod-Operator berechnet nicht dasselbe wie die IEEE Rest-Operation, er verh¨alt sich wie der Operator % in Java. Alle numerischen Berechnungen werden in XPath mit Fließkommawerten ausgef¨ uhrt; es gibt keine Ganzzahl-Arithmetik. Die im IEEE definierten speziellen Werte4 sind durch das Sprachkonzept von Haskell nicht direkt abbildbar. Der Ausdruck 1 div 0 ergibt in XPath positiv Unendlich. Haskell w¨ urde diese Berechnung mit einem Programmfehler abbrechen. Aus diesem Grund war es notwendig, alle m¨oglichen Kombinationen der speziellen Werte durch das Pattern Matching abzudecken. Beispiel: (Ausschnitt aus der Funktion xPathMulti) xPathMulti _ (XPVNumber (Float a)) (XPVNumber (Float b)) = XPVNumber (Float (a * b)) xPathMulti _ (XPVNumber NegInf) (XPVNumber (Float a)) | a < 0 = XPVNumber PosInf | otherwise = XPVNumber NegInf xPathMulti _ (XPVNumber PosInf) (XPVNumber (Float a)) | a < 0 = XPVNumber NegInf | otherwise = XPVNumber PosInf ... xPathMulti a b c = xPathSpez a b c 4

Pos0, Neg0, PosInf, NegInf, NaN

38

Um die Anzahl der zu beachtenden Kombinationen m¨oglichst gering zu halten, wurden identische F¨alle der verschiedenen Operatoren zusammengefasst. Dies ist allerdings nur f¨ ur den Fehlerfall und das Ergebnis NaN m¨oglich. Alle anderen Kombinationen lassen sich nicht sinnvoll zusammenfassen, da die Ergebnisse der Operatoren zu unterschiedlich sind. Beispiel: (Zusammenfassen gleicher Kombinationen) xPathSpez _ (XPVError e) _ = XPVError e xPathSpez _ _ (XPVError e) = XPVError e xPathSpez _ _ _ = XPVNumber NaN

4.5 Un¨ arer Ausdruck Das un¨are Minus negiert sein Argument. Der spezielle Wert NaN kann nicht negiert werden und wird unver¨andert zur¨ uckgeliefert. Alle anderen Werte sind berechenbar. Beispiel: (Ausschnitt aus der Funktion xPathUnary :: XPathFilter xPathUnary (XPVNumber (Float f)) xPathUnary (XPVNumber Pos0) ... xPathUnary (XPVNumber NaN)

xPathUnary) = XPVNumber (Float (-f)) = XPVNumber Neg0 = XPVNumber NaN

4.6 Relationale Ausdr¨ ucke Bei relationalen Ausdr¨ ucken werden drei Vergleiche unterschieden: 1. Vergleiche zwischen zwei Knotenmengen 2. Vergleiche zwischen einer Knotenmenge und einem beliebigen Typ 3. Vergleiche, an denen keine Knotenmenge beteiligt ist

4.6.1 Knotenmengen Vergleiche Zwei Knotenmengen Der Vergleich zweier Knotenmengen erfolgt u ¨ber den Vergleich der Zeichenkettenwerte (siehe Abschnitt 3.1.1) der beteiligten Knoten. Er liefert den Wert wahr, wenn mindestens ein Knoten in der ersten Knotenmenge existiert, f¨ ur den der Vergleich mit einem Knoten der zweiten Menge den Wert wahr ergibt. Dieses Verhalten gilt f¨ ur alle Operatoren5 . Eine Knotenmenge Der Vergleich einer Knotenmenge mit einer Zeichenkette Z1 ist erfolgreich, wenn ein Knoten in der Menge existiert, f¨ ur den der Vergleich seines Zeichenkettenwerts mit Z1 wahr ergibt. Wird eine Knotenmenge mit einer Zahl verglichen, wird der Zeichenkettenwert der Knoten u ¨ber die Funktion number in einen numerischen Wert konvertiert und anschließend verglichen. Ein boolscher Wert wird identisch behandelt. Die Konvertierung erfolgt u ¨ber die Funktion boolean. 5

Eq, NEq, Less, LessEq, Greater, GreaterEq

39

Keine Knotenmenge Ist keine Knotenmenge und als Operator entweder Eq oder NEq beteiligt, werden die beiden Teilausdr¨ ucke vor dem Vergleich in einen gemeinsamen Typ konvertiert. Liefert dabei wenigstens einer der Teilausdr¨ ucke einen boolschen Wert, wird das Ergebnis des anderen Ausdruckes, u ¨ber die Funktion boolean, in den boolschen Typ umgewandelt. Ist einer der Teilausdr¨ ucke vom Typ number, erfolgt der Vergleich u ¨ber number. In allen anderen F¨allen werden beide Teilausdr¨ ucke in Zeichenketten konvertiert. F¨ ur die Anwendung der Operatoren Less, LessEq, Greater oder GreaterEq werden beide Teilausdr¨ ucke in Zahlen umgewandelt und numerisch verglichen.

4.6.2 Numerische Vergleiche Um zwei Werte des Datentypen XPNumber numerisch vergleichen zu k¨onnen, ist es notwendig, den Datentyp als Instanz der Klassen Eq und Ord zu definieren. Innerhalb der Instanz-Deklaration wird beschrieben, wie sich die speziellen Werte des IEEE zu den normalen Fließkommazahlen verhalten. Der Wert negativ Unendlich ist kleiner, positiv Unendlich gr¨oßer als jede Fließkommazahl. Der Gleichheitstest f¨ ur die Werte positiv und negativ Null ergibt den Wert wahr. NaN l¨asst sich mit keiner Zahl vergleichen, das Ergebnis des Tests ist immer falsch. Beispiel: (Ausschnitt aus der Definition von Eq und Ord) instance Eq XPNumber where ... Neg0 == Neg0 = True Float f == Float g = f == g PosInf == PosInf = True _ == _ = False -- NaN is always false instance Ord XPNumber where a <= b a >= b a > b NaN < _ ... Float f < Float g _ < PosInf

= (a < b) || (a == b) = (a > b) || (a == b) = b < a = False = f < g = True

4.7 Lokalisierungspfade F¨ ur die Auswertung von Lokalisierungspfaden ist es notwendig, innerhalb des XML-Baumes frei navigieren zu k¨onnen. Die Berechnung der child-Achse ben¨otigt eine Abw¨artsbewegung im Baum. Die following-sibling- bzw. preceding-sibling-Achse ist eine Seitw¨artsbewegung auf derselben Ebene. Eine Aufw¨artsbewegung ist schließlich f¨ ur die parent- oder ancestor-Achse erforderlich. Das Datenmodell der Haskell XML Toolbox erlaubt aber lediglich, den Baum abw¨arts zu traversieren. Eine Aufw¨artsbewegung ist nicht m¨oglich.

40

4.7.1 Navigierbare B¨ aume [English 02] Das von Joe English im Rahmen von HXML6 entwickelte Modul navigable trees stellt die ben¨otigte Funktionalit¨at zur Verf¨ ugung. Es basiert auf dem Datentyp NavTree a, welcher das gesamte XML-Dokument im Speicher h¨alt. Beispiel: (Datentyp f¨ ur navigierbare B¨aume) data NavTree a = NT (NTree a) -- self [NavTree a] -- ancestors [NTree a] -- previous siblings (in reverse order) [NTree a] -- following siblings ¨ Uber die Funktionen upNT, downNT, leftNT, rightNT :: NavTree a -> Maybe (NavTree a) ist es m¨oglich, sich durch den Baum zu bewegen. Zus¨atzlich definiert das Modul Funktionen, die die Knoten einer XPath-Achse berechnen. Es werden alle Achsen, mit Ausnahme der attribute- und namespace-Achsen, unterst¨ utzt. Beispiel: (unterst¨ utzte XPath-Achsen im Modul navigable trees) ancestorAxis, ancestorOrSelfAxis, childAxis, descendantAxis, descendantOrSelfAxis, followingAxis, followingSiblingAxis, parentAxis, precedingAxis, precedingSiblingAxis, selfAxis :: NavTree a -> [NavTree a] Attribute-Achse Das Verhalten der attribute-Achse ist implementationsabh¨angig und wird nicht exakt von XPath spezifiziert. Attribute sind in der Haskell XML Toolbox u ¨ber die Kindknoten an einen XTag gebunden. Der Attributname ist der Wert des Typen XAttr. Der Attributwert wird als XText Knoten in den Kindern von XAttr gespeichert. Beispiel: (Datentyp f¨ ur Attribute in der Haskell XML Toolbox) type AttrName = String data XNode = ... | XTag TagName XmlTrees -- tag with list of attributes -- (inner node or leaf) | XAttr AttrName -- attribute, attribute value -- is stored in children Der allgemeine Typ NavTree a -> [NavTree a], der im Modul navigable trees f¨ ur die Achsen verwendet wird, kann nicht f¨ ur die Definition der attribute-Achse genutzt werden. Um an die Attribut-Liste eines XTag zu kommen, ist es notwendig, den Typ XNode, anstatt des polymorphen Typen a, zu verwenden. Beispiel: (Definiton der attribute-Achse) attributeAxis :: NavTree XNode -> [NavTree XNode] attributeAxis [email protected](NT (NTree (XTag _ al) _) a _ _) = foldr (\ attr -> ((NT attr (t:a) [] []):)) [] al attributeAxis _ = [] Die namespace-Achse wird noch nicht durch die Haskell XML Toolbox unterst¨ utzt (siehe Abschnitt: 4.1.4). 6

ein in Haskell geschriebener, nicht validierender XML-Parser

41

Konvertieren eines Baumes Der Parser der Haskell XML Toolbox liefert das zu verarbeitende XML-Dokument als Baum vom Typ NTree. Vor der Auswertung eines XPath-Ausdruckes muss der XMLTree in einen navigierbaren Baum u uhrt werden. Dies erfolgt u ¨berf¨ ¨ber die Funktion ntree, die ebenfalls vom Modul navigable trees bereitgestellt wird. Die Funktion subtree konvertiert den navigierbaren Baum wieder in einen XMLTree.

4.7.2 Relativer und absoluter Pfad Die Auswertung eines relativen Pfades beginnt am aktuellen Kontextknoten. F¨ ur einen absoluten Lokalisierungspfad muss die Dokumentenwurzel berechnet werden, da die Auswertung eines absoluten Pfades immer von der Wurzel aus erfolgt. Beispiel: (Auswertung eines Lokalisierungspfades) locPathEval :: Env -> LocationPath -> XPathFilter locPathEval env (LocPath Abs steps) = evalSteps env steps . getRoot locPathEval env (LocPath Rel steps) = evalSteps env steps Die Dokumentenwurzel wird u ¨ber die Funktion getRoot berechnet. Sie traversiert innerhalb des Baumes aufw¨arts, bis die Wurzel erreicht ist. Beispiel: (Berechnung der Dokumentenwurzel) getRoot :: XPathFilter getRoot (XPVNode (n:_)) = XPVNode [getRoot’ n] where getRoot’ tree = case upNT tree of Nothing -> tree Just t -> getRoot’ t

4.7.3 Lokalisierungsschritte Ein Lokalisierungspfad besteht aus einer Liste von Lokalisierungsschritten (XStep), die nacheinander verarbeitet werden. Jeder Schritt berechnet u ¨ber eine Achse eine Knotenmenge, die die Ausgangsmenge f¨ ur den n¨achsten Schritt darstellt. Beispiel: (Bestimmen der XPath-Achse) evalStep :: XStep -> XPathFilter evalStep (Step Child nt pred) = evalStep’ nt pred . getAxis childAxis evalStep (Step Parent nt pred) = evalStep’ nt pred . getAxis parentAxis ... Dieser Ansatz f¨ uhrt zu einer Codeverdoppelung, da jede Achse u ¨ber das Pattern Matching definiert sein muss. Der zweite Ansatz nutzt eine Tabelle, um eine Zuordnung zwischen einer Achse und der entsprechenden Achsenfunktion herzustellen.

42

Beispiel: (Bestimmen der XPath-Achse u ¨ber eine Tabelle) axisFctL :: [ (AxisSpec, (NavXmlTree -> NavXmlTrees)) ] axisFctL = [ (Ancestor, ancestorAxis) , (AncestorOrSelf, ancestorOrSelfAxis) , ... ] evalStep :: Env -> XPathValue -> XStep -> XPathValue evalStep env ns (Step axisSpec nt pr) = evalStep’ env pr nt (getAxisNodes axisSpec ns)

4.7.4 Knotentests Die durch eine Achse ausgew¨ahlte Knotenmenge wird durch einen Knotentest gefiltert. Die Achsenfunktionen stellen dabei sicher, dass sich nur Knoten des richtigen Hauptknotentyps in der zu filternden Menge befinden. Die attribute-Achse liefert nur Knoten vom Typ Attribut, alle anderen Achsen7 haben als Hauptknotentyp den Elementtyp. Der Namens- oder Typtest wird u ¨ber Filterfunktionen der Haskell XML Toolbox realisiert. isXTextNode pr¨ uft beispielsweise, ob es sich bei dem Knoten um den Typ XText handelt. Alle anderen Knotentypen werden aus der Menge entfernt. Der Namenstest * sowie der Typtest node() werden u ur jeden Knoten der ¨ber die id-Funktion abgebildet, da diese Tests f¨ Menge erf¨ ullt sind. Beispiel: (Namens- und Typtest) nodeTest :: NodeTest -> XPathFilter nodeTest (NameTest "*") = id nodeTest (NameTest s) = filterNodes (isTagNode s) nodeTest (PI s) = filterNodes (isPiNode s) nodeTest (TypeTest t) = typeTest t typeTest typeTest typeTest typeTest typeTest

:: XPathNode -> XPathFilter XPNode = id XPCommentNode = filterNodes isXCmtNode XPPINode = filterNodes isXPiNode XPTextNode = filterNodes isXTextNode

filterNodes :: (XNode -> Bool) -> XPathFilter filterNodes fct (XPVNode ns) = XPVNode ([n | [email protected](NT (NTree node _) _ _ _) <- ns , fct node]) Da das XPath-Modul auf navigierbaren B¨aumen (NavTree) arbeitet, k¨onnen Funktionen der Haskell XML Toolbox, die Mengen filtern, nicht verwendet werden. Diese Filter arbeiten auf dem Typ NTree. Die Funktion filterNodes selektiert daher aus dem Typ NavTree die XNode-Komponente, die durch einen Filter der Haskell XML Toolbox getestet werden kann.

4.7.5 Pr¨ adikate Pr¨adikate erm¨oglichen komplexere Filter als Knotentests. Ein Pr¨adikat, das gegen eine Knotenmenge getestet wird, kann ein beliebiger Ausdruck sein. Pr¨adikate sind die einzigen Ausdr¨ ucke in XPath, die bei der Berechnung von Teilausdr¨ ucken 7

die namespace-Achse wird nicht betrachtet

43

die Kontextposition und die Kontextgr¨oße ¨andern. Alle anderen Ausdr¨ ucke wirken sich maximal auf den Kontextknoten aus. Vor der Auswertung eines Pr¨adikats wird die Kontextgr¨oße (length ns) bestimmt und die Kontextposition auf den Wert eins gesetzt. Beispiel: (Bestimmen der Kontextgr¨oße und Position) evalPredL :: Env -> [Expr] -> XPathFilter evalPredL env pr [email protected](XPVNode ns) = foldl (evalPred env 1 (length ns)) n pr Die Funktion evalPred setzt diese beiden Werte und den aktuellen Kontextknoten zum Auswertungskontext zusammen. Der Test des Kontextknotens erfolgt durch testPredicate. Liefert testPredicate den Wert wahr, wird der Knoten in die Ergebnismenge aufgenommen. Anderenfalls wird die Kontextposition um eins erh¨oht und der Test mit dem n¨achsten Knoten der Menge als Kontextknoten fortgesetzt. Beispiel: (Auswerten eines Pr¨adikats) evalPred :: Env -> Int -> Int -> XPathValue -> Expr -> XPathValue evalPred env pos len (XPVNode (x:xs)) ex = case testPredicate env (pos, len, x) ex (XPVNode [x]) of XPVBool True -> XPVNode (x : n) XPVBool False -> nextNode where [email protected](XPVNode n) = evalPred env (pos+1) len (XPVNode xs) ex testPredicate :: Env -> Context -> Expr -> XPathFilter testPredicate env [email protected](pos, _, _) ex ns = case evalExpr env context ex ns of XPVNumber (Float f) -> XPVBool (f == fromIntegral pos) XPVNumber _ -> XPVBool False _ -> xboolean context env [evalExpr env context ex ns] Die R¨ uckgabe der Funktion testPredicate wird durch die Berechnung des Teilausdruckes und anschließende Konvertierung des Ergebnisses in einen boolschen Wert bestimmt. Ist das Ergebnis des Teilausdruckes eine Zahl, entf¨allt die Konvertierung. Wenn diese Zahl der aktuellen Kontextposition entspricht, wird der Wert wahr zur¨ uckgegeben, sonst der Wert falsch. Der h¨aufig ben¨otigte Test, ob ein Knoten an einer bestimmten Stelle in der Knotenmenge vorkommt, wird hierdurch vereinfacht. Der Lokalisierungspfad para[3] ist ¨aquivalent zu para[position()=3].

4.7.6 Entfernen doppelter Teilb¨ aume Die Resultatmenge eines Lokalisierungsschrittes kann identische Teilb¨aume mehrfach enthalten. In der folgenden Abbildung entspricht der Knoten mit der Nummer 1 dem aktuellen Kontextknoten. Die child-Achse w¨ahlt die grau markierten Knoten aus. Wird auf die resultierenden Teilb¨aume die parent-Achse angewendet, wird der Knoten 1 insgesamt viermal in der Ergebnismenge vorhanden sein. Vor der Auswertung des n¨achsten Lokalisierungsschrittes m¨ ussen gleiche Teilb¨aume entfernt werden. Zwei Teilb¨aume sind gleich, wenn die Anzahl ihrer Vorg¨anger (oder Nachfolger) auf jeder Ebene bis zur Dokumentenwurzel identisch ist.

44

Abbildung 4.1: Doppelte Teilb¨aume Beispiel: (Entfernen doppelter Teilb¨ aume) remDups :: XPathFilter remDups (XPVNode (x:xs)) | isNotIn x xs = XPVNode (x : y) | otherwise = remDups (XPVNode xs) isNotIn :: Eq a => NavTree a -> [NavTree a] -> Bool isNotIn n xs = getRelPosL (Just n) ‘notElem‘ map (\ x -> getRelPosL (Just x)) xs getRelPosL :: Maybe (NavTree a) -> [Int] getRelPosL (Just [email protected](NT _ _ prev _)) = length prev : getRelPosL (upNT t) Die Funktion getRelPosL berechnet die Anzahl der Vorg¨anger eines Kontextknotens in einer Liste. Ist in der Resultatmenge kein Teilbaum mit einer identischen Liste vorhanden (isNotIn), wird der Teilbaum der Menge hinzugef¨ ugt.

4.8 Filter-Ausdr¨ ucke und Mengenvereinigung Liefert ein Ausdruck eine Knotenmenge, wird sie, wie im Abschnitt 4.7.5 beschrieben, durch eine Liste von Pr¨adikaten gefiltert. Ist das Resultat eines zu filternden Ausdruckes keine Knotenmenge, bricht die Verarbeitung mit einer Fehlermeldung ab. Beispiel: (Verarbeitung eines Filter-Ausdruckes) filterEval :: Env -> Context -> [Expr] -> XPathFilter filterEval env cont (prim:predicates) ns = case evalExpr env cont prim ns of [email protected](XPVNode _) -> evalPredL env predicates n _ -> XPVError "Return of a filterexpression is not a nodeset" Mengenvereinigung Zwei Knotenmengen, die durch Filter-Ausdr¨ ucke oder Lokalisierungspfade ausgew¨ahlt wurden, lassen sich u ¨ber den Union-Operator vereinigen. Da es sich bei der internen Darstellung der Mengen um Listen handelt, wird hierf¨ ur der Haskell Operator ++ verwendet. Eventuell vorhandene doppelte Teilb¨aume werden anschließend u ¨ber die Funktion remDubs entfernt.

45

4.9 Darstellung eines Ergebnisses Die Darstellung eines XPath-Ergebnisses als Text-Repr¨asentation erfolgt durch die Funktion xPValue2String. Die folgenden Beispiele beziehen sich auf das XML-Dokument aus Abschnitt 3.1. Die XPath-Ausdr¨ ucke decken alle f¨ unf m¨oglichen Ergebnistypen ab. Beispiel: (Knotenmenge: rezept/zutat) ---XTag zutat | id="mehl" | +---XText "200g Mehl" Beispiel: (Zeichenkette: string(rezept/anleitung)) Zuerst nehmen Sie das Mehl und mischen es mit ... Beispiel: (Boolscher Wert: 1 < 2) true Beispiel: (Zahl: 2 + 4 div 0) Infinity Beispiel: (Fehlerfall: 2 + myFunction()) Error: Call to undefined function myFunction

4.10 Modul-Hierarchie Das Modul XPath exportiert alle notwendigen Funktionen f¨ ur die Auswertung eines Ausdruckes. Es bildet damit den zentralen Einstiegspunkt. XPathToString stellt sowohl einen geparsten Ausdruck, als auch das Ergebnis des Ausdruckes dar. Im Modul XPathFct sind alle Funktionen der Grund-Bibliothek implementiert. XPathArithmetic enth¨alt die arithmetischen Berechnungen nach IEEE 754. XPathEval fasst die Auswertung der verschiedenen Teilausdr¨ ucke zusammen. Das Modul XPathDataTypes enth¨alt schließlich alle notwendigen Typ-Deklarationen f¨ ur XPath.

Abbildung 4.2: Modul-Hierarchie

46

5 Schlussbetrachtung Das Ziel dieser Diplomarbeit bestand in der Konzeption und Implementation eines XPathModuls f¨ ur die Haskell XML Toolbox.

5.1 Erreichtes Der Entwurf des Parsers konnte vollst¨andig abgeschlossen werden. Das entstandene Datenmodell ist in der Lage, einen beliebigen XPath-Ausdruck abzubilden. Die Verwendung der Parsec-Bibliothek erlaubte eine intuitive und zielgerichtete Umsetzung der XPath-Grammatik in einen Parser. Das zu Beginn aufgetretene Problem der langsamen Verarbeitungsgeschwindigkeit konnte im Laufe der Entwicklung behoben werden. Es resultierte aus einem zu großen “look-ahead“ des Parsers bei der Umsetzung einiger Grammatikregeln. Die aktuelle Version des Parsers reduziert den Einsatz eines “look-ahead“ auf die Regel f¨ ur Filter-Ausdr¨ ucke und die Schl¨ usselw¨orter der XPath-Grammatik. Der Parser und das Datenmodell, das einen geparsten Ausdruck repr¨asentiert, sind weitestgehend unabh¨angig von der Haskell XML Toolbox implementiert. Es werden nur einige Hilfsfunktionen des XML-Parsers innerhalb von XPath verwendet. Dies erm¨oglicht, den Parser außerhalb der Haskell XML Toolbox Umgebung zu nutzen und ihn auf individuelle Anforderungen anzupassen. Die Auswertung eines Ausdruckes konnte nicht vollst¨andig erreicht werden, da die aktuelle Version der Haskell XML Toolbox XML-Namensr¨aume nicht unterst¨ utzt. Alle anderen Teilausdr¨ ucke werden durch das XPath-Modul in vollem Umfang verarbeitet. Die Entwicklung des Moduls erfolgte parallel zum Ausbau der Haskell XML Toolbox. Ver¨anderungen an der Datenstruktur der Haskell XML Toolbox wurden von Herrn Prof. Dr. Schmidt zeitnah umgesetzt. Diese Notwendigkeit ergab sich vor allem im Bereich der Darstellung von Attributen. Sie repr¨asentieren innerhalb von XPath einen eigenen Knotentyp, der mit fr¨ uheren Versionen der Haskell XML Toolbox nicht abbildbar war. Das XPath-Modul wurde mit Hugs98 [Hugs 98] und dem Glasgow Haskell Compiler [GHC 02] in der Version 5.04 unter Linux- und Windows-Systemen entwickelt. Alle selbst geschriebenen Module lassen sich unter GHC mit dem Flag -Wall ohne Warnungen compilieren.

5.2 Konformit¨ at XPath ist haupts¨achlich f¨ ur den Einsatz als Komponente innerhalb von umgebenen Prozessoren konzipiert worden. XPath u ur ¨berl¨asst es diesen Spezifikationen, Kriterien f¨ die Konformit¨at festzulegen und definiert selbst keinerlei Konformit¨atskriterien f¨ ur eine unabh¨angige XPath-Implementation.

47

Das entwickelte Modul konnte aus diesem Grund nicht in einer standardisierten Testumgebung f¨ ur XPath gepr¨ uft werden. Alle Tests mussten manuell durchgef¨ uhrt und ausgewertet werden. Die Kontrolle der Parser-Funktionalit¨at erfolgte durch den XQuery Grammar Test [Grammar 02]. Er enth¨alt u ucke, die alle vom Parser verarbeitet ¨ber 1000 XPath-Ausdr¨ werden. Der Test beinhaltet allerdings keine Baum- oder XML-Darstellung des geparsten Ausdruckes, so dass das Ergebnis nicht automatisch verifiziert werden konnte. Der manuelle Vergleich, von circa 20 Prozent der Ausdr¨ ucke, liefert eine 100 prozentige Erfolgsquote. Die Auswertung eines Ausdruckes wurde u ¨ber die XSLT-Testsuite des National Institut of Standards and Technology [NIST 02] gepr¨ uft. Sie umfasst 200 Testf¨alle, von denen circa 50 Prozent erfolgreich durchlaufen werden. Ein Test der restlichen 100 F¨alle kann nicht ohne XSLT-Prozessor durchgef¨ uhrt werden.

5.3 Ausblick Die Popularit¨at von XML zur Darstellung von Informationen wird weiterhin zunehmen. Die einheitliche Repr¨asentation von XML-Dokumenten als Baum mit verschiedenen Knotentypen sowie die effiziente Filtertechnik zur Bearbeitung der Dokumente, versetzen die Haskell XML Toolbox in die Lage, den steigenden Anforderungen durch XML zu gen¨ ugen. Der Ausbau der Haskell XML Toolbox wird fortgesetzt. Namensr¨aume k¨onnen schon in der folgenden Version der Haskell XML Toolbox eingesetzt werden. Alle hierf¨ ur notwendi¨ gen Anderungen am Datenmodell wurden bereits durchgef¨ uhrt. Christine Apfel, Master-Studentin der Fachhochschule Wedel, hat in ihrer Thesis “Konzeption und Design eines XSLT Prozessors unter dem Aspekt der funktionalen Programmierung mit Haskell“ [Apfel 02] die Anforderungen an einen XSLT-Prozessor sehr exakt beschrieben. In absehbarer Zeit wird auf Basis der Arbeit von Frau Apfel und dem vorliegenden XPath-Modul die Implementation eines XSLT-Prozessors f¨ ur die Haskell XML Toolbox erfolgen. Durch die Integration des entwickelten XPath-Moduls in einen umgebenen Prozessor wird ein standardisierter Test m¨oglich. Aus den Testergebnissen resultierende Optimierungen der Verarbeitungsgeschwindigkeit sowie die Korrektur eventuell vorhandener Fehler, werden weitere Aufgaben f¨ ur die nahe Zukunft sein.

48

Literaturverzeichnis

[Apfel 02]

Christine Apfel: Master Thesis: Konzeption und Design eines XSLT Prozessors unter dem Aspekt der funktionalen Programmierung mit Haskell, 2002

[Bach 00]

Mike Bach: XSL und XPath - verst¨andlich und praxisnah, Addison-Wesley, ISBN 3-8273-1661-8, 2000

[Becker 02]

¨ Oliver Becker: Deutsche Ubersetzung der XML Path Language (XPath) Version 1.0, http://www.obqo.de/w3c-trans/xpath-de

[English 02]

Joe English: HXML, http://www.flightlab.com/ joe/hxml/

[GHC 02]

Homepage des Glasgow Haskell Compilers, http://www.haskell.org/ghc/

[Grammar 02] The XPath 2.0 Grammar Test Page, http://www.w3.org/2002/08/applets/xpathApplet.html [Haskell 02]

Homepage von Haskell, http://www.haskell.org/

[Hugs 98]

Homepage von Hugs98, http://www.haskell.org/hugs/

[IEEE 00]

Sun Microsystems: The Java Language Specification, http://java.sun.com/docs/books/jls/second edition/html/

[NIST 02]

NIST: National Institut of Standards http://xw2k.sdct.itl.nist.gov/xml/page5.html

[Parsec 00]

Daan Leijen: Parsec: a free monadic parser combinator library for Haskell, http://www.cs.uu.nl/∼daan/parsec.html

and

Technology,

[Schmidt 02] Martin Schmidt: Master Thesis: Design and Implementation of a validating XML parser in Haskell, 2002 [Thompson 99] Simon Thompson: Haskell: The Craft of Functional Programming, Second Edition, Addison-Wesley, ISBN 0-201-34275-8, 1999 [Toolbox 02] Homepage der Haskell XML Toolbox, http://www.fh-wedel.de/∼si/HXmlToolbox/index.html [W3C 99]

World Wide Web Consortium: XML Path Language (XPath) Version 1.0, http://www.w3.org/TR/xpath

49

Weitere Quellen

In diesem Abschnitt werden die nicht in das Literaturverzeichnis passenden Quellen aufgef¨ uhrt, die aber mindestens genauso viel zu dieser Arbeit beigetragen haben, wie die dort aufgef¨ uhrten. LATEX Helmut Kopka: LATEX: Eine Einf¨ uhrung, Addison-Wesley, ISBN 3-89319-199-2, 1990 W¨ orterb¨ ucher - Die deutsche Rechtschreibung, DUDENVERLAG, ISBN 3-411-04011-4, 1996 - Oxford Advanced Learner’s Dictionary, Cornelsen Verlag, ISBN 3-464-11223-3, 1995 - Dictionary LEO, http://dict.leo.org Antworten auf alle m¨ oglichen (mehr oder weniger) fachlichen Fragen gaben: - Prof. Dr. Uwe Schmidt, Fachhochschule Wedel - Dipl.-Ing.(FH), MSc. Henry Kleta, Fachhochschule Wedel - Andreas Ehlers Korrekturleser: - Sabrina T¨ urke - Sven Dietze - Wiebke Leander seid bedankt...

50

Eidesstattliche Erkl¨ arung Hiermit erkl¨are ich an Eides statt, dass ich die vorliegende Arbeit selbstst¨andig ohne Benutzung anderer als der angegebenen Hilfsmittel angefertigt habe.

Hamburg, 20.02.2003

(Torben Kuseler)

51