XSL / Konvertierung von XML nach XML / XML Schema-Validation in XSLT 2.0

XML Schema-Validation in XSLT 2.0

XML Schema-Validation in XSLT 2.0

➪ Neben dem Type-Casting atomarer Datentypen besteht in XSLT 2.0 die Möglichkeit, auch selbst definierte simple sowie komplexe Schema-Datentypen zu definieren und die Inhalte von Attributen bzw. Elementen gegenüber diesen Typvorgaben zu validieren. Damit werden komplexe Teilbäume definierbar, die in der Konvertierungsphase validiert werden können. Das ist sinnvoll, wenn der Konvertierungsprozeß auch ohne vorgeschaltete Schemavalidierung beginnen soll.

Aber warum sollte man das tun: XML-Verarbeitung ohne vorherige Validierung? Der Sinn der Schemavalidierung besteht doch gerade darin, ein XML-Dokument hinsichtlich seiner Datenstruktur (Elemente, Attribute, Namespaces) und deren atomarer Datentypen zu prüfen. Das ist doch die beste Gelegenheit, Datenqualität abzusichern, indem man fehlerhafte Input-Daten erst gar nicht zur Weiterverarbeitung zuläßt. Wenn also der XML Input nicht valide ist gegenüber dem XML Schema, dann wird die Weiterverarbeitung gestopp, der XSL-Konvertierungsprozeß wird nicht gestartet. Wieso sollte man darauf verzichten?

pic/XSL_Workflow.png

Die vorstehende Grafik zeigt einen typischen XSLT Workflow, in dem externe Datenformate in einem ersten Schritt in XML konvertiert werden. Dabei kann XML Schema bereits bei der Zuweisung der temporären Datenstruktur helfen. Das generierte XML Input Dokument könnte nun gegen das entsprechende XML Schema validiert werden. Sofern diese Validierung keine Fehler ergibt, kann eine Anschlußkonvertierung in eine temporäre XML-Zielstruktur erfolgen, die wiederum gegen das Ziel-XSD validiert werden kann. Zum Schluß könnte eine Konvertierung in diverse Endformate erfolgen.

Eine XSD-Validierung vor Beginn des Konvertierungsprozesses macht nur Sinn, wenn der Workflow gestoppt werden soll, sobald die XSD-Validierung auf einen Fehler läuft: die XSL-Konvertierung würde also erst gar nicht starten. Dafür kann es triftige Gründe geben.

Ein Grund mag sein: Sie verfolgen eine kompromißlose Politik, daß Input-Streams entweder vollständig fehlerfrei oder vollständig unbrauchbar sind. Entweder "stimmt" das Input-Dokument hundertprozentig - oder gar nicht. Eine Grauzone "dazwischen" kann es so gesehen nicht geben.

Das ist speziell dann der Fall, wenn Sie den Input anhand jenes XML Schemas prüfen, das der Datenlieferant selber (hoffentlich) zur Verfügung stellt. Damit prüfen Sie, ob der Datenlieferant seine eigenen Standards einhält (was in der Realität oft genug nicht der Fall ist).

Und die Annahme scheint gerechtfertigt: wenn das Dokument schon in Teilen nicht stimmt, dann besteht die Gefahr, daß sich Fehler auch in jenen Bereichen eingeschlichen haben, die Sie für die Anschlußkonvertierung benötigen. Also stoppen Sie lieber das Ganze, bevor Sie sich die Mühe machen, durch eine aufwändige Implementierung Datenfehler automatisiert zu erkennen und beheben.

Zudem ist eine solche vorherige XSD-Validierung auch ein Stück Sicherheit, wenn Ihre Implementierungslogik konsequent auf einem bestimmten XML Schema des Datenlieferanten aufbaut, quasi fest damit "verdrahtet" ist. Sendet der Datenlieferant nun ohne Vorwarnung andere Datenstrukturen an Ihr System (etwa irrtümlich, oder weil er zwischenzeitlich eine Versionsänderung mit neuen Namespaces durchgeführt hat, ohne Sie davon zu informieren), dann besteht keine Gefahr einer zufälligen Fehlkonvertierung mit Informationsverlust, die sich ohne Vorprüfung ergeben könnte.

Auf der anderen Seite ist die Aussagekraft der Schemavalidierung begrenzt, da sich die XML Schemata zwar sehr genau und streng, aber auch ebenso lax definieren lassen. Die Möglichkeiten, die XML Schema bietet, werden selten vollständig genutzt. Ich habe wiederholt XSDs gesehen, deren Elemente und Attribute pauschal als xs:string definiert wurden, sogar einige, wo nur das Rootelement und einige allgemeine Strukturdefinitionen, der Rest aber als deklariert wurde. Eine Deklaration gegenseitiger Abhängigkeiten im Sinne von Primär-/Fremdschlüsseln habe ich in XSD's fast nie gefunden, obwohl diese in den XML-Dokumenten vorhanden war: diese Dinge mßten dann später im Konvertierungsprozß nachgebildet werden. Das Argument "Wir haben ein XML Schema" sagt daher nichts aus über die Qualität des XML Schemas, das schließlich als Stopp-Kriterium für umfangreiche Konvertierungsprozesse dienen soll.

Ebenfalls problematisch ist, daß die Eingangsvalidierung sich grundsätzlich auf das gesamte Dokument bezieht. Die Anschlußprogrammierung wertet aber nur selten mehr als zwanzig Prozent der Eingangsdaten aus. Wenn die Validierung - und damit der gesamte Konvertierungsprozeß - wegen einiger Formalfehler schief geht, die bei der Datenauswertung ohnehin igoriert werden, dann kann das durchaus folgenreich sein. Nehmen wir an, ein Kunde sendet einem Wirtschaftsunternehmen einen Millionenauftrag in XML-Format. Das Unternehmen wird sich dreimal überlegen, den Auftrag abzulehnen wegen einiger Formalfehler, die für die automatisierte Annahme des Auftrags irrelevant sind.

Zudem wird die Qualität der gesamten Datenlage beim Datenempfänger durch teilweise gestoppte Eingangskonvertierung nicht unbedingt erhöht. Es kommt (gar nicht selten) vor, daß aktuell eingehende Datenströme sich auf andere Daten beziehen, die zeitversetzt entweder bereits geflossen oder noch zu erwarten sind. Wenn es dem Datenempfänger wichtig ist, einen möglichst geschlossenen, vollständigen Datenkontext über einen ganzen Zeitraum verfügbar zu haben, dann kann die Eingangsvalidierung sehr hinderlich sein. Es ergeben sich Datenlücken, die die Aussagekraft des Ganzen einschränken können.

Dabei ist es nicht notwendig, eine "schlechte Datenqualität" der Inputstreams vorher durch Validierung abzufangen, um die Folgeanwendung (den Konvertierungsprozeß) nicht zu belasten. Das wäre nur dann zwingend erforderlich, wenn die Folgeanwendung selbst nicht in der Lage ist, eine suboptimale Datenqualität abzuwehren. Das ist bei XSLT 2.0 aber nicht der Fall.

Eine eher pagmatische Sicht der Dinge ist daher, ob sich der Inputstream nicht doch irgendwie verwenden läßt - auch ohne vorgeschaltete Validierung, notfalls auch ohne "feste Verdrahtung" mit dem XML Schema des Datenlieferanten. Freilich setzt das eine exzellente Implementierungsqualität voraus, die Fehler des Inputstreams automatisiert erkennt und behandelt. Insbesondere ist es möglich, die XSD-Möglichkeiten zur typsauberen Definition atomarer wie komplexer Datentypen in XSLT einzubinden und so die Eingangs- und Ausgangsvalidierung in den Konvertierungsprozeß zu integrieren. Die Möglichkeiten sind in XSLT 2.0 und verwandten Standards vorhanden; sie müssen nur genutzt (und ausreichend getestet) werden.

Betrachten wir die folgende Konvertierungsstrecke:

pic/XSL_Workflow2.png

Hier wird eine Input Datei mittels verschiedener aufeinander aufbauender Konvertierungsschritte (K1 bis k5) in unterschiedliche Folgedaten konvertiert, die ein sehr unterschiedliches Format haben können. Der Einfachheit halber wollen wir annehmen, daß alle Outputdokumente im XML Format erstellt wurden. Dabei stoßen die XML-Dokumente x1, x2, x4, x8 lediglich eine Folgekonvertierung an; sie sind daher nur temporäre Dateien, die unmittelbar nach ihrer Konvertierung wieder verworfen werden.

x9 wird generiert, wobei dessen ursprüngliche Verwendung mittlerweile entfallen ist, was aber erst nach einiger Zeit zufällig bemerkt wird. Damit sind die Konvertierungsschritte k4 und k5 obsolet; bereits die Generierung von x4 und x7 sind überflüssig. Das kommt häufiger vor, als man glauben sollte. Da jede dieser Konvertierungsschritte Rechenzeit beansprucht und ggf. High-Priority-Konvertierungen verzögern könnte, ist es sehr sinnvoll, die Aktualität der Konvertierungsstrecke zu überwachen.

x5, x6 und x8 seien Enddokumente zum Weiterversand für die Kunden, zur festen Datenhaltung in XML- oder relationalen Datenbanken, oder sie dienen als Grundlage für Managemententscheidungen. Auch wenn es im vorliegenden Beispiel nur um die Konvertierungsschritte k1, k2, k3 geht (da die beiden anderen im Grunde überflüssig sind), stellt sich die grundsätzliche Frage, ob XSL-Konvertierungen eine XSD-Validierung des Inputs vorgeschaltet werden sollte oder nicht.

Was würde passieren, wenn ein in seiner Struktur oder in seinen Datentypen teilweise oder völlig fehlerhaftes Dokument in die XSL-Konvertierung liefe? Antwort: wenn die XSL-Logik die möglichen Fehler nicht automatisch erkennt und behandelt, dann ist der Output fehlerhaft. Dabei kann es passieren, daß das Input Dokument nur in Feldern fehlerhaft ist, die für die anschließende XSLT-Konvertierung nicht benötigt werden: die restlichen Felder, die für das Mapping verwendet werden, können fehlerfrei sein.

In einem solchen Fall ist die Inputvalidierung kontraproduktiv. Korrekte (valide) Daten werden nicht prozessiert, weil in derselben Gesamt-Datei auch irrelevante Daten enthalten sind, die nicht den strengen Vorgaben entsprechen. Derartige Versuche, Datenlieferanten zu guter Datenqualität "erziehen" zu wollen, grenzen an Prinzipienreiterei: sie können extrem teuer werden, wenn prozeßkritische Daten oder bedeutende Aufträge nicht übermittelt werden.

Aber auch für jene Daten, die für die XSLT-Transformation wichtig sind, bietet die Schemavalidierung der Input-Daten keine hinreichende Sicherheit, der einen Abbruch des Workflows vor der Konvertierung grundsätzlich rechtfertigt. Es kann nämlich passieren, daß die XSLT-interne Logik bestimmte Datentypen, Wertgrenzen zwingend voraussetzt, die in der Schema-Validierung des XML Inputs nicht definiert sind und daher auch nicht überprüft werden. Das hat auch mit einer laschen XML Schema-Definition zu tun.

Problematisch wird es, wenn XML Schema keine Standards erzwingt, sondern je nach den Prozeßerfordernissen "zurechtgebogen" und dabei entschärft wird. Ein einfaches Beispiel: das XML-Element "wert" sei im XML Schema als xs:decimal deklariert. Die XML-Daten kommen jedoch in folgendem Format: <wert>123,45</wert>. Korrekt im Sinn vom XML Schema wäre <wert>123.45</wert>, daher würde die XML Schema Validierung auf einen Fehler laufen, der anschließende Konvertierungsprozeß würde gestoppt.

Wenn nun an dem Grundsatz der Schemavalidierung VOR Weiterverarbeitung zwar festgehalten, derart hinderliche Spezialproblemchen aber trotzdem gezielt zugelassen werden sollen, dann bleibt nur, das XML Schema so zurechtzubiegen, daß es als Dezimaltrenner sowohl ein Komma als auch einen Punkt akzeptiert. Das wäre möglich durch eine Umdefinition von "wert" als xs:string mit einem pragmatisch gedrechselten Pattern. Ein solchermaßen "entschärftes" XML Schema zieht in der anschließenden XSLT Konvertierungsphase zusätzlichen Programmieraufwand nach sich: 123,45 muß erst nach 123.45 konvertiert werden, bevor in XSLT / XPath korrekt damit kalkuliert werden kann.

Je schlechter daher die Input-Datenqualität, desto höher ist der Programmieraufwand der Folgeapplikationen, um brauchbare Endergebnisse zu erhalten. Das beginnt bereits bei simplen Datentypen: etwa wenn geprüft werden muß, ob sich ein Wert als xs:decimal type-casten lässt, was bei "36.57" der Fall ist, bei "36,57" jedoch zu Problemen führt, die anschließend ggf. aufwändig abgefangen werden müssen.

Bereits bei diesem trivialen Beispiel zeigt sich, ob vor einer Weiterverarbeitung der Daten überhaupt validiert werden soll - und falls ja, wie das XML Schema definiert werden muss, um eine Weiterverarbeitung der Inputdaten zu ermöglichen, auch wenn der Dezimaltrenner ein Komma ist. Zwei einfache Beispiele sollen das demonstrieren.


<xs:schema 
  xmlns:xs="http://www.w3.org/2001/XMLSchema" 
  elementFormDefault="qualified" 
  attributeFormDefault="unqualified">
  <xs:element name="ROOT">
    <xs:simpleType>
      <xs:restriction base="xs:decimal">
        <xs:maxInclusive value="99999"/>
        <xs:minInclusive value="-99999"/>
      </xs:restriction>
    </xs:simpleType>
  </xs:element>
</xs:schema>

Das vorstehende XML Schema definiert ein ROOT-Element vom Datentyp xs:decimal im Wertebereich von -99999 bis 99999, das nur entsprchende Werte zulässt. "36.57" wäre OK, "36,57" jedoch nicht.


<xs:schema 
  xmlns:xs="http://www.w3.org/2001/XMLSchema" 
  elementFormDefault="qualified" 
  attributeFormDefault="unqualified">
  <xs:element name="ROOT">
    <xs:simpleType>
      <xs:restriction base="xs:string">
        <xs:pattern 
       value="[-]{0,1}[0-9]{1,5}[.,]{0,1}[0-9]{0,5}"/>
      </xs:restriction>
    </xs:simpleType>
  </xs:element>
</xs:schema>

Das modifizierte XML Schema string_decimal.xsd definiert einen modifizierten String mit bis zu 5 Stellen vor und nach dem Komma, wobei der Dezimaltrenner sowohl Punkt als auch Komma sein kann und auch negative Werte zulässig sind. "36.57" wäre genauso akzeptabel wie "36,57" oder jeweils negative Werte. (Vorsicht: dieses Pattern bildet nicht exakt denselben Wertebereich ab; 99999.1 wäre nach string_decimal.xsd valide, nach decimal.xsd jedoch fehlerhaft.)

Wenn die XSD eine Validierung nach dem String-Pattern erlaubt, so dass der Workflow nicht bereits mit der Validierung der Inputdaten beendet ist (wenn die XSD also "entschärft" wurde), sollte (oder muss) im Folgeschritt, der Auswertung, trotzdem eine Datenkonvertierung mit anschließendem Typecast durchgeführt werden, um mit den Werten sinnvoll und typsauber arbeiten zu können.

Diese Entschärfung kann so weit gehen, daß sie unwirksam wird. Ich habe oft das Argument gehört "Wir haben ein Schema". Dessen Brauchbarkeit wird jedoch nur selten reflektiert. Es hilft wenig, "irgendein" Schema zu haben. Wenn das gewählte XML Schema überhaupt nichts mit den XML-Dokumenten zu tun hat, die dagegen validiert werden sollen, dann ist das Schema ähnlich unbrauchbar, als wenn man sich mit dem Stadtplan von Hamburg in Köln zurecht finden wollte.

Bedeutsamer ist ein anderes Problem. Je mehr man eine XSD "entschärft", desto nutzloser wird sie für die Validierung, und desto höher sind die Anforderungen an die Programmierqualität der Folge-Anwendungen. Ein stark entschärftes Schema, das alles Mögliche "durchlässt", ist unbauchbar, und man kann sich die Validierung der Input-Daten sparen. Es ist ähnlich, als wenn man mit einem weitmaschigen Fischernetz


<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" 
  elementFormDefault="qualified" 
  attributeFormDefault="unqualified">
  <xs:element name="ROOT" type="xs:anyType"/>
</xs:schema>

Das vorstehende XML Schema läßt alles Mögliche zu, auch "Hallo" oder einen komplexen Baum unterhalb ROOT (siehe .

Umgekehrt bietet XML Schema zahlreiche Möglichkeiten zu detaillierter und sehr effizienter Datenmodellierung. Hilfreich, aber selten verwendet ist, eindeutige (xs:key, xs:unique) und abhängige (xs:keyref) Schlüssel zu definieren, analog zu den Primär- und Sekundärschlüsseln in relationalen Datenbanken.

XML Schema bietet also nicht nur zahlreiche Wege, individuell konfigurierte komplexe Strukturbäume mit Elementen, Attributen, Datentypen und namespaces zu definieren, sondern auch Beziehungsstrukturen abzubilden. Damit ist es sehr brauchbar für die Datenmodellierung, zumal es sich nahtlos in relationale Datenbanken sowie in der Objektorientierten Programmierung integrieren läßt: complextypes erlauben die automatische Generierung von Datenbanktabellen ebenso wie Klassen diverser OOP-Sprachen, was bereits in den Webservices effizient zum Einsatz kommt.

XML Schema bietet die ganze Bandbreite der Datenkontrolle: von der sehr genauen Fehlersuche mit dem Läusekamm bis hin zur äußerst toleranten Auslegung, die flexibel jede denkbare Strukturdefinition zulässt. Hier kommt es auf die Frage an, welche Datenqualität benötigt wird.

In diesen Fällen ist die Datenvalidierung eine Frage der Annahmepolitik des jeweiligen Datenempfängers. Einige stehen auf dem Standpunkt: wenn der Lieferant uns keine streng validen Daten schickt, dann lehnen wir den Empfang ab und stoppen den Prozeß; eine Weiterverarbeitung der Daten findet nicht statt. Keine Kompromisse. Ein Beispiel dafür sind Behörden, etwa Zollbehörden. Die wissen sehr genau, welche Informationen sie in welcher Form haben wollen. Wenn die Daten nicht in der klar definierten Form eintreffen, dann wird die Verarbeitung abgelehnt, das Schiff bleibt im Hafen liegen, zu Liegegebühren von 100.000 Dollar - pro Tag.

Ein weiterer Bereich für zwingend hohe Anforderungen an Datenqualität sind GIS-Informationen, also Geodaten. Hier machen nachträgliche Fehlerkorrekturen keinen Sinn, die durch noch so effiziente Programme herauszufinden versuchen, was der Datenlieferant gemeint haben könnte.

Andere Firmen bewerten das umsatzbezogen: Datenlieferungen bedeuten Aufträge, also akzeptieren wir die Daten, ohne sie zu validieren, und anschließend müssen unsere hochbezahlten Programmierer sehen, wie sie aus dem Chaos das Beste machen. Auch ein Standpunkt.

Es macht also Sinn, die Input-Datenvalidierung nur dann einzuschalten, wenn ein Workflow (die Weiterverarbeitung der Daten) gestoppt werden soll, sobald die Inputdaten nicht jenen Kriterien entsprechen, die in der mit dem Datenlieferanten vereinbarten Strukturdefinition vorgegeben sind.

Dabei spielt auch die Frage eine Rolle, ob es sinnvoll ist, den Workflow zu stoppen, weil die Validierung lediglich wegen einiger Input-Datenfelder schiefgeht, die für die folgende Auswertung irrelevant sind. Häufig werden nicht alle Daten eines XML Input Dokuments für die Folgeapplikation benötigt, sondern nur ein Teil, oft weniger als zwanzig Prozent. In diesen Fällen bietet sich an, nicht jene XML Schemadefinition für die Validierung zu verwenden, die mit dem Datenlieferanten ggf. vereinbart (von ihm geliefert) wurde, sondern eine modifizierte, die nur jene Datenfelder prüft, die für die Weiterverarbeitung benötigt werden, und die restlichen Felder ignoriert.

Hinzu kommt, daß die Input-Validierung nicht vor Programmierfehlern in der folgenden Auswertung schützt. So kann es vorkommen, daß im XSD-Input-Dokument einzelne Felder optional deklariert sind (wenn diese Felder im XML-Input-Dokument fehlen, dann meldet die Validierung keinen Fehler). Stellen wir uns weiter vor, daß - basierend auf diesen optionalen Input-Feldern - im Zieldokument mandantory Output-Felder generiert werden sollen. Hier wäre es ein klarer Programmierfehler, blind darauf zu vertrauen, daß die optionalen Input-Felder vorhanden sind. Es ist wichtig, diesen Fall im Programm abzufangen und Defaultwerte zu setzen, so daß das Output Dokument sinnvoll weiter verarbeitet werden kann. Alternativ könnte an dieser Stelle auch die Auswertung abgebrochen werden, etwa mit einer Fehlermeldung an den Developer.

Ein weiteres Problem ist, dass diejenigen, die die XSD's (unmittelbar oder mittelbar, da XSD's automatisch generiert werden) definieren, selten dieselben sind, die sich mit der folgenden Auswertung befassen. Häufig werden mehrere XML Schemadateien zur Verfügung gestellt, die aufeinander aufbauen und sich gegenseitig includieren / importieren. In der Regel ist damit die Definition von Namespaces verbunden, was die automatische Datenauswertung nicht eben leichter macht.

In dem Moment, wo der Datenlieferant seine Applikation ändert (mit dem Hinweis, daß moderne Datensysteme leben und sich auch einmal ändern können; neue Klassen, Versionen etc.), ist damit oft eine Änderung der namespaces, evtl. gar der komplexen Datenstrukturen verbunden, die die gesamten Programme, die auf der bisherigen Struktur arbeiten, über den Haufen wirft. Nichts läuft mehr. Rien ne vas plus.

XML-Schema-Validierung komplexer Variablen

In diesen Kontext passt auch die Schemavalidierung für temporäre komplexe Variablen. Im Kapitel über XML Beispiele hatte ich von alternativen Datenstrukturen gesprochen, deren interne Abhängigkeiten im XSLT Stylesheet teilweise aufwändig nachvollzogen werden müssen. Haben wir es mit einer XML-Dokumentstruktur zu tun, die im Kern einer Datenbankabfrage über mehrere Tabellen entspricht, dann werden klare XPath Statements schwierig. (Zu "XML Aufbau entspricht der Datenbankstruktur")

Um trotzdem zu einer temporären Struktur zu kommen, die sich auch mit anderen XSL-Logiken abarbeiten läßt (zum Beispiel für die Konvertierung nach HTML), lohnt es sich, diese temporäre Struktur zu definieren - und ihre Korrektheit zu überprüfen, bevor eine Folgekonvertierung in ein Endformat stattfindet.

pic/tempTreeNode.png


<xs:schema 
 xmlns:xs="http://www.w3.org/2001/XMLSchema" 
 elementFormDefault="qualified">
 <xs:simpleType name="myStringMax20">
  <xs:annotation>
   <xs:documentation>definiert einen 20 Chars langen 
     String, dessen erstes Zeichen [A-Z] sein muss; die 
     restlichen Zeichen (mind. 1, max. 19) sind [a-z].
   </xs:documentation>
  </xs:annotation>
  <xs:restriction base="xs:string">
   <xs:pattern value="[A-Z][a-z]{1,19}"/>
  </xs:restriction>
 </xs:simpleType>
 <xs:element name="Orte">
  <xs:annotation>
   <xs:documentation>Rooteement für den temp. Baum</xs:documentation>
  </xs:annotation>
  <xs:complexType>
   <xs:sequence>
    <xs:element ref="Ort" maxOccurs="unbounded" minOccurs="0"/>
   </xs:sequence>
  </xs:complexType>
 </xs:element>
 <xs:element name="Ort">
  <xs:complexType>
   <xs:sequence>
    <xs:element ref="id"/>
    <xs:element ref="name"/>
    <xs:element maxOccurs="unbounded" 
                minOccurs="0" ref="Mensch"/>
   </xs:sequence>
  </xs:complexType>
 </xs:element>
 <xs:element name="Mensch">
  <xs:complexType>
   <xs:sequence>
    <xs:element ref="id"/>
    <xs:element ref="name"/>
    <xs:element ref="vorname"/>
    <xs:element ref="Gehalt"/>
    <xs:element maxOccurs="unbounded" 
                minOccurs="0" ref="Kauf"/>
   </xs:sequence>
  </xs:complexType>
 </xs:element>
 <xs:element name="Kauf">
  <xs:complexType>
   <xs:sequence>
    <xs:element ref="bez"/>
    <xs:element ref="Gesamt"/>
   </xs:sequence>
  </xs:complexType>
 </xs:element>
 <xs:element name="bez" type="myStringMax20"/>
 <xs:element name="Gesamt" type="xs:decimal"/>
 <xs:element name="id" type="xs:nonNegativeInteger"/>
 <xs:element name="name" type="myStringMax20"/>
 <xs:element name="vorname" type="myStringMax20"/>
 <xs:element name="Gehalt" type="xs:decimal"/>
</xs:schema>

In der folgenden Logik wird dieser temporäre Baum aus einer Tabellenstruktur generiert. Im Mensch-Loop wird über sämtliche Childnodes des Input-Elements Mensch iteriert, deren Elementname nicht "idOrt" ist. Für jedes davon wird über den Element-Konstruktor xsl:element sowie über die local-name()-Funktion ein entsprechendes Element generiert. Das erleichtert das Mapping gerade bei zahlreichen Elementen, die unverändert übernommen werden sollen.


<xsl:for-each select="child::*[local-name() != 'idOrt']">

Zur Validierung der temporären komplexen Variable "vOrte_from_tab" wird zunächst das XML Schema importiert; die Vaidierung wird mit xsl:validation="strict" durchgeführt. Der Rest der Logik besteht in einer einfachen, aber exakten Adressierung von Elementen im XML input mit Hilfe von Variablen.

Da "xsl:import-schema" nur von einem XSL-Prozessor ausgeführt werden kann, der auch Schema-aware ist, empfiehlt sich hier der Einschub "use-when="system-property('xsl:is-schema-aware') eq 'yes'".


 <xsl:import-schema 
  use-when="system-property('xsl:is-schema-aware') eq 'yes'"
  schema-location="../xsd/tempTreeOrte.xsd"/>
 <xsl:variable name="vOrte_from_tab" as="item()">
  <Orte xsl:validation="strict">
   <xsl:for-each select="/ROOT/Ort">
    <xsl:variable name="vidort" select="id"/>
    <Ort>
     <id><xsl:value-of select="$vidort"/></id>
     <name><xsl:value-of select="name"/></name>
     <xsl:for-each select="/ROOT/Mensch[idOrt=$vidort]">
      <Mensch>
       <xsl:for-each 
        select="child::*[local-name() != 'idOrt']">
        <xsl:element name="{local-name()}">
         <xsl:value-of select="."/>
        </xsl:element>
       </xsl:for-each>
       <xsl:variable name="vidmensch" 
        select="id"/>
       <xsl:for-each select="/ROOT/Kauf[idMensch=$vidmensch]">
        <Kauf>
         <xsl:variable name="vidware" select="idWare"/>
         <bez>
          <xsl:value-of 
           select="/ROOT/Ware[id=$vidware]/bez"/>
         </bez>
         <Gesamt>
          <xsl:value-of 
           select="/ROOT/Ware[id=$vidware]/xs:decimal(preis) 
           * xs:decimal(anzahl)"/>
         </Gesamt>
        </Kauf>
       </xsl:for-each>
      </Mensch>
     </xsl:for-each>
    </Ort>
   </xsl:for-each>
  </Orte>
 </xsl:variable>

Obwohl die Logik im Kern auch in XSLT 1.0 umgesetzt werden könnte, hat die Verwendung von XSLT 2.0 eine Reihe von Vorteilen. Der erste klare Vorteil liegt beim Type-Casting als decimal: würde dieses beim Produkt Gesamt = (preis * anzahl) nicht in dieser Weise vorgenommen, so würde das System automatisch auf xs:double casten (auch anzahl!) - mit der Folge, daß einige unschöne Resultate entstehen würden, zum Beispiel

<Gesamt>181.92999999999998</Gesamt> statt <Gesamt>181.93</Gesamt>. Auf diese Weise werden Fehlerquellen von vornherein vermieden, die später wieder aufwändig beseitigt werden müßten.

Der zweite bedeutende Vorteil liegt darin, daß auch der gesamte relevante Ergebnisbaum durch XML Schema exakt definiert und geprüft werden kann.

Dabei ist es ausreichend, jene Elemente zu mappen, die für die weitere Verwendung erforderlich sind. Andere Elemente des Input-Dokuments, die keine weitere Verwendung finden, können im temporären Ergebnisbaum ignoriert werden.

Das Konzept funktioniert alternativ auch mit .

wg / 4. März 2018



Fragen? Anmerkungen? Tips?

Bitte nehmen Sie Kontakt zu mir auf:

Vorname
Nachname
Mailadresse







Vielen Dank für Ihr Interesse an meiner Arbeit.


V.i.S.d.P.: Wilfried Grupe * Klus 6 * 37643 Negenborn

☎ 0151. 750 360 61 * eMail: info10@wilfried-grupe.de

www.wilfried-grupe.de/XSL_XSD_Validierung.html