XML | XML-Schema | XPath | XSL-T | XSL-FO | XQuery | XProc | SVG |
XML-Schema / XML-Schema 1.1
![]() |
![]() |
➪ XML-Schema 1.1 bietet mit erweiterten Konzepten für Assertions (assert für komplexe Datentypen, assertion für simple Datentypen), bedingten Typisierungen, schemaweiten Attributen, openContent bzw. defaultOpenContent leistungsfähige Unterstützung bei der Datenvalidierung.
Auf dieser Seite:Für die XML-Schema-Versionierung gibt es einen speziellen Namespace, der auf eine Webseite des W3C verweist. Über diese Webseite ist auch ein "XMLSchema-versioning.xsd" erreichbar.
xmlns:vc="http://www.w3.org/2007/XMLSchema-versioning"
vc:minVersion="1.1"
https://www.w3.org/2007/XMLSchema-versioning/XMLSchema-versioning.xsd
"XMLSchema-versioning.xsd" dient lediglich zur Dokumentation, nicht aber dazu, irgendetwas zu validieren. Gleichwohl sind die Attribute minVersion bzw. maxVersion definiert, die beide vom Typ xs:decimal sein müssen. Dort ist auch der konventionelle Präfix-Name vc empfohlen.
Leistungsfähige XML-Schema-Editoren passen denn auch das Root-Element des XML-Schemas für die erweiterte Version entsprechend an:
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema"
elementFormDefault="qualified"
vc:minVersion="1.1"
xmlns:vc="http://www.w3.org/2007/XMLSchema-versioning">
</xs:schema>
Obwohl die XML-Schema-Versionierungen nicht zu Validierungszwecken gedacht sind, prüfen die Prozessoren im Rahmen eines Preprocessings, ob die im XML-Schema definierten Elemente den Vorgaben minVersion und maxVersion entsprechen. Andernfalls werden sie (wie <xs:complexType name="mycomplexType" vc:maxVersion="1.0" vc:minVersion="1.0" >) nicht beachtet.
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
elementFormDefault="qualified"
vc:minVersion="1.1"
vc:maxVersion="1.2"
xmlns:vc="http://www.w3.org/2007/XMLSchema-versioning">
<xs:simpleType
name="mysimpletype"
vc:minVersion="1.1"
vc:maxVersion="1.2">
<xs:restriction base="xs:string">
<xs:enumeration value="Hallo"/>
<xs:enumeration value="Moin"/>
</xs:restriction>
</xs:simpleType>
<xs:complexType
name="mycomplexType"
vc:maxVersion="1.2"
vc:minVersion="1.1">
<xs:all>
<xs:element
name="mychildnode"
type="mysimpletype"/>
</xs:all>
</xs:complexType>
<xs:complexType
name="mycomplexType"
vc:maxVersion="1.0"
vc:minVersion="1.0" >
<xs:all>
<xs:element
name="mychildnode2"
type="mysimpletype"/>
</xs:all>
</xs:complexType>
<xs:element name="myelement" type="mycomplexType"/>
</xs:schema>
Leistungsfähige Editoren geben beim Editieren von XML-Schema entsprechende Warn- und (bei Validierung) auch Fehlermeldungen heraus.
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema"
elementFormDefault="qualified"
vc:minVersion="1.2"
vc:maxVersion="1.2"
xmlns:vc="http://www.w3.org/2007/XMLSchema-versioning">
</xs:schema>
... würde von vornherein nicht beachtet:
Die Schema-Deklaration wird nicht beachtet,
da der Wert des Attributs "minVersion" größer
ist als XML-Schema 1.1 (minVersion="1.2").
Assertions dienen der verfeinerten Werte-Kontrolle. Ein einfaches Beispiel: mysimpletype definiert einen xs:integer, der nicht "0" sein darf.
<xs:simpleType name="mysimpletype">
<xs:restriction base="xs:integer">
<xs:assertion test="$value != 0"/>
</xs:restriction>
</xs:simpleType>
Betrachten Sie den Fall, dass ein Integerwert > 0 und < 100 definiert werden soll. In XML-Schema 1.0 greift xs:restriction auf xs:maxExclusive und xs:minExclusive zurück.
<xs:simpleType name="minexclmaxecl">
<xs:restriction base="xs:integer">
<xs:maxExclusive value="100"/>
<xs:minExclusive value="0"/>
</xs:restriction>
</xs:simpleType>
In XML-Schema 1.1 überprüft "ungeraderTyp_0_100" zudem mittels xs:assertion, ob der Integer-Wert eine ungerade Zahl zwischen 0 und 100 ist.
<xs:simpleType name="ungeraderTyp_0_100">
<xs:restriction base="xs:integer">
<xs:assertion test="$value > 0
and $value < 100
and $value mod 2 = 1" />
</xs:restriction>
</xs:simpleType>
"ungeraderTyp_0_100" lässt sich alternativ auch so definieren:
<xs:simpleType name="ungeraderTyp_0_100">
<xs:restriction base="xs:integer">
<xs:assertion test="$value > 0"/>
<xs:assertion test="$value < 100"/>
<xs:assertion test="$value mod 2 = 1" />
</xs:restriction>
</xs:simpleType>
Suboptimal, aber möglich wäre, den Wert als xs:string zu casten und dessen Stringlänge zu ermitteln. Ich führe das hier an, um auf die flexible Verwendbarkeit der XPath-Funktionen hinzuweisen.
<xs:simpleType name="minexclmaxecl">
<xs:restriction base="xs:integer">
<xs:assertion
test="string-length(xs:string($value)) < 3"/>
<xs:assertion
test="string-length(xs:string($value)) > 1"/>
</xs:restriction>
</xs:simpleType>
Auch zeitliche Beschränkungen sind möglich; beispielsweise soll geprüft werden, ob ein Ereignis später als 01.12.2017 12 Uhr stattfindet.
<xs:simpleType name="ST_Fruehestens" >
<xs:restriction base="xs:dateTime">
<xs:assertion
test="$value > xs:dateTime('2017-12-01T12:00:00.0')"/>
</xs:restriction>
</xs:simpleType>
Anstelle einer xs:enumeration ist auch die Arbeit mit einer entsprechenden Assertion möglich.
<xs:simpleType name="Arbeitstag">
<xs:restriction base="xs:string">
<xs:assertion
test="$value = ('MO', 'DI', 'MI', 'DO', 'FR')"/>
</xs:restriction>
</xs:simpleType>
Statt aufwendiger Deklaration von xs:pattern können Sie das auch der matches-Funktion überlassen, die in einer Assertion aufgerufen wird. Die Definition regulärer Ausdrücke bleibt Ihnen indes nicht erspart.
<xs:element name="myelement">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:assertion
test="matches($value, '[A-Z]{1}[a-z]{1,19}')"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
Das gilt analog auch für die Anwendung der tokenize-Funktion in Verbindung mit matches. Der folgende Aufruf lässt eine beliebige Anzahl von Werten zu, die jeweils durch ein Blank getrennt dem vorher definierten regulären Ausdruck entsprechen: Nur Buchstaben, das erste Zeichen groß, die restlichen klein.
<xs:element name="myelement">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:assertion
test="every $m in
tokenize(xs:string($value), ' ')
satisfies (
matches(xs:string($m),
'[A-Z]{1}[a-z]{1,}'))"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
Also auch auf diese Weise können Sie die Wochentage überprüfen:
<myelement>Montag Dienstag Mittwoch Donnerstag Freitag</myelement>
Interessant ist hier auch die Arbeit mit der translate-Funktion. Wenn Sie sicherstellen wollen, dass in einer Zeichenkette auch Zahlen auftreten können, so können Sie sämtliche Nicht-Zahlen löschen und prüfen, ob der Rest als xs:integer gecastet werden kann.
<xs:element name="myelement">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:assertion
test="translate($value,
translate($value, '0123456789', '')
, '')
castable as xs:integer"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
Das folgende Beispiel definiert ein Integer-Array mit folgenden Einschränkungen:
<xs:simpleType name="Integerarray">
<xs:restriction>
<xs:simpleType>
<xs:list itemType="xs:integer"/>
</xs:simpleType>
<xs:assertion test="count($value) < 5"/>
<xs:assertion test="$value[1] = max($value)"/>
<xs:assertion test="sum($value) = 9"/>
<xs:assertion test="every $m in $value satisfies $m > 0"/>
</xs:restriction>
</xs:simpleType>
Assertions übernehmen sehr flexibel die Existenzkontrolle für bestimmte Elemente bzw. Attribute. Angenommen, Sie wollten ein Element "myelement" entweder mit dem Attribut "a" oder "b" ausstatten, aber nicht mit beiden.
<xs:assert test="exists(@a | @b)"/> würde zulassen, dass beide Attribute vorhanden sind. Daher wird die Prüfung notwendig, ob
<xs:element name="myelement">
<xs:complexType>
<xs:attribute name="a" use="optional"/>
<xs:attribute name="b" use="optional"/>
<xs:assert
test="if (
(exists(@a) and not(exists(@b)))
or
(exists(@b) and not(exists(@a))))
then (true())
else (false())"/>
</xs:complexType>
</xs:element>
Das folgende Beispiel GeometrFigur stelle eine geometrische Figur dar, die die optionalen Grundelemente Umfang und Flaeche vorgibt. Zur späteren Verwendung werden noch die beiden Attribute "myTYPE" (required) und "maxwert" (optional) mitgegeben.
<xs:simpleType name="ST_Massangabe">
<xs:restriction base="xs:decimal">
<xs:assertion test="$value > 0"/>
</xs:restriction>
</xs:simpleType>
<xs:complexType name="GeometrFigur">
<xs:sequence>
<xs:element name="Flaeche"
type="ST_Massangabe"
minOccurs="0"/>
<xs:element name="Umfang"
type="ST_Massangabe"
minOccurs="0"/>
</xs:sequence>
<xs:attribute name="maxwert"
type="ST_Massangabe"
use="optional"/>
<xs:attribute name="myTYPE" use="required">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="kreis"/>
<xs:enumeration value="rechteck"/>
<xs:enumeration value="abstrakt"/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
</xs:complexType>
Der RechteckType erweitert GeometrFigur um die Childnodes Laenge und Breite. Zusätzlich wird kontrolliert,
<xs:complexType name="RechteckType">
<xs:complexContent>
<xs:extension base="GeometrFigur">
<xs:sequence>
<xs:element name="Laenge" type="ST_Massangabe"/>
<xs:element name="Breite" type="ST_Massangabe"/>
</xs:sequence>
<xs:assert test="Laenge > Breite"/>
<xs:assert
test="if(exists(@maxwert))
then (Laenge <= @maxwert)
else (true())"/>
<xs:assert
test="if(exists(Flaeche))
then (Flaeche = Laenge * Breite)
else (true())"/>
<xs:assert
test="if(exists(Umfang))
then (Umfang = (Laenge + Breite) * 2)
else (true())"/>
</xs:extension>
</xs:complexContent>
</xs:complexType>
<xs:element name="myelement" type="RechteckType"/>
Somit würde dieses XML-Schema beispielsweise folgende Werte definieren:
<myelement maxwert="20" myTYPE="rechteck">
<Flaeche>6</Flaeche>
<Umfang>10</Umfang>
<Laenge>3</Laenge>
<Breite>2</Breite>
</myelement>
Ein ähnlicher Ansatz wie vorher existiert auch beim KreisTyp, der den Radius vorgibt und die abhängigen (optionalen) Größen Flaeche, Umfang und Durchmesser kontrolliert. Auch die Abhängigkeit des Radius vom optionalen Attribut maxwert ist gegeben.
<xs:complexType name="KreisTyp">
<xs:complexContent>
<xs:extension base="GeometrFigur">
<xs:sequence>
<xs:element
name="Radius"
type="ST_Massangabe"/>
<xs:element
name="Durchmesser"
type="ST_Massangabe"
minOccurs="0"/>
</xs:sequence>
<xs:assert
test="if(exists(@maxwert))
then (Radius <= @maxwert)
else (true())"/>
<xs:assert
test="if (exists(Umfang))
then (Umfang = Radius * 2 * 3.14159)
else (true())"/>
<xs:assert
test="if (exists(Flaeche))
then (Flaeche = Radius * Radius * 3.14159)
else (true())"/>
<xs:assert
test="if (exists(Durchmesser))
then (Durchmesser = Radius * 2)
else (true())"/>
</xs:extension>
</xs:complexContent>
</xs:complexType>
<xs:element name="myelement" type="KreisTyp"/>
Das folgende XML-Dokument wäre damit vollauf valide:
<myelement maxwert="3" myTYPE="kreis">
<Radius>3</Radius>
<Durchmesser>6</Durchmesser>
<Flaeche>28.27431</Flaeche>
<Umfang>18.84954</Umfang>
</myelement>
Nun hängt es von dem Attribut myTYPE ab, ob myelement vom KreisTyp, RechteckTyp oder GeometrFigur ist.
<xs:element name="myelement">
<xs:alternative test="@myTYPE eq 'kreis'"
type="KreisTyp"/>
<xs:alternative test="@myTYPE eq 'rechteck'"
type="RechteckTyp"/>
<xs:alternative type="GeometrFigur"/>
</xs:element>
Wenn die Target-Namespaces identisch sind, kann in einem zweiten XML-Schema-Dokument ein xs:complexType, der in einem anderen XML-Schema definiert wurde, verändert werden. So können die Felder der xs:complexType GeometrFigur auch umbenannt/überschrieben werden:
<xs:override schemaLocation="XSDTest_1_1.xsd">
<xs:complexType name="GeometrFigur">
<xs:sequence>
<xs:element name="__flaeche"
type="ST_Massangabe" minOccurs="0" />
<xs:element name="__umfang"
type="ST_Massangabe" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
</xs:override>
... sodass mit den neuen Elementnamen gearbeitet werden kann.
<__flaeche>7</__flaeche>
<__umfang>5</__umfang>
Das redefine von XML-Schema 1.0 ist veraltet.
<xs:redefine schemaLocation="XSDTest_1_1.xsd">
Nehmen Sie noch ein etwas komplexeres Beispiel mit mehreren XML-Schema-Dokumenten, die jeweils über einen eigenen Namespace verfügen und sich gegenseitig importieren. Im ersten XML-Schema SomeSimpleTypes_With_NS.xsd wird lediglich ein simpleType mit einem regulären Ausdruck definiert.
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
elementFormDefault="qualified"
targetNamespace="wilfried-grupe.de/someSimpleTypes"
xmlns:myST="wilfried-grupe.de/someSimpleTypes"
version="1.1"
vc:minVersion="1.1"
xmlns:vc="http://www.w3.org/2007/XMLSchema-versioning">
<xs:simpleType name="stringmax20">
<xs:restriction base="xs:string">
<xs:pattern value="[A-Z]{1}[a-z]{1,19}"/>
</xs:restriction>
</xs:simpleType>
</xs:schema>
Im zweiten XML-Schema Mensch_someelements_withNS.xsd, das SomeSimpleTypes_With_NS.xsd importiert, seien nur einige Attribute und Elemente sowie deren Typen und Namespaces aufgelistet.
<xs:schema
targetNamespace="wilfried-grupe.de/someelements"
xmlns:ns2="wilfried-grupe.de/someelements"
xmlns:myST="wilfried-grupe.de/someSimpleTypes"
version="1.1"
elementFormDefault="qualified"
attributeFormDefault="qualified"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xpathDefaultNamespace="wilfried-grupe.de/someelements"
xmlns:vc="http://www.w3.org/2007/XMLSchema-versioning"
vc:minVersion="1.1">
<xs:import namespace="wilfried-grupe.de/someSimpleTypes"
schemaLocation="SomeSimpleTypes_With_NS.xsd"/>
<xs:attribute name="HOBBY" type="myST:stringmax20"/>
<xs:attribute name="ALTER1" type="xs:nonNegativeInteger"/>
<xs:attribute name="ALTER2" type="xs:nonNegativeInteger"/>
<xs:element name="vorname" type="myST:stringmax20"/>
<xs:element name="nachname" type="myST:stringmax20"/>
<xs:element name="NN" type="myST:stringmax20"/>
<xs:element name="VN" type="myST:stringmax20"/>
<xs:element name="age" type="xs:nonNegativeInteger"/>
</xs:schema>
Das dritte XML-Schema Mensch_withNS.xsd importiert das zweite (und damit auch das erste) und definiert mit dessen Namespace und den dort definierten Elementen/Attributen die Zielstruktur "MENSCH". Zudem überprüft das XML-Schema-Dokument durch mehrere xs:assert das Vorkommen einiger Elemente bzw. Attribute.
<xs:schema
xmlns:ns2="wilfried-grupe.de/someelements"
targetNamespace="wilfried-grupe.de/Beispiel"
xmlns:ns3="wilfried-grupe.de/Beispiel"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
vc:minVersion="1.1"
xmlns:vc="http://www.w3.org/2007/XMLSchema-versioning"
version="1.1"
elementFormDefault="qualified"
attributeFormDefault="qualified"
xpathDefaultNamespace="wilfried-grupe.de/Beispiel">
<xs:import
namespace="wilfried-grupe.de/someelements"
schemaLocation="Mensch_someelements_withNS.xsd"/>
<xs:complexType name="MENSCH_TYP">
<xs:all>
<xs:element ref="ns2:nachname" minOccurs="0" maxOccurs="1"/>
<xs:element ref="ns2:NN" minOccurs="0" maxOccurs="1"/>
<xs:element ref="ns2:vorname" minOccurs="0" maxOccurs="1"/>
<xs:element ref="ns2:VN" minOccurs="0" maxOccurs="1"/>
</xs:all>
<xs:attribute ref="ns2:HOBBY" use="required"/>
<xs:attribute ref="ns2:ALTER1" use="optional"/>
<xs:attribute ref="ns2:ALTER2" use="optional"/>
<xs:assert
test="
if (
(exists(@ns2:ALTER1) and not(exists(@ns2:ALTER2)))
or
(exists(@ns2:ALTER2) and not(exists(@ns2:ALTER1))))
then (true())
else (false())" />
<xs:assert
test="
if (
(exists(ns2:nachname) and not(exists(ns2:NN)))
or
(exists(ns2:NN) and not(exists(ns2:nachname))))
then (true())
else (false())" />
<xs:assert
test="
if (
(exists(ns2:vorname) and not(exists(ns2:VN)))
or
(exists(ns2:VN) and not(exists(ns2:vorname))))
then (true())
else (false())" />
</xs:complexType>
<xs:element name="MENSCH" type="ns3:MENSCH_TYP"/>
</xs:schema>
Diese drei XML-Schemata zusammen definieren ein XML-Dokument, das beispielsweise so ...
<ns3:MENSCH xmlns:ns2="wilfried-grupe.de/someelements"
xmlns:ns3="wilfried-grupe.de/Beispiel"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="wilfried-grupe.de/Beispiel
file:/C:/wg/Mensch_withNS.xsd"
ns2:HOBBY="XML"
ns2:ALTER1="22">
<ns2:NN>Holzflos</ns2:NN>
<ns2:vorname>Hugo</ns2:vorname>
</ns3:MENSCH>
... oder auch so aussehen könnte (ohne xsi:schemaLocation):
<ns3:MENSCH xmlns:ns2="wilfried-grupe.de/someelements"
xmlns:ns3="wilfried-grupe.de/Beispiel"
ns2:HOBBY="Java"
ns2:ALTER1="33">
<ns2:nachname>Saftlos</ns2:nachname>
<ns2:VN>Sabine</ns2:VN>
</ns3:MENSCH>
wg / 31. Dezember 2019
Fragen? Anmerkungen? Tipps?
Bitte nehmen Sie Kontakt zu mir auf.
V.i.S.d.P.: Wilfried Grupe * Klus 6 * 37643 Negenborn
☎ 0151. 750 360 61 * eMail: info10@wilfried-grupe.de