Abstract

XML strukturiert Daten in einigen wenigen Konstrukten, hauptsächlich in Elementen und Attributen. Die Sprache XML Path Language (XPath) definiert eine Möglichkeit, wie Teile von XML-Dokumenten für die weitere Verarbeitung selektiert werden können. XPath wird hauptsächlich von XSL Transformations (XSLT) verwendet, aber auch von anderen XML-Sprachen wie etwa XML Schema. XPath ist eine sehr kompakte Sprache mit einer Syntax, die Pfadausdrücke widerspiegelt, wie sie aus Dateisystemen wohl bekannnt sind. Diese Pfadausdrücke sind jedoch generalisiert und damit sehr viel mächtiger als die vergleichsweise einfachen Pfadausdrücke für Dateisysteme. Aufgrund ihrer Verwendung in vielen verschiedenen XML-Sprachen ist XPath eine der wichtigsten XML Sprachkomponenten.

Inhalt (XPath)

  1. XPath [24]

Übersicht

Lokalisierungspfade

Ein erstes Beispiel

Grundlage für das erste Beispiel zu XPath ist eine erweiterte Version der Projektverwaltung.

<?xml version="1.0" encoding="ISO-8859-15"?>
<ProjektVerwaltung xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="F:\bsz\webseite\src\vorlesung\projektverwaltung3.xsd">
 <Person PersID="Pers01" mitarbeitInProjekt="Prj01">
  <Vorname>Hans</Vorname>
  <Nachname>Hinterhuber</Nachname>
 </Person>
 <Person PersID="Pers02" mitarbeitInProjekt="Prj02">
  <Vorname>Franz</Vorname>
  <Vorname>Xaver</Vorname>
  <Nachname>Obermüller</Nachname>
  <Qualifikationsprofil>
   <xhtml:u>IT-Kompetenz</xhtml:u>
   <xhtml:em>verschiedene</xhtml:em> Betriebssysteme und
         <Leistungsstufe>professionelle</Leistungsstufe>
   <xhtml:em>
    <Qualifikation>Programmierung</Qualifikation>
   </xhtml:em>
         verschiedener Programmiersprachen
         <xhtml:em>
    <xhtml:u>
     <Qualifikation>Entwickler</Qualifikation>
    </xhtml:u>
   </xhtml:em> von 1988-1990
         <xhtml:u>
    <Qualifikation>Projektleiterfunktion</Qualifikation>
   </xhtml:u>
         von <xhtml:b>1990-93</xhtml:b> im X42-Projekt in Abteilung AB&amp;C
      </Qualifikationsprofil>
 </Person>
 <Person PersID="Pers03" mitarbeitInProjekt="Prj02">
  <Vorname>Fritz</Vorname>
  <Nachname>Meier</Nachname>
  <Geburtsname value="Huber"/>
 </Person>
 <Projekt ID="Prj01" Projektleiter="Pers01" Mitarbeiter="Pers01"/>
 <Projekt ID="Prj02" Projektleiter="Pers02" Mitarbeiter="Pers03"/>
</ProjektVerwaltung>

Freie Lokalisierungsschritte (1/2)

Freie Lokalisierungsschritte (2/2)

Definition Lokalisierungsschritt

Ein Lokalisierungsschritt setzt sich aus dem Namen der Achse gefolgt von zwei Doppelpunkten und einem Knotentest , optional ergänzt um ein auszuwertendes Prädikat , zusammen.
Wird keine Achse spezifiziert, so gilt vorgabegemäß die Achse child .
Ein Knotentest ist syntaktisch ein QName , der genau dann erfüllt ist, wenn der Knotenname mit dem Namen des Knotentests übereinstimmt.
Das Prädikat filtert die Ergebnismenge hinsichtlich verschiedener Charakteristika wie Existenz von Kindknoten oder Attributen, Position in der Ergebnismenge, etc.

Achsen in XPath (1/2)

Achsen in XPath (2/2)

Für die einzelnen Achsen existieren darüber hinaus auch noch Feineinstufungen.
Die folgende Tabelle listet alle durch die Verwendung von Achsen zugänglichen Knotenmengen relativ zum aktuellen Knoten (Knoten 8). In der letzten Spalte ist die Knotenmenge jeweils graphisch dargestellt. der aktuelle Knoten ist jeweils rot markiert.

Achse Semantik Im Beispiel selektierte Knoten Graphik
self Lokalisiert den aktuellen Knoten. Als abkürzende Schreibweise kann der Punkt . verwendet werden. XPath-Ausdruck:
/node1/node3/node8/self::node8
Ergebnisknotenmenge : {8}
child Lokalisiert die (direkten) Kindknoten des aktuellen Knotens. XPath-Ausdruck:
/node1/node3/node8/child::*
Ergebnisknotenmenge : {12, 13, 14}
descendant Lokalisiert transitiv alle Kindknoten des aktuellen Knotens, außer Attribut- und Namensraumknoten. XPath-Ausdruck:
/node1/node3/node8/descendant::*
Ergebnisknotenmenge : {12, 13, 14, 15, 16}
descendant-or-self Lokalisiert transitiv alle Kindknoten des aktuellen Knotens (außer Attribut- und Namensraumknoten), sowie den Knoten selbst. XPath-Ausdruck:
/node1/node3/node8/descendant-or-self::*
Ergebnisknotenmenge : {8, 12, 13, 14, 15, 16}
parent Lokalisiert den Elternknoten des aktuellen Knotes, falls existent. XPath-Ausdruck:
/node1/node3/node8/parent::*
Ergebnisknotenmenge : {3}
ancestor Lokalisiert transitiv alle Elternknoten des aktuellen Knotes.
Die ancestor -Achse enthält daher immer den Wurzelknoten, außer der aktuelle Knoten ist es selbst; in diesem Falle liefert die Achse die leere Menge.
XPath-Ausdruck:
/node1/node3/node8/ancestor::*
Ergebnisknotenmenge : {1, 3}
ancestor-or-self Lokalisiert transitiv alle Elternknoten des aktuellen Knotes, sowie den aktuellen Knoten.
Diese Achse enthält immer den Wurzelknoten des Dokuments.
XPath-Ausdruck:
/node1/node3/node8/ancestor-or-self::*
Ergebnisknotenmenge : {1, 3, 8}
preceding Lokalisiert alle dem aktuellen Knoten vorausgehenden Knoten, ohne seine Vorfahren sowie Attribut- und Namensraumknoten. XPath-Ausdruck:
/node1/node3/node8/preceding::*
Ergebnisknotenmenge : {2, 5, 6, 7}
preceding-sibling Lokalisiert die im Dokument vor dem aktuellen Knoten auftretenden Geschwisterknoten. XPath-Ausdruck:
/node1/node3/node8/preceding-sibling::*
Ergebnisknotenmenge : {7}
following Lokalisiert alle dem aktuellen Knoten nachfolgenden Knoten ohne dessen Kind-, Attribut und Namensraumknoten. XPath-Ausdruck:
/node1/node3/node8/following::*
Ergebnisknotenmenge : {9, 4, 10, 11}
following-sibling Lokalisiert alle nachfolgenden „Geschwister“ des aktuellen Knotens, d.h. Knoten auf derselben Hierarchieebene. XPath-Ausdruck:
/node1/node3/node8/following-sibling::*
Ergebnisknotenmenge : {9}
attribute Lokalisiert Attribut(e) eines Knotens. XPath-Ausdruck:
/node1/node3/node8/attribute::*
Ergebnisknotenmenge : {Att1}
namespace Lokalisiert Namensraum-Attribute eines Knotens. XPath-Ausdruck:
/node1/node3/node8/namespace::*
Ergebnisknotenmenge : {xmlns:xml="http://www.w3.org/XML/1998/namespace", xmlns:x="namespace:www.jeckle.de/vorlesung/xml"}

Filtern mit Prädikaten

Filtern mit Prädikaten - ein erstes Beispiel

Wird der folgende XPath-Ausdruck auf unser Beispiel der Projektverwaltung angewendet...

//Person[Qualifikationsprofil]/Nachname

... so erhält man folgendes Ergebnis:

<Nachname>Obermüller</Nachname>

Die einzelnen Schritte im Überblick:

Anmerkung : Das Beispiel nutzt im Prädikat die abkürzende Schreibweise zur Angabe der Vorgabeachse child . Die ausführliche Schreibweise des XPath-Ausdruckes lautet: //Person[child::Qualifikationsprofil]/Nachname

Filtern mit Prädikaten - erweitertes Beispiel

Das folgende Beispiel zeigt die Verwendung von Prädikaten bei mehreren Lokalisierungsschritten. Folgende Aufgabe soll gelöst werden:
Auswählen aller Vorname n als Kinder von Person en-Knoten, deren Nachname mit dem Buchstaben O beginnt. Weitere Einschränkung: die Person en-Knoten müssen ihrerseits Kinder von Knoten des Typs Projektverwaltung sein.

  1. Auswählen aller Knoten des Typs Person an beliebiger Stelle des Dokuments.
    //Person
    <Person PersID="Pers01" mitarbeitInProjekt="Prj01"> ... </Person>
    <Person PersID="Pers02" mitarbeitInProjekt="Prj02"> ... </Person>
    <Person PersID="Pers03" mitarbeitInProjekt="Prj02"> ... </Person>
  2. Einschränken der Knotenmenge auf nur diejenigen Personen, die Kindelemente von Projektverwaltung sind.
    //Person[parent::ProjektVerwaltung]
    <Person PersID="Pers01" mitarbeitInProjekt="Prj01"> ... </Person>
    <Person PersID="Pers02" mitarbeitInProjekt="Prj02"> ... </Person>
    <Person PersID="Pers03" mitarbeitInProjekt="Prj02"> ... </Person>
  3. Auswählen aller Vorname n, die Kindelemente von Person sind.
    //Person[parent::ProjektVerwaltung]/Vorname
    <Vorname>Hans</Vorname>
    <Vorname>Franz</Vorname>
    <Vorname>Xaver</Vorname>
    <Vorname>Fritz</Vorname>
  4. Einschränken der Knotenmenge auf nur diejenigen Vornamen, auf die im Dokument ein Geschwisterelement Nachname folgt.
    //Person[parent::ProjektVerwaltung]/Vorname[following-sibling::Nachname]
    <Vorname>Hans</Vorname>
    <Vorname>Franz</Vorname>
    <Vorname>Xaver</Vorname>
    <Vorname>Fritz</Vorname>
  5. Verwendung der vordefinierten Funktion starts-with zur zusätzlichen Formulierung der Einschränkung, daß der Nachname mit dem Buchstaben O beginnen muß.
    //Person[parent::ProjektVerwaltung] / Vorname[starts-with(following-sibling::Nachname,'O')]
    <Vorname>Franz</Vorname>
    <Vorname>Xaver</Vorname>

In XPath vordefinierte Funktionen (1/5)

XPath-Funktionen für Knotenmengen (node-sets)

Funktionsprototyp Funktionalität
number last() Liefert die Größe der aktuellen Knotenmenge; damit den Index des letzten Elements.
number position() Liefert die Position des aktuellen Knotens innerhalb der Knotenmenge. Der erste Knoten trägt die Positionsnummer 1.
number count( node-set ) Gibt die Anzahl der Elemente der übergebenen Knotenmenge zurück.
node-set id( object ) Liefert denjenigen Knoten, dessen ID-typisiertes Attribut den Argumentwert aufweist.
Anmerkung: Zur Nutzung dieser Funktion muß zwingend eine Dokument-Grammatik (DTD oder Schema) zum Eingangsdokument vorliegen.
string local-name ( node-set? ) Liefert den lokalen Namen (oder die Menge der Namen) der übergebenen Knotenmenge. Wird keine Knotenmenge übergeben, dann wird der aktuelle Knoten als Argument genutzt.
string namespace-uri ( node-set? ) Gibt die Namensraum-URI der übergebenen Knotenmenge zurück. Wird keine Knotenmenge übergeben, dann wird der aktuelle Knoten als Argument genutzt.
Anmerkung: Handelt es sich nicht um einen Element- oder Attributknoten, so ist die zurückgegebene Zeichenkette leer.
string name ( node-set? ) Liefert die qualifizierten Namen (gebildet aus Namensraumkürzel und lokalem Namen) der übergebenen Knotenmenge, oder des aktuellen Knotens bei leerer Knotenmenge.
Anmerkung: Nur für Element- und Attributknoten liefert name andere Resultate als local-name .

In XPath vordefinierte Funktionen (2/5)

XPath-Funktionen für Zeichenketten

Funktionsprototyp Funktionalität
string string ( object? ) Liefert Zeichenkettenrepräsentation einer Knotenmenge. Dabei wird der Zeichenkettenwert des ersten Knotens in der Dokumentreihenfolge zurückgegeben, andernfalls die leere Zeichenkette.
string concat ( string , string , string* ) Verkettet mindestens zwei Zeichenketten.
boolean starts-with ( string1 , string2 ) Liefert true , falls string1 das zweite Argument string2 als Präfix enthält; andernfalls false .
boolean contains ( string1 , string2 ) Liefert true falls string1 die Zeichenkette aus string2 enthält; andernfalls false .
string substring-before ( string1 , string2 ) Liefert denjenigen Teil der Zeichenkette string1 , der sich vor dem ersten Auftreten der Zeichenkette string2 befindet.
string substring-after ( string1 , string2 ) Liefert denjenigen Teil der Zeichenkette string1 , der sich nach dem ersten Auftreten der Zeichenkette string2 befindet.
string substring ( string , number1 , number2? ) Liefert eine Zeichenkette der Länge number2 aus string , beginnend mit der Position number1 . Fehlt das dritte Argument, so wird der Teilstring bis zum Ende der Zeichenkette string zurückgegeben.
Anmerkung: Das erste Zeichen trägt die Indexnummer 1, nicht 0 wie in Java und C üblich.
number string-length( string? ) Liefert die Länge der übergebenen Zeichenkette. Wird kein Argument übergeben, so wird die Länge des zuvor in eine Zeichenkette konvertierten aktuellen Knotens zurückgegeben.
string normalize-space ( string? ) Liefert die übergebene Zeichenkette unter Entfernung führender, schließender und mehrfacher Leerzeichen zurück. Ferner werden noch evtl. in der Argumentzeichenkette enthaltenen Entitätsreferenzen aufgelöst.
Anmerkung: Der Normalisierungsvorgang entspricht damit der Attributwertenormalisierung nach Abschnitt 3.3.3 der XML-Spezifikation .
string translate ( string1 , string2 , string3 ) Liefert die Zeichenkette string1 , wobei jedes Zeichen aus string2 durch das Zeichen an derselben Position aus string3 ersetzt wurde.

In XPath vordefinierte Funktionen (3/5)

Boole'sche XPath-Funktionen

Funktionsprototyp Funktionalität
boolean boolean ( object ) Liefert die Boole'sche Repräsentation des übergebenen Arguments.
Hierbei gilt:
  • Eine Zahl wird genau dann nach true konvertiert, wenn sie weder Null (unbeachtlich ihres Vorzeichens) noch eine nicht darstellbare Zahl ( NaN ) ist.
  • Eine Knotenmenge ergibt true , wenn sie nicht leer ist.
  • Eine Zeichenkette ergibt true , wenn sie nicht leer (d.h. Länge größer Null) ist.
  • Die Konvertierung anderer Typen ist typabhängig, und nicht durch den Standard festgelegt.
boolean not ( boolean ) Negiert das übergebene Argument.
boolean true() Liefert statisch den Wert true .
boolean false() Liefert statisch den Wert false .
boolean lang ( string ) Liefert true , wenn der aktuelle Knoten ein xml:lang -Attribut gemäß der als Argument übergebenen Sprache besitzt.

In XPath vordefinierte Funktionen (4/5)

Zahlenorientierte XPath-Funktionen

Funktionsprototyp Funktionalität
number number ( object? ) Konvertiert ein Objekt in eine Zahl gemäß folgender Regeln:
  • Eine Zeichenkette wird in eine Fließkommazahl gemäß IEEE 754 konvertiert, wenn sie aus einem optionalen Leerzeichen, gefolgt durch ein optionales Minuszeichen, gefolgt von einem optionalen Leerzeichen und einer Ziffernfolge besteht.
  • Der Boole'sche Wert true wird zu 1 , der Wert false zu 0 konvertiert.
  • Eine Knotenmenge wird zunächst in eine Zeichenkette übersetzt, und dann gemäß der oben definierten Regeln umgesetzt.
  • Die Konvertierung anderer Typen erfolgt typabhängig, und ist nicht durch den Standard geregelt.
Wird kein Argument übergeben, so wird stattdessen der aktuelle Knoten als einziges Element einer Knotenmenge interpretiert.
number sum ( node-set ) Liefert die Summe aller Elemente der übergebenen Knotenmenge, die zuvor in eine Zahl konvertiert werden.
number floor ( number ) Liefert die größte ganze Zahl, die nicht größer als das Argument ist.
Beispiele: floor(7.4)=7 , floor(−5)=−5 und floor(−5.4)=−6 .
number ceiling ( number1 ) Liefert die kleinste ganze Zahl, die nicht kleiner als das Argument ist.
Beispiele: ceiling(7.4)=8 , ceiling(−5)=−5 und ceiling(−5.4)=−5 .
number round ( number ) Liefert das Argument auf die nächste ganze Zahl gerundet. Gibt es zwei solche -- wie bei Nachkommastelle gleich 0.5 immer der Fall -- so wird die größere zurückgeliefert.

In XPath vordefinierte Funktionen (5/5)

Mathematische Operatoren

Funktionsprototyp Funktionalität
+ Addition
- Subtraktion
Anmerkung: Weil XML in Elementnamen den Bindestrich erlaubt, muß dieser Operator in einem Ausdruck immer durch Leerzeichen von den Operanden getrennt werden, andernfalls wird der gesamte Ausdruck als Name gewertet.
* Multiplikation
Außer wenn innerhalb von XPath-Ausdrücken als Knotentest eingesetzt.
div Division
Achtung: Das Symbol / dient ausschließlich als Trennzeichen innerhalb Lokalisierungspfaden!
mod Modulo
Rest einer ganzzahligen Division.
Beispiel: 5 mod 2 ergibt 1 und -5 mod 2 ergibt -1 .

Ein umfangreiches Beispiel

Für das nachfolgende umfangreichere Beispiel wird die folgende erweiterte Projektverwaltung betrachtet:

<?xml version="1.0" encoding="UTF-8"?>
<ProjektVerwaltung xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="L:\vorlesung\src\projektverwaltung-erweitert.xsd">
 <Person PersID="Pers01" mitarbeitInProjekt="Prj01">
  <Vorname>Hans</Vorname>
  <Nachname>Hinterhuber</Nachname>
 </Person>
 <Person PersID="Pers02" mitarbeitInProjekt="Prj02">
  <Vorname>Franz</Vorname>
  <Vorname>Xaver</Vorname>
  <Nachname>Obermüller</Nachname>
  <Qualifikationsprofil>
   <xhtml:u>IT-Kompetenz</xhtml:u>
   <xhtml:em>verschiedene</xhtml:em> Betriebssysteme und
         <Leistungsstufe>professionelle</Leistungsstufe>
   <xhtml:em>
    <Qualifikation>Programmierung</Qualifikation>
   </xhtml:em>
         verschiedener Programmiersprachen
         <xhtml:em>
    <xhtml:u>
     <Qualifikation>Entwickler</Qualifikation>
    </xhtml:u>
   </xhtml:em> von 1988-1990
         <xhtml:u>
    <Qualifikation>Projektleiterfunktion</Qualifikation>
   </xhtml:u>
         von <xhtml:b>1990-93</xhtml:b> im X42-Projekt in Abteilung AB&amp;C
      </Qualifikationsprofil>
 </Person>
 <Person PersID="Pers03" mitarbeitInProjekt="Prj02">
  <Vorname>Fritz</Vorname>
  <Nachname>Meier</Nachname>
  <Geburtsname value="Huber"/>
 </Person>
 <Projekt ID="Prj01" Projektleiter="Pers01" Mitarbeiter="Pers01"/>
 <Projekt ID="Prj02" Projektleiter="Pers02" Mitarbeiter="Pers03"/>
</ProjektVerwaltung>

Ein umfangreiches Beispiel

Folgende Aufgabe soll gelöst werden:
Welchen Knoten im Dokument lokalisiert folgender XPath-Ausdruck:

//Person[count(Vorname)=1]/ Nachname[following-sibling::Geburtsname[@value]]/ parent::Person/@mitarbeitInProjekt

Schrittweises Nachverfolgen der einzelnen Lokalisierungsschritte und Filterungen:

Der XPath-Ausdruck lokalisiert den Attributknoten mitarbeitInProjekt von Person 3 mit dem Wert Prj02 .

XPath - Übungen

Welches Ergebnis liefern folgende XPath-Ausdrücke?

//Person[//child::Qualifikationsprofil]/Nachname
<Nachname>Hinterhuber</Nachname>
<Nachname>Obermüller</Nachname>
<Nachname>Meier</Nachname>
//Person[parent::ProjektVerwaltung]/Vorname[following-sibling::Vorname]
<Vorname>Franz</Vorname>
/ProjektVerwaltung/Person[attribute::PersID='Pers01']//Nachname
<Nachname>Hinterhuber</Nachname>

Anwendungsbeispiel: Integritätsbedingungen in XML-Schema (1/4)

Anwendungsbeispiel XML-Schema: Unique-Einschränkung (2/4)

Im folgenden Beispiel wird das unique -Element verwendet, um zu formulieren, daß das Attribut PersID des Elements Person eindeutig sein muß (dies entspricht -- noch -- der bisherigen ID-Typisierung).

<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema 
 xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
 elementFormDefault="qualified" 
 attributeFormDefault="unqualified">
<xsd:element name="ProjektVerwaltung">
 <xsd:complexType>
  <xsd:sequence>
   <xsd:element name="Person" type="PersonType" maxOccurs="unbounded"/>
   <xsd:element name="Projekt" type="ProjektType" maxOccurs="unbounded"/>
  </xsd:sequence>
  <xsd:attribute name="version" type="xsd:string" fixed="1.0"/>
 </xsd:complexType>
 <xsd:unique name="uniquenessPersID">
  <xsd:selector xpath="Person"/>
  <xsd:field xpath="@PersID"/>
 </xsd:unique>
</xsd:element>

<xsd:complexType name="PersonType">
 <xsd:attribute name="PersID" type="xsd:token"/>
</xsd:complexType>

<xsd:complexType name="ProjektType"/>

</xsd:schema>

Anwendungsbeispiel XML-Schema: Zusammengesetzter Schlüssel innerhalb eines unique-Elements (3/4)

Das nächste Beispiel zeigt die Verwendung mehrerer field - Elemente zur Realisierung zusammengesetzter Schlüssel.

<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema 
 xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
 elementFormDefault="qualified" 
 attributeFormDefault="unqualified">
<xsd:element name="ProjektVerwaltung">
 <xsd:complexType>
  <xsd:sequence>
   <xsd:element name="Person" type="PersonType" maxOccurs="unbounded"/>
   <xsd:element name="Projekt" type="ProjektType" maxOccurs="unbounded"/>
  </xsd:sequence>
  <xsd:attribute name="version" type="xsd:string" fixed="1.0"/>
 </xsd:complexType>
 <xsd:unique name="uniquenessPersID">
  <xsd:selector xpath="Person"/>
  <xsd:field xpath="Vorname"/>
  <xsd:field xpath="Nachname"/>
 </xsd:unique>
</xsd:element>

<xsd:complexType name="PersonType">
 <xsd:sequence>
  <xsd:element name="Vorname" type="xsd:token" minOccurs="1" maxOccurs="unbounded"/>
  <xsd:element name="Nachname" type="xsd:token" maxOccurs="1"/> 
 </xsd:sequence>
</xsd:complexType>

<xsd:complexType name="ProjektType"/>

</xsd:schema>

Anwendungsbeispiel XML-Schema: Referenzierung, Einschränkung der Referenzmenge (4/4)

Mit Hilfe der XML-Schema-Elemente key und keyref ist es möglich, Referenzen auf bestimmte Referenzmengen einzuschränken. Hiermit kann sichergestellt werden, daß als Werte eines Attributs mitarbeitInProjekt auch wirklich nur auf Schlüssel verwiesen werden kann, die für ein Projekt definiert wurden. Damit ist es im Gegensatz zu DTDs nicht mehr möglich, an dieser Stelle auf IDs von Personen zu verweisen.

<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema 
 xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
 elementFormDefault="qualified" 
 attributeFormDefault="unqualified">
 <xsd:element name="ProjektVerwaltung">
  <xsd:complexType>
   <xsd:sequence>
    <xsd:element name="Person" type="PersonType" maxOccurs="unbounded"/>
    <xsd:element name="Projekt" type="ProjektType" maxOccurs="unbounded"/>
   </xsd:sequence>
   <xsd:attribute name="version" type="xsd:string" fixed="1.0"/>
  </xsd:complexType>
  
  <xsd:key name="projectKey">
   <xsd:selector xpath="Projekt"/>
   <xsd:field xpath="@ID"/>
  </xsd:key>
  <xsd:keyref name="projectReference" refer="projectKey">
   <xsd:selector xpath="Person"/>
   <xsd:field xpath="@mitarbeitInProjekt"/>
  </xsd:keyref>
 </xsd:element>
 
 <xsd:complexType name="PersonType">
  <xsd:attribute name="mitarbeitInProjekt" type="xsd:token"/>
 </xsd:complexType>
 <xsd:complexType name="ProjektType">
  <xsd:attribute name="ID" type="xsd:token"/>
 </xsd:complexType>
</xsd:schema>

Vorteile gegenüber ID/IDREF

Zusammenfassend lassen sich folgende Vorteile gegenüber dem ID/IDREF -Mechanismus festhalten: