Als Ausgangssituation dient ein einfaches Datenmodell für Wertpapierdepots (Abbildung 1).
XML erzeugen: Von einfachen Strukturen ...
Im ersten Schritt wird das Generieren der XML-Dokumente betrachtet. Dazu kommen die Funktionen des SQL/XML-Standards [1] zum Einsatz. Sie dienen zum Erzeugen von XML mit SQL und sind Bestandteil des ANSI-SQL-Standards (SQL:2003).- XMLElement(): erzeugt ein XML-Tag
- XMLAttributes(): erzeugt ein oder mehrere XML-Attribute
- XMLComment(): erzeugt einen XML-Kommentar
- XMLRoot(): generiert den XML-Prolog
- XMLAgg(): dient zum Erzeugen von Hierarchien
select XMLElement("Gruss", 'Hallo Welt') TEXTfrom dualTEXT-------------------------<Gruss>Hallo Welt</Gruss>
Listing 1: Einfache XML-Sicht auf die Wertpapier-Tabelle==============================================================create view WERTPAPIER_XML_VIEW asselectXMLRoot(XMLElement("wertpapier",XMLAttributes(wp.ISIN as "isin",dp.KONTONR as "depotnummer"),XMLElement("bezeichnung", wp.BEZEICHNUNG),XMLElement("stueck_nominale", wp.STUECK_NOM))) as XMLfrom WERTPAPIER_TAB wp join DEPOT_TAB dp
SQL> select XML from WERTPAPIER_XML_VIEWXML--------------------------------------------------------<wertpapier isin="US00010281" depotnummer="500917211"><bezeichnung>Oracle Corp</bezeichnung><stueck_nominale>1000</stueck_nominale></wertpapier><wertpapier isin="DE01020911" depotnummer="500917211"><bezeichnung>Bundesanleihe 10/2010</bezeichnung>:
... hin zu komplexen Strukturen
In der Praxis sind meist komplexere, hierarchische XML-Strukturen gefordert. Auch diese lassen sich mit den SQL/XML-Funktionen erzeugen. XMLAgg() fügt eine neue Hierarchieebene ein. Das Beispiel in Listing 2 erzeugt zwei Hierarchieebenen, wobei jedes XMLAgg() in eine Unterabfrage (Sub-Select) eingebettet ist.Es ist einleuchtend, dass die SQL-Abfrage mit zunehmender Komplexität der zu erzeugenden XML-Dokumente immer länger und unübersichtlicher wird. In der Praxis empfiehlt es sich daher, nach dem "Bausteinprinzip" vorzugehen – also zunächst Views für kleine XML-Dokumente aus einzelnen Tabellen zu erzeugen und diese dann in anderen Views zusammenzufassen.
Da virtuelle XML-Dokumente aus einer XML-View tatsächlich gespeicherten gleichgestellt sind, können Operationen wie Stylesheet-Transformationen (XML-TRANSFORM) oder Datenextraktion (EXTRACTVALUE) auch mit XML-Views durchgeführt werden. Daraus kann dennoch eine relationale Übersicht über alle Depots eines Kunden angefordert werden.
selectextractvalue(kd.XML, '/kunde/name') name,extractvalue(value(dp), '/depot/@kontonummer') dpnrfrom KUNDE_XML_VIEW kd,table(xmlsequence(extract(kd.XML, '/kunde/depot'))) dpNAME DPNR-----------------------------------------Mustermann 500917211Meier 500189212: :
XML abrufen? Ganz einfach mit HTTP!
Mit dem Erstellen der Views ist der erste Teil der XML-Schnittstelle abgeschlossen. Die relationalen Tabellendaten können nun als XML-Dokumente aus der Datenbank abgerufen werden. Dies ist in der Oracle-Datenbank übrigens nicht nur per SQL, sondern auch per HTTP-Protokoll möglich. Eine standardmäßig installierte Oracle-Datenbank "lauscht" auf Port 8080 auf HTTP-Anfragen. Mit einem speziell formulierten URL kann die XML-View aus Listing 2 direkt angesprochen werden (Abbildung 3): http://[host]:8080/oradb/[DB-USER]/[VIEW-NAME].Listing 2: Erstellung komplexer XML-Dokumente mit den SQL/XML-Funktionen==============================================================create view KUNDE_XML_VIEW asselectXMLElement("kunde",XMLAttributes(kd.KUNDE_ID as "kundennummer"),XMLElement("name", kd.NAME),XMLElement("vorname", kd.VORNAME),XMLElement("ort", kd.ORT),(selectXMLAgg(XMLElement("depot",XMLAttributes(dp.KONTONR as "kontonummer"),(selectXMLAgg(XMLElement("wertpapier",XMLAttributes(wp.ISIN as "isin"),XMLElement("bezeichnung", wp.BEZEICHNUNG),XMLElement("stueck_nominale", wp.STEUCK_NOM)))from WERTPAPIER_TAB wp where depot_id = dp.depot_id)))from DEPOT_TAB dp where dp.kunde_id = kd.kunde_id)) as XMLfrom KUNDE_TAB kd
XML entgegennehmen
Die vollständige XML-Schnittstelle muss XML auch entgegennehmen können. Wird ein XML-Dokument gespeichert, so soll die Datenbank dessen Inhalt auf die relationalen Tabellen verteilen.Versucht man, ein XML-Dokument per SQL INSERT in die View einzufügen, so erhält man eine Fehlermeldung. Der Grund dafür ist die fehlende Update-Fähigkeit der View (siehe Kasten "DML auf Views").
XML-Views können wie gewöhnliche relationale Views updatefähig oder nichtupdatefähig sein. In der Theorie ist jede View updatefähig, sofern keine Aggregatsfunktionen wie SUM(), AVG() oder andere verwendet werden. Denn in diesem Fall werden die Daten von der View verdichtet, Änderungen können nicht mehr auf die Originaldaten zurückgeführt werden.
Jede View, die keine Aggregatsfunktionen verwendet, ist demnach updatefähig – soweit die Theorie. In der Praxis können jedoch alle am Markt befindlichen Datenbanken DML auf Views mit mehr oder weniger komplexen Definitionen (SQL Joins) nicht mehr umsetzen.
SQL> insert into KUNDE_XML_VIEW values ('<kunde>...');insert into KUNDE_XML_VIEW values ('<kunde>...')*ERROR at line 1:ORA-01733: virtual column not allowed here
Der Aufbau eines INSTEAD-OF-Triggers ist in Listing 3 dargestellt.
Listing 3: Deklaration und "Gerüst" eines INSTEAD-OF-Triggers==============================================================create or replace trigger tr_kunde_xml_viewinstead of insert or update or deleteon kunde_xml_view for each rowdeclarebeginif inserting then...end if;if updating then...end if;if deleting then...end if;end;
| DML-Operation | "Altes" Dokument | "Neues" Dokument |
|---|---|---|
| INSERT | Nicht verfügbar | :new |
| UPDATE | :old | :new |
| DELETE | :old | Nicht verfügbar |
Zunächst wird die "Root"-Ebene des XML-Dokuments in die relationale Tabelle KUNDE_TAB übernommen (Listing 4).
Listing 4: INSTEAD-OF-Trigger – Bearbeitung der Root-Ebene==============================================================:if inserting theninsert into kunde_TAB (kunde_id, name, vorname, ort)values (extractvalue(:new.XML, '/kunde/@kundennummer'),extractvalue(:new.XML, '/kunde/name'),extractvalue(:new.XML, '/kunde/vorname'),extractvalue(:new.XML, '/kunde/ort')) returning kunde_id into v_kundeid;:end if;:
Die Informationen zu Depot und Wertpapieren können im XML-Dokument mehrfach vorkommen – daher müssen sie anders behandelt werden. Die Funktion TABLE(XMLSEQUENCE(EXTRACT(...))) extrahiert das XML-Fragment mit den Depot-Informationen und erzeugt daraus eine Sequenz über die einzelnen Depots (Listing 5). Die Schleife (loop) läuft über diese Sequenz. Die Schleifen können geschachtelt werden.
Listing 5: INSTEAD-OF-Trigger – Übernahme der mehrfach vorkommenden Elemente==============================================================:for dp_lst in (selectextractvalue(value(dp), '/depot/@kontonummer') as ktonrfrom table(xmlsequence(extract(:new.XML, '/kunde/depot'))) dp) loopinsert into DEPOT_TAB (kunde_id, KONTONR)values (dp_list.ktonr, v_kundeid);-- Hier eine geschachtelte Schleife für die Verarbeitung-- der Wertpapier-Informationenend loop;:
Nach Erstellung des Triggers ist die XML-Schnittstelle vollständig. Ein SQL INSERT in die View ist nun erfolgreich. Die Inhalte finden sich anschließend in den relationalen Tabellen wieder.
SQL> insert into kunde_xml_view values ('<kunde>...');1 row created.
Fazit
Mit der vorgestellten Technik kann man eine XML-Schnittstelle direkt in der Datenbank hinterlegen. Im Vergleich zu vielfach verfügbaren, fertigen Frameworks ist diese Variante auf den ersten Blick aufwendiger. Bei genauerer Betrachtung bieten sich jedoch einige Vorteile:- Information hiding: Das XML-Dokument kann direkt aus der Datenbank abgerufen werden. Der Nutzer greift auf eine View zu – die Herkunft der Daten bleibt verborgen.
- Offenheit: Die so erzeugte XML-Schnittstelle ist für viele Programmierumgebungen (Java, .NET, PHP, Perl, C/C++ ...) nutzbar. Die einzige Voraussetzung ist die Fähigkeit zur Kommunikation mit der Datenbank.
- Performance: Besonders das Erzeugen von XML ist hier sehr performant gelöst. Denn die Datenbank stellt das XML-Dokument zusammen und liefert es "auf einmal" aus. Dies ist wesentlich effizienter als das Ausliefern zahlreicher Einzelsätze.




