1 NEUHohenstein.fm

Werbung
Generierung von XML aus relationalen Daten
Uwe Hohenstein
Generierung von XML
aus relationalen Daten
1
Einleitung
Die Relevanz von XML in der heutigen
IT-Landschaft ist unbestritten und hat zu
sehr vielfältigen Einsätzen geführt. Eine
wichtige Rolle kommt dabei der adäquaten Speicherung und Verwaltung von
XML-Dokumenten zu [Klettke & Meyer
2003]. Die Forschung und Entwicklung
hat in diesem Bereich zur neuen Technologie der nativen XML-Datenbanken mit
einer direkten und dedizierten Speicherung von XML geführt. Aus diesen Arbeiten sind Produkte wie Tamino von der
Software AG [Schöning 2001] entstanden.
Allerdings befinden sich große Mengen an Geschäftsdaten in »altbackenen«
relationalen Datenbanken – im Prinzip
entsteht hier aus XML-Sicht eine neue
Ausprägung von Legacy-Daten.
Eine Konvertierung dieser relationalen Daten nach XML ist sinnvoll:
• Für einen Datenaustausch über XML:
XML wird immer mehr als Datenaustauschformat verwendet, um Daten
von einem Rechner zu einem anderen
zu schicken. Das gilt natürlich auch
für die in relationalen Datenbanken
vorliegenden Daten.
• Für eine Präsentation von relationalen Daten im Web, um beispielsweise
Kataloge dynamisch zusammenzustellen und mit XSLT-Stylesheets
kunden- oder endgerätespezifisch
(HTML, WML etc.) aufzubereiten.
Der Großteil dieser relationalen Daten
wird weiterhin von Datenbankanwendungen benutzt, so dass sich eine Migration
in eine XML-Datenbank verbietet. Somit
ist häufig die Situation anzutreffen, dass
für eine zuverlässige Datenspeicherung
eine relationale Datenbank benutzt wird,
wohingegen XML zur flexiblen Darstellung der Daten zum Einsatz kommt.
Demzufolge ist eine Brücke nötig, um die
Anforderungen XML-basierter Applikationen mit den Möglichkeiten eines
RDBMS zu kombinieren.
Die RDBMS-Hersteller haben frühzeitig reagiert: Es gibt viele proprietäre
52
Ansätze von namhaften Herstellern wie
IBM, Microsoft oder Oracle, die SQL erweitern oder neuartige Abbildungsvorschriften definieren. Auf den Markt drängen zudem viele Drittanbieter mit Mapping-Tools wie Castor oder XML-DBMS
[Bourret 2002], die auf beliebige relationale Datenbanken aufsetzen und sich somit eine Herstellerunabhängigkeit bewahren.
Dieser Beitrag geht als Ergänzung
zum Übersichtsartikel [Klettke & Meyer
2003] auf diese konzeptionellen Lösungen im Detail ein, wobei auf die Komposition von XML aus relationalen Daten
fokussiert wird; die Speicherung von
XML-Dokumenten in relationalen Strukturen wird nur kurz angerissen. Aufgrund der sehr verschiedenartigen Ansätze entsteht gerade im Rahmen der SQLStandardisierung der SQL/XML-Standard, der dem Wildwuchs Einhalt gebieten soll. Dieser wird anschließend beschrieben.
2
Proprietäre Herstelleransätze
Der Ausgangspunkt für eine XML-Erzeugung sind bestehende Tabellen. Zur
Illustration der verschiedenen Ansätze
werden zwei Beispieltabellen benutzt:
Person (Nr, Name, Plz, Ort,
Strasse, Hausnr)
Telefon (PNr, Telnr)
Eine Fremdschlüsselbeziehung von Telefon.PNr zu Person.Nr drückt eine
mengenwertige Eigenschaft aus: Eine
Person besitzt mehrere Telefone.
Abbildung 1 zeigt eine denkbare Repräsentation eines zugehörigen Datenbestands als XML-Dokument.
Das <Personen>-Element umschließt den Dateninhalt, jedes Tupel
wird als <Person>-Element mit der
Nummer als XML-Attribut repräsentiert.
Abweichend von der relationalen Darstellung werden im XML-Dokument die
Adressteile zu einem neuen XML-Element <Adresse> strukturiert. Des Weiteren kommt es zu einer Schachtelung der
Telefone als
Wiederholungsgruppe
<TelListe>.
<Personen>
<Person Nr="1">
<Name> Lucky Luke </Name>
<Adresse>
<Plz> 81730 </Plz>
<Ort> München </Ort>
<Strasse> Otto-Hahn-Ring
</Strasse>
<Hausnr> 6 </Hausnr>
</Adresse>
<TelListe>
<Telefon> 089/123456
</Telefon>
<Telefon> 0171/34567
</Telefon>
</TelListe>
</Person>
<Person Nr="2">
...
</Person>
</Personen>
Abb. 1: XML-Darstellung
Die nachfolgend diskutierten Ansätze
werden grob in drei Kategorien unterteilt:
a) Die beschreibungsbasierten Ansätze
spezifizieren eine Abbildung von Tabellen nach XML.
b) Die XML-basierten Verfahren definieren eine XML-Sicht auf relationale Daten.
c) Die SQL-basierten Ansätze erweitern
SQL um neue XML-Funktionen.
2.1 IBMs DB2 XML Extender
Die hier diskutierte Funktionalität ist ab
DB2 UDB Version 7.1 verfügbar.
a) XML Collection
Der beschreibungsbasierte Ansatz der
XML Collections beruht auf einer so genannten Document Access Definition
(DAD). Eine DAD ist eine XML-Datei
mit einer Abbildungsbeschreibung. Im
Prinzip lässt sich die Datei als ein XMLTemplate auffassen, in das relationale Daten als Textinhalte eingebettet werden.
XML Collection bietet zwei Verfahren zur Konstruktion von XML:
1) Die Daten werden über eine SQL-Anfrage berechnet.
2) Komplette Tabellen, evtl. mit Tupelselektionen, bilden den Inhalt.
Der Ansatz (1) ist im Gegensatz zu (2)
aufgrund des »View Update«-Problems
nur für lesende Zugriffe vorgesehen.
Ein Beispiel einer DAD-Datei zeigt
für (1), wie ein SQL-Statement Daten aus
der Datenbank selektiert und im Sinne
von Abbildung 1 als XML aufbereitet.
Datenbank-Spektrum 7/2003
Generierung von XML aus relationalen Daten
<?xml version="1.0"?>
<!DOCTYPE DAD SYSTEM
"/dxx_xml/test/dtd/dad.dtd">
<DAD>
<validation>NO</validation>
<Xcollection>
<SQL_stmt>
SELECT p.Nr, Name, Plz,
p.Ort, p.Strasse,
p.Hausnr, t.Telnr
FROM Person p, Telefon t
WHERE p.Nr=t.PNr
ORDER BY p.Nr
</SQL_stmt>
<prolog>?xml version="1.0"?
</prolog>
<doctype>!DOCTYPE Test SYSTEM
"test.dtd"</doctype>
<root_node>
<element_node name="Person">
<attribute_node name="Nr">
<column name="Nr"/>
</attribute_node>
<element_node name="Name">
<text_node>
<column name="Name"/>
</text_node>
</element_node>
<element_node
name="Adresse">
<element_node name="Plz">
<text_node>
<column name="Plz"/>
</text_node>
...
</element_node
</element_node
<element_node
name="TelListe">
<element_node
name="Telefon"
multi_occurrence="YES">
<text_node>
<column name="Telnr"/>
</text_node>
</element_node>
</element_node
</element_node>
</root_node>
</Xcollection>
</DAD>
Das <SQL_stmt>-Element der <Xcollection> spezifiziert zunächst die auszuwertende SQL-Anfrage. Die Anfrage
hat gewisse Konventionen einzuhalten:
• Die Reihenfolge der im SELECTStatement angesprochenen Tabellen
entspricht dem hierarchischen Aufbau des zu erzeugenden Dokuments.
• Die Namen der Ergebnisspalten müssen eindeutig sein, da die XML-Einheiten Bezug über diese Namen nehmen. Natürlich ist eine Umbenennung mit AS-Aliasen möglich.
• Die Spalten müssen tabellenweise
gruppiert sein, wobei jeweils ein lo-
Datenbank-Spektrum 7/2003
kaler Identifikator der Gruppe vorangeht; dieser kann ein Primärschlüssel
der entsprechenden Tabelle oder vom
DBMS mit generate_unique()
generiert sein.
• Zwischen den Tabellen müssen JoinBedingungen bestehen.
• Eine abschließende Sortierung über
die Identifikatoren muss ebenfalls die
XML-Hierarchie reflektieren.
Nachfolgend wird die XML-Dokumentstruktur festgelegt. Hinter <root_
node> folgt die Wurzel des XML-Ergebnisdokuments. <element_node> kennzeichnet Elemente und <attribute_
node> legt Attribute fest. Im Prinzip
handelt es sich hierbei um eine spezielle
Schemabeschreibungssprache, die gewisse Grundzüge mit XML-Schema teilt,
aber dennoch proprietär ist. Die Struktur
des resultierenden XML-Dokuments ist
mit diesen Mechanismen relativ frei definierbar. Zum Beispiel sind Elemente wie
<Adresse> oder <TelListe> einfügbar. Das XML-Attribut multi_occurrence drückt bei <element_node
name="Telefon"> eine Wiederholungsgruppe aus.
Um das Anfrageergebnis dann im
XML-Dokument »einzusortieren«, wird
der Bezug zu den relationalen Daten hergestellt. <text_node> zeichnet einen
Textknoten aus, der z.B. über <column
name="..."> aus einer Ergebnisspalte
aufgefüllt wird; der Bezug zur SQL-Anweisung erfolgt über Namensgleichheit.
Bei XML-Attributen kann der Wert direkt
über <column>, d.h. ohne Textknoten,
berechnet werden.
Das Ergebnis kann zusätzlich mit
XSLT aufbereitet werden, indem ein
<stylesheet>-Element ein Stylesheet
registriert. Des Weiteren ist auch eine Validierung des Ergebnisses gegenüber einer DTD mit <validation> möglich.
Beim Ansatz (2) werden statt Anfragen ganze Tabellen behandelt. Dadurch
wird die Abbildung »umkehrbar«; eine
Speicherung von XML-Daten wird möglich. Syntaktisch werden nun bei
<root_node> zum Wurzelelement mit
<RDB_node> alle zu berücksichtigenden
Tabellen aufgelistet:
<root_node>
<element_node name="Person">
<RDB_node>
<table name="Person">
<table name="Telefon">
<condition>
Person.Nr=Telefon.PNr
</condition>
</RDB_node>
...
Hiermit sind die beteiligten Tabellen festgelegt. <condition> drückt zudem
eine Join-Bedingung aus, um die Tabellen in Beziehung zu setzen. Ist auch eine
XML-Speicherung gewünscht, so ist zusätzlich für jede Tabelle eine Schlüsselangabe mit key="spalte1 spalte2
..." erforderlich. Anschließend kann
die innere Struktur des Wurzelelements
festgelegt werden, indem Elemente und
Attribute wie folgt Bezug zu Tabellen und
Spalten nehmen:
<RDB_node>
<table name="Person"/>
<column name="Nr"/>
</RDB_node>
Die Verarbeitung wird mit verschiedenen
gespeicherten Prozeduren angestoßen,
denen eine DAD-Datei dad mitgegeben
wird und mit denen sich XML-Dokumente aus relationalen Daten gemäß der spezifizierten Abbildung komponieren lassen. So gibt z.B. dxxGenXMLCLOB
(CLOB dad, ..., CLOB result,
int maxRows, int numRows, long
returnCode,
varchar
returnMsg) das resultierende XML-Do-
kument als CLOB-Wert über den OUTParameter result zurück. Der Parameter maxRows ist nützlich, um das Ergebnis portionsweise abzuholen, indem die
Anzahl Tupel beschränkt wird. Das verkürzt die Verarbeitungszeit.
dxxShredXML(CLOB dad, CLOB
xmlobj, long returnCode, varchar
returnMsg) ist für die XML-Speiche-
rung mit dem Ansatz (2) relevant. Das
übergebene Dokument xmlobj wird gemäß der DAD dad zerlegt und feinstrukturiert in der Datenbank gespeichert.
b) Xperanto / XTables
Xperanto [Fan et al. 2002], neuerdings
auch als XTables bezeichnet, ist eine
Middleware, die sich noch im Prototypstadium befindet. Hier soll es dennoch erwähnt werden, da der Ansatz die zukünftige Entwicklung maßgeblich prägen wird.
Das Prinzip besteht darin, eine XMLSicht für relationale Daten als XQueryAusdruck zu spezifizieren. Insofern ist
der Ansatz der Kategorie (b) zuzuordnen.
Die Sicht ist selbst wieder mit XQuery
abfragbar, so dass das Konzept in sich abgeschlossen ist.
53
Generierung von XML aus relationalen Daten
Da der XQuery-Anfragemechanismus eigentlich für XML und nicht für relationale Datenbanken gedacht ist, ist
eine XML-Repräsentation der Datenbank
als Ausgangspunkt nötig:
<db>
<Person>
<row>
<Nr> 1 </Nr>
<Name> Lucky Luke </Name>
<Plz> 81730 </Plz>
<Ort> München </Ort>
<Strasse> Otto-Hahn-Ring
</Strasse>
<Hausnr> 6 </Hausnr>
</row>
...
</Person>
<Telefon>
<row>
<PNr> 1 </PNr>
<Telnr>089/123456</Telnr>
</row>
<row>
<PNr> 2 </PNr>
<Telnr>0171/34567</Telnr>
</row>
...
</Telefon>
</db>
Diese Default-XML-Sicht ist implizit
vorhanden und trägt den festen Namen
default. Sie repräsentiert direkt die Tabellen und Tupel. Je Tabelle gibt es ein
Element mit dem Tabellennamen, das
wiederum die Tupel als <row>-Elemente
enthält. Auf der Defaultsicht aufbauend
können benutzerdefinierte XML-Sichten
mit XQuery spezifiziert werden:
CREATE VIEW vw AS (
<Personen> {
for $p in
view("default")/Person/row
return
<Person>
<Nr> {$p/Nr} </Nr>
<Name> {$p/Name} </Name>
<Adresse>
<Plz> {$p/Plz} </Plz>
...
</Adresse>
<TelListe> {
for $t in view("default")/
Telefon/row
where $p/Nr=$t/PNr
return
<Telefon> {$t/Telnr}
</Telefon> }
</TelListe>
</Person> }
</Personen>
)
Der XQuery-Ausdruck baut die XMLStruktur aus Abbildung 1 auf. Mit
view("default") wird innerhalb des
54
Ausdrucks Bezug auf die Defaultsicht
default genommen. Mit for $p werden alle Person-Tupel durchlaufen, um
<Person>-Elemente zusammenzustellen. Die innere Schleife for $t bestimmt
die Telefone jeder Person $p. Ein return-Ausdruck liefert jeweils das Teilergebnis, wobei Ausdrücke wie {$p/Plz}
ausgewertet werden.
Diese View vw repräsentiert ein
XML-Dokument, das nun ausgebbar ist.
Derartige XML-Sichten lassen sich
mit view("vw") wieder in XQuery-Anfragen nutzen, d.h., man bewegt sich nun
in der XML-Welt und nicht mehr in SQL.
Nichtsdestoweniger werden XQuery-Anfragen intern relational »ausgeführt«, d.h.
in SQL übersetzt und an die SQL-Anfragebearbeitung weitergeleitet.
2.2 Microsoft SQL Server 2000
Die folgende Diskussion bezieht sich auf
»XML for Microsoft SQL Server 2000
Web«, Release 2. Weitere Unterlagen finden sich unter den URLs http://msdn.
microsoft.com/xml und http://msdn.
microsoft.com/sqlxml.
a) ADO.NET
Der für die Microsoft-Welt nahe liegende
Mechanismus nutzt das DataSet-Konzept
aus ADO.NET. Ein DataSet lässt sich mit
SQL füllen und ist dann im Prinzip eine
tabellenartige Hauptspeicherrepräsentation einer oder mehrerer Ergebnistabellen.
DataSet-Methoden ermöglichen das
Produzieren von XML bzw. umgekehrt
das Zerlegen von XML in Tabellen:
• ds.WriteXml("outfile.xml")
schreibt den Inhalt eines DataSet als
XML in die angegebene Datei.
• ds.ReadXml("infile.xml")
liest ein XML-Dokument und speichert es feingranular als DataSet.
Angenommen, ein DataSet ds mit dem
Namen MyDataSet enthält den Inhalt
der Tabellen Person und Telefon.
ADO.NET nimmt dann folgende mit
Xperanto vergleichbare, vorgegebene flache Darstellung des DataSet-Inhalts:
<MyDataSet>
<Person>
<Nr> 1 </Nr>
<Name> Lucky Luke </Name>
<Plz> 81730 </Plz> ...
</Person>
...
<Telefon>
<PNr> 1 </PNr>
<Telnr> 089/123456 </Telnr>
</Telefon>
<Telefon>
<PNr> 1 </PNr>
<Telnr> 0171/34567 </Telnr>
</Telefon>
...
</MyDataSet>
Je Tupel entsteht ein XML-Element mit
dem Namen der Tabelle. Die Einflussnahme auf das XML-Format ist nur begrenzt. Über DataSet-Funktionalität lässt
sich beispielsweise mit col.ColumnMapping=MappingType.Element/Attribute die XML-Repräsentation einer Spalte col als Element oder
Attribut festlegen. Eine Schachtelung der
Telefone innerhalb vom <Person> kann
über DataSet-interne Beziehungen zwischen Tabellen erfolgen (rel.Nested=true).
b) XML-Sichten mit annotierten
Abbildungsschemata
Wie in DB2 besteht auch hier die Möglichkeit, eine XML-Sicht im SQL-Server zu definieren. Das Prinzip ist jedoch
ein anderes: Zum einen wird XML-Schema als Beschreibungssprache benutzt,
zum anderen sind nur XPath- statt
XQuery-Anfragen auf der XML-Sicht
ausführbar. Ein Beispiel myxsd.xsd einer Sicht ist:
<xsd:schema xmlns:xsd="http://
www.w3.org/2001/XMLSchema"
xmlns:sql="urn:schemas-micro
soft-com:mapping-schema">
<xsd:annotation>
<xsd:appinfo>
<sql:relationship
name="Person_Telefon"
parent="Person"
parent-key="Nr"
child="Telefon"
child-key="PNr"/>
</xsd:appinfo>
</xsd:annotation>
<xsd:element name="Person"
sql:relation="Person">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="Nr"
type="xsd:integer"
sql:field="Nr"/>
<xsd:element name="Name"
type="xsd:string"
sql:field="Name"/>
<xsd:element name="Adresse"
sql:relation="Person">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="Plz"
type="xsd:integer"
Datenbank-Spektrum 7/2003
Generierung von XML aus relationalen Daten
sql:field="Plz"/>
...
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element ref="TelListe"
sql:relationship=
"Person_Telefon"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="TelListe">
<xsd:complexType>
<xsd:element name="Telefon"
type="xsd:string"
maxOccurs="unbounded"
sql:field="Telnr"/>
</xsd:complexType>
</xsd:element>
</xsd:schema>
Das XML-Schema legt die XML-Elemente als <element> und die Datentypen als <complexType> fest, um die
Struktur aus Abbildung 1 zu definieren.
sql-Annotationen spezifizieren den Zusammenhang zu Tabellen und Spalten:
sql:relation= "..." bestimmt innerhalb von <xsd:element> eine Tabelle für ein Element, sql:field spezifiziert eine Spalte für innere Elemente
oder Attribute. Schachtelungen entstehen
mit sql:relationship: Das referenzierte Relationship wird in <xsd:annotation> als <sql:relationship
name= .../> mit parent/child-Angaben unter <xsd:appinfo> definiert.
Mit der Sicht bewegt man sich ausschließlich in der XML-Welt, so dass
nun XPath-Anfragen formulierbar sind.
Im einfachsten Fall wird mit einem leeren XPath-Ausdruck " " das gesamte
Dokument zurückgegeben, aber auch
Extraktionen sind möglich. Unterstützt
wird nur eine XPath1.0-Untermenge, die
nur einige Rekursionsachsen und keine
arithmetischen und String-Operationen
bietet.
Folgendes Beispiel zeigt eine XPathAnfrage in ADO, welche alle Telefonnummern einer Person ausgibt:
cmd.Dialect = "{EC2A4293-" +
"E898-11D2-B1B7-00C04F680C56}"
cmd.Properties
("Mapping Schema") = "myxsd.xsd"
cmd.CommandText =
"/Person[Nr='1']//Telefon"
Über Properties wird der Bezug zur
obigen XSD-Datei myxsd.xsd hergestellt, CommandText erhält den XPath.
Das resultierende DataSet kann mit
ADO.NET ausgegeben werden.
Datenbank-Spektrum 7/2003
Eine XPath-Anfrage liefert nicht notwendigerweise ein gültiges XML-Dokument; es ist manchmal aufgrund einer
fehlenden Wurzel nur ein Fragment. In
diesem Fall kann in ADO eine umschließende Wurzel bereitgestellt werden.
Änderungen am Dokument lassen
sich gemäß der XML-Sicht über spezielle
XML-Dokumente, »Updategrams«, ausführen, in denen mit <updg:before>
und <updg:after> der Vorher- bzw.
Nachherzustand beschrieben wird.
Das Ergebnis ist ein relational geprägtes,
flaches XML-Format, das direkt die Tabellenstruktur reflektiert. Bei Joins, wie
im obigen Fall, kommt es dabei zu Redundanzen, die vom SQL-Ergebnis herrühren: Zu jedem Telefon werden die Personendaten des Besitzers wiederholt.
AUTO vermeidet diese Redundanz, indem es eine Schachtelung einführt:
<ROOT xmlns:updg="urn:schemamicrosoft-com:xml-updategram">
<updg:sync
mapping-schema="myxsd.xsd">
<updg:before>
<Nr> 1 </Nr>
</updg:before>
<updg:after>
<Name> Ms. Marple </Name>
</updg:after>
</updg:sync>
</ROOT>
Die FROM-Liste gibt die Reihenfolge der
Schachtelung vor. Auf diese Weise entsteht eine implizite Gruppierung, welche
die beiden Telefon-Daten im <Person>-Element einbettet:
Der <sync>-Teil stellt den Bezug zur
XSD-Datei her. <before> qualifiziert
die zu modifizierenden Tupel. Ist der
<after>-Teil leer, so werden alle qualifizierten Tupel gelöscht. Ohne <before> wird <after> als Dokument
aufgefasst und neu eingefügt. Mit <before> und <after> ist es eine Änderung. Hier wird im Tupel mit Nr=1 (before) der Name auf Ms. Marple (after) abgeändert.
c) FOR XML-Klausel
Die FOR XML-Klausel ist eine SQL-Erweiterung. Insofern gehört der Ansatz zur
Kategorie (c). Da die Abarbeitung im Datenbankkern integriert ist, kann das
DBMS Optimierungen bei der Auswertung vornehmen.
Die FOR XML-Anweisung erweitert
die SELECT-Grundform um:
FOR XML RAW | AUTO | EXPLICIT
Die RAW-Variante nimmt eine Standardumsetzung vor, die jedoch kaum beeinflussbar ist. Für jedes Tupel des Ergebnisses wird ein <row>-Element mit den SELECT-Spalten als Attribute generiert;
Nullwerte führen zu komplett weggelassenen Attributen. Die Anfrage
SELECT * FROM Person p, Telefon t
WHERE p.Nr=t.PNr FOR XML RAW
ergibt beispielsweise
<row Nr="1" Name="Lucky Luke" ...
PNr="1" Telefon="089/123456">
<row Nr="1" Name="Lucky Luke" ...
PNr="1" Telefon="0171/34567">
SELECT * FROM Person p, Telefon t
WHERE p.Nr=t.PNr ORDER BY p.Nr
FOR XML AUTO ELEMENTS
<Person>
<Nr> 1 </Nr>
<Name> Lucky Luke</Name>
<Plz> 81730 </Plz> ...
<Telefon>
<PNr> 1 </PNr>
<Telnr> 089/123456 </Telnr>
</Telefon>
<Telefon>
<PNr> 1 </PNr>
<Telnr> 0171/34567 </Telnr>
</Telefon>
</Person>
...
Der Tabellenname wird jeweils als Elementname genommen. Der Zusatz ELEMENTS lässt die SELECT-Spalten zu inneren Elementen werden, wirkt aber nur
pauschal für das komplette Ergebnis.
Ohne ihn wären die Spaltenwerte wieder
zu Attributen geworden:
<Person Nr="1" Name="Lucky Luke"
...> <Telefon PNr="1"...> ...
Bei der internen Bearbeitung wird für jedes Person-Tupel ein XML-Element erzeugt. Zu allen unmittelbar folgenden Ergebnistupeln zur selben Person werden
die Telefon-Anteile eingebettet. Daher
ist die Sortierung mit ORDER BY bedeutend, weil ansonsten die <Person>-Elemente zu einer Nr, jeweils mit den nachfolgenden Telefonnummern, verstreut
auftreten würden.
Auch bei AUTO ist das erzeugte XMLMuster noch recht starr. Beispielsweise
ist keine Einfügung von zusätzlichen
Strukturierungselementen wie <TelListe> oder <Adresse> möglich.
Diese Defizite werden durch EXPLICIT behoben. EXPLICIT bietet die volle
Flexibilität wie z.B. eine individuelle
Wahl Attribut/Element oder Berechnun-
55
Generierung von XML aus relationalen Daten
SELECT 1 AS Tag, NULL AS Parent, p.Nr AS "Person!1!Nr",
p.Name AS "Person!1!Name", NULL AS "Adresse!2!Plz!ELEMENT",
..., NULL AS "TelListe!2", NULL AS "Telefon!3!Telnr"
FROM Person p
UNION
SELECT 2 AS Tag, 1 AS Parent, NULL AS "Person!1!Nr",
NULL AS "Person!1!Name", p.Plz AS "Adresse!2!Plz!ELEMENT",
... NULL AS "TelListe!2", NULL AS "Telefon!3!Telnr"
FROM Person p
UNION
SELECT 2 AS Tag, 1 AS Parent, NULL AS "Person!1!Nr",
NULL AS "Person!1!Name", NULL AS "Adresse!2!Plz!ELEMENT",
... p.Nr AS "TelListe!2", NULL AS "Telefon!3!Telnr"
FROM Person p
WHERE p.Nr = t.PNr
SELECT 3 AS Tag, 2 AS Parent, NULL AS "Person!1!Nr",
NULL AS "Person!1!Name", NULL AS "Adresse!2!Plz!ELEMENT",
... NULL AS "TelListe!2", t.Telnr AS "Telefon!3!Telnr"
FROM Person p, Telefon t
WHERE p.Nr = t.PNr
ORDER BY [Person!1!Nr]
FOR XML EXPLICIT
• eine Spalte mit Namen Tag (Hierarchienummer)
• eine Spalte Parent (Hierarchienummer des Vaterknotens)
• weitere Spalten der vorgeschriebenen
Form Element!Stufe!Name!Art
Abbildung 2 zeigt eine Anfrage, die das
Ergebnis aus Abbildung 1 generiert. Typischerweise werden mit einem UNION
die Daten der einzelnen Hierarchiestufen
zusammengefügt. Die Anfrage für diese
an und für sich simple Aufgabe wird sehr
komplex und fehleranfällig. Es ist auch
nicht ausgeschlossen, dass ungültige
XML-Dokumente produziert werden.
Zum Verständnis des Prinzips soll die
virtuelle Ergebnistabelle in Abbildung 3
betrachtet werden, die den Ausgangspunkt der Generierung bildet. Die als Tag
und Parent benannten Spalten legen die
PaVater-Sohn-Beziehung
fest:
rent=NULL zeigt eine Wurzel an,
Tag=2 hat wegen Parent=1 den Vater 1
und so fort. Dies beeinflusst die XMLSchachtelung. Die restlichen Spalten
definieren die XML-Elemente und ihre
Werte, jeweils festgelegt durch die
Adresspezielle
Namensgebung:
se!2!Plz!ELEMENT repräsentiert ein
Element Adresse auf der zweiten Hierarchiestufe, dem ein Attribut Plz mitge-
56
string c = "Server=(local);Data"
+"base=northwind;UID=sa;PWD=;";
SqlConnection adoConn
= new SqlConnection(c);
adoConn.Open();
SqlCommand adoCmd = new SqlCommand
("SELECT ... FOR XML RAW");
adoCmd.Connection = adoConn;
DataSet ds = new DataSet();
ds.ReadXml(adoCmd.ExecuteXmlReader(), XmlReadMode.Fragment);
ds.WriteXml(Console.Out);
Neben der Einbettung in ADO.NET gibt
es auch die Möglichkeit, XPath- und
SQL-Anfragen mit einem Webbrowser
auszuführen, beispielsweise als URL:
http://IISServer/nwind?sql=SELECT+...+FOR+XML+AUTO?root=ERG
Abb. 2: SQL-Anfrage mit FOR XML EXPLICIT
gen, was aber durch komplexe und längliche Anfragen bezahlt werden muss.
Der SELECT-Teil der SQL-Anfrage
hat ein gewisses Format einzuhalten. Folgendes muss vorhanden sein:
FOR XML-Anfragen lassen sich als
SQL-Anfrage interaktiv ausführen oder
in eine Programmierschnittstelle einbetten, z.B. mit ADO in C# :
geben wird; der Wert berechnet sich aus
der SELECT-Anweisung. TelListe!2
erzeugt nur ein Element ohne Textinhalt;
der SQL-Wert von p.Nr ist irrelevant. Es
entsteht je Tupel mit Parent=NULL ein
XML-Element der Art:
<Person>
<Nr> 1 </Nr>
<Name> Lucky Luke </Name>
<Adresse>
<Plz> 81730 </Plz>
<Ort>München<Ort>
...
</Adresse>
<TelListe>
<Telefon Telnr="089/123456"/>
<Telefon Telnr="0171/34567"/>
</TelListe>
</Person>
Ohne den Zusatz !ELEMENT werden
Spaltenwerte wieder als Attribute repräsentiert. Andere Angaben sind:
• XMLTEXT: Der Wert wird als literales
XML dargestellt
• CDATA übernimmt den Wert als CDATA-Abschnitt
• ID für ID-Angaben und analog für
IDREF(S)
• HIDE unterdrückt einen Wert in der
XML-Ausgabe
HIDE ist z.B. sinnvoll, um über Spalten
zu sortieren, die nicht Bestandteil des Ergebnisses werden sollen.
Auch bei EXPLICIT muss wieder
eine Sortierung dafür sorgen, dass die
Söhne einer Stufe n unmittelbar ihrem
Vater (der Stufe n-1) folgen.
Durch den Parameter root=ERG bekommt das generierte XML-Dokument
eine umschließende Wurzel ERG zugewiesen. Ohne diese Wurzel würde das Ergebnis im Fall mehrerer Ergebnistupel
ungültiges XML ergeben.
Sowohl die FOR XML-Anweisung als
auch die XPath-Ausdrücke für XMLSichten können in XML-Templates eingebunden werden, die über HTTP oder
WebDAV aufrufbar sind. Hinzu gesellt
sich die Möglichkeit einer XSLT-Nachbearbeitung. Das folgende Template bettet ein FOR XML- (query) und ein XPathAnfrageergebnis (xpath-query) ein:
<ROOT xmlns:sql="urn:schemasmicrosoft-com:xml-sql">
<SQL-Ergebnis>
<sql:query> FOR XML-Anfrage
</sql:query>
</SQL-Ergebnis>
<XPath-Ergebnis>
<sql:xpath-query
mapping-schema="myxsd.xsd">
XPath-Ausdruck
</sql:xpath-query>
</XPath-Ergebnis>
</ROOT>
Der Abruf des Templates ist dann:
http://IISServer/nwind?template=<ROOT>+xmlns:sql=...</ROOT>
Ein solches Template kann auch in ADO
ausgeführt werden.
2.3 Oracle9i
Oracle bietet seit der Version 8i eine umfangreiche XML-Unterstützung wie z.B.
das XML SQL Utility (XSU). Mit der
Datenbank-Spektrum 7/2003
Generierung von XML aus relationalen Daten
Tag
Parent
Person!1!Nr ...
Adresse!2!Plz!Element ...
TelListe!2
Telefon !3!Telnr
1
2
2
3
3
1
...
NULL
1
1
2
2
NULL
1
NULL
NULL
NULL
NULL
2
NULL
81730
NULL
NULL
NULL
...
NULL
NULL
1
NULL
NULL
NULL
NULL
NULL
089/123456
0171/34567
Abb. 3: Virtuelle Ergebnistabelle
Version 9i kommt ein neuer Objekttyp
XMLType zur Abstraktion hinzu, der als
Spaltenwertebereich zur Aufnahme von
XML-Dokumenten konzipiert ist und die
Speicherungsform wählbar und transparent macht. Spezielle SQL-Funktionen
können XMLType-Dokumente verarbeiten, wobei XPath-Funktionalität geboten
wird. Das Buch »Webanwendungen entwickeln mit Oracle9i« [Hohenstein &
Schmatz 2003] geht im Detail auf die gebotene Unterstützung ein.
a) XML SQL Utility
XSU stellt eine programmatische Schnittstelle bereit, mit der sich Anfrageergebnisse als XML-Dokument präsentieren
lassen. Es ist in Java geschrieben und als
Programmierschnittstelle über die bereitgestellten Java-Klassen OracleXMLQuery und OracleXMLSave benutzbar.
Es stehen aber auch Pakete DBMS_XMLQuery und DBMS_XMLSave in der
proprietären Sprache PL/SQL zur Verfügung.
Oracle verfolgt in XSU einen anderen
beschreibungsbasierten Ansatz als DB2
und SQLServer: Die Ergebnisstruktur
und Schachtelung wird mit objektrelationalen Konzepten aufgebaut. Die Umsetzung der objektrelationalen Strukturen
nach XML erfolgt dann gemäß folgender
»kanonischer« Abbildung:
Ergebnis
Tupel
Spaltenwert
innere
Tabelle
<ROWSET>
<ROW>
<Spaltenname>
<Spaltenname> für die
Kollektion und je Eintrag
<Spaltenname_ITEM>
Objekt
rekursive Behandlung der
Struktur
Referenz
<Spaltenname REFTYPE="REF T"> mit OID
Tab. 1: Kanonische Abbildung
Ein Beispiel veranschaulicht das Prinzip:
SELECT p.Nr, p.Name,
Adresse_Typ(Plz,Ort,Strasse,
Hausnr) AS Adresse,
Datenbank-Spektrum 7/2003
CAST(MULTISET(SELECT Telnr
FROM Telefon
WHERE PNr=p.Nr)
AS Telefon_Tab) AS TelListe
FROM Person p
Hier wird in SQL eine geschachtelte
Struktur aufgebaut. Der Objekttypkonstruktor Adresse_Typ strukturiert die
Einzelspalten Plz, Ort etc. zu einem
Objekt. MULTISET erstellt eine innere
Tabelle TelListe, d.h., der Wert ist
selbst wieder eine Tabelle. Voraussetzung
ist folgender Objekttyp und TABLE-Typ:
CREATE TYPE Adresse_Typ AS OBJECT
(Plz NUMBER, Ort VARCHAR(30),
Strasse VARCHAR(30),
Hausnr VARCHAR(5));
CREATE TYPE Telefon_Tab
AS TABLE OF VARCHAR(20);
Die gemäß der kanonischen Abbildung
erzeugte XML-Struktur lautet:
<?xml version="1.0"?>
<ROWSET>
<ROW num="1">
<NR> 1 <NR>
<NAME> Lucky Luke </NAME>
<ADRESSE>
<PLZ> 81730 </PLZ>
<ORT> München </ORT>
<STRASSE> Otto-Hahn-Ring
</STRASSE>
<HAUSNR> 6 </HAUSNR>
</ADRESSE>
<TELLISTE>
<TELLISTE_ITEM num="1">
089/123456
</TELLISTE_ITEM>
<TELLISTE_ITEM num="2">
0171/34567
</TELLISTE_ITEM>
</TELLISTE>
</ROW>
<ROW num="2">
...
</ROW>
...
</ROWSET>
Die in Oracle SQL aus flachen Tabellen
erzeugte geschachtelte Struktur wird in
ein geschachteltes XML-Dokument umgesetzt. ROWSET und ROW sind dabei
Tags, die die gesamte Ergebnismenge
bzw. jedes einzelne Tupel auszeichnen.
Jedes Tupel wird über ein num-Attribut
nummeriert. Jeder Wert eines Tupels wird
ebenfalls zu einem Element und mit einem Tag umschlossen, das nach dem Namen der Spalte bzw. einem Alias in der
SELECT-Anweisung benannt ist. Ein Alias ist nützlich, wenn komplexe Ausdrücke oder aggregierende Funktionen in
SQL benutzt werden. Ein Alias kann
dann dem Tag einen sprechenden Namen
geben. Auch aus XML-Sicht ungültige
Bezeichner lassen sich so vermeiden.
Nullwerte erscheinen nicht im Ergebnis;
das komplette Element zum Attribut verschwindet in diesem Fall.
Um einen Spaltenwert als XML-Attribut zu übernehmen, kann ein mit einem
'@' beginnender Alias genommen werden.
Ein Alias '@Nr' würde zum Beispiel die
Spalte Nr zu einem Attribut des Tags
<ROW num="1" NR="1"> machen.
Geschachtelte Strukturen, gegeben
durch Objekte oder innere Tabellen, werden entsprechend aufgelöst. Bei objektwertigen Spalten wird die innere Struktur
direkt über Tags reflektiert. Zum Beispiel
untergliedert sich <ADRESSE> in <PLZ>,
<ORT>, <STRASSE> und <HAUSNR>
entsprechend der Struktur des Objekttyps
Adresse_Typ. Die innere Tabelle wird
gemäß dem Alias als <TELLISTE>-Element dargestellt. Die einzelnen Einträge
der inneren Tabelle werden mit
<TELLISTE_ITEM> markiert, d.h., dem
Listen-Tag wird ein _ITEM nachgestellt.
Oracles objektrelationale Erweiterungen bieten mächtige Möglichkeiten, die
Struktur des XML-Dokuments zu beeinflussen. Oracle benutzt also keine spezielle Abbildungssprache für die Umsetzung von Tabellendaten nach XML.
Die Verarbeitung kann in Java und
PL/SQL erfolgen. Die Java-Klasse OracleXMLQuery besitzt Konstruktoren,
denen neben einer JDBC-Datenbankverbindung eine SQL-Anfrage übergeben
wird:
//JDBC -Connection öffnen:
Connection conn =
Drivermanager.getConnection
("jdbc:oracle:thin:@myhost" +
57
Generierung von XML aus relationalen Daten
":1521:mydb","SCOTT","TIGER");
OracleXMLQuery q
= new OracleXMLQuery(conn,
"SELECT ... FROM ...");
org.w3c.dom.Document domDoc =
q.getXMLDOM();
q.close();
Das Connection-Objekt legt die Datenbank mydb auf dem Rechner myhost
sowie das Schema SCOTT/TIGER fest.
Das XML-Ergebnis einer Anfrage kann
über verschiedene get-Methoden abgeholt werden. So liefert getXMLDOC das
Anfrageergebnis in einer DOM-Repräsentation, so dass die Funktionalität des
Oracle XML Developer’s Kit (XDK)
nutzbar ist, um z.B. XSLT-Transformationen durchzuführen, eine DTD zu erzeugen oder nachfolgend Parser anzuwenden. Die Funktion getXMLString
gibt alternativ das Ergebnis als Zeichenkette aus.
Den Methoden kann ein Node-Parameter mitgegeben werden, der zur Wurzel des Ergebnisdokuments wird; das eigentliche Ergebnis wird zum Teilbaum.
In XSU ist auch ein XSLT-Prozessor
integriert, der dazu benutzt werden kann,
XSLT-Transformationen auf dem Ergebnis anzuwenden.
Die Klasse OracleXMLQuery stellt
diverse Methoden bereit, mit denen sich
die Schreibweise beeinflussen lässt. Mit
setRowTag(String tag) wird z.B.
<ROW> zu <tag> umbenannt. setRowSetTag(String tag) wirkt analog auf
<ROWSET>. Ebenso lassen sich die numAttribute des <ROW>-Tags und der inneren Kollektionen mit setRowldAttrName(String n) bzw. setCollIdAttrName(String n) umbenennen.
Wird bei den Prozeduren null als Parameter angegeben, so wird kein Element
bzw. Attribut erzeugt.
Weitere Methoden sind hilfreich, um
ein Anfrageergebnis stückweise in XMLDokumente umzuwandeln. Mit setMaxRows(anz) wird jeweils die Anzahl
der zu verarbeitenden Tupel festgelegt.
Mit setSkipRows(i*anz) können
dann im i-ten Schleifendurchlauf die bereits bearbeiteten Sätze übersprungen
werden, bevor mit restartQuery()
die Anfrage erneut ausgeführt wird. Der
Mechanismus ist nützlich, um Hauptspeicher zu sparen, da nicht mehr das komplette Dokument auf einmal erstellt werden muss.
Mit XSU hat ein Programmierer auch
umgekehrt die Möglichkeit, XML-Doku-
58
mente zu speichern. XML-Dokumente,
die der kanonischen Abbildung entsprechen, lassen sich mit der Java-Klasse
OracleXMLSave wieder feingranular
auf mehrere Tabellen verteilen. Nicht
auftretende Tags werden als NULL gespeichert. Das Speichern setzt voraus,
dass die XML-Dokumente ein festes
Schema, z.B. durch eine DTD gegeben,
besitzen.
OracleXMLSave sav = new
OracleXMLSave(conn,"MyPerson");
sav.insertXML(sav.getUrl("f"));
sav.close();
Beim Konstruktoraufruf ist die Tabelle
oder Sicht anzugeben, auf die das Dokument zu verteilen ist. Wenn sich das
XML-Dokument über mehrere Tabellen
erstreckt, dann muss eine Objektsicht
über diese Tabellen definiert werden,
z.B. zur Speicherung des oben generierten XML-Dokuments eine Objektsicht
MyPerson:
CREATE VIEW MyPerson AS
SELECT von oben
Beim Speichern erfolgt damit die Aufteilung des Dokuments auf die der Sicht zugrunde liegenden Tabellen Person und
Telefon. In der Regel ist ein INSTEAD
OF-Trigger für die View notwendig, um
die Wirkung von Einfügen, Ändern und
Löschen eindeutig zu definieren.
Ein großer Vorteil von XSU ist, dass
sich auch Dokumentteile effizient löschen und ändern lassen. Das übergebene
Dokument dient als Muster für die Suche,
d.h., das Dokument legt die Vergleichswerte für eine WHERE-Bedingung fest.
Zudem beschreibt das Dokument bei Einfügungen und Änderungen den neuen Zustand des Dokuments. Einzelheiten hierzu sind in [Hohenstein & Schmatz 2003]
nachzulesen.
b) XMLType-Sichten
Auch in Oracle9i besteht die Möglichkeit,
XML-Sichten über relationale Daten zu
legen. Ähnlich wie im SQL-Server wird
hierzu ein XML-Schema mySchema.xsd
angelegt, um die Struktur der XML-Sicht
zu definieren. Das Schema kann dann
wie folgt zur Sichtdefinition benutzt werden:
CREATE VIEW MyView OF XMLType
XMLSCHEMA "http://www.oracle.com
/xsd/mySchema.xsd#Person"
WITH OBJECT IDENTIFIER (extract
(SYS_NC_RowInfo$, '/Person/@Nr')
.getNumVal())
AS SELECT SYS_XMLGen(VALUE(p))
FROM MyPerson p
Die Sicht besteht aus XMLType-Objekten. XMLType ist ein vordefinierter Objekttyp, der XML-Dokumente repräsentiert, deren Struktur durch das über XMLSCHEMA referenzierte Schema definiert
wird. Hinter # steht der Einstiegspunkt
zur Validierung. Jedes XMLType-Objekt
erhält einen Objektidentifikator, dessen
Wert hier mit extract über einen XPath
'/Person/@Nr'
extrahiert
wird.
SYS_NC_RowInfo$ bezeichnet dabei die
implizite XMLType-Spalte in der Sicht.
Zur Berechnung der XML-Sicht aus
relationalen Daten wird hier die XML-generierende SQL-Funktion SYS_XMLGen
genutzt (siehe unten).
Oracles SQL definiert zwei Funktionen existsNode und extract, die
XPath-Funktionalität für XMLType bieten und zur Verarbeitung der XML-Sicht
benutzt werden können:
SELECT extract(VALUE(v),
'/Person/Adresse/Plz')
FROM MyView v
WHERE existsNode(VALUE(v),
'/Person//Telefon')
existsNode prüft die Existenz des über
den XPath /Person//Telefon adressierten Elements (d.i. ein Telefon), während extract ein Fragment (die Plz)
über XPath aus dem Dokument extrahiert. Beide Funktionen erwarten ein
XMLType-Objekt als ersten Parameter,
das hier als Sichtobjekt mit VALUE(v)
berechnet wird.
c) SQL-Funktionen und Pakete
Das PL/SQL-Paket DBMS_XMLGEN stellt
eine Möglichkeit dar, um XML-Dokumente aus den Ergebnissen objektrelationaler SQL-Anfragen zu generieren.
Beim Lesen aus der Datenbank ist die
XML-Struktur bis auf kleinere Unterschiede durch die bei XSU diskutierte kanonische Abbildung gegeben. Als wesentlicher Unterschied besteht aber keine
Möglichkeit, mit einer Umkehrabbildung
XML-Dokumente in die Datenbank zu
schreiben bzw. zu löschen und zu ändern.
Als Vorteil hat DBMS_XMLGEN eine bessere Performanz als XSU zu verbuchen,
da die Funktionalität direkt im Datenbankkern integriert ist.
Das folgende Beispiel zeigt das Prinzip von DBMS_XMLGEN anhand eines PL/
SQL-Programms:
Datenbank-Spektrum 7/2003
Generierung von XML aus relationalen Daten
DECLARE
ctx DBMS_XMLGEN.ctxHandle;
result CLOB;
BEGIN
ctx := DBMS_XMLGEN.newContext
('SELECT ...');
result :=
DBMS_XMLGEN.getXML(ctx);
DBMS_XMLGEN.closeContext(ctx);
END;
DBMS_XMLGEN.ctxHandle ist ein vordefinierter Objekttyp. Die Funktion
newContext legt zu einer SQL-Anfrage
eine Instanz ctx an. Über sie erfolgt anschließend die gesamte Steuerung. Mit
getXML lässt sich dann zu ctx bzw. zur
dahinter stehenden Anfrage ein XMLDokument als CLOB abrufen.
Wie in
XSU stehen in
DBMS_XMLGEN diverse Funktionen wie
setSkipRows oder setRowTag zur
Verfügung.
Die allein stehenden SQL-Funktionen SYS_XMLGEN und SYS_XMLAGG
bieten ebenfalls eine Möglichkeit, XMLDokumente in SQL-Anweisungen, insbesondere interaktiv unter SQL*Plus, aus
Anfrageergebnissen zu erzeugen.
SYS_XMLGEN hat eine ähnliche Wirkung wie DBMS_XMLGEN. Die Struktur
des erzeugten XML-Dokuments ist wieder durch eine kanonische Abbildung gegeben und kann durch die objektrelationalen Konzepte beeinflusst werden. Ein
Aufrufbeispiel ist:
SELECT SYS_XMLGEN(Adresse_Typ
(Plz,Ort,Strasse,Hausnr))
FROM Person WHERE Nr = 1
Je Tupel wird ein XMLType-Objekt mit
folgendem Inhalt konstruiert:
<?xml version="1.0"?>
<ROW> <PLZ> 81730 </PLZ>
<ORT> München </ORT> ... </ROW>
Die Wirkung ist, als würde
'SELECT Adresse_Typ(...) FROM ...'
der Prozedur DBMS_XMLGEN.newContext übergeben und ausgeführt werden.
Anders als dort kann hier nur ein einzelner Ausdruck in der SELECT-Liste auftreten. Dennoch ist es wieder möglich, ein
komplexes Objekt, bestehend aus eingebetteten Objekten, Referenzen und geschachtelten Tabellen, zusammenzustellen. Auf diese Weise lassen sich ungeachtet der Restriktion komplexere
XML-Ergebnisstrukturen aufbauen.
Wie bei DBMS_XMLGEN werden
durch die kanonische Abbildung die
Spaltennamen direkt als Tags übernom-
Datenbank-Spektrum 7/2003
men. Im Fall von Funktionsaufrufen oder
komplexen SELECT-Ausdrücken wird
<ROW> zum Tag. Mit einem zweiten
SYS_XMLGEN-Parameter kann aber in
SYS_XMLGEN(Adresse_Typ(...),
SYS_XMLGENFORMATTYPE.
createFormat('ADR'))
das <ROW>-Tag zu <ADR> umbenannt
werden. Ein weiterer optionaler Parameter erlaubt Verarbeitungsinstruktionen,
was insbesondere für eine nachfolgende
Stylesheet-Transformation nützlich ist.
Damit kann jederzeit reines HTML oder
ein anderes Format erzeugt werden.
Während SYS_XMLGEN jedes Ergebnistupel separat bearbeitet – je Tupel entsteht ein XMLType-Objekt –, werden
durch SYS_XMLAGG mehrere Tupel zu einem einzigen XMLType aggregiert. Alle
Ergebniswerte sind aneinander gehängt
und mit dem Tag <ROWSET> umschlossen. SYS_XMLAGG ist eine aggregierende
Funktion im Sinne von AVG oder COUNT.
Als solche kann sie auch mit GROUP BY
kombiniert werden:
SELECT
SYS_XMLAGG(SYS_XMLGEN(Nr))
FROM Person GROUP BY Name
Diese Anfrage gruppiert gleiche NameWerte. Je Name wird die Menge der Personennummern berechnet und für jede
Nummer SYS_XMLGEN(Nr) ausgewertet. Das Ergebnis wird anschließend mit
SYS_XMLAGG aggregiert, so dass sich ein
einziges Ergebnistupel ergibt:
<ROWSET>
<NR> 10
<NR> 20
</ROWSET>
<ROWSET>
<NR> 15
<NR> 25
<NR> 35
</ROWSET>
</NR>
</NR>
</NR>
</NR>
</NR>
2.4 Abbildungswerkzeuge von
Fremdanbietern
Neben den RDBMS-Herstellern hat sich
eine Tool-Landschaft mit diversen Abbildungswerkzeugen für relationale Datenbanken etabliert, die sich ebenfalls mit
der XML-Generierung und -Speicherung
befassen. Diese Werkzeuge haben den
Vorteil der Datenbankunabhängigkeit,
was der Portabilität zugute kommt. Auch
hier gibt es wieder mehr oder minder
komplexe Abbildungssprachen unterschiedlicher Funktionalität.
Als frei verfügbarer Kandidat sei
XML-DBMS [Bourret 2002] erwähnt. Es
hat die nützliche Eigenschaft, die hierarchische Struktur eines XML-Dokuments,
insbesondere die Reihenfolge der Kinder
auf einer Hierarchiestufe wie auch die
Character-Daten und Attributwerte, zu
erhalten; viele Ansätze haben hiermit
Probleme. Das heißt, Dokumente lassen
sich in derselben Form rekonstruieren,
wie sie gespeichert wurden. Das kann
aber zu Lasten der Performanz gehen.
Castor, ein weiteres Beispiel, basiert
auf einer objektrelationalen Abbildung,
bei der zunächst Objekttypen über relationale Tabellen spezifiziert werden, die
anschließend mit einer Standardabbildung als XML ausgegeben werden.
Manche Werkzeuge wie Allora bieten
eine komfortable grafische Unterstützung
zur Erstellung einer Abbildungsvorschrift.
In der Regel handelt es sich bei diesen
Ansätzen um eine Middleware, die zwischen einer Applikation und einer Datenbank vermittelt. Demzufolge muss eine
Applikation geschrieben werden, um den
Mechanismus zu nutzen.
3
Der SQL/XML-Standard
Der SQL-Standard untergliedert sich inzwischen in mehrere Teile der »ISO/IEC
JTC 1/SC32/WG3 Database Languages –
SQL«. Im Jahr 2000 ist der Teil »Part 14:
XML-Related Specifications (SQL/
XML)« hinzugekommen, der von der offenen SQLX-Gruppe, jetzt zu H2.3 Task
Group umbenannt, initiiert wurde. IBM
und Oracle sind maßgebliche Treiber dieser Gruppe. Unter www.sqlx.org finden
sich Einzelheiten zur Gruppe und zum
aktuellen Stand.
Die SQL/XML-Standardisierung ist
immer noch im Fluss. Nichtsdestoweniger weisen IBMs DB2 und Oracle9i bereits erste Implementierungen auf.
Grundlage des Standards ist ein neuer
Datenbankdatentyp »XML«, der in Oracle
beispielsweise XMLType heißt. Dieser
kann als üblicher Wertebereich für Tabellenspalten genommen werden; die Werte
repräsentieren dabei XML-Dokumente.
Im Folgenden wird für diese Werte die
Bezeichnung XML-Objekt gewählt.
3.1 SQLX-Funktionen
SQL/XML definiert im Wesentlichen
neue SQL-Funktionen, die SQLX-Funktionen, mit denen sich XML-Dokumente
59
Generierung von XML aus relationalen Daten
als Objekte des Typs XML zusammenstellen lassen.
Die Funktion XMLElement erzeugt
aus SQL-Ausdrücken ein XML-Element,
ggf. mit Attributen versehen.
SELECT XMLElement(NAME "Person",
XMLAttributes(Nr AS id),
Name, Ort)
FROM Person
Je Tupel entsteht ein XML-Objekt der Art:
<Person id="10">
Lucky Luke München </Person>
Das hinter NAME angegebene Tag wird als
Elementname genommen und bildet die
Wurzel jedes generierten XML-Objekts.
Die SQL-Ausdrücke Name und Ort werden zum Inhalt des Elements ausgewertet.
Mit XMLAttributes(...) lassen
sich SQL-Ausdrücke zum erzeugten Element als Attributwerte hinzufügen. Im
Normalfall wird der Ausdruckbezeichner, also z.B. der Spaltenname, als Attributname verwendet. Mit AS lässt sich
aber auch explizit ein Alias wie id vergeben. Wird ein Ausdruck zu einem Nullwert ausgewertet, so entfällt das entsprechende Attribut bzw. Element.
XMLElement-Funktionen können
verschachtelt werden, um eine geschachtelte XML-Struktur zu erzeugen:
SELECT
XMLElement(NAME "p:Person",
XMLAttributes('http://www.' ||
'hr.com /hr' AS "xmlns:p"),
Nr AS PNr),
XMLElement(NAME "Name",Name),
XMLElement(NAME "Plz",Plz))
FROM Person
Der Ausdruck zur XML-Attributberechnung ist in diesem Fall eine URL als Zeichenkettenkonstante. Normalerweise ist
ein Escape-Mechanismus wirksam, der
in XML ungültige Zeichen durch den
Hexcode des Zeichens ersetzt. Eine
wichtige Ausnahme ist das Symbol ‘:’,
das unverändert bleibt. Auf diese Weise
lassen sich Namespaces durch entsprechende Aliase p:Person setzen. Allerdings findet keine Überprüfung der Namespace-Präfixe statt; der Namespace
muss also nicht korrekt eingerichtet und
referenziert sein.
Das Ergebnis ist hier:
<p:Person xmlns:p="http://
www.hr.com/hr" PNr="10">
<Name> Lucky Luke </Name>
<Plz> 81730 </Plz>
</p:Person>
Eine weitere SQLX-Funktion XMLForest ist für strukturierte Record-Ausga-
60
ben nützlich. Die Funktion liefert einen
Wald von XML-Elementen. Die Ausdrücke werden wie üblich ausgewertet und
bilden jeweils ein Element, das ggf. mit
einem Alias bezeichnet wird. Das Ergebnis hängt für jedes Tupel alle diese Elemente aneinander. Der Aufruf XMLForest(Nr,Name) erzeugt somit folgenden Wald als XML-Objekt:
<Nr> 10 </Nr>
<Name> Ms. Marple </Name>
Um aus diesem Fragment ein gültiges
XML-Dokument zu erhalten, lassen sich
anschließend durch XMLElement die
mit XMLForest erzeugten Elemente zu
<Person> ...</Person> umklammern:
SELECT XMLElement("Person",
XMLForest(Nr,Name))
FROM Person
XMLForest ähnelt in der Wirkung einer
XMLElement,...,XMLEleFolge
ment. Der Unterschied besteht darin,
dass diese mehrere XML-Objekte zurückgibt, während es bei XMLForest nur ein
Ergebniswert ist.
XMLConcat(XML,...,XML) konkateniert die übergebenen XML-Argumente zu einem einzigen XML-Objekt.
Das Ergebnis ist ein Fragment. Ein NULLWert als Argument wird einfach ignoriert.
Die Sequenz wird typischerweise als Folge von XMLElement-Aufrufen berechnet. Mit der XMLConcat-Funktion lässt
sich XMLForest simulieren, nur dass
hier die XML-Elemente individuell spezifiziert werden:
SELECT XMLConcat(
XMLElement(NAME "Nr",Nr),
XMLElement(NAME "Name",Name))
FROM Person
erzeugt je Tupel wieder:
<Nr> 10 </Nr>
<Name> Ms. Marple </Name>
Um mehrere Tupel zu einem einzigen
XML-Objekt zu verknüpfen, gibt es die
aggregierende Funktion XMLAgg. XMLAgg wird typischerweise zusammen mit
GROUP BY benutzt, wodurch sie auf jede
Gruppe angewendet wird.
SELECT XMLElement(NAME "Person",
XMLAttributes(Name AS "PName"),
XMLAgg(XMLElement(NAME "Nr",Nr)
ORDER BY Nr))
FROM Person p
GROUP BY Name;
erzeugt:
<Person PName="Ms.Marple">
<Nr> 10 </Nr>
<Nr> 20 </Nr>
</Person>
...
Die Gruppierung über GROUP BY Name
liefert jeweils Gruppen von Tupeln mit
demselben Name-Wert. Für jede Gruppe
berechnet XMLAgg die Konkatenation der
XMLElement(NAME "Nr",Nr)-Werte.
Mit einer optionalen ORDER BY-Angabe
innerhalb XMLAgg wird je Gruppe eine
Reihenfolge definiert und eingehalten.
Schließlich gibt es noch eine mächtige generische Funktion, die die Funktionalität der anderen Funktionen umfasst.
XMLGen('<Person Nr="{$nr}"> ' ||
'<Name> {$n} </Name> ' ||
'</Person>',
Nr AS nr, Name AS n)
erzeugt je Tupel:
<Person Nr="10"> <Name>
Ms.Marple </Name> </Person>
Der erste Ausdruck ergibt die XMLStruktur als Zeichenkette. Die Platzhalter
{$x} werden durch die Auswertungen
der nachfolgenden SQL-Ausdrücke substituiert. Der Zusammenhang erfolgt über
Namensgleichheit. Platzhalter sind nicht
nur für Elementinhalte und Attributwerte
möglich, auch Element- und Attributnamen lassen sich im Gegensatz zu XMLElement erzeugen.
3.2 Standardkonformität
Standards haben es so an sich, dass sie
von Herstellern zwar erfüllt werden, jeder
Hersteller es sich aber nicht nehmen lässt,
»nützliche« Zusatzfunktionalität anzubieten.
Oracle zum Beispiel stellt zusätzliche
Funktionen bereit, die mit den speziellen
SQL-Erweiterungen harmonieren. Hierzu zählt XMLSequence(XMLType), das
die Top-Level-Elemente des XMLTypeObjekts als Sequenz bestimmt. Zur Erinnerung sei erwähnt, dass XMLType Oracles Implementierung des XML-Objekttyps
ist. Gültige XML-Dokumente bzw. XMLType-Objekte haben genau eine Wurzel,
so dass dann nur eine einelementige Sequenz entsteht; XMLType-Fragmente,
wie sie z.B. durch Oracles SQL-Funktion
extract berechnet werden, besitzen jedoch mehrere Wurzeln. Das Ergebnis ist
eine Sequenz von XML-Objekten als Instanz des Typs XMLSequenceType, der
äquivalent zu VARRAY OF XMLType ist.
Die Funktion ist nützlich, um Wiederholungsgruppen in XML wie die Telefonliste zu entschachteln. Sei Doks eine Tabelle mit einer XMLType-Spalte xml:
Datenbank-Spektrum 7/2003
Generierung von XML aus relationalen Daten
SELECT id, VALUE(t) FROM Doks d,
TABLE(XMLSequence(extract
(d.xml, '//Telefon'))) t;
extract liefert mehrere Telefon-Elemente, die mit XMLSequence zu einem
VArray zusammengefügt werden. TABLE
erlaubt dann, eine Variable t an die einzelnen Telefon-Werte zu binden.
XMLConcat kann ebenfalls ein XMLSequenceType verarbeiten, indem es
die einzelnen Werte zu einem XMLType
konkateniert.
Eine
andere
Oracle-Funktion
XMLColAttVal nimmt mehrere Parameter der Form Ausdruck [ AS Alias
], um daraus einen Wald von <column>Elementen als XMLType-Objekt zu erzeugen, indem jeder Ausdruck zu einem
<column>-Element ausgewertet wird:
<column name="Alias_1"> Wert_1
</column>
<column name="Alias_n"> Wert_n
</column>
Die Aliase bzw. die Ausdruckbezeichner
werden somit zu Attributwerten.
3.3 Zeichenumsetzung
Bei der Umsetzung von SQL- in XMLBezeichner besteht das Problem, dass in
SQL mehr Zeichen als in XML erlaubt
sind. Zum Beispiel sind in SQL möglich:
• Identifier, die mit XML beginnen
(XML ist in XML reserviert)
• ‘:’(das in XML für Namespace-Angaben verwendet wird)
Um gültiges XML zu erhalten, ist eine
Umsetzung der SQL-Identifier in Unicode nötig. Bei der Auswertung findet
folgende implizite Transformation statt:
• Wird ein Attribut als Spaltenname genommen, so wird der Name »fully escaped«.
• Ein Alias wird »partially escaped«.
Tabelle 2 zeigt ein paar Beispiele für Umsetzungen von Sonderzeichen in beiden
Varianten:
SQLIdentifier
fully
escaped
partially
escaped
Name
NAME
NAME
"Name"
Name
Name
"Name v"
Name_x0020_v
Name_x0020_v
"Name_v"
Name_x005F_v
Name_x005F_v
"n:Name"
n_x003A_Name
n:Name
xmldata
_xFFFF_xmldata xmldata
Tab. 2: Umsetzungen von Sonderzeichen
Datenbank-Spektrum 7/2003
Entsprechend gibt es eine Umkehrabbildung von XML zu SQL, die z.B.
_x0020_ in ein Leerzeichen umwandelt. Auch Werte werden implizit umgesetzt:
• TIME'11:35:16' zu 11:35:16
• Eine Zeichenkette 'Schulz' zu
Schulz (ohne Anführungszeichen)
• INTERVAL'1:17' zu PT1H17M
Der SQL/XML-Standard spezifiziert des
Weiteren, wie z.B. eine Tabelle (oder ein
ganzes Datenbankschema) in XML-Darstellung repräsentiert wird, ähnlich zur
Defaultsicht von DB2, oder wie ein
XML-Schema inkl. Datentypen abgeleitet wird.
4
Zusammenfassung
Dieser Beitrag behandelte die Generierung von XML aus relationalen Daten.
Was angesichts der nativen XML-Datenbanken überflüssig erscheint, hat durchaus seine Berechtigung: Heutzutage liegen viele Daten in relationalen Datenbanken vor – und werden es auch noch in
Zukunft. Die RDBMS-Hersteller bieten
zur Gewinnung von XML aus relationalen Daten vielfältige Unterstützung. Es
zeigt sich aber, dass die Ansätze sehr heterogen sind: Das Spektrum reicht von
SQL-Erweiterungen über Abbildungsbeschreibungen und XML-Schema-Annotationen bis hin zu XML-Sichten. Ergänzt
wird die Palette durch Produkte von
Nicht-DBMS-Herstellern.
Inzwischen entsteht im Rahmen der
SQL-Standardisierung der SQL/XMLStandard, der SQLX-Funktionen einführt. Alle namhaften Hersteller werden
sicherlich im Laufe der Zeit diesen Standard unterstützen, teilweise tun sie es bereits. Wahrscheinlich wird auch IBMs
Xperanto die XML-Unterstützung in relationalen Datenbanken prägen, da es
sich XQuery zunutze macht, die XMLund relationale Welt koppelt und auf diese Weise eine gute Flexibilität bietet. Sicherlich wird die Bedeutung von XQuery
in diesem Umfeld steigen.
In diesem Beitrag wurde nur der Teilaspekt der Generierung betrachtet. Relationale DBMS bieten in der Regel auch
die umgekehrte Möglichkeit, XML-Dokumente feinstrukturiert auf Tabellen zu
verteilen, was kurz angerissen wurde. Ein
anderer Ansatz legt ein XML-Dokument
komplett in ein uninterpretiertes CLOB
ab. In diesem Fall steckt die XML-Funktionalität in der Freitextsuche, die z.B. bei
DB2 durch den Text-Extender oder bei
Oracle durch die OracleText-Cartridge
gegeben ist [Hohenstein & Schmatz
2003].
5
Literatur
[Bourret 2002] Bourret, R.: XML-DBMS: Middleware for Transferring Data between XML
and Relational Databases. http://www.rpbourret.com/xmldbms/index.htm, 2002.
[Eisenberg & Melton 2001] Eisenberg, A.; Melton, J.: SQL/XML and the SQLX Informal
Group of Companies. ACM SIGMOD Record, Vol. 30, No. 3, Sept. 2001.
[Fan et al. 2002] Fan, C.; Funderburk, J.; Lam,
H.-I. et al.: Xperanto: Bridging Relational
Technology and XML. http://www7b.software.
ibm.com/dmdd/library/techarticle/0203shekita/
0203shekita.pdf. 2002.
[Hohenstein & Schmatz 2003] Hohenstein, U.;
Schmatz, K.-D.: Webanwendungen entwickeln mit Oracle9i – Java, XML, JDBC &
SQLJ,
Oracle9i
Application
Server.
dpunkt.verlag, 2003.
[Klettke & Meyer 2003] Klettke, M.; Meyer, H.:
Speicherung von XML-Dokumenten – eine
Klassifikation. In: Datenbank-Spektrum,
Heft 5/2003, S. 40-50.
[Schöning 2001] Schöning, H.: XML-Datenbanken. In: Datenbank-Spektrum, Heft 1/2001,
S. 33-34.
[SQLX 2002] ISO/IEC JTC 1/SC32/WG3 Database Languages – SQL – Part 14: XML-Related Specifications (SQL/XML) – Final Committee Draft, H2-2002-063, WG3:ICN-011,
März 2002.
Dr. Uwe Hohenstein studierte Informatik an der TU
Braunschweig. Dort promovierte er 1989 mit Arbeiten auf dem Gebiet des
konzeptionellen
Datenbankentwurfs. Seit 1990 ist
er im Bereich Forschung
und Entwicklung der Siemens AG tätig, wo er sich
als Projektleiter um die effiziente und produktive
Nutzung aktueller Datenbanktechnologien in
konkreten Anwendungen kümmert. In diesem
Umfeld sammelte er viele Erfahrungen bei der
Auswahl, der Bewertung und dem Einsatz von
relationalen, objektorientierten und objektrelationalen Datenbanksystemen. Seine Erfahrungen
hat er in vielen Publikationen und auf diversen
Fachtagungen vorgestellt.
Dr. Uwe Hohenstein
Siemens AG München
CT SE 2
81730 München
[email protected]
http://www.siemens.com
61
Herunterladen