XML wurde vom vom W3C als universelle Auszeichnungssprache - vor allem für das Internet - standardisiert und eignet sich hervorragend zum Datenaustausch zwischen heterogenen Datenbanken. Daher wird XML hier beschrieben.
Um das Umfeld von XML etwas kennenzulernen, wird auch auf Konzepte wie Namensräume und die Sprachen XLink und XPointer eingegangen. Außerdem werden beispielhaft zwei wichtige Anfragesprachen für XML vorgestellt: XML-QL und XQL.
Anschließend wird noch als Anregung das "Document Object Model" angesprochen, welches zur einfachen Implementierung einiger XML-Anwendungen dienen kann.
Die meisten Erklärungen erfolgen anhand von Beispielen. Als Hauptbeispiel dient eine imaginäre CD-Sammlung im Internet.
Inhaltsverzeichnis
1 Das Problem
2 XML
2.1 Einführung
2.2 DTD
2.2.1 Elementdefinitionen
2.2.2 Attributdefinitionen
2.2.3 Entitäten
2.2.4 Anwendung einer DTD
2.3 Wohlgeformtheit und Gültigkeit von Dokumenten
2.4 Namensräume
2.5 Referenzen
2.5.1 XLink
2.5.2 XPointer
3 Anfragesprachen
3.1 XML-QL
3.1.1 Einfache Anfragen
3.1.2 Selektion nach Kriterien
3.1.3 Gruppierung mit IDs
3.1.4 Auswerten von Elementnamen
3.1.5 Verbinden von mehreren Quellen
3.1.6 Indexnummern
3.1.7 Pfadausdrücke
3.1.8 Sortierung
3.2 XQL
3.2.1 Suchen einzelner Elemente nach deren Bezeichnung
3.2.2 Wählen von Attributen
3.2.3 Selektieren nach bestimmten Bedingungen
3.2.4 Datentypen
3.2.5 Methoden
3.2.6 Namensräume
3.2.7 Vereinigung und Schnitt
3.2.8 Kollektionen
3.2.9 Gruppierung
3.2.10 Wahl des Dokuments
4 DOM
Zusammenfassung
XML wurde vom W3C als als universelle Auszeichnungssprache - vor allem für das Internet - standardisiert und eignet sich hervorragend zum Datenaustausch zwischen heterogenen Datenbanken. Daher wird XML hier beschrieben.
Um das Umfeld von XML etwas kennenzulernen, wird auch auf Konzepte wie Namensräume und die Sprachen XLink und XPointer eingegangen. Außerdem werden beispielhaft zwei wichtige Anfragesprachen für XML vorgestellt: XML-QL und XQL.
Abschließend wird noch als Anregung das Document Object Model angesprochen, welches zur einfachen Implementierung eigener XMLAnwendungen dienen kann.
Die meisten Erläuterungen erfolgen anhand von Beispielen. Als Hauptbeispiel dient eine imaginäre CD-Sammlung im Internet. Für die theoretischen Grundlagen rund um Daten im Internet empfiehlt sich das Buch[1].
1 Das Problem
Immer mehr Daten werden im Internet bereit gestellt. Dabei geschieht diese Bereitstellung meist so, dass man auf eine Anfrage eine HTML-formatierte Textseite erhält wie z.B. bei Suchmaschinen. Hierbei geht man davon aus, dass die Antworten von einem Menschen ausgewertet - also gelesen - werden. Der Trend geht jedoch immer mehr in die Richtung, Daten aus dem Internet auch elektronisch weiterzuverarbeiten (z.B. Meta-Suchmaschinen, die eine Anfrage an mehrere im Netz verfügbare Suchmaschinen stellen und die Er- gebnisse zusammenfassen). Diese elektronische Weiterverarbeitung muss nun den HTML-Text parsen um die Informationen auszulesen. Hierzu muss der genaue Aufbau des Quelldokuments bekannt sein - und das für jede Such- maschine einzeln, da jede ihre Ergebnisse jeweils anders präsentiert.
Zur Veranschaulichung der Problematik soll hier folgendes Beispiel gewählt werden: Mehrere Freunde wollen ihre CD-Sammlungen in das Internet stel- len und somit ihre Daten über verfügbare CDs austauschen. Dabei denkt sich jeder ein eigenes Format aus und überführt dieses in HTML-Code. Ver- mutlich wird es bei jedem irgendwie auf eine Tabelle hinauslaufen, jedoch werden nur sehr wenige in ihrem Aufbau anderen genau gleichen. So neh- men einige vielleicht eine Form von Wertung in die Tabellen auf, andere den Typ der CD oder Links zu den Interpreten - wieder andere nehmen nicht eine große Tabelle sondern für jeden Anfangsbuchstaben der Interpreten eine eigene. So kann sich der bloße Inhalt der Tabellen schon stark unterscheiden.
Abbildung in dieser Leseprobe nicht enthalten
Abbildung 1: Zwei Darstellungsmöglichkeiten für die gleiche CD Zwei mögliche Darstellungsmöglichkeiten sind in Abb. 1 dargestellt.
Dem Menschen machen diese Unterschiede nichts aus. Er schaut einmal auf die Überschriften und weiß, wo er welche Information zu suchen hat. Will man die dargebotenen Informationen jedoch elektronisch weiterverarbeiten, so muss man für die Daten jeder einzelnen Person einen eigenen Parser bauen und jedesmal entsprechend ändern, wenn eine der Personen z.B. auf die Idee kommt, die Titel der CDs nicht mehr in normaler Schrift sondern fett zu drucken oder die Reihenfolge der Spalten zu ändern. Besonders ärgerlich ist diese mühselige und fehlerträchtige Bearbeitung, wenn das zu filternde Doku- ment ursprünglich aus einer datenbankähnlichen und strukturierten Quelle generiert wurde.
Es wäre daher wünschenswert gewesen, wenn sich die Freunde vorher auf ein bestimmtes Format zum Austausch geeinigt hätten. Dieses Format soll die Darstellung natürlich nicht soweit festlegen, dass die Seiten nicht mehr zu den restlichen Homepages der Personen passen. Auch wäre es schlecht, wenn jemand aufgrund des ”Gruppenzwangs“seine Wertungender CDsoderdie Links zu den Interpreten entfernen müsste.
Gewünscht ist also ein Format, das einerseits gewisse Strukturen festlegt (wie z.B. dass ein Interpret genau einen Namen und mindestens eine CD hat), andererseits jedoch genügend Freiheiten für persönliche Erweiterungen lässt. Dieses gewährleistet XML (eXtensible Markup Language).
2 XML
2.1 Einführung
XML wurde als eingeschränkte Form von SGML entworfen und vom W3C standardisiert[5]. Es gleicht im syntaktischen Aufbau HTML. So gibt es Marken (Tags), die in spitzen Klammern (< und >) eingeschlossen sind und die Struktur des Dokuments beschreiben. Der große Unterschied zu HTML ist jedoch, dass es keine vordefinierten Marken gibt. Genau wie die Zeichen- folge
Abbildung in dieser Leseprobe nicht enthalten
im HTML-Code angibt, dass T eine Tabelle darstellt, so definiert z.B. der XML-Code
Abbildung in dieser Leseprobe nicht enthalten
dass hier durch C eine CD beschrieben wird (es wird jedoch wohlgemerkt nicht gesagt, was denn eine CD genau ist). Wie HTML also das Layout eines Dokuments beschreibt, so wird durch XML der Inhalt festgelegt indem durch die Marken Teile des Dokuments zu Elementen zusammengefasst werden.
XML-Marken können außerdem wie Marken in HTML Attribute in der Form
Abbildung in dieser Leseprobe nicht enthalten
haben (wie z.B. der <a>-Tag in HTML). Hier werden den Attributen x1 bis xn die Werte y1 bis yn zugewiesen.
Die Darstellung der CD aus Abb. 1 und einiger weiterer sähe in XML z.B. wie in Abb. 2 gezeigt aus.
Ein weiterer Unterschied zu HTML besteht in XML darin, dass jede öffnende Marke der Form <t> auch wieder durch eine Marke der Form </t> geschlossen werden muss (In HTML-Dokumenten ist es klar, dass beim Beginn eines neuen durch <p> gekennzeichneten Absatzes der alte beendet wird - dieses implizite Wissen ist jedoch bei XML-Dokumenten aufgrund der nicht vorgegebenen Struktur nicht vorhanden). Soll zwischen einer öffnenden Marke und ihrem schließenden Gegenstück kein Text stehen (also etwa <T > </T >), so kann man das Paar abgekürzt darstellen als <T />.
Zur Darstellung von Zeichen wird in XML Unicode benutzt. Zudem unter- scheidet XML im Gegensatz zu HTML zwischen Groß- und Kleinschreibung.
Kommentare werden in XML analog zu HTML folgendermaßen markiert: <!-- K -->
Abbildung in dieser Leseprobe nicht enthalten
Abbildung 2: Eine durch XML beschriebene CD-Sammlung
Anweisungen für Anwendungsprogramme können in XML als sog. Processing Instructions (PI s) gespeichert werden. Dargestellt werden sie durch <? . . . ?>. Die XML-Version wird z.B. durch die Zeile angegeben (was in jedem Dokument geschehen sollte).
Abbildung in dieser Leseprobe nicht enthalten
Als wichtiger Unterschied zu Datenbanken muss noch angeführt werden, dass es sich bei XML um eine Auszeichnungssprache handelt. Dieses macht sich dadurch bemerkbar, dass Elemente in XML geordnet sind. Man muss beispielsweise nicht wie in einer Datenbank zu evtl. gespeicherten einzelnen Liedern einer CD die Tracknummer mitspeichern sondern kann dieses implizit mit der Auflistungsreihenfolge festlegen. Zu beachten ist jedoch, dass Attribute definitionsgemäß keine Reihenfolge besitzen.
2.2 DTD
Bei XML handelt es sich nicht einfach nur um eine erweiterbare Auszeichnungssprache, sondern um eine Sprache, in der sich die Syntax von Auszeichnungssprachen definieren lässt - genauer gesagt handelt es sich also um eine Metagrammatik für kontextfreie Grammatiken.
Diese Grammatikdefinition wird als DTD (document type definition) be- zeichnet und kommt aus dem Umfeld von SGML, von dem XML eine Teil- menge bildet. Jede HTML-Version besitzt z.B. eine solche SGML-DTD und mit XHTML wird derzeit eine XML-DTD für HTML 4 erarbeitet[9].
Abbildung in dieser Leseprobe nicht enthalten
Abbildung 3: Eine DTD für CDs
Zu beachten ist, dass es für ein XML-Dokument keine DTD geben muss. Jedes XML-Dokument enthält eine implizite Struktur durch die Marken (was als semistrukturiert (semistructured) bezeichnet wird). Eine DTD ist nur eine Möglichkeit, diese Struktur explizit vorzugeben.
Wie eine solche DTD aussehen kann, soll am Beispiel einer DTD für die CD-Sammlung erläutert werden (Abb. 3):
2.2.1 Elementdefinitionen
In der ersten Zeile wird das Element CD-Sammlung definiert, wodurch die Markierung <CD-Sammlung> · · · </CD-Sammlung> ein Bestandteil der definier- ten Sprache wird. Die Regel für das Element gibt an, dass innerhalb der Markierung beliebig viele Elemente des Typs Interpret stehen dürfen.
Innerhalb einer <Interpret>-Markierung muss wiederum genau ein NameElement, bei Gruppen evtl. beliebig viele Mitglied-Elemente und mindestens ein Titel-Element stehen, und das in dieser Reihenfolge.
Für die Formulierung dieser Regeln kann man in XML mit ( ) gruppieren, Alternativen mit | und Sequenzen mit Kommata angeben. Kardinalitäten von evtl. Wiederholungen werden durch * (0 bis beliebig), + (1 bis beliebig) und ? (0 oder 1-mal) definiert.
Die Zeilen drei bis fünf besagen, dass zwischen den dort aufgeführten Markierungen beliebiger Text stehen darf, was durch das Schlüsselwort ANY besagt wird. Neben ANY existiert auch die Regel EMPTY die besagt, dass ein damit ausgezeichnetes Element leer bleiben muss (dieses macht dann Sinn, wenn für das Element Attribute definiert werden).
2.2.2 Attributdefinitionen
In den restlichen Zeilen werden mögliche Attribute für die Elemente Interpret und Titel vorgegeben. Bei Interpret ist dies das optionale (#IMPLIED) Attribut URL, das aus einer Zeichenkette (in XML durch CDATA angegeben) bestehen muss. Wird ein Attribut verlangt (soll also z.B. festgelegt werden, dass immer ein URL angegeben werden muss), kann man dieses mit dem Schlüsselwort #REQUIRED vorgeben.
Für das Element Titel ist das Attribut Wertung aufgeführt. Dieses kann die Werte "1" bis "6" oder "keine" haben, wobei letzteres implizit gewählt wird, wenn nichts angegeben ist.
Weitere wichtige Typen für Attribute sind sog. Bezeichner (Typ ID). Jedem Element darf nur ein ID-Attribut zugewiesen werden und dessen Wert muss im Dokument später eindeutig sein. Referenzen auf so benannte Elemente werden durch den Typ IDREF oder IDREFS angegeben (der Typ IDREFS er- laubt eine durch Leerzeichen getrennte Auflistung mehrerer IDs). Durch diese Technik kann die starre Baumstruktur von XML-Dokumenten aufgebrochen werden und es sind sogar zyklische Beziehungen möglich (z.B. können hier- mit in einer Personendatenbank Beziehungen zwischen Eltern und Kindern sowie von Ehepaaren modelliert werden).
Sollen beispielsweise die Mitglieder einer Band beim Interpreten als ein Attribut Mitglieder IDREFS #IMPLIED angegeben werden, so sähe dies im Dokument folgendermaßen aus:
Abbildung in dieser Leseprobe nicht enthalten
In diesem Fall müssen natürlich auch die Mitglieder selbst im Dokument genannt sein, z.B. als
Abbildung in dieser Leseprobe nicht enthalten
Hierfür wiederum muss das Attribut Kennung selbstverständlich auch mit dem Typ ID definiert sein.
Zudem ist es auch möglich, Attribute als Konstanten festzulegen. So legt die Definition Art CDATA #FIXED "cd" für das Element, in dessen Attributliste diese Zeile auftaucht, ein Attribut Art mit dem Wert cd fest, ohne dass dieses später in dem Dokument genannt werden muss.
2.2.3 Entitäten
Sog. Entitäten (entities) dienen in einer DTD zur Definition von Termina- len und Nichtterminalen, die später rein textuell expandiert werden. Man unterscheidet hier zwischen zwei verschiedenen Typen von Entitäten:
Die General Entities sind Kürzel, die im XML-Dokument verwendet werden können. Dort werden sie zu dem für sie definierten Ersetzungstext expandiert. Genutzt werden sie in HTML z.B. für die Definition von Sonderzeichen. So wird durch die Definition
Abbildung in dieser Leseprobe nicht enthalten
in einer DTD das Kürzel gnr definiert. Im Dokument wird es verwendet, indem man es mit & einleitet und mit ; abschließt:
Abbildung in dieser Leseprobe nicht enthalten
Parameter Entities hingegen finden nur innerhalb der definierenden DTD Verwendung. Diese können z.B. eine häufig auftretende Regel kapseln, die auf diese Weise nur einmal festgelegt werden muss. Von den General Entities unterscheidet man sie, indem man sie mit einem %-Zeichen markiert, z.B.
< !ENTITY % chrattr "geaendertAm CDATA #REQUIRED" > Ihr Aufruf gleicht dem der General Entities.
2.2.4 Anwendung einer DTD
Soll ein XML-Dokument einer bestimmten DTD entsprechen, so wird dieses durch die Zeile
Abbildung in dieser Leseprobe nicht enthalten
im Kopf des Dokumentes gesagt: Der Typ des Dokuments ist eine CDSammlung und sie entspricht der DTD in der im Link angegebenen Datei schema.dtd. Bei dieser Angabe handelt es sich normalerweise immer um eine komplette URL.
Wie bereits gesagt muss ein XML-Dokument jedoch keine zugrunde legende DTD besitzen.
2.3 Wohlgeformtheit und Gültigkeit von Dokumenten
Ein XML-Dokument gilt als wohlgeformt (well-formed), wenn es einigen Regeln für XML-Dokumente entspricht, beispielsweise dass die Schachtelung der Elemente balanciert ist und dass es nur ein Wurzelelement gibt.
Wenn es zudem eine DTD benennt, bezeichnet man es als gültig (valid), wenn es dieser DTD genügt. Man unterscheidet in diesem Sinne bei XML-Parsern zwischen validierenden und nichtvalidierenden Parsern, je nachdem, ob sie die Einhaltung der Regeln einer genannten DTD überprüfen oder nur auf Wohlgeformtheit testen.
2.4 Namensräume
Es besteht die Möglichkeit, in einem XML-Dokument mehrere verschiedene Dokumente zusammenzufügen oder Marken mit verschiedenen Bedeutungs- ursprüngen zu mischen. Dies kann der Fall sein, wenn z.B. ein HTML- Fragment wie eine HTML-Tabelle ein Teil eines Dokuments werden soll oder in einem Dokument eine mathematische Formel auftaucht, die einer eigenen DTD gehorcht (eine solche DTD existiert z.B. mit der Mathematical Markup Language - MathML[7] ).
Um in einem solchen Fall Namenskonflikte zu vermeiden oder einfach nur unterscheiden zu können, welche Marke zu welchem Teil gehört, definiert das W3C sog. Namensräume (namespaces), in dem alle Markenbezeichner eindeutig sind[8].
Einen solchen Namensraum definiert man durch Zuweisung einer Zeichenkette (für gewöhnlich eine URL) an ein Kürzel. Dieses geschieht in einer Marke, ab der dann das Kürzel gültig ist, in folgender Form:
Abbildung in dieser Leseprobe nicht enthalten
Hier werden an die Kürzel k1 bis kn die URLs U1 bis Un gebunden. Eine gültige Bindung wäre also z.B.
< MyDoc xmlns:math="http://www.w3.org/TR/REC-MathML" >.
Verwendet wird ein Kürzel k dann in folgender Art, um einen Markenbezeichner T einem Namensraum zuzuordnen:
< k:T ... >···< /k:T >.
Nun kann es mühselig sein, jeder Marke seinen Namensraum mitzugeben, wenn z.B. in einem sehr großen Dokument nur ein paar kleine Formeln vor- kommen sollen. In solchen Fällen ist es möglich, einen bestimmten Namens- raum als Standard festzulegen, indem man einfach bei der Definition das Kürzel wegläßt:
xmlns="U "
Alle Marken, die keinen Namensraum angeben, gelten dann implizit als zu diesem Standard-Namensraum gehörig.
Namensraum-Präfixe können übrigens nicht nur für ganze Marken angegeben werden, sondern können auch nur für einzelne Attribute innerhalb einer Marke gelten. Hierzu setzt man das Präfix einfach vor das Attribut (k:x="y"). Diese Methode wird z.B. bei XLink angewandt.
Verwirrend mag übrigens die Frage sein, auf was denn die angegebenen URLs zeigen müssen. Die einfache Antwort ist: auf nichts Bestimmtes! Es muss nicht einmal eine wirklich existierende URL angegeben werden. Dies wird vom W3C nur als Vorschlag angegeben, da es sich bei URLs um im Internet eindeutige Resourcen handelt und die Namensräume ja gerade eindeutig sein sollen.
2.5 Referenzen
Ein großer Vorteil hypermedialer Dokumente sind Verweise innerhalb von Dokumenten und auf andere Dokumente. In HTML können solche Links mit Hilfe des <A>-Tags realisiert werden. In XML gibt es zwei Verfahren: Die XML Linking Language (XLink )[10] um Verknüpfungen zwischen Doku- menten zu beschreiben (steht kurz vor der Standardisierung vom W3C) und die XML Pointer Language (XPointer )[12] um Addressierungen innerhalb von Dokumenten zu realisieren (ist noch in der Entwicklung).
Im Gegensatz zu Verknüpfungen, wie sie mit ID/IDRef-Konstruktionen erstellt werden können, benötigt man für XLink und XPointer keine vordefinierten Ziele in Dokumenten.
2.5.1 XLink
Mit XLink können in XML sowohl einfache unidirektionale Links als auch komplexere Strukturen erzeugt werden. Damit ein Link als solcher erkannt werden kann, sollte er mit einem Präfix dem Namensraum mit der URL http://www.w3.org/1999/xlink zugeordnet werden.
Damit auch Elemente aus anderen Namensräumen als XLink-Elemente dienen können, gibt es globale Attribute, die dieses angeben. Die globalen Attribute sind type, href, role, title, show, actuate, from und to.
Jedes XLink-Element benötigt das type-Attribut. Dieses besagt als erstes, ob es sich um einen einfachen (simple) oder einen erweiterten (extended) Link handelt.
Ein einfacher Link verbindet ähnlich dem <a href="...">-Element in HTML immer nur zwei Dokumente: das aktuelle und das, auf das verwiesen wird. Einfache Links besitzen alle Informationen, die benötigt werden, in einem Link-Element in Form von Attributen. Diese können sein:
href: Die Ziel-URL des Links.
role: Die Funktion, die der Link einnimmt (für die elektronische Auswer- tung).
title: Der Titel für den Link in einer für Menschen lesbaren Art. show: Legt das Verhalten des Browsers fest:
new lädt das neue Dokument in ein neues Fenster, replace überschreibt die aktuelle Dokumentansicht mit dem neuen Dokument, embed fügt das Zieldokument in das aktuelle ein (wie z.B. Bilder in HTML mit dem <IMG>-Tag) und
undefined lässt die Darstellung offen.
actuate: Legt fest, wann der Link verfolgt werden soll:
onLoad verfolgt den Link, sobald das Dokument geladen wird, onRequest wartet auf ein Ereignis nach dem Laden des Dokuments, z.B. auf den Klick eines Benutzers.
Ein Beispiel für einen einfachen Link ist
Abbildung in dieser Leseprobe nicht enthalten
Soll es sich bei dem Link um einen erweiterten Link handeln, so werden die Ziele nicht direkt als Attribute in dem Link-Element selbst sondern in Kindern dieses Elements angegeben. Für ein Link-Element mit dem Typ extended sind daher nur die Attribute role und title definiert. Als Kinder kommen für einen erweiterten Link folgende Element-Typen (jeweils in dem type-Attribut angegeben) in Frage: locator-Typ-Elemente addressieren das Ziel, das an dem Link beteiligt ist. Für diesen Typ ist daher auch die Nennung des Attributs href zwingend vorgeschrieben. Das Element kann zudem noch ein role- und ein title-Attribut besitzen.
arc-Typ-Elemente sind die eigentlichen Verknüpfungen und legen die Re- geln für die Bearbeitung der teilnehmenden Dokumente fest. Ein so ausgezeichnetes Element kann bis auf href alle Attribute eines einfa- chen Links und zusätzlich noch from- und to-Attribute haben, in denen Ursprung und Ziel der Verknüpfung genannt werden (es muss sich also jeweils um ein locator- oder ein resource-Typ-Element handeln). resource-Typ-Elemente beinhalten lokale Resourcen, die an dem Link teil- nehmen. Ein solches Element darf role- und title-Attribute haben.
title-Typ-Elemente kapseln einfach einen für Menschen lesbaren Titel.
Ein komplexeres Beispiel findet sich in Abb. 4. Hieran erkennt man auch sehr gut den Sinn von Konstantendefinitionen für Attribute in DTDs. So kann man z.B. für das Element englisch die Attribute type, role und title festlegen, so dass im Dokument nur noch href zugewiesen werden braucht.
2.5.2 XPointer
XPointer erlaubt wie bereits erwähnt die Addressierung innerhalb von XML- Dokumenten. Die Sprache ermöglicht sowohl das Durchwandern der Baum- struktur als auch die Wahl interner Elemente oder ganzer Bereiche aufgrund verschiedener Eigenschaften wie Element-Typen, Attributwerten, textuellem Inhalt oder relativer Positionen und nicht nur abhängig von expliziten ID- Attributen.
Die Addressierung anhand von IDs ist jedoch die einfachste Möglichkeit und bekannt durch HTML: Mit #I addressiert man das Element mit der ID I, wobei es sich jedoch nur um eine Abkürzung für #xpointer(id("I")) han- delt, die u.a. aus Gründen der Abwärtskompatibilität zu HTML-Dokumenten übernommen wurde.
Abbildung in dieser Leseprobe nicht enthalten
Abbildung 4: Beispiel für einen erweiterten XLink
Allgemein baut XPointer auf der XML Path Language (XPath) auf[11]. Der Name deutet an, dass XPath durch die hierarchische Struktur eines XML- Dokuments navigiert. XPath wird im übrigen auch für XML Transformati- ons (XSLT ) benutzt, also um z.B. aus XML-Dokumenten HTML-Seiten zu generieren.
XPath stellt ein XML-Dokument als einen Baum von Knoten dar, wobei es Elementknoten, Attributknoten und Textknoten gibt. Von jedem Knoten aus kann man dessen Kinder (z.B. die ersten fünf Knoten oder den dritten Knoten mit Namen Titel), dessen Geschwister (alle oder den direkten Vorgänger oder Nachfolger) und die Vorfahren addressieren. Dieses Verfahren wird (in einer erweiterten Form) auch bei XQL angewandt und soll dort (ab Seite 20) erläutert werden.
3 Anfragesprachen
Wie dargestellt eignet sich XML sehr gut zum Datenaustausch im Internet. Solche Daten wollen natürlich ausgewertet werden. Bei dieser Auswertung kann man grundsätzlich zwei verschiedene Ansätze unterscheiden: Einerseits gibt es die ”Datenbanksicht“.Vondieserausmöchtemanstruktur- und inhaltsbasierte Anfragen an eine oder mehrere evtl. sehr große XML- Datenquellen stellen um ein genaues Ergebnis zu erhalten. Eine mächtige und direkt aus XML heraus entstandene Sprache für diese Ziele ist XML- QL.
Die andere Sichtweise ist die aus der Dokumentverarbeitung. Hier beschäftigt man sich eher mit der Suche nach einzelnen Textstellen und der Überführung eines Dokuments in mehrere Repräsentationen. Hier sei das Stichwort des personalisierten Webs genannt: Einzelne Benutzer setzen auf eine Quelle - z.B. eine Suchmaschine - eigene Sichten, um persönlich gestaltete und evtl. gefilterte Ergebnisse zu erhalten. Eine Anfragesprache aus diesem Bereich ist XQL, welche eine Obermenge von der Selektionsmöglichkeiten der Extensible Stylesheet Language (XSL) [[6]] - wahrscheinlich der Sprache, um XML-Daten in HTML-Dokumente umzuwandeln - bildet.
Einen Vergleich von XML-QL mit XQL sowie zweier weiterer Anfragesprachen findet man unter [[3]].
3.1 XML-QL
XML-QL (XML-Query Language) besitzt alle wichtigen Fähigkeiten einer Datenbank-Anfragesprache. Sowohl selektieren einzelner Elemente aufgrund gewisser Eigenschaften als auch deren Extrahierung ist möglich. Mit XMLQL kann man Elemente reduzieren (d.h. deren Unterelemente ausblenden), restrukturieren und mehrere verschiedene Elemente zu einem neuen Element kombinieren. Eine gute Übersicht hierüber bietet auch[2].
Zudem erzeugt XML-QL eine XML konforme Ausgabe. Somit ist es für Anwendungen egal, ob sie ein direktes XML-Dokument erhalten oder das Ergebnis einer Anfrage. Ebenso erlaubt XML-QL überall dort, wo ein XMLDokument erwartet wird, das Ergebnis einer Unteranfrage (man kann XMLQL-Anfragen also schachteln).
Die wohl wichtigste Eigenschaft, die XML-QL von Anfragesprachen wie SQL und OQL unterscheidet, ist jedoch, dass XML-QL kein Schema der Daten benötigt.
3.1.1 Einfache Anfragen
XML-QL soll hier anhand von Beispielanfragen vorgestellt werden. Eine einfache Anfrage könnte z.B. sein: ”WelcheCDsvonSavatagesindinder Sammlung?“ Die XMl-QL-Anfrage hierzu könnte folgendermaßen aussehen:
Abbildung in dieser Leseprobe nicht enthalten
Wie man sieht, wurde die Anfrage in die Markierung <result> . . . </result> eingeschlossen. Dieses wurde gemacht, damit das Ergebnis wieder ein gültiges XML-Dokument ist (ein solches darf ja nur ein Element als Wurzel besitzen) und hat mit der reinen Anfrage nichts zu tun. Zudem wurde in der Anfrage von einer Abkürzungsmethode in XML-QL Gebrauch gemacht: </> schließt immer die nächst passende Markierung.
Eine Anfrage an sich besteht wie im Beispiel immer aus einem WHERE- und einem CONSTRUCT-Block. In dem WHERE-Block werden hier alle Titel, die in das angegebene Muster passen (die also ein Kind eines Interpret-Elements sind, in dem ein Name-Element mit dem Wert Savatage enthalten ist) an die Variable $t gebunden. Für jede solche gefundene gültige Bindung wird die CONSTRUCT-Klausel aufgerufen, in der das Ergebnis mit der Markierung title versehen und ausgegeben wird.
3.1.2 Selektion nach Kriterien
Im nächsten Beispiel sollen nur solche CDs ausgegeben werden, deren Wertung besser oder gleich 3 ist:
Abbildung in dieser Leseprobe nicht enthalten
Hier wird für jede gefundene CD ein eigenes cd-Element angelegt, in dem jeweils der Interpret, der Titel und die Wertung ausgegeben werden. Es wird also die ursprüngliche Struktur, in der jedem Interpreten alle CD-Titel auf einmal zugeordnet waren, aufgebrochen. Hierbei handelt es sich um eine wei- tere Stärke von XML-QL, da man so ein Dokument zwischen verschiedenen DTDs konvertieren kann. Will man dieses jedoch vermeiden, kann man die Anfrage aufteilen:
Abbildung in dieser Leseprobe nicht enthalten
Bei dieser Anfrage wird für jeden Interpreten der gesamte Inhalt (also der Na- me, alle Titel und evtl. sonstige Werte) mit dem Schlüsselwort CONTENT_AS an die Variable $i gebunden. Einen ähnlichen Effekt hat das Schlüsselwort ELEMENT_AS, bei dem zusätzlich noch die Markierung des Elements aufge- nommen wird (es handelt sich bei dieser Funktion somit um ”syntaktischen Zucker“, da die Markierung ja auch explizit bei der Auswertung wieder mit angegeben werden kann). Der Inhalt dieser Bindung wird dann jeweils in ei- ner Unteranfrage ausgewertet. Dadurch bleibt zwar die ursprüngliche Struk- tur erhalten, es werden aber auch Interpreten in das Ergebnis aufgenommen, die keine einzige CD mit einer Wertung besser oder gleich[3] haben.
3.1.3 Gruppierung mit IDs
Um dieses zu verhindern, kann man von IDs Gebrauch machen. Soll bei der Auswertung einer XML-QL-Anfrage ein Element mit einem Attribut ID erzeugt werden, so geht XML-QL implizit davon aus, dass dieses Attribut den Typen ID besitzt und überprüft alle bisherigen Ergebnisse darauf, ob nicht schon ein Element mit einer solchen ID erzeugt wurde. Ist dieses der Fall, werden diese beiden Elemente zu einem zusammengefasst. Die folgende Anfrage arbeitet mit dieser Technik:
Abbildung in dieser Leseprobe nicht enthalten
Hierbei wird für jeden Interpreten aus dessen Namen mithilfe der Funktion f eine eindeutige ID berechnet. Diese Funktion muss extern von der Auswertungsumgebung vorgegeben sein und ist nicht standardisiert.
3.1.4 Auswerten von Elementnamen
Es lassen sich jedoch nicht nur Attribut- und Elementwerte an Variablen binden, sondern auch Elementnamen. Um für diese Funktion ein Beispiel zu konstruieren nehmen wir an, dass in der bisherigen CD-Sammlung Maxi- CDs, EPs und normale CDs unterschieden werden und zwar in der Form, dass die Markierung Titel durch die Markierungen Maxi, EP und CD ersetzt wird. Eine Anfrage, die alle Maxi-CDs und EPs von Savatage findet sähe dann z.B. so aus:
Abbildung in dieser Leseprobe nicht enthalten
3.1.5 Verbinden von mehreren Quellen
Des weiteren kann man über Variablenbindungen auch Joins ausführen. Wenn beispielsweise in der Datei www.cds.de/info.xml Informationen zu einigen Interpreten gespeichert sind, kann man diese mit der Sammlung auf folgende Weise zusammenführen:
Abbildung in dieser Leseprobe nicht enthalten
Durch die erste Verwendung der Variable $n wird diese an einen möglichen Interpreten gebunden. Bei der zweiten Verwendung dient sie zur Auswahl der entsprechenden Information in der zweiten Datei. Gibt es eine solche Information zu dem Interpreten wird ein Ergebnis ausgegeben. Es handelt sich bei dieser Konstruktion also um einen equi join. Will man einen outer join erzeugen, so kann man dieses mit zwei getrennten Anfragen erzielen die für sich jeden Interpreten erzeugen und diese über die oben genannte ID-Generierung ”verschmelzen“.
3.1.6 Indexnummern
Letztlich kann man Variablen auch an Indexnummern binden, die jedes Element implizit aus seiner Position im XML-Dokument in Relation zu seinem Geschwister-Elementen erhält. Die Nummerierung erfolgt Null-basiert. Die Bindung erfolgt durch Angabe der Variable in eckigen Klammern innerhalb der Marke ([$i]). Die folgende Anfrage sucht mit dieser Funktion die ersten drei CDs jedes Interpreten und erzeugt ein zusätzliches leeres Element <und-andere/>, wenn es mehr CDs gibt:
Abbildung in dieser Leseprobe nicht enthalten
Zu beachten ist, dass jeder Interpret laut DTD als erstes Element einen Namen hat. Somit hat das Name-Element die Indexnummer 0 und die Titel die Nummern 1 bis n.
3.1.7 Pfadausdrücke
Die wohl mächtigste Eigenschaft von XML-QL ist jedoch die Auswertung von regulären Pfadausdrücken. Da XML beliebig tief verschachtelte Strukturen erlaubt, muss auch die Anfragespra che beliebig tief gehen können. Hierzu bietet XML-QL folgende Konstruktoren von Pfadausdrücken an: Die Wie- derholung (*), die Auswahl (|) sowie die Konkatenation (.). Zudem gibt es noch den Unterstrich (_), der als Platzhalter für ein beliebiges Element fungiert. Der Ausdruck
< (_*).(Adresse|Wohnort).Strasse >
passt also auf alle Elemente mit Namen Strasse, die ein Kind eines Adresse- oder Wohnort-Elements sind und ansonsten beliebig tief im XML-Dokument liegen.
3.1.8 Sortierung
Zu guter Letzt kann man mit XML-QL auch sortieren: Hierfür reicht ein ORDER_BY mit der entsprechenden Variable zwischen der WHERE- und der CONSTRUCT-Klausel aus.
3.2 XQL
XQL arbeitet wie XML-QL auf einer Baum-Semantik eines XML-Dokuments. Jedoch werden hier auch Attribute oder die eingeschlossenen Textabschnitte von Elementen, Kommentare und Anweisungen als einzelne Knoten betrachtet (im Prinzip wie beim Document Object Model).
Durch diese Knoten kann man ähnlich wie durch eine Verzeichnisstruktur gängiger Betriebssysteme navigieren. Ausgegangen wird dabei immer von einem sog. Kontext, einem aktuell gewähltem Knoten (beim Vergleich mit der Verzeichnisstruktur entspräche dieser dem aktuellen Verzeichnis).
3.2.1 Suchen einzelner Elemente nach deren Bezeichnung
Die einfachste Anfrage besteht aus der Nennung eines Elementnamens, welche jedes so benannte Element im Dokument zurückliefert - egal wie tief es im Dokumentbaum liegt. So liefert also
Name
alle Interpretennamen, die in unserer CD-Sammlung aufgelistet sind.
Will man die Ebene, aus der man die Name-Elemente bekommen will, vorgeben, so kann man auch den kompletten Pfad angeben:
/CD-Sammlung/Interpret/Name
liefert nur die Namen, die von der Wurzel des Dokuments aus dem Pfadausdruck entsprechend im Baum liegen. Dass dabei von der Wurzel ausgegangen werden soll, wird durch den führenden Schrägstrich (/) vorgegeben. Ohne diesen führenden Schrägstrich liefert die ähnliche Anfrage
Interpret/Name
alle Name-Elemente im Dokument, die Kind eines Interpret-Elements sind. Bei den Interpret-Elementen wiederum ist es egal, wo sie im Dokument liegen.
Soll eine Position relativ zum aktuellen Kontext vorgegeben werden, so kann man den Kontext durch einen führenden Punkt angeben:
./Name
findet nur Namen, die direkte Nachfahren des Kontextes sind.
Der Stern (*) steht wie bekannt für ein beliebiges Element. So liefert die Anfrage
/CD-Sammlung/*/Name
alle Namen aus der CD-Sammlung, die eine Kind eines Kindes der Wurzel darstellen. Will man alle Nachfahren eines bestimmten Knoten, die einen vorgegebenen Namen haben, erhalten - egal in welcher Tiefe - gibt man dies mit zwei hintereinander folgenden Schrägstrichen an (//).
Interpret//Name
findet somit alle Namen, die irgendwo stehen und irgendwann ein Interpret- Element als Vorfahr haben. Sie ist also nicht äquivalent mit der vorherigen Anfrage Interpret/*/Name! Die Konstruktion Interpret ist übrigens eine Abkürzung für .//Interpret (nicht jedoch für //Interpret - dieses impli- ziert eine Suche im ganzen Dokument, da die Anfrage mit einem / beginnt).
3.2.2 Wählen von Attributen
Wie bereits angedeutet, werden auch Attribute als eigene Knoten behandelt. Attribute werden durch ein vorangestelltes @ markiert.
/CD-Sammlung/Interpret/Titel/@Wertung
liefert also alle Wertungen. Will man alle Attribute wählen, kann man die Konstruktion @* verwenden.
3.2.3 Selektieren nach bestimmten Bedingungen
Nun will man natürlich nicht immer alle Elemente eines bestimmten Namens haben. Selektionsbedingungen werden bei XQL nach dem entsprechenden Element in eckigen Klammern ([. . . ]) angegeben. Dabei können Bedingungen entweder direkt Wahrheitswerte ergeben (z.B. bei Gleichheitsbedingungen) oder eine Menge von Elementen. Bei letzterem gilt die Bedingung als erfüllt, wenn die Menge nicht leer ist. So findet
Interpret/Titel[@Wertung]
alle Titel, die ein Wertungsattribut haben und
Interpret[Titel/@Wertung]
alle Interpreten, die mindestens einen Titel mit Wertung besitzen. Titel[@Wertung <= 2]
liefert alle Titel, deren Wertung 2 oder besser ist. Mit der Anfrage Interpret[Name = ’Savatage’]
erhält man alle Interpreten mit Namen Savatage (genauer: alle Interpreten, die mindestens ein Name-Element mit dem Wert Savatage als Kind haben - s.u.).
Selektionsbedingungen müssen natürlich nicht immer am Schluss stehen. Will man zum Beispiel alle Titel von Savatage haben, so erreicht man dieses mit der Anfrage
Interpret[Name = ’Savatage’]/Titel.
Man kann Bedingungen auch logisch verknüpfen. Hierzu gibt es die Schlüsselwörter $and$, $or$ und $not$. Alle Gruppen, die zwar Titel, aber keine Mitglieder gespeichert haben, findet
Interpret[Titel $and$ $not$ Mitglied].
Präferenzen können durch runde Klammern gesetzt werden.
Neben der Gleichheit (=) existiert auch noch ein Operator für Ungleichheit: !=.Alternativ können sie auch durch $eq$ (für Gleichheit) oder $ne$ (für Ungleichheit) ersetzt werden. Darüber hinaus existieren die Vergleiche klei- ner (< oder $lt$), kleiner gleich (<= oder $le$), größer (> oder $gt$) sowie größer gleich (>= oder $ge$). Bei String-Vergleichen gibt es zusätzlich noch die Möglichkeit, die Relevanz der Groß- bzw. Kleinschreibung auszuschalten, und zwar durch ein vorangestelltes i, z.B. $ieq$ für Gleichheit oder $ile$ für kleiner gleich.
Wird eine Menge von Elementen mit einem Wert verglichen (wie bei der obigen Anfrage Interpret[Name = ’Savatage’]/Titel - hier kann ja evtl. ein Interpret mehrere Namen haben wenn sich das Dokument nicht an die DTD hält - so gilt die Bedingung als erfüllt, wenn sie für mindestens ein Element gilt. Will man vorgeben, dass die Bedingung für alle Elemente gilt, so erreicht man dies durch das vorangestellte Schlüsselwort $all$. Die Voreinstellung entspricht $any$.
Interpret[$all$ Titel/@Wertung $le$ 3]
findet also alle Interpreten, bei denen alle CDs eine Wertung von mindestens drei haben.
3.2.4 Datentypen
XQL erkennt übrigens die Datentypen selbst, wenn ein Vergleich mit Litera- len stattfindet. Dabei gibt es die Typen text, long (ganze Zahl) und double (Fließkommazahl). Hierzu muss das Literal jedoch immer auf der rechten Seite des Vergleiches auftauchen. ”Manuell“kanneineTypkonversionz.B. durch (long) ’[15] ’ durchgeführt werden, also durch Voranstellen des Typs in runden Klammern.
3.2.5 Methoden
Bei text() handelt es sich zudem um eine sog. Methode, die man auf alle Knoten anwenden kann. Sie liefert immer den Text den ein Element enthält und den aller Nachfahren - jedoch ohne Tagnamen und ohne Kommentare. Außerdem werden Leerzeichen zusammengefasst, wenn der Knoten nicht das Attribut xml:space auf ’preserve’ gesetzt hat. Bei dieser Methode wird jedoch nicht der Typ angepasst!
Daneben gibt es die Methoden value(), nodeName() und nodeType(), die auf Elemente angewandt werden können. value() liefert den angepassten Wert des Elements (oder das gleiche wie text(), wenn der Typ nicht erkannt oder unterstützt wird). NodeName() liefert den Namen des Knotens und nodeType() den Typ. Die verschiedenen Typen werden bei der Beschreibung von DOM auf Seite 27 kurz angesprochen.
Methoden werden mit einem Ausrufezeichen (!) an den entsprechenden Knoten angehängt oder einfach so in der Bedingung genannt, wenn sie auf den zu untersuchenden Knoten angewendet werden soll, z.B.
Interpret[Titel!text() = ’Sirens’]
oder
Interpret[text() = ’Savatage’]
Eine weitere sehr wichtige Methode existiert, um herauszufinden, an welcher ”Position“einKnotenzwischenseinenGeschwisternsteht.Diesesistdie Funktion index(), die die Null-basierte Indexzahl liefert. So findet
Interpret[text() = ’Savatage’]/Titel[index() <= [3]]
die ersten vier (null bis drei) CDs von Savatage. Die Indexnummer kann auch alleine in der Bedingung stehen.
Titel[@Wertung][[0]]
findet die erste CD mit Wertung (durch die erste Bedingung werden alle CDs ohne Wertung herausgefiltert - auf das Ergebnis wird die zweite Bedingung angewendet). Der letzte Index wird durch end() repräsentiert. Durch Anga- be einer negativen Zahl , z.B. −n, erhält man das Element, das n−1 Stellen vor dem letzten Element steht. − 1 steht also für das letzte, −2 für das vor- letzte Element und so weiter. Durch die Angabe m $to$ n erhält man alle Elemente von m bis n.
Zu beachten ist, dass diese Art der Indexierung nicht mit der in XML-QL zu verwechseln ist. Bei XML-QL wird der Index aus der Position des Elements in Relation zu seinen Geschwistern gewonnen. Bei XQL hingegen wird das Zwischenergebnis ”durchnummeriert“ und Indexangaben hierauf angewandt.
3.2.6 Namensräume
Namen werden normalerweise immer mit ihrem Namensraumzusatz angege- ben, so dieser im Dokument vermerkt ist. Die Methode baseName() liefert den reinen Namen ohne Namensraumangabe, prefix() nur den Präfix und namespace() die URI-Angabe des Namensraumes. Zudem kann man bei Namensräumen mit dem Stern arbeiten:
*:Name
findet alle Namenselemente, egal welchem Namensraum sie angehören und @xml:*
alle Attribute, die dem xml-Namensraum zugeordnet sind.
3.2.7 Vereinigung und Schnitt
Eine Vereinigung von zwei Ergebnismengen erreicht man durch das Schlüsselwort $union$, was durch den senkrechten Strich (|) abgekürzt werden kann, Schnittmengen erreicht man mit $intersect$. So liefert
Titel $union$ Name
alle Titel- und Name-Elemente.
3.2.8 Kollektionen
Letztlich gibt es noch Methoden, die alle Kind-Knoten eines bestimmten Typs des aktuellen Knoten zurückliefern. Dieses sind:
textNode() für alle Text-Knoten,
comment() für alle Kommentar-Knoten,
pi() für alle
”processinginstructions“,
element([’name’]) für alle Element-Knoten,
attribute([’name’]) für alle Attribut-Knoten sowie
node() für alle Nicht-Attribut-Knoten (entspricht der getChildNodes()- Funktion beim DOM).
Bei den Methoden für die Element- bzw. Attributknoten kann man wahlweise noch einen Namen angeben. In diesem Fall werden nur Knoten in die Kollektion aufgenommen, die diesem Namen entsprechen.
Die gelieferten Kollektionen kann man auch indexieren. So erhält man ein- fach mit
Interpret/element(’Titel’)[[0]]
die erste CD aller Interpreten.
Abbildung in dieser Leseprobe nicht enthalten
Abbildung 5: DOM-Baum
3.2.9 Gruppierung
Lange Anfragen können in XQL aufgeteilt und durch geschweifte Klammern ({. . . }) gruppiert werden.
3.2.10 Wahl des Dokuments
Ist das Dokument, auf dem die Anfrage ausgeführt wird, nicht vorgegeben, so kann es mit der Methode document(’U ’) mit einer URL U als Wurzel angegeben werden.
4 DOM
Wer selber Programme zur Verarbeitung von XML-Dokumenten schreiben will kann jetzt schon auf eine große Zahl vorgefertigter Schnittstellen zugrei- fen. Als Beispiel soll hier kurz das Document Object Model (DOM ) vorge- stellt werden. Implementierungen hierfür findet man unter anderem unter xml.apache.org von IBM für Java (XML4J ) bzw. für C (XML4C ). Die allgemeine DOM-Spezifikation findet man unter [4]. Codefragmente werden hier in Java repräsentiert.
Um ein XML-Dokument zu verarbeiten erzeugt man zuerst ein DOMParser- Objekt. Diesem kann man eine entweder lokal vorhandene Datei oder eine URL zum Parsen übergeben (wahlweise validierend). Danach kann man sich vom Parser ein Document-Objekt geben lassen, das die Wurzel des Baumes, der das XML-Dokument darstellt, ist. Abbildung 5 zeigt einen solchen Baum zum Beispieldokument von Seite 6 (Abb. 2).
DOMParser parser = new DOMParser(); Document document;
parser.parse(file);
document = parser.getDocument();
Im DOM wird alles als eigener Knoten repräsentiert. Um dennoch unterscheiden zu können, um was es sich bei einem bestimmten Knoten handelt, kann man sich über die Funktion getNodeType() den Typen des Knoten geben lassen. Die wichtigsten Typen sind:
DOCUMENT_NODE Der Knoten, den man vom Parser erhält und der die Wurzel des Baumes darstellt.
ELEMENT_NODE ein normales Element - von diesem kann man z.B. eine Li- ste der Attribute (getAttributes()), den nächsten oder vorgehenden Bruder (getNextSibling() bzw. getPreviousSibling()), den Vater (getParentNode()) oder auch eine Liste aller Kinder (getChildNodes()) erhalten, so er welche hat (hasChildNodes()).
ATTRIBUTE_NODE Ein Attribut - man kann den Wert des Attributs auslesen (getNodeValue()) oder auch setzen (setNodeValue(String s)).
TEXT_NODE Ein Textknoten, also der
”Inhalt“zwischenzweiMarkierungen
- auch dessen Wert kann man mit getNodeValue() abfragen. COMMENT_NODE Ein Kommentar.
PROCESSING_INSTRUCTION_NODE Eine Bearbeitungsanweisung.
Den Namen eines Knoten erhält man mit getNodeName(). Zudem kann man einfach Knoten einfügen (z.B. mit appendChild(Node)) oder auch löschen (mit removeChild(Node)).
Mit all diesen Funktionen ist es kein Problem, auch große XML-Dokumente zu verarbeiten und sogar zu verändern (vorausgesetzt, sie sind wohlgeformt, was bei vielen Dokumenten im Internet (noch) nicht der Fall ist - ansonsten erhält man nur eine Exception).
Literatur
[1] Serge Abiteboul, Peter Buneman und Dan Suciu. Data On The Web, From Relations to Semistructured Data and XML. Morgan Kaufmann Publishers, San Mateo, CA, USA, 1999.
[2] A. Deutsch, M. Fernandez, D. Florescu, A. Levy, D. Maier und D. Suciu. Querying XML data. IEEE Data Engeneering Bulletin, 22(3):10-18, September 1999.
[3] M. Fernandez, J. Siméon, and P. Wadler. XML Query Lan- guages: Experiences and Exemplars. http://www-db.research.bell- labs.com/user/simeon/xquery.html.
[4] W3C, http://www.w3.org/TR/REC-DOM-Level-1. Document Object Model (DOM) Level 1 Specification.
[5] W3C, http://www.w3.org/TR/REC-xml. Extensible Markup Language (XML) 1.0.
[6] W3C, http://www.w3.org/TR/xsl/. Extensible Stylesheet Language (XSL) Version 1.0.
[7] W3C, http://www.w3.org/TR/REC-MathML. Mathematical Markup Language (MathML).
[8] W3C, http://www.w3.org/TR/REC-xml-names. Namespaces in XML.
[9] W3C, http://www.w3.org/TR/xhtml1. XHTMLTM 1.0: The Extensible HyperText Markup Language.
[10] W3C, http://www.w3.org/TR/xlink. XML Linking Language (XLink).
[11] W3C, http://www.w3.org/TR/xpath. XML Path Language (XPath).
[12] W3C, http://www.w3.org/TR/xptr. XML Pointer Language (XPoin- ter).
-
-
-
-
Téléchargez vos propres textes! Gagnez de l'argent et un iPhone X. -
-
Téléchargez vos propres textes! Gagnez de l'argent et un iPhone X. -
-
Téléchargez vos propres textes! Gagnez de l'argent et un iPhone X. -
-
Téléchargez vos propres textes! Gagnez de l'argent et un iPhone X. -
-
Téléchargez vos propres textes! Gagnez de l'argent et un iPhone X. -
-
Téléchargez vos propres textes! Gagnez de l'argent et un iPhone X. -
-
Téléchargez vos propres textes! Gagnez de l'argent et un iPhone X. -
-
Téléchargez vos propres textes! Gagnez de l'argent et un iPhone X. -
-
Téléchargez vos propres textes! Gagnez de l'argent et un iPhone X. -
-
Téléchargez vos propres textes! Gagnez de l'argent et un iPhone X. -
-
Téléchargez vos propres textes! Gagnez de l'argent et un iPhone X. -
-
Téléchargez vos propres textes! Gagnez de l'argent et un iPhone X. -
-
Téléchargez vos propres textes! Gagnez de l'argent et un iPhone X. -
-
Téléchargez vos propres textes! Gagnez de l'argent et un iPhone X. -
-
Téléchargez vos propres textes! Gagnez de l'argent et un iPhone X. -
-
Téléchargez vos propres textes! Gagnez de l'argent et un iPhone X. -
-
Téléchargez vos propres textes! Gagnez de l'argent et un iPhone X. -
-
Téléchargez vos propres textes! Gagnez de l'argent et un iPhone X. -
-
Téléchargez vos propres textes! Gagnez de l'argent et un iPhone X. -
-
Téléchargez vos propres textes! Gagnez de l'argent et un iPhone X. -
-
Téléchargez vos propres textes! Gagnez de l'argent et un iPhone X. -
-
Téléchargez vos propres textes! Gagnez de l'argent et un iPhone X. -
-
Téléchargez vos propres textes! Gagnez de l'argent et un iPhone X. -
-
Téléchargez vos propres textes! Gagnez de l'argent et un iPhone X. -
-
Téléchargez vos propres textes! Gagnez de l'argent et un iPhone X. -
-
Téléchargez vos propres textes! Gagnez de l'argent et un iPhone X. -
-
Téléchargez vos propres textes! Gagnez de l'argent et un iPhone X. -
-
Téléchargez vos propres textes! Gagnez de l'argent et un iPhone X.