XSD (XML Schema Definition)

+ andere TechDocs
+ XML
+ JAXB (Binding)
+ XSL, XSLT, XSL-FO
+




Inhalt

  1. Begriffe und Übersicht
  2. Vorwort zu den folgenden Beispielen
  3. "Russian Doll Design" ("Matrjoschka", geschachteltes Baumstruktur-Schema)
  4. "Salami Slice Design" (Schema mit Referenzen auf global deklarierte Elemente)
  5. "Venetian Blind Design" (Schema mit global deklarierten benannten Typen)
  6. Import eines anderen Schemas mit anderem Namespace
  7. Eindeutige ID ("unique") und Aufzählungstyp ("enumeration")
  8. Beziehungen mit "ID" und "IDREF"
  9. Beziehungen mit "key" und "keyref"
  10. XSD-Validierung per Java
  11. XSD-Validierung per Java mit Multithreading über threadsichere Schema-Klasse
  12. JAXB (Java Architecture for XML Binding)


Begriffe und Übersicht

XML Schema,
XSD (XML Schema Definition),
XSI (XML Schema Instanz)

XML Schema definiert Art und Struktur von XML-Dokumenten und den enthaltenen Elementen und ermöglicht eine Validierung. Ein XML Schema wird als XML Schema Definition in einer XML-Datei üblicherweise mit der Dateiendung .xsd gespeichert. XML Schemas sind wesentlich leistungsfähiger als DTDs und ersetzen diese zunehmend.

Eine einfaches XSD-Schema kann zum Beispiel so aussehen:

<?xml version="1.0" encoding="ISO-8859-1"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           xmlns="http://meinnamespace.meinefirma.de"
           targetNamespace="http://meinnamespace.meinefirma.de"
           elementFormDefault="qualified">
  <xs:element name="MeinRootElement">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="MeinUnterElement" type="xs:string" />
      </xs:sequence>
    </xs:complexType>
  </xs:element>
</xs:schema>

Der xmlns:xs-Namensraum muss für XSD immer wie angegeben definiert werden. Der Bezeichner xs könnte auch anders gewählt werden (z.B. xsd).
xmlns definiert den Default-Namespace dieser XSD-Schema-Datei (ein Default-Namespace gilt nur für Elemente und nicht für Attribute).
Der targetNamespace muss dem im Ziel-Instanzdokument verwendeten Namespace entsprechen.
In einfachen Fällen können die xmlns- und targetNamespace-Angaben auch entfallen.

Ein einfaches dieses Schema verwendendes XML-Dokument (eine so genannte "Instanz") kann zum Beispiel so aussehen:

<?xml version="1.0" encoding="ISO-8859-1"?>
<MeinRootElement xmlns="http://meinnamespace.meinefirma.de"
                 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                 xsi:schemaLocation="http://meinnamespace.meinefirma.de
                                     http://www.meinefirma.de/MeinSchema.xsd">
  <MeinUnterElement>
     Elementinhalt
  </MeinUnterElement>
</MeinRootElement>

xmlns definiert den Default-Namespace der Elemente in dieser XML-Datei (ein Default-Namespace gilt nur für Elemente und nicht für Attribute).
Der xmlns:xsi-Namensraum muss für XSI immer wie angegeben definiert werden.
xsi:schemaLocation enthält zwei durch Leerzeichen getrennte Teile: Zuerst wird der im XSD-Schema definierte targetNamespace angegeben und dann die Datei des XSD-Schemas, entweder als Datei im lokalen Dateisystem oder alternativ wie hier im Beispiel als URL (die in diesem Fall natürlich auf eine tatsächlich vorhandene und verfügbare Datei verweisen muss).

Sie können solche Beispiel-XML-Instanzdokumente zu einer Schema-XSD-Datei übrigens auch leicht mit Eclipse automatisch generieren lassen. Plazieren Sie eine beliebige Schema-XSD-Datei in das Verzeichnis eines Eclipse-Projekts und je nach Eclipse-Version müssen Sie:
entweder im Eclipse Package Explorer (oder Project Explorer) mit der rechten Maustaste auf die Schema-XSD-Datei klicken und Generate | XML File... wählen,
oder Sie müssen wählen: File | New | Other… | XML | XML File | Next | Next | Create XML file from an XML schema file.
Falls Sie als Schema-XSD-Datei obiges Beispiel wählen, sieht das generierte XML-Ergebnis dem gezeigten XML-Beispiel sehr ähnlich.

Mit Eclipse können Sie auch die Validierung testen: Speichern Sie das oben gezeigte XSD-Schema in MeinSchema.xsd und das XML-Instanzdokument in MeinDokument.xml, ändern Sie in MeinDokument.xml die Schema-Location von http://www.meinefirma.de/MeinSchema.xsd zu MeinSchema.xsd und wählen Sie in Eclipse "Validate", indem Sie mit der rechten Maustaste entweder auf den Verzeichnisnamen oder auf den Dateinamen oder in das XML-Instanzdokument klicken.

Wenn Sie innerhalb eines Java-Programms validieren möchten, können Sie beispielsweise DocumentBuilderFactory.setSchema(), SAXParserFactory.setSchema() oder Validator.validate() verwenden (siehe auch XsdValidation.java).

Eine erste Einführung zum XML Schema finden Sie unter http://de.wikipedia.org/wiki/XML_Schema. Genaueres finden Sie im englischen Original in der W3C XML Schema Specification unter http://www.w3.org/XML/Schema oder ins deutsche übersetzt unter Einführung, Strukturen und Datentypen.

Java-Klassen hierzu finden Sie in http://docs.oracle.com/javase/7/docs/api/javax/xml/validation/package-summary.html



Vorwort zu den folgenden Beispielen

Bitte beachten Sie die Encoding-Angaben. Wenn Ihr Editor nicht mit dem in den Beispielen meistens angegebenen "ISO-8859-1"-Encoding speichert, müssen Sie die Encoding-Angaben entsprechend ändern.



"Russian Doll Design" ("Matrjoschka", geschachteltes Baumstruktur-Schema)

Speichern Sie folgendes XML-Instanzdokument: Adr1.xml

<?xml version="1.0" encoding="ISO-8859-1"?>
<adressen xmlns="http://meinnamespace.meinefirma.de"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://meinnamespace.meinefirma.de AdrSchemaGeschachtelt.xsd">
   <adresse>
      <name>Torsten Horn</name>
      <strasse>Meinestr. 42</strasse>
      <plz>52072</plz>
      <ort>Aachen</ort>
   </adresse>
   <adresse datum="2009-11-11">
      <firma />
      <name>Ich AG</name>
      <postfach>4711</postfach>
   </adresse>
</adressen>

xmlns definiert den Default-Namespace der Elemente in dieser XML-Datei.

Der xmlns:xsi-Namensraum muss für XSI immer wie angegeben definiert werden (siehe auch Liste der XML-Namensräume).

xsi:schemaLocation enthält zwei durch Leerzeichen getrennte Teile: Zuerst wird der im XSD-Schema definierte targetNamespace angegeben und dann die Datei des XSD-Schemas, entweder als Datei im lokalen Dateisystem (wie hier im Beispiel) oder alternativ als URL (die anders als die Namespace-URLs dann natürlich auf eine tatsächlich vorhandene und verfügbare Datei verweisen muss).

Das XML-Instanzdokument enthält als Rootelement eine adressen-Liste, die beliebig viele adresse-Elemente enthält. Das name-Element ist in allen Adressen enthalten, aber andere Elemente sind nicht in allen Adressen enthalten. Die zweite Adresse enthält nicht nur Elemente, sondern das adresse-Start-Tag beinhaltet zusätzlich ein datum-Attribut. Außerdem enthält diese Adresse das leere firma-Element, welches signalisieren soll, dass es sich um eine Firma handelt. Bitte beachten Sie, dass als XSD-Schema die Datei AdrSchemaGeschachtelt.xsd eingetragen ist.

Speichern Sie folgendes XSD-Schema: AdrSchemaGeschachtelt.xsd

<?xml version="1.0" encoding="ISO-8859-1"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           xmlns="http://meinnamespace.meinefirma.de"
           targetNamespace="http://meinnamespace.meinefirma.de"
           elementFormDefault="qualified">
   <xs:element name="adressen">
   <xs:complexType>
      <xs:sequence>
         <xs:element name="adresse" minOccurs="0" maxOccurs="unbounded">
         <xs:complexType>
            <xs:sequence>
               <xs:element name="firma" minOccurs="0"> <xs:complexType /> </xs:element>
               <xs:element name="name"  type="xs:string" />
               <xs:choice>
                  <xs:element name="strasse"  type="xs:string" minOccurs="0" />
                  <xs:element name="postfach" type="xs:positiveInteger" minOccurs="0" />
               </xs:choice>
               <xs:element name="plz" type="xs:positiveInteger" minOccurs="0" />
               <xs:element name="ort" type="xs:string" minOccurs="0" />
            </xs:sequence>
            <xs:attribute name="datum" type="xs:date" />
         </xs:complexType>
         </xs:element>
      </xs:sequence>
   </xs:complexType>
   </xs:element>
</xs:schema>

Das Besondere beim "Russian Doll Design" ("Matrjoschka") ist die Schachtelung mit lokalen Definitionen, deren Baumstruktur der des XML-Instanzdokuments entspricht. Es gibt nur ein globales Element mit ausschließlich anonymen Inline-Typdefinitionen für direkt und indirekt untergeordnete Elemente und Attribute. Solche Baumstruktur-Schemas sind bei kleinen XML/XSD-Dateien einfacher und schneller zu verstehen, aber für größere Projekte meistens weniger gut geeignet.

XSD-Schema-Dateien sind XML-Dateien. Das Rootelement muss schema lauten (siehe auch Listen der XML Schema Elemente und Attribute und einführende Erläuterungen zum XML Schema bei Wikipedia).

Der xmlns:xs-Namensraum muss für XSD immer wie angegeben definiert werden (siehe auch Liste der XML-Namensräume). Der Bezeichner xs könnte auch anders gewählt werden (z.B. xsd).

xmlns definiert den Default-Namespace dieser XSD-Schema-Datei.

Der targetNamespace muss dem im Ziel-Instanzdokument verwendeten Namespace entsprechen.

In einfachen Fällen können die targetNamespace- und xmlns-Angaben auch entfallen, siehe zum Beispiel Java-Codegenerierung aus XSD mit JAXB.

elementFormDefault: Wenn es Kindselemente gibt (wie immer bei geschachtelten Schemas) und diese lokalen Unterelemente ebenfalls den xmlns-Default-Namespace erhalten sollen, dann muss elementFormDefault="qualified" gesetzt werden (siehe auch Hide (Localize) Namespaces Versus Expose Namespaces).

element: Definiert die einzelnen XML-Elemente.

complexType: Definiert kompliziertere Elemente, z.B. Elemente mit Kindelementen und/oder Attributen. Beachten Sie, dass auch das leere firma-Element als complexType definiert wird, allerdings als leerer. Falls außer Kindelementen und/oder Attributen auch ein Elementinhalt erlaubt sein soll, muss mixed="true" gesetzt werden.

sequence: Definiert eine geordnete Struktur mit fester Reihenfolge. Die Alternative wäre all.

choice: Definiert eine Auswahl: Nur eins der genannten Elemente darf verwendet werden (entweder strasse oder postfach).

minOccurs und maxOccurs: Wenn diese Angaben fehlen, muss das Element genau einmal vorhanden sein. minOccurs="0" erlaubt das Fehlen dieses Elements. maxOccurs="unbounded" erlaubt eine beliebige Anzahl der Elemente.

attribute: Definiert Attribute (alternativ zum element).

xs:string, xs:positiveInteger, xs:date: Vordefinierte Datentypen.

Testen Sie die Validierung mit einem beliebigen XML-Validierungstool. Zum Beispiel mit Eclipse, indem Sie mit der rechten Maustaste in das XML-Instanzdokument klicken und "Validate" wählen. Oder mit XsdValidation.java:

java XsdValidation AdrSchemaGeschachtelt.xsd Adr1.xml



"Salami Slice Design" (Schema mit Referenzen auf global deklarierte Elemente)

Speichern Sie folgendes XML-Instanzdokument: Adr2.xml

<?xml version="1.0" encoding="ISO-8859-1"?>
<adressen xmlns="http://meinnamespace.meinefirma.de"
          xmlns:mns="http://meinnamespace.meinefirma.de"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://meinnamespace.meinefirma.de AdrSchemaSalami.xsd">
   <adresse>
      <name>Torsten Horn</name>
      <strasse>Meinestr. 42</strasse>
      <plz>52072</plz>
      <ort>Aachen</ort>
   </adresse>
   <adresse mns:datum="2009-11-11">
      <firma />
      <name>Ich AG</name>
      <postfach>4711</postfach>
   </adresse>
</adressen>

Adr2.xml ist sehr ähnlich wie obige Adr1.xml und enthält denselben Nutzinhalt. Diesmal ist als XSD-Schema AdrSchemaSalami.xsd eingetragen. Bitte beachten Sie außerdem, dass zusätzlich zum xmlns-Default-Namespace über xmlns:mns=... noch ein mns-Namespace definiert wird, der dem datum-Attribut vorangestellt wird, weil andernfalls ein Attribut ohne Namespace-Prefix zu keinem Namensraum gehören würde, da Attribute nicht automatisch dem Default-Namensraum zugeordnet werden.

Speichern Sie folgendes XSD-Schema: AdrSchemaSalami.xsd

<?xml version="1.0" encoding="ISO-8859-1"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           xmlns="http://meinnamespace.meinefirma.de"
           targetNamespace="http://meinnamespace.meinefirma.de">
   <xs:element name="adressen">
      <xs:complexType>
         <xs:sequence>
            <xs:element ref="adresse" minOccurs="0" maxOccurs="unbounded" />
         </xs:sequence>
      </xs:complexType>
   </xs:element>
   <xs:element name="adresse">
      <xs:complexType>
         <xs:sequence>
            <xs:element ref="firma" minOccurs="0" />
            <xs:element ref="name" />
            <xs:choice>
               <xs:element ref="strasse"  minOccurs="0" />
               <xs:element ref="postfach" minOccurs="0" />
            </xs:choice>
            <xs:element ref="plz" minOccurs="0" />
            <xs:element ref="ort" minOccurs="0" />
         </xs:sequence>
         <xs:attribute ref="datum" />
      </xs:complexType>
   </xs:element>
   <xs:element   name="firma">   <xs:complexType /> </xs:element>
   <xs:element   name="name"     type="xs:string" />
   <xs:element   name="strasse"  type="xs:string" />
   <xs:element   name="postfach" type="xs:positiveInteger" />
   <xs:element   name="plz"      type="xs:positiveInteger" />
   <xs:element   name="ort"      type="xs:string" />
   <xs:attribute name="datum"    type="xs:date" />
</xs:schema>

Das Besondere beim "Salami Slice Design" ist das wenig geschachtelte Schema mit Referenzen auf viele global deklarierte Elemente und Attribute ("global" bedeutet: direkte Kinder des schema-Rootelements). Die Kindselemente werden nicht lokal definiert, sondern per ref referenziert. Das Salami Slice Design ähnelt der Vorgehensweise bei DTDs.

Testen Sie die Validierung mit einem beliebigen XML-Validierungstool. Zum Beispiel mit Eclipse, indem Sie mit der rechten Maustaste in das XML-Instanzdokument klicken und "Validate" wählen. Oder mit XsdValidation.java:

java XsdValidation AdrSchemaSalami.xsd Adr2.xml



"Venetian Blind Design" (Schema mit global deklarierten benannten Typen)

Normale Variante mit elementFormDefault="qualified"

Speichern Sie folgendes XML-Instanzdokument: Adr3.xml

<?xml version="1.0" encoding="ISO-8859-1"?>
<adressen xmlns="http://meinnamespace.meinefirma.de"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://meinnamespace.meinefirma.de AdrSchemaVenetianBlind.xsd">
   <adresse>
      <name>Torsten Horn</name>
      <strasse>Meinestr. 42</strasse>
      <plz>52072</plz>
      <ort>Aachen</ort>
   </adresse>
   <adresse datum="2009-11-11">
      <firma />
      <name>Ich AG</name>
      <postfach>4711</postfach>
   </adresse>
</adressen>

Adr3.xml ist sehr ähnlich wie obige Adr1.xml und Adr2.xml und enthält denselben Nutzinhalt. Diesmal ist als XSD-Schema AdrSchemaVenetianBlind.xsd eingetragen.

Speichern Sie folgendes XSD-Schema: AdrSchemaVenetianBlind.xsd

<?xml version="1.0" encoding="ISO-8859-1"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           xmlns="http://meinnamespace.meinefirma.de"
           targetNamespace="http://meinnamespace.meinefirma.de"
           elementFormDefault="qualified">

   <xs:element name="adressen">
      <xs:complexType>
         <xs:sequence>
            <xs:element name="adresse" type="adresseType" minOccurs="0" maxOccurs="unbounded" />
         </xs:sequence>
      </xs:complexType>
   </xs:element>

   <xs:complexType name="adresseType">
      <xs:sequence>
         <xs:element name="firma" minOccurs="0"> <xs:complexType /> </xs:element>
         <xs:element name="name"  type="xs:string" />
         <xs:choice>
            <xs:element name="strasse"  type="xs:string" minOccurs="0" />
            <xs:element name="postfach" type="xs:positiveInteger" minOccurs="0" />
         </xs:choice>
         <xs:element name="plz" type="xs:positiveInteger" minOccurs="0" />
         <xs:element name="ort" type="xs:string" minOccurs="0" />
      </xs:sequence>
      <xs:attribute name="datum" type="xs:date" />
   </xs:complexType>

</xs:schema>

Das Besondere beim "Venetian Blind Design" ist, dass es (meistens) nur ein einziges global definiertes Element gibt, aber (meistens) viele global definierte benannte Typen (in diesem sehr einfachen Beispiel nur einen, aber weiter unten finden Sie Beispiele mit mehreren). Auch wenn es in diesem einfachen Beispiel nicht so deutlich wird, ist das Venetian Blind Design in den meisten Fällen die sinnvollste Variante (siehe auch Global versus Local):

Die drei genannten Design-Varianten können auch gemischt auftreten.

Testen Sie die Validierung mit einem beliebigen XML-Validierungstool. Zum Beispiel mit Eclipse, indem Sie mit der rechten Maustaste in das XML-Instanzdokument klicken und "Validate" wählen. Oder mit XsdValidation.java:

java XsdValidation AdrSchemaVenetianBlind.xsd Adr3.xml

Alternative Variante ohne elementFormDefault="qualified"

Alternativ könnte das "Venetian Blind Design"-Schema auch ohne elementFormDefault="qualified" formuliert werden. Dann könnten die XML- und die XSD-Dateien folgendermaßen aussehen:

Adr3-b.xml

<?xml version="1.0" encoding="ISO-8859-1"?>
<mns:adressen xmlns:mns="http://meinnamespace.meinefirma.de"
              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xsi:schemaLocation="http://meinnamespace.meinefirma.de AdrSchemaVenetianBlind-b.xsd">
   <adresse>
      <name>Torsten Horn</name>
      <strasse>Meinestr. 42</strasse>
      <plz>52072</plz>
      <ort>Aachen</ort>
   </adresse>
   <adresse datum="2009-11-11">
      <firma />
      <name>Ich AG</name>
      <postfach>4711</postfach>
   </adresse>
</mns:adressen>

AdrSchemaVenetianBlind-b.xsd

<?xml version="1.0" encoding="ISO-8859-1"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           xmlns="http://meinnamespace.meinefirma.de"
           targetNamespace="http://meinnamespace.meinefirma.de">

   <xs:element name="adressen">
      <xs:complexType>
         <xs:sequence>
            <xs:element name="adresse" type="adresseType" minOccurs="0" maxOccurs="unbounded" />
         </xs:sequence>
      </xs:complexType>
   </xs:element>

   <xs:complexType name="adresseType">
      <xs:sequence>
         <xs:element name="firma" minOccurs="0"> <xs:complexType /> </xs:element>
         <xs:element name="name"  type="xs:string" />
         <xs:choice>
            <xs:element name="strasse"  type="xs:string" minOccurs="0" />
            <xs:element name="postfach" type="xs:positiveInteger" minOccurs="0" />
         </xs:choice>
         <xs:element name="plz" type="xs:positiveInteger" minOccurs="0" />
         <xs:element name="ort" type="xs:string" minOccurs="0" />
      </xs:sequence>
      <xs:attribute name="datum" type="xs:date" />
   </xs:complexType>

</xs:schema>


Import eines anderen Schemas mit anderem Namespace

Das folgende Beispiel ist etwas konstruiert, aber zur Verdeutlichung des Imports eines anderen XSD-Schemas soll es reichen.

Speichern Sie folgendes XML-Instanzdokument: Adr4.xml

<?xml version="1.0" encoding="ISO-8859-1"?>
<mns:Bestellung xmlns:mns="http://meinnamespace.meinefirma.de"
                xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                xsi:schemaLocation="http://meinnamespace.meinefirma.de Adr4.xsd">
   <PostAdresse>
      <name>Torsten Horn</name>
      <postfach>4711</postfach>
      <ort>Aachen</ort>
   </PostAdresse>
   <LieferAdresse>
      <nam>Torsten Horn</nam>
      <str>Meinestr. 42</str>
      <plz>52072</plz>
      <ort>Aachen</ort>
   </LieferAdresse>
   <Bestellposten> ... </Bestellposten>
</mns:Bestellung>

Das XML-Instanzdokument enthält zwei Adressen mit verschiedenem Aufbau. Die beiden Adress-Typdefinitionen sollen aus verschiedenen XSD-Schematas kommen und zufälligerweise denselben Typnamen (adresseType) haben.

Bei schemaLocation ist Adr4.xsd eingetragen.

Speichern Sie das XSD-Schema: Adr4.xsd

<?xml version="1.0" encoding="ISO-8859-1"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           targetNamespace="http://meinnamespace.meinefirma.de"
           xmlns="http://meinnamespace.meinefirma.de"
           xmlns:andererNs="http://anderernamespace.anderefirma.de">

   <xs:import namespace="http://anderernamespace.anderefirma.de"
              schemaLocation="Adr4AnderesSchema.xsd" />

   <xs:element name="Bestellung">
      <xs:complexType>
         <xs:sequence>
            <xs:element name="PostAdresse"   type="adresseType" />
            <xs:element name="LieferAdresse" type="andererNs:adresseType" />
            <xs:element name="Bestellposten" type="xs:string" />
         </xs:sequence>
      </xs:complexType>
   </xs:element>

   <xs:complexType name="adresseType">
      <xs:sequence>
         <xs:element name="firma" minOccurs="0"> <xs:complexType /> </xs:element>
         <xs:element name="name"  type="xs:string" />
         <xs:choice>
            <xs:element name="strasse"  type="xs:string" minOccurs="0" />
            <xs:element name="postfach" type="xs:positiveInteger" minOccurs="0" />
         </xs:choice>
         <xs:element name="plz" type="xs:positiveInteger" minOccurs="0" />
         <xs:element name="ort" type="xs:string" minOccurs="0" />
      </xs:sequence>
      <xs:attribute name="datum" type="xs:date" />
   </xs:complexType>

</xs:schema>

Dieses XSD-Schema importiert für die Lieferadresse das andere XSD-Schema Adr4AnderesSchema.xsd, in welchem ebenfalls (aber anders) der Typ adresseType global definiert ist.

Speichern Sie auch das andere XSD-Schema: Adr4AnderesSchema.xsd

<?xml version="1.0" encoding="ISO-8859-1"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
            targetNamespace="http://anderernamespace.anderefirma.de">

   <xsd:complexType name="adresseType">
      <xsd:sequence>
         <xsd:element name="nam" type="xsd:string" />
         <xsd:element name="str" type="xsd:string" />
         <xsd:element name="plz" type="xsd:positiveInteger" />
         <xsd:element name="ort" type="xsd:string" />
      </xsd:sequence>
   </xsd:complexType>

</xsd:schema>

Testen Sie die Validierung mit einem beliebigen XML-Validierungstool. Zum Beispiel mit Eclipse, indem Sie mit der rechten Maustaste in das XML-Instanzdokument klicken und "Validate" wählen. Oder mit XsdValidation.java:

java XsdValidation Adr4.xsd Adr4.xml

Sie können übrigens im XML-Instanzdokument auch mehrere XSD-Schemadateien referenzieren, indem Sie bei xsi:schemaLocation="..." mehrere Paare von Namespaces und XSD-Dateien angeben.



Eindeutige ID ("unique") und Aufzählungstyp ("enumeration")

Speichern Sie folgendes XML-Instanzdokument: Adr5.xml

<?xml version="1.0" encoding="ISO-8859-1"?>
<adressen xmlns="http://meinnamespace.meinefirma.de"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://meinnamespace.meinefirma.de AdrSchemaMitUniqueUndEnum.xsd">
   <adresse id="42">
      <name>Torsten Horn</name>
      <strasse>Meinestr. 42</strasse>
      <plz>52072</plz>
      <ort>Aachen</ort>
      <land>DE</land>
   </adresse>
   <adresse id="43" datum="2009-11-11">
      <firma />
      <name>Ich AG</name>
      <postfach>4711</postfach>
   </adresse>
</adressen>

Adr5.xml ist ähnlich wie die obigen Adr*.xml, enthält aber zwei zusätzliche Angaben: das Attribut id und das Element land.

Speichern Sie folgendes XSD-Schema: AdrSchemaMitUniqueUndEnum.xsd

<?xml version="1.0" encoding="ISO-8859-1"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           xmlns="http://meinnamespace.meinefirma.de"
           targetNamespace="http://meinnamespace.meinefirma.de"
           elementFormDefault="qualified">

   <xs:element name="adressen">
      <xs:complexType>
         <xs:sequence>
            <xs:element name="adresse" type="adresseType" minOccurs="0" maxOccurs="unbounded" />
         </xs:sequence>
      </xs:complexType>
      <xs:unique      name="adresseID">
         <xs:selector xpath="adresse" />
         <xs:field    xpath="@id" />
      </xs:unique>
   </xs:element>

   <xs:complexType name="adresseType">
      <xs:sequence>
         <xs:element name="firma" minOccurs="0"> <xs:complexType /> </xs:element>
         <xs:element name="name"  type="xs:string" />
         <xs:choice>
            <xs:element name="strasse"  type="xs:string"          minOccurs="0" />
            <xs:element name="postfach" type="xs:positiveInteger" minOccurs="0" />
         </xs:choice>
         <xs:element name="plz"  type="xs:positiveInteger" minOccurs="0" />
         <xs:element name="ort"  type="xs:string"          minOccurs="0" />
         <xs:element name="land" type="landType"           minOccurs="0" />
      </xs:sequence>
      <xs:attribute name="datum" type="xs:date" />
      <xs:attribute name="id"    type="xs:long" use="required" />
   </xs:complexType>

   <xs:simpleType name="landType">
      <xs:restriction base="xs:string">
         <xs:enumeration value="DE" />
         <xs:enumeration value="FR" />
         <xs:enumeration value="GB" />
         <xs:enumeration value="US" />
      </xs:restriction>
   </xs:simpleType>

</xs:schema>

Über unique wird definiert, dass das id-Attribut der Adresse eindeutig sein muss und nicht doppelt vergeben werden darf.

Über restriction und enumeration werden erlaubte Werte für das land-Element deklariert.

Testen Sie die Validierung mit einem beliebigen XML-Validierungstool. Zum Beispiel mit Eclipse, indem Sie mit der rechten Maustaste in das XML-Instanzdokument klicken und "Validate" wählen. Oder mit XsdValidation.java:

java XsdValidation AdrSchemaMitUniqueUndEnum.xsd Adr5.xml

Setzen Sie testweise im XML-Instanzdokument Adr5.xml bei <land>...</land> ungültige Werte ein, vergeben Sie bei id="..." doppelte ID-Nummern und sehen Sie sich jeweils die Validierungsfehlermeldungen an.



Beziehungen mit "ID" und "IDREF"

Speichern Sie folgendes XML-Instanzdokument: Buecher1.xml

<?xml version="1.0" encoding="ISO-8859-1"?>
<buecher xmlns="http://meinnamespace.meinefirma.de"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://meinnamespace.meinefirma.de Buecher1.xsd">
   <autor id="A42">
      <name>Hinz</name>
      <ort>Hamburg</ort>
   </autor>
   <autor id="A43">
      <name>Kunz</name>
      <ort>Krefeld</ort>
   </autor>
   <verlag id="V151">
      <name>Aachener Java-Verlag</name>
      <ort>Aachen</ort>
   </verlag>
   <verlag id="V152">
      <name>Bonner XML-Verlag</name>
      <ort>Bonn</ort>
   </verlag>
   <buch autorID="A43" verlagID="V151">
      <titel>XML mit Java</titel>
   </buch>
</buecher>

Das XML-Instanzdokument enhält Autoren, Verlage und Bücher. Damit bei den Büchern nicht jedesmal alle Daten zum Autor und Verlag wiederholt werden müssen, enthalten die Bücher lediglich Verweise auf die bereits definierten Elemente.

Speichern Sie folgendes XSD-Schema: Buecher1.xsd

<?xml version="1.0" encoding="ISO-8859-1"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           xmlns="http://meinnamespace.meinefirma.de"
           targetNamespace="http://meinnamespace.meinefirma.de"
           elementFormDefault="qualified">

   <xs:element name="buecher">
      <xs:complexType>
         <xs:sequence>
            <xs:element name="autor"  type="autorType"  maxOccurs="unbounded" />
            <xs:element name="verlag" type="verlagType" maxOccurs="unbounded" />
            <xs:element name="buch"   type="buchType"   maxOccurs="unbounded" />
         </xs:sequence>
      </xs:complexType>
   </xs:element>

   <xs:complexType name="autorType">
      <xs:sequence>
         <xs:element name="name" type="xs:string" />
         <xs:element name="ort"  type="xs:string" minOccurs="0" />
      </xs:sequence>
      <xs:attribute  name="id"   type="xs:ID" use="required"/>
   </xs:complexType>

   <xs:complexType name="verlagType">
      <xs:sequence>
         <xs:element name="name" type="xs:string" />
         <xs:element name="ort"  type="xs:string" minOccurs="0" />
      </xs:sequence>
      <xs:attribute  name="id"   type="xs:ID" use="required"/>
   </xs:complexType>

   <xs:complexType name="buchType">
      <xs:sequence>
         <xs:element name="titel"    type="xs:string" />
      </xs:sequence>
      <xs:attribute  name="autorID"  type="xs:IDREF" use="required"/>
      <xs:attribute  name="verlagID" type="xs:IDREF" use="required"/>
   </xs:complexType>

</xs:schema>

Testen Sie die Validierung mit einem beliebigen XML-Validierungstool. Zum Beispiel mit Eclipse, indem Sie mit der rechten Maustaste in das XML-Instanzdokument klicken und "Validate" wählen. Oder mit XsdValidation.java:

java XsdValidation Buecher1.xsd Buecher1.xml

Testen Sie Folgendes (und sehen Sie sich die jeweiligen Validierungsfehlermeldungen bei ungültigen Werten an):

Durch die ID-Ausdrücke (type="xs:ID") wird sichergestellt, dass die Autoren-id- und Verlag-id-Nummern eindeutig sind und nicht doppelt vergeben werden können (ähnlich wie unique im vorherigen Beispiel).

Durch die IDREF-Ausdrücke (type="xs:IDREF") wird sichergestellt, dass bei Buchelementen (<buch autor="A43" verlag="V151">) als Autoren-Verweis und als Verlags-Verweis nur tatsächlich definierte ID-Werte eingesetzt werden können.

Das ID/IDREF-Verfahren hat zwei Nachteile:
- Als Verlags-Verweis können irrtümlich Autoren-ID-Werte (und umgekehrt) eingesetzt werden.
- Die IDs müssen mit Buchstaben beginnen, was die Verwendung als (z.B. per Sequenz generierte) Datenbank-ID erschwert.

Meistens wird das im Folgenden vorgestellte key/keyref-Verfahren bevorzugt.



Beziehungen mit "key" und "keyref"

Speichern Sie folgendes XML-Instanzdokument: Buecher2.xml

<?xml version="1.0" encoding="ISO-8859-1"?>
<buecher xmlns="http://meinnamespace.meinefirma.de"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://meinnamespace.meinefirma.de Buecher2.xsd">
   <autor id="42">
      <name>Hinz</name>
      <ort>Hamburg</ort>
   </autor>
   <autor id="43">
      <name>Kunz</name>
      <ort>Krefeld</ort>
   </autor>
   <verlag id="151">
      <name>Aachener Java-Verlag</name>
      <ort>Aachen</ort>
   </verlag>
   <verlag id="152">
      <name>Bonner XML-Verlag</name>
      <ort>Bonn</ort>
   </verlag>
   <buch autorID="43" verlagID="151">
      <titel>XML mit Java</titel>
   </buch>
</buecher>

Das XML-Instanzdokument enhält wieder Autoren, Verlage und Bücher. Damit bei den Büchern nicht jedesmal alle Daten zum Autor und Verlag wiederholt werden müssen, enthalten die Bücher wieder lediglich Verweise auf die bereits definierten Elemente.

Speichern Sie folgendes XSD-Schema: Buecher2.xsd

<?xml version="1.0" encoding="ISO-8859-1"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           xmlns="http://meinnamespace.meinefirma.de"
           targetNamespace="http://meinnamespace.meinefirma.de"
           elementFormDefault="qualified">

   <xs:element name="buecher">
      <xs:complexType>
         <xs:sequence>
            <xs:element name="autor"  type="autorType"  maxOccurs="unbounded" />
            <xs:element name="verlag" type="verlagType" maxOccurs="unbounded" />
            <xs:element name="buch"   type="buchType"   maxOccurs="unbounded" />
         </xs:sequence>
      </xs:complexType>
      <xs:key         name="autorKey">
         <xs:selector xpath="autor" />
         <xs:field    xpath="@id" />
      </xs:key>
      <xs:keyref      name="autorKeyref" refer="autorKey">
         <xs:selector xpath="buch" />
         <xs:field    xpath="@autorID" />
      </xs:keyref>
      <xs:key         name="verlagKey">
         <xs:selector xpath="verlag" />
         <xs:field    xpath="@id" />
      </xs:key>
      <xs:keyref      name="verlagKeyref" refer="verlagKey">
         <xs:selector xpath="buch" />
         <xs:field    xpath="@verlagID" />
      </xs:keyref>
   </xs:element>

   <xs:complexType name="autorType">
      <xs:sequence>
         <xs:element name="name" type="xs:string" />
         <xs:element name="ort"  type="xs:string" minOccurs="0" />
      </xs:sequence>
      <xs:attribute  name="id"   type="xs:long" use="required" />
   </xs:complexType>

   <xs:complexType name="verlagType">
      <xs:sequence>
         <xs:element name="name" type="xs:string" />
         <xs:element name="ort"  type="xs:string" minOccurs="0" />
      </xs:sequence>
      <xs:attribute  name="id"   type="xs:long" use="required" />
   </xs:complexType>

   <xs:complexType name="buchType">
      <xs:sequence>
         <xs:element name="titel"    type="xs:string" />
      </xs:sequence>
      <xs:attribute  name="autorID"  type="xs:long" use="required" />
      <xs:attribute  name="verlagID" type="xs:long" use="required" />
   </xs:complexType>

</xs:schema>

Testen Sie die Validierung mit einem beliebigen XML-Validierungstool. Zum Beispiel mit Eclipse, indem Sie mit der rechten Maustaste in das XML-Instanzdokument klicken und "Validate" wählen. Oder mit XsdValidation.java:

java XsdValidation Buecher2.xsd Buecher2.xml

Übrigens können Sie sich mit Eclipse die XSD-Struktur ansehen, wie folgende Abbildung zeigt:

Buecher2.xsd

XSD-Validierung per Java

Speichern Sie folgende Java-Klasse: XsdValidation.java

import java.io.*;
import javax.xml.XMLConstants;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.*;
import org.xml.sax.*;

public class XsdValidation
{
   public static void main( String[] args ) throws Exception
   {
      if( args.length != 2 ) {
         System.out.println( "Bitte XSD-Schema und XML-Dokument angeben." );
         return;
      }
      System.out.println( args[0] + " + " + args[1] );
      XsdValidation.validate( args[0], args[1] );
    }

   public static void validate( String xsdSchema, String xmlDokument ) throws SAXException, IOException
   {
      SchemaFactory schemaFactory = SchemaFactory.newInstance( XMLConstants.W3C_XML_SCHEMA_NS_URI );
      Schema        schema = schemaFactory.newSchema( new File( xsdSchema ) );
      Validator     validator = schema.newValidator();
      validator.setErrorHandler( new XsdValidationLoggingErrorHandler() );
      validator.validate( new StreamSource( new File( xmlDokument ) ) );
   }
}

class XsdValidationLoggingErrorHandler implements ErrorHandler
{
   public void warning( SAXParseException ex ) throws SAXException
   {
      System.out.println( "Warnung: " + ex.getMessage() );
   }

   public void error( SAXParseException ex ) throws SAXException
   {
      System.out.println( "Fehler: " + ex.getMessage() );
   }

   public void fatalError( SAXParseException ex ) throws SAXException
   {
      System.out.println( "Fataler Fehler: " + ex.getMessage() );
   }
}

Bauen Sie in eine XML-Datei Fehler ein und rufen Sie im Kommandozeilenfenster beispielsweise auf:

javac XsdValidation.java

java XsdValidation Buecher2.xsd Buecher2.xml

Wenn Sie keinen speziellen ErrorHandler benötigen, lassen Sie die validator.setErrorHandler()-Zeile einfach weg. Dann erhalten Sie beim ersten Fehler eine Exception.

Falls Sie eine Exception ähnlich zu folgender erhalten:

org.xml.sax.SAXParseException: src-resolve: Cannot resolve the name '...' to a(n) 'attribute declaration' component.

Dann konnte wahrscheinlich eine "<xs:import ..."-Anweisung nicht ausgeführt werden.
Falls die betreffende "<xs:import ..."-Anweisung auf eine lokale Datei verweist, zum Beispiel so:

<xs:import namespace="http://www.w3.org/XML/1998/namespace" schemaLocation="xml.xsd" />

Dann muss die entsprechende Datei (im Beispiel xml.xsd) im aktuellen Verzeichnis existieren (oder durch eine Internetadresse ersetzt werden).
Falls die betreffende "<xs:import ..."-Anweisung auf eine Internet-URL verweist, etwa so:

<xs:import namespace="http://www.w3.org/XML/1998/namespace" schemaLocation="http://www.w3.org/2001/03/xml.xsd" />

Dann muss Ihr Internet-Zugriff funktionieren. Falls Sie sich hinter einer Proxy-Firewall befinden, müssen Sie die Proxy-Parameter angeben, zum Beispiel so:

java -Dhttp.proxyHost=127.0.0.1 -Dhttp.proxyPort=3128 XsdValidation %1 %2



XSD-Validierung per Java mit Multithreading über threadsichere Schema-Klasse

Speichern Sie folgende Java-Klasse: MultithreadingXsdValidation.java

import java.io.File;
import javax.xml.XMLConstants;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.*;
import org.xml.sax.*;

public class MultithreadingXsdValidation
{
   // Erster Parameter:  XSD-Schema
   // Weitere Parameter: XML-Dokumente
   // Beispielkommandozeile:
   //     java MultithreadingXsdValidation MyXsd.xsd 1.xml 2.xml 3.xml
   public static void main( String[] args ) throws Exception
   {
      if( args.length < 2 ) {
         System.out.println( "Bitte XSD-Schema und ein oder mehrere XML-Dokumente angeben." );
         return;
      }
      // Threadsicheres Schema:
      Schema xsdSchema = compileXsdSchema( args[0] );
      // Multithreading:
      for( int i=1; i<args.length; i++ ) {
         System.out.println( args[0] + " + " + args[i] );
         (new Thread( new ValidationRunnable( xsdSchema, args[i] ) )).start();
      }
   }

   public static Schema compileXsdSchema( String xsdSchema ) throws SAXException
   {
      SchemaFactory schemaFactory = SchemaFactory.newInstance( XMLConstants.W3C_XML_SCHEMA_NS_URI );
      return schemaFactory.newSchema( new File( xsdSchema ) );
   }

   public static void validate( Schema xsdSchema, String xmlDokument )
   {
      try {
         Validator validator = xsdSchema.newValidator();
         validator.setErrorHandler( new XsdValidationLogErrorHandler( xmlDokument ) );
         validator.validate( new StreamSource( new File( xmlDokument ) ) );
      } catch( Exception ex ) {
         throw new RuntimeException( ex );
      }
   }
}

class ValidationRunnable implements Runnable
{
   Schema xsdSchema;
   String xmlDokument;

   ValidationRunnable( Schema xsdSchema, String xmlDokument )
   {
      this.xsdSchema   = xsdSchema;
      this.xmlDokument = xmlDokument;
   }

   @Override
   public void run()
   {
      MultithreadingXsdValidation.validate( xsdSchema, xmlDokument );
   }
}

class XsdValidationLogErrorHandler implements ErrorHandler
{
   String xmlDokument;

   public XsdValidationLogErrorHandler( String xmlDokument )
   {
      this.xmlDokument = xmlDokument;
   }

   public void warning( SAXParseException ex ) throws SAXException
   {
      System.out.println( xmlDokument + ": Warnung: " + ex.getMessage() );
   }

   public void error( SAXParseException ex ) throws SAXException
   {
      System.out.println( xmlDokument + ": Fehler: " + ex.getMessage() );
   }

   public void fatalError( SAXParseException ex ) throws SAXException
   {
      System.out.println( xmlDokument + ": Fataler Fehler: " + ex.getMessage() );
   }
}

Erzeugen Sie beispielsweise mehrere Buecher2-*.xml-Dateien und rufen Sie im Kommandozeilenfenster auf:

javac MultithreadingXsdValidation.java

java MultithreadingXsdValidation Buecher2.xsd Buecher2-1.xml Buecher2-2.xml Buecher2-3.xml



JAXB (Java Architecture for XML Binding)

XML-Schema ist ein wichtiger Bestandteil zu JAXB. JAXB erleichtert die XML-Verarbeitung mit Java. Dazu gehören folgende vier Schwerpunkte:





Weitere Themen: andere TechDocs | XML | JAXB (Binding) | XSL, XSLT, XSL-FO
© 2009-2010 Torsten Horn, Aachen