Back To Top

info@comelio.com

  • Berlin, Germany
    Comelio GmbH
    Fon: +49.30.8145622.00
    Fax: +49.30.8145622.10

  • Frankfurt, Germany
    Comelio GmbH (Ecos Office)
    Fon: +49.69.1732068.30
    Fax: +49.69.1732068.39

  • Düsseldorf, Germany
    Comelio GmbH (Ecos Office)
    Fon: +49.211.6355642.00
    Fax: +49.211.6355642.09

  • Hamburg, Germany
    Comelio GmbH (Ecos Office)
    Fon: +49.40.209349960
    Fax: +49.40.209349969

  • Hannover, Germany
    Comelio GmbH (Ecos Office)
    Fon: +49.511.165975060
    Fax: +49.511.165975069

  • Stuttgart, Germany
    Comelio GmbH (Ecos Office)
    Fon: +49.711.460512750
    Fax: +49.711.460512759

  • München, Germany
    Comelio GmbH (Ecos Office)
    Fon: +49.711.460512750
    Fax: +49.711.460512759

  • Miami, USA
    Comelio, Inc. (Regus)
    Fon: +1.305.395.7962
    Fax: +1.305.395.7964

  • Kolkata, India
    Comelio Business Solutions Pvt. Ltd.
    Fon: +9133.4601.4451
    Fax:+9133.4601.4452

XML Schema für DB-Modellierung

Comelio Forschung und Entwicklung Softwareentwicklung XML Schema DB-ModellierungDie Vorteile, die sich durch den Einsatz von XML Schema bei der Datenmodellierung ergeben, sind vor allen Dingen in der sehr allgemeinen Speicherung der Daten zu sehen. Statt proprietäre SQL-Befehle oder eine Grafik wie ein ER-Modell, OR-Modell oder eine vereinfachte Version von beiden, erhält man mit einer XML Schema-Datei eine Textdatei, welche die Beschreibung der Feldnamen und ihrer Datentypen verwendet. Ein Vorteil gegenüber SQL besteht darin, dass auf die Besonderheiten der einzelnen Datenbanksysteme verschiedener Hersteller, die sich oft auch in der DDL-Syntax unterscheiden, keine Rücksicht genommen zu werden braucht. Ein weiterer Vorteil liegt darin, dass eine Textdatei und nicht etwa eine Grafik entsteht, die mit sehr einfachen Mitteln lesbar ist und kein spezielles Entwicklungswerkzeug erfordert. Die Erzeugung von SQL-Dateien gelingt dann beispielsweise über XSLT.

Jahr

2005

Finanzierung

Comelio GmbH

Ergebnis

  • Fachliches Modell und Anforderungsanalyse
  • Prototyp in XSLT und .NET für die Generierung von SQL-Skripten zur Erstellung einer relationalen Datenbank

Datenmodellierung mit Elementen und Attributen

Comelio Forschung und Entwicklung Softwareentwicklung XML Schema DB-Modellierung Elemente und AttributeWie im Anleser schon erwähnt, besteht selbstverständlich prinzipiell die Möglichkeit, eine eigene Schema-Datei zu entwickeln, in der die Tabellennamen, Datentypen und Einschränkungen in eigenen Beziehungen gespeichert sind. Dabei könnten auch weiterhin die Datentypen aus XML Schema so wie in jeder anderen Datei für das Element Feld übernommen werden. Hierbei würde man ein eigenes XML-Instanzdokument erstellen, das die Datenbankdaten enthält. Alternativ bieten sich allerdings auch die beiden folgenden sehr einfachen Möglichkeiten an, XML Schema direkt für diese Aufgabe zu verwenden: Anstatt eine Schema-Datei für Dokumente zu entwickeln, die Datenmodelle enthält, setzt man direkt eine Schema-Datei ein, deren Instanzdokumente quasi die in der Datenbank vorhandenen oder geplanten Datenstrukturen sind. Dies ist ein grundsätzlich anderer Ansatz, bei dem eine XML Schema-Datei zum ersten Mal selbst Inhalte enthält, die ansonsten nur in den bisher verwendeten Instanzdokumenten vorhanden waren.

Beispieldatenbank

XML Schema Datenbank Modellierung

Felder als Elemente

Comelio Forschung und Entwicklung Softwareentwicklung XML Schema DB-Modellierung Elemente und AttributeEine erste Möglichkeit für die Abbildung von Datenstrukturen in einer Datenbank ergibt sich über die Konstruktion, die einzelnen Tabellenfelder als Kind-Elemente eines Elements zu definieren, das seinerseits die Tabelle definiert. So enthält folgender kurzer Ausschnitt die Definition einer Tabelle ANRUF mit den Feldern als Kind-Elemente. Die jeweiligen Datentypen der Elemente gelten dann als Datentypen für die Datenbankfelder.

<?xml version="1.0" encoding="ISO-8859-1"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="ANRUF">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="A_NR" type="xs:decimal"/>
        <xs:element name="A_TYP">
          <xs:simpleType>
            <xs:restriction base="xs:string">
              <xs:maxLength value="1"/>
            </xs:restriction>
          </xs:simpleType>
        </xs:element>
        <xs:element name="A_VON" type="xs:decimal"/>
        <xs:element name="A_NACH" type="xs:decimal"/>
        <xs:element name="A_BEGINN" type="xs:dateTime"/>
        <xs:element name="A_ENDE" type="xs:dateTime"/>
        <xs:element name="A_DAUER" type="xs:decimal"/>
        <xs:element name="A_TNR" type="xs:decimal"/>
        <xs:element name="A_PREIS" type="xs:decimal"/>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
...

Man erhält, wie  in der Abbildung gzeigt, eine Reihe von einfachen Elementen, die untereinander in keiner hierarchischen Beziehung zueinander stehen und jeweils in flacher Form Felder in Form von Kind-Elementen enthalten.

XML Schema Datenbank Modellierung

Felder als Attribute

Comelio Forschung und Entwicklung Softwareentwicklung XML Schema DB-Modellierung Elemente und AttributeEine zweite Möglichkeit für die Abbildung von Datenstrukturen in einer Datenbank ergibt sich über die Konstruktion, die einzelnen Tabellenfelder als Attribute eines Elements zu definieren, das seinerseits die Tabelle definiert. So enthält folgender kurzer Ausschnitt die Definition einer Tabelle ANRUF mit den oben in der Abbildung angegebenen Feldern als Attributen. Die jeweiligen Datentypen der Attribute gelten dann als Datentypen für die Datenbankfelder.

<?xml version="1.0" encoding="ISO-8859-1"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="ANRUF">
    <xs:complexType>
      <xs:attribute name="A_NR" type="xs:decimal"/>
      <xs:attribute name="A_TYP">
        <xs:simpleType>
          <xs:restriction base="xs:string">
            <xs:maxLength value="1"/>
          </xs:restriction>
        </xs:simpleType>
      </xs:attribute>
      <xs:attribute name="A_VON" type="xs:decimal"/>
      <xs:attribute name="A_NACH" type="xs:decimal"/>
      <xs:attribute name="A_BEGINN" type="xs:dateTime"/>
      <xs:attribute name="A_ENDE" type="xs:dateTime"/>
      <xs:attribute name="A_DAUER" type="xs:decimal"/>
      <xs:attribute name="A_TNR" type="xs:decimal"/>
      <xs:attribute name="A_PREIS" type="xs:decimal"/>
    </xs:complexType>
  </xs:element>
...

Transformation in SQL

Comelio Forschung und Entwicklung Softwareentwicklung XML Schema DB-Modellierung Elemente und AttributeHat man keine Entwicklungsumgebung zur Hand oder möchte man die Transformation von einer XML Schema-Datei in SQL selbst durchführen, gelingt dies über ein einfaches XSLT-Stylesheet, das in diesem Abschnitt für Elemente und Attribute, aber auch in einer Kombinationsform vorgestellt werden soll. Man erhält nach der Transformation jeweils ein einfaches SQL-Skript, das die Angaben in den beiden bereits verwendeten Schema-Dateien nutzt und Felder mit den im Dokument angegebenen Feldnamen sowie ihren im Dokument angegeben Datentypen erstellt.

Dabei muss berücksichtigt werden, für welche Datenbank das SQL-Skript erstellt werden soll, damit die korrekten Datentypen ausgewählt werden können. In diesem Fall wird es sich stets um ein Skript handeln, das für den Einsatz in Oracle gedacht ist. Weitere Datenbanken lassen sich dann berücksichtigen, wenn man bspw. die Datentyperkennung in einem gesonderten Template unterbringt, das jeweils den gleichen Parameter erwartet – also in diesem Fall die übergebene Zeichenkette der in der XML Schema-Datei gefundenen Werte – und dieses Template über eine für jede Datenbank individuell konfigurierte Datei in die vorhandene Schema-Datei inkludiert. Alternativ bietet sich natürlich auch die Möglichkeit an, nicht für jede Datenbank eine neue, einzubindende Datei zu erstellen, sondern stattdessen in einem umfangreichen Template mit einem zusätzlichen Schaltparameter die unterschiedlichen Datenbanken voneinander zu unterscheiden. Beim Aufruf müsste dann die entsprechende Datenbank über einen standardisierten Parameterwert übergeben werden.

Felder als Elemente

Comelio Forschung und Entwicklung Softwareentwicklung XML Schema DB-Modellierung Elemente und AttributeIm ersten Fall weist die XML Schema-Datei innerhalb der einzelnen Elemente, welche die Tabellen mit Hilfe ihres name-Attributs definieren, für jedes einzelne Feld in einer Tabelle ein Kind-Element auf. Die Tabellenelemente findet der Ausdruck //xs:element[parent::xs:schema], für den eine reihenweise Verarbeitung dieser Elemente angestoßen wird. In der Variablen aktuellesElement speichert man das gerade zu verarbeitende Element bzw. die gerade zu erstellende Tabelle, mit deren Hilfe dann über den Ausdruck //xs:element [ancestor::xs:element/@name=$aktuellesElement] jedes einzelne Kind-Element gefunden wird, das es dann zu verarbeiten gilt.

Diese Verarbeitung besteht zunächst aus einer Ausgabe innerhalb eines Klammerausdrucks, der für die Eingrenzung der Feldliste gebraucht wird. Der Name der zu erstellenden Spalte ergibt sich aus dem name-Attribut des jeweiligen Elements. Komplizierter ist die Erzeugung des Datentyps, da er bei der einfachen Verwendung von Datentypen in XML Schema als Wert des type-Attributs erscheint. Setzt man zur weiteren Einschränkung weitere Fassetten ein, befindet sich diese Angabe im base-Attribut des restriction-Containers, das wiederum innerhalb eines simpleType-Containers liegt. Weil die eigentliche Verarbeitung des im base- oder type-Attribut gefundenen Wertes gleich ist, kann man beide situativ mit Hilfe des Lokalisierungspfades @type | xs:simpleType/xs:restriction/@base auswählen. Mögliche Einschränkungen sind im Standardfall ausschließlich Einschränkungen der Länge. Weitere Einschränkungen über Bedingungen wie CONSTRAINT "TYP" CHECK(A_Typ IN ('g', 'p') müssten noch in das Stylesheet eingebaut werden, indem man sich auf enumeration-Elemente bezieht und dieselben ausliest. Für die Länge allerdings ist die Extraktion sehr einfach, weil man hier über descendant::xs:maxLength/@value jeweils innerhalb des maxLength-Elements das value-Attribut findet, indem genau der Wert gespeichert ist, der später im SQL-Quelltext innerhalb eines Klammerausdrucks als Typbeschränkung in den Ausgabestrom geschrieben wird. Unabhängig davon, welche Datentypangabe der Prozessor findet, übergibt man den gefundenen Wert schließlich an eine spezielle Vorlage, die den Wert mittels einer einfachen Fallunterscheidung untersucht und einen für die jeweilige Datenbank passenden Wert bestimmt und ausgibt.

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xsl:include href="textausrichtung.xslt"/>
  <xsl:output method="text" version="1.0" 
              encoding="ISO-8859-1"/>
  <xsl:template match="//xs:element[parent::xs:schema]">
    <xsl:text>DROP TABLE "</xsl:text>
    <xsl:value-of select="@name"/>
    <xsl:text>";
</xsl:text>
    <xsl:text>CREATE TABLE "</xsl:text>
    <xsl:value-of select="@name"/>
    <xsl:text>" (
</xsl:text>
    <xsl:variable name="aktuellesElement" select="@name"/>
    <xsl:for-each select="//xs:element
            [ancestor::xs:element/@name=$aktuellesElement]">
      <xsl:call-template name="Einzug">
        <xsl:with-param name="grenze" select="5"/>
      </xsl:call-template>
      <xsl:text>"</xsl:text>
      <xsl:value-of select="@name"/>
      <xsl:text>"</xsl:text>
      <xsl:apply-templates select="@type | 
                 xs:simpleType/xs:restriction/@base"/>
      <xsl:apply-templates select="descendant::
                                   xs:maxLength/@value"/>
      <xsl:choose>
        <xsl:when test="position()=last()">
          <xs:text>
);
</xs:text>
        </xsl:when>
        <xsl:otherwise>
          <xsl:text>,
</xsl:text>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:for-each>
  </xsl:template>
  <xsl:template match="@type | 
                xs:simpleType/xs:restriction/@base">
    <xsl:call-template name="Datentyp">
      <xsl:with-param name="xsWert" select="."/>
    </xsl:call-template>
  </xsl:template>
  <xsl:template match="xs:maxLength/@value">
    <xsl:text>(</xsl:text>
    <xsl:value-of select="."/>
    <xsl:text>)</xsl:text>
  </xsl:template>
  <xsl:template name="Datentyp">
    <xsl:param name="xsWert"/>
    <xsl:text> </xsl:text>
    <xsl:choose>
      <xsl:when test="$xsWert = 'xs:decimal'">
        <xsl:text>NUMBER</xsl:text>
      </xsl:when>
      <xsl:when test="$xsWert = 'xs:string'">
        <xsl:text>VARCHAR2</xsl:text>
      </xsl:when>
      <xsl:when test="$xsWert = 'xs:dateTime'">
        <xsl:text>DATE</xsl:text>
      </xsl:when>
    </xsl:choose>
  </xsl:template>
</xsl:stylesheet>

Man erhält schließlich sehr einfachen, aber dennoch innerhalb der jeweiligen Datenbank wirkungsvollen SQL-Quelltext, der innerhalb einer DB-Sitzung unter Verwendung der Standardspeichereinstellungen die entsprechenden Tabellen erzeugt.

...
DROP TABLE "GKUNDE";
CREATE TABLE "GKUNDE" (
      "G_NR" NUMBER,
      "G_NAME" VARCHAR2(200),
      "G_BRANCHE" VARCHAR2(100),
      "G_STRASSE" VARCHAR2(30),
      "G_PLZ" NUMBER,
      "G_STADT" VARCHAR2(30),
      "G_VORWAHL" NUMBER,
      "G_TELNR" NUMBER,
      "G_BEGINN" DATE,
      "G_ENDE" DATE
);
DROP TABLE "MITARBEITER";
CREATE TABLE "MITARBEITER" (
      "M_NR" NUMBER,
      "M_ANREDE" VARCHAR2(5),
      "M_VORNAME" VARCHAR2(20),
      "M_NACHNAME" VARCHAR2(30),
      "M_STRASSE" VARCHAR2(40),
      "M_HAUSNR" VARCHAR2(5),
      "M_PLZ" NUMBER,
      "M_STADT" VARCHAR2(30),
      "M_VORWAHL" NUMBER,
      "M_TELNR" NUMBER,
      "M_FUNKTION" VARCHAR2(30)
);
...

Felder als Attribute

Comelio Forschung und Entwicklung Softwareentwicklung XML Schema DB-Modellierung Elemente und AttributeIm zweiten Fall weist die XML Schema-Datei innerhalb der einzelnen Elemente, welche die Tabellen mit Hilfe ihres name-Attributs definieren, für jedes einzelne Feld in einer Tabelle ein Attribut auf. Die Tabellenelemente findet der Ausdruck //xs:element[parent::xs:schema], für den eine reihenweise Verarbeitung dieser Elemente angestoßen wird. In der Variablen aktuellesElement speichert man das gerade zu verarbeitende Element bzw. die gerade zu erstellende Tabelle, mit deren Hilfe dann über den Ausdruck //xs:element[ancestor::xs:attribute/@name=$aktuellesElement] jedes einzelne Attribut gefunden wird, das es dann zu verarbeiten gilt.

Da für Attribute ebenfalls der Datentyp in einem type-Attribut oder bei Verwendung einer Einschränkung innerhalb eines simpleType- und dann im base-Attribut eines restriction-Containers angegeben wird, bleibt der gesamte Rest des zuvor für den Fall erstellten Stylesheets, dass Kind-Elemente die einzelnen Spalten angeben, erhalten.

Aus der Tatsache, dass die für die Verarbeitung grundlegenden Strukturen für die Kind-Elemente und Attribute gleich sind, lässt sich ein weiteres Stylesheet generieren, das für beide Fälle gleichermaßen gültig ist. Es enthält in einer umfangreichen ODER-Lokalisierung jeweils den passenden Pfad für den einen wie für den anderen Fall.

<xsl:for-each select="//xs:attribute[ancestor::xs:element/
                        @name=$aktuellesElement] | 
                     //xs:element[ancestor::xs:element/
                        @name=$aktuellesElement]">

Erweiterung um Primär- und Fremdschlüssel

Comelio Forschung und Entwicklung Softwareentwicklung XML Schema DB-Modellierung Elemente und AttributeUm zu zeigen, dass auch Erweiterungen des bisher als vernünftig und effizient bewerteten Konzepts, direkt XML Schema für die Datenmodellierung von Datenbanken zu verwenden, möglich sind, sollen im folgenden Beispiel Primär- und Fremdschlüssel in die Datei integriert werden. Dabei drängen sich natürlich die ohnehin schon vorhandenen Strukturen zur Schlüsselerzeugung und Referenz auf, die von den beiden Schema-Komponenten xs:key und xs:keyref her bekannt sind. Dabei sind überlegungen, in welchem Zusammenhang die Schlüssel in XML Schema gelten bzw. was die Positionierung des Schlüssels für die Einzigartigkeitsprüfung innerhalb des Dokuments oder innerhalb der Gültigkeit eines Elements anbetrifft, hier völlig unwichtig.

Da ein Schlüssel innerhalb einer Tabelle gültig sein muss bzw. nicht unterschieden wird, ob er innerhalb eines Elements oder eines Dokuments gültig ist, weil das XML Schema-Dokument keine Dokumente validieren soll, sondern ein wenig zweckentfremdet Datenmodelle beschreibt, ist es für die Verarbeitung mit XSLT besonders erstrebenswert, die Schlüssel an der gleichen hierarchischen Position im Dokument zu positionieren. Dabei können die Schlüssel entweder alle außen auf der obersten Dokumentebene platziert werden, wo sie deutlich und sichtbar alle zusammen stehen, was gerade bei umfangreichen Tabellenbeschreibungen interessant sein könnte. Es besteht allerdings auch die Möglichkeit, sie direkt bei den Elementen der obersten Ebenen zu platzieren, die ihrerseits die verschiedenen Tabellen beschreiben. Dies hilft nicht nur, die Schlüssel genau einer Tabelle zuzuordnen, sondern es wäre der Logik von XML Schema folgend der adäquate Platz. Weil gerade ein Schlüssel innerhalb einer Tabelle bzw. innerhalb eines Elements gültig sein soll, ist die Definition eines Schlüssels als direktes Kind-Element eines tabellenbeschreibenden Elements genau richtig. Die Schlüsselverweise der Fremdschlüssel werden dann ebenfalls hier positioniert und verweisen auf die entsprechenden Primärschlüssel der anderen Elemente bzw. Tabellen.

Im folgenden Dokument sind zunächst für einen bestimmten Ausschnitt die unterschiedlichen Schlüssel definiert, wobei ein Schlüssel und sein zugehöriger Verweis gefettet gehalten sind. Es handelt sich dabei um ein Dokument, in dem die Felder durch Attribute dargestellt werden. Dies soll allerdings nachher bei der Verarbeitung keine Rolle spielen, was natürlich das Transformationsdokument zwar etwas umfangreicher, dafür allerdings universell einsetzbar macht. Insgesamt ist allerdings – sofern man die Transformation noch einmal selbst erstellen möchte – die Verwendung der Element-Form für die einzelnen Felder einfacher, da zum Wert im xpath-Ausdruck der xs:key- und xs:keyref-Elemente jeweils auch das @-Zeichen zur Navigation entlang der Attributachse gehört, was gleich extra berücksichtigt werden muss.

<xs:element name="POSTEN">
  <xs:complexType>
   ...
  </xs:complexType>
  <xs:key name="PoSchluessel">
    <xs:selector xpath="."/>
    <xs:field xpath="@P_NR"/>
  </xs:key>
  <xs:keyref name="RVerweis" refer="RSchluessel">
    <xs:selector xpath="."/>
    <xs:field xpath="@R_NR"/>
  </xs:keyref>
  <xs:keyref name="TVerweis" refer="TSchluessel1">
    <xs:selector xpath="."/>
    <xs:field xpath="@T_NR"/>
  </xs:keyref>
</xs:element>
...
<xs:element name="TARIF">
  <xs:complexType>
    <xs:attribute name="T_NR" type="xs:decimal"/>
    <xs:attribute name="T_NAME">
...
  </xs:complexType>
  <xs:key name="TSchluessel1">
    <xs:selector xpath="."/>
    <xs:field xpath="@T_NR"/>
  </xs:key>
  <xs:key name="TSchluessel2">
    <xs:selector xpath="."/>
    <xs:field xpath="@T_NAME"/>
  </xs:key>
</xs:element>

Wie oben schon angedeutet, unterscheiden sich die beiden Dateiformen für die Verarbeitung der Schlüssel sehr viel deutlicher als für die Erstellung der Feld-Liste. Hier konnte ja durch eine einfache ODER-Verknüpfung sowohl der Fall, dass die Elemente in Attributen, wie auch der, dass sie in Elementen liegen, gelöst werden. Weil jedoch die Verlinkung innerhalb der XPath-Ausdrücke für Schlüssel und Verweise in ein Attribut hinein über die @-Achse verläuft, steht natürlich auch hier in jedem Attributwert des Attributs xpath an erster Stelle das die Achse angebende @-Zeichen.

Mit //xs:element[parent::xs:schema] findet man zunächst wieder alle Eltern-Elemente, welche die Tabellen angeben. In Ergänzung zum bereits oben abgedruckten Stylesheet, von dem hier aus Platzgründen nur die neuen Bereiche zu finden sind, unterscheidet der Ausdruck position()=last() and not(//xs:key[ancestor::xs:element/ @name=$aktuellesElement]), ob überhaupt Schlüsselelemente zu finden sind oder nicht. Ist dies nicht der Fall, wird die Verarbeitung wie zuvor mit dem Beenden des SQL-Quelltextes für die gerade bearbeitete Tabelle fortgesetzt. Andernfalls findet der Ausdruck //xs:key[ancestor::xs:element/ @name=$aktuellesElement] alle Schlüsselelemente des aktuellen Tabellendefinitionselements, für die in einer Schleife mit dem gleichen Auswahlkriterium unterschieden werden muss, ob es sich beim Fundort des Schlüsselwortes um eine Attributachse oder um eine Elementachse handelt.
Hier ist eine wichtige Einschränkung zu machen, die mit den überlegungen weiter unten zusammenhängt: Dieses Stylesheet erwartet, dass im xpath-Ausdruck des xs:field-Elements genau das Attribut oder der Name des Elements zu finden ist, in dem der Schlüsselwert enthalten ist. Es darf also derzeit kein Punkt bzw. die current()-Funktion enthalten sein. In diesem Fall – so müsste man zusätzlich in einer Fallunterscheidung ergänzen – könnte nur zwangsläufig der Wert des xpath-Attributs des xs:selector-Elements den passenden Knoten liefern.

Die Wertausgabe erfolgt dann zweigeteilt durch die Fallunterscheidung für die Attributachse über den Testausdruck starts-with(xs:field/@xpath, '@') mit Hilfe des Lokalisierungspfades substring(xs:field/@xpath, 2) für das xsl:value-of-Element und für die Element-Form mit Hilfe des sehr einfachen Lokalisierungspfades xs:field/@xpath im Standardfall.

Für die Erzeugung von Fremdschlüsselbeziehungen folgt man dem gleichen Prinzip, indem zunächst auf die Existenz von xs:keyref-Knoten mit Hilfe des Ausdrucks not(//xs:keyref[ancestor:: xs:element / @name=$aktuellesElement]) hin getestet wird. Ist dies nicht der Fall, beendet man den SQL-Quelltext für diese Tabelle, wohingegen man im anderen Fall in einer Schleife die gleichermaßen mit //xs:keyref[ancestor:: xs:element / @name=$aktuellesElement] gefundenen Elemente der Reihe nach verarbeitet. Dabei gleicht diese Verarbeitung der gerade für die Primärschlüssel gefundenen Werte, was die XPath-Ausdrücke betrifft, wenn auch ansonsten andere Zeichenkettenkonkatenationen (Zusammensetzungen) notwendig sind, um den korrekten Ausgabestrom zu erzeugen.

Für die den Schlüsselverweisen zugehörigen Zieltabellen, die ja neben dem Auffinden und der Ausgabe der Schlüsselfelder ebenfalls notwendig sind, findet der Ausdruck //xs:element[xs:key/ @name=$schluessel]/@name" die zugehörigen Namen der Eltern-Elemente bzw. aus SQL-Perspektive die benötigten Tabellennamen. Da die Referenzen in der Form tabellenname.spaltenname erfolgen müssen, schreibt das Stylesheet zunächst den gefundenen Tabellennamen (Wert des name-Attributs des Eltern-Elements vom gesuchten Schlüssel) in den Ausgabestrom, gefolgt vom ähnlich wie bei der Primärschlüsselausgabe behandelten Wert der Spaltennamen, in dem der Fremdschlüsselwert auffindbar ist.

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xsl:include href="textausrichtung.xslt"/>
  <xsl:output method="text" version="1.0" 
              encoding="ISO-8859-1"/>
  <xsl:template match="//xs:element[parent::xs:schema]">
...
      <xsl:apply-templates select="@type | 
           xs:simpleType/xs:restriction/@base"/>
      <xsl:apply-templates 
           select="descendant::xs:maxLength/@value"/>
      <xsl:choose>
        <xsl:when test="position()=last() and 
             not(//xs:key[ancestor::xs:element/
             @name=$aktuellesElement])">
          <xs:text>)
);
</xs:text>
        </xsl:when>
        <xsl:otherwise>
          <xsl:text>,
</xsl:text>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:for-each>
    <xsl:if test="//xs:key[ancestor::xs:element/
                    @name=$aktuellesElement]">
      <xsl:text>PRIMARY KEY(</xsl:text>
      <xsl:for-each select="//xs:key[ancestor::xs:element/
                              @name=$aktuellesElement]">
        <xsl:choose>
         <xsl:when test="starts-with(xs:field/@xpath, '@')">
            <xsl:text>"</xsl:text>
         <xsl:value-of select="substring(xs:field/@xpath, 
                                                       2)"/>
          </xsl:when>
          <xsl:otherwise>
            <xsl:text>"</xsl:text>
            <xsl:value-of select="xs:field/@xpath"/>
            <xsl:text>"</xsl:text>
          </xsl:otherwise>
        </xsl:choose>
        <xsl:choose>
          <xsl:when test="position() > 1  and 
                          not(position()=last())">
            <xsl:text>" </xsl:text>
          </xsl:when>
          <xsl:otherwise>
            <xsl:text>"</xsl:text>
          </xsl:otherwise>
        </xsl:choose>
        <xsl:choose>
          <xsl:when test="not(//xs:keyref[ancestor::
                    xs:element/@name=$aktuellesElement])">
            <xsl:choose>
              <xsl:when test="position()=last()">
                <xs:text>)
);
</xs:text>
              </xsl:when>
              <xsl:otherwise>
                <xsl:text>, </xsl:text>
              </xsl:otherwise>
            </xsl:choose>
          </xsl:when>
          <xsl:otherwise>
            <xsl:text>),
</xsl:text>
            <xsl:for-each select="//xs:keyref[ancestor::
                 xs:element/@name=$aktuellesElement]">
              <xsl:text>FOREIGN KEY (</xsl:text>
              <xsl:choose>
                <xsl:when test="starts-with(xs:field/@xpath, 
                                                      '@')">
                  <xsl:text>"</xsl:text>
                  <xsl:value-of select="substring
                                     (xs:field/@xpath, 2)"/>
                  <xsl:text>"</xsl:text>
                </xsl:when>
                <xsl:otherwise>
                  <xsl:text>"</xsl:text>
                  <xsl:value-of select="xs:field/@xpath"/>
                  <xsl:text>"</xsl:text>
                </xsl:otherwise>
              </xsl:choose>
              <xsl:variable name="schluessel" 
                            select="@refer"/>
              <xsl:text>) REFERENCES "</xsl:text>
              <xsl:value-of select="//xs:element[xs:key/
                            @name=$schluessel]/@name"/>
              <xsl:text>"(</xsl:text>
              <xsl:choose>
                <xsl:when test="starts-with(//xs:key
                [@name=$schluessel]/xs:field/@xpath, '@')">
                  <xsl:text>"</xsl:text>
                  <xsl:value-of select="substring(//xs:key
                  [@name=$schluessel]/xs:field/@xpath, 2)"/>
                  <xsl:text>"</xsl:text>
                </xsl:when>
                <xsl:otherwise>
                  <xsl:text>"</xsl:text>
                  <xsl:value-of select="//xs:key
                  [@name=$schluessel]/xs:field/@xpath"/>
                  <xsl:text>"</xsl:text>
                </xsl:otherwise>
              </xsl:choose>
              <xsl:choose>
                <xsl:when test="position()=last()">
                  <xs:text>)
);
</xs:text>
                </xsl:when>
                <xsl:otherwise>
                  <xsl:text>), 
</xsl:text>
                </xsl:otherwise>
              </xsl:choose>
            </xsl:for-each>
          </xsl:otherwise>
        </xsl:choose>
      </xsl:for-each>
    </xsl:if>
  </xsl:template>

Man erhält das folgende, um die Fremdschlüsselbeziehungen ergänzte Ausgabedokument in der SQL-Syntax für Oracle. Wichtig für die Funktionsweise ist wie immer – wenngleich auf diesen Umstand die Dokumentation des XSLT-Dokuments nicht hingewiesen hat –, dass stets die Fälle berücksichtigt werden, dass mehrere Fremdschlüssel enthalten sind, nur einer oder auch keiner vorhanden ist. In Abhängigkeit von diesen Umständen ist entweder das Ende des SQL-Quelltextes (keine weiteren, der letzte oder gar kein Knoten gefunden) oder ein Komma auszugeben.

DROP TABLE "TARIF";
CREATE TABLE "TARIF" (
      "T_NR" NUMBER,
      "T_NAME" VARCHAR2(20),
…
PRIMARY KEY("T_NR", "T_NAME")
);
DROP TABLE "POSTEN";
CREATE TABLE "POSTEN" (
      "P_NR" NUMBER,
      "R_NR" NUMBER,
      "T_NR" NUMBER,
      "P_SUMME" NUMBER,
PRIMARY KEY("P_NR"),
FOREIGN KEY ("R_NR") REFERENCES "RECHNUNG"("R_NR"), 
FOREIGN KEY ("T_NR") REFERENCES "TARIF"("T_NR")
);
DROP TABLE "MITARBEITER";
CREATE TABLE "MITARBEITER" (
      "M_NR" NUMBER,
...
      "M_FUNKTION" VARCHAR2(30),
PRIMARY KEY("M_NR")
);

Zusätzliche SQL-Eigenschaften

Comelio Forschung und Entwicklung Softwareentwicklung XML Schema DB-Modellierung Elemente und AttributeEine ganz wesentliche SQL-Eigenschaft ist natürlich in großen Datenbanken die Angabe von Einschränkungen, wie sie in folgendem kurzen Auszug erscheinen:

...
  "A_TNR" NUMBER(3)    NOT NULL,
  "A_PREIS" NUMBER(10, 2) NOT NULL, 
    CONSTRAINT "BEGINN" CHECK(A_Beginn < A_Ende), 
    CONSTRAINT "ENDE"   CHECK(A_Ende > A_Beginn), 
    CONSTRAINT "DAUER"  CHECK(A_Dauer > 0),
    CONSTRAINT "TYP"    CHECK(A_Typ IN ('g', 'p')),
    PRIMARY KEY("A_NR"))
...

Einige dieser Einschränkungen wie z.B. der eingeschränkte Wertebereich für die Spalte A_Typ lassen sich leicht über die xs:enumeration-Fassette direkt über die Syntax von XML Schema modellieren. Untere und obere Grenzen (sowohl eingeschlossene als auch ausgeschlossene) können ebenfalls in XML Schema mit dem Schrankenkonzept über {min|max}{In|Ex}clusive realisiert werden.

Andere allerdings, wie die überprüfungen auf bestimmte Werte hin, die aus Spalteninformationen bezogen werden, würden in jedem Fall verlangen, dass man eigene Elemente erstellt und diese in XML Schema z.B. über einen eigenen Namensraum integriert. Dies ist in den meisten Fällen nicht zulässig, wohl kann man aber Attribute aus einem anderen Namensraum verwenden, ohne die allgemeinen Regeln von XML Schema zu verletzten.

Diese Attribute bedürfen lediglich der Möglichkeit, vorher eingegrenzte bzw. standardisierte Ausdrücke in der Form feldname operator feldname zu übernehmen. Die Transformation muss diese Ausdrücke dann in der im Dokument gefundenen Reihenfolge innerhalb eines CHECK(-ausgelesener Inhalt-)-Ausdrucks wieder in den Ausgabestrom schreiben. Problematisch wäre die Angabe mehrerer Bedingungen, da jeweils drei Attribute zu einer Gruppe zusammengefasst werden müssten. Einfacher wird es, wenn man akzeptiert, dass die Angaben im Grunde genommen für XML Schema sowieso keine Bedeutung gewinnen können, da sie simple Textinhalte von Attributen darstellen und man letztendlich die gesamte zusätzliche Bedingungen als Attributwert speichern könnte. Daraus ergibt sich dann direkt der Wert für den Eintrag in SQL.