28. Mai 2009

Tabellendaten als XML im Browser: einfach so!

English title: Accessing table data as XML with a browser - no coding required

Vor einiger Zeit hatte ich ja mal ein kleines Tutorial zum Thema XML erzeugen mit den SQL/XML-Funktionen veröffentlicht. Damit ist es möglich, Tabellendaten in beliebiger Art und Weise als XML aufzubereiten.
Some time ago I published a tutorial about generating XML using the SQL/XML functions. With this functions you can construct XML from table data. The functions are very powerful - you can construct any XML structure you want.
Aber wusstet Ihr schon, dass Ihr XML auch völlig ohne Code generieren könnt ...?
But did you know that you can generate simple XML without any coding ...?
Seit Oracle9i gibt es das DB URI Servlet und die DB URI Types. Und das lässt sich ganz einfach nutzen. Zuerst solltet Ihr prüfen, ob der HTTP-Listener eurer Datenbank aktiv ist. Das geschieht ganz einfach mit einem lsnrctl status.
Since Oracle9i there is the DBURI Servlet and the DBURI type. The usage of this is very simple. But beforehand you should check whether the HTTP listener of your database is actually running. This is done with lsnrctl status.
$ lsnrctl status
LSNRCTL for Linux: Version 11.1.0.7.0 - Production on 27-MAY-2009 19:57:37

Copyright (c) 1991, 2008, Oracle.  All rights reserved.

Connecting to (DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=192.168.2.140)(PORT=1521)))
STATUS of the LISTENER
------------------------
Alias                     LISTENER
Version                   TNSLSNR for Linux: Version 11.1.0.7.0 - Production
Start Date                27-MAY-2009 19:49:19
Uptime                    0 days 0 hr. 8 min. 18 sec
Trace Level               off
Security                  ON: Local OS Authentication
SNMP                      OFF
Listener Parameter File   /oracle/u01/app/oracle/product/11.1.0/network/admin/listener.ora
Listener Log File         /oracle/u01/app/oracle/diag/tnslsnr/vmware/listener/alert/log.xml
Listening Endpoints Summary...
  (DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=192.168.2.140)(PORT=1521)))
  (DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=vmware.de.oracle.com)(PORT=8081))(Presentation=HTTP)(Session=RAW))
Services Summary...
Service "orcl.doag.org" has 1 instance(s).
  Instance "orcl", status READY, has 2 handler(s) for this service...
Service "orclXDB.doag.org" has 1 instance(s).
  Instance "orcl", status READY, has 3 handler(s) for this service...
Service "orcl_XPT.doag.org" has 1 instance(s).
  Instance "orcl", status READY, has 2 handler(s) for this service...
The command completed successfully
Wenn die rote Zeile bei euch nicht vorhanden ist, müsst Ihr den HTTP-Listener erst aktivieren. Das geht bei 11g-Datenbanken mit der Prozedur DBMS_XDB.SETHTTPPORT oder auch bei älteren Datenbanken mit dem SQL-Skript $ORACLE_HOME/rdbms/admin/catxdbdbca.sql. Nehmt einen TCP/IP-Port eurer Wahl; mit dem Port "0" wird der HTTP-Listener abgeschaltet.
If the red line is missing in your environment the HTTP listener is deactivated (which is the default). You can activate it with the procedure DBMS_XDB.SETHTTPPORT in Oracle11g and the $ORACLE_HOME/rdbms/admin/catxdbdbca.sql in older releases. Just choose an TCP/IP port; zero ("0") deactivates the listener.
Nun könnt Ihr Tabellendaten als XML abrufen. Startet einen Browser und gebt mal folgende URL ein, umdie Daten der EMP-Tabelle zu betrachten.
Now you can start viewing table data - start your browser and enter the following URL.
http://[database-host]:[http-port]/oradb/SCOTT/EMP
Ihr werdet zunächst aufgefordert, euch einzuloggen; nehmt einen Datenbankuser, der die Tabelle EMP lesen kann (naheliegenderweise SCOTT). Daraufhin solltet Ihr in etwa folgendes Ergebnis sehen.
First you get prompted for username and password. Enter the credentials of a user which is capable to select the EMP table (I'd suggest the SCOTT user). You should see the following result then.
Tabellendaten als XML - im Browser
Die XML-Struktur ist in diesem Fall vorgegeben; sie kann nicht beeinflusst werden. Aber im Gegenzug generiert die Datenbank ohne viel Aufwand XML aus den Tabellendaten. Wenn Ihr eigene XML-Strukturen benötigt, sind wir wieder bei den eingangs erwähnten SQL/XML-Funktionen. Und in manchen Fällen reicht diese einfache XML-Struktur vielleicht sogar aus ...
The structure of the XML document cannot be changed - it is always that simple. If you need other XML structures you have to code a view with the above mentioned SQL/XML functions. But there might be cases in which this simple structure is sufficient.
Ihr könnt die Ansicht auch mit Kriterien beschränken; dazu wird XPath-Syntax verwendet. Aber Achtung; das DB URI Servlet unterstützt nicht die komplette XPath-Syntax, nur ein Subset kann verwendet werden. Die XML-Funktionen in der Datenbank wie EXTRACTVALUE oder EXISTSNODE unterstützen XPath dagegen vollständig. So zeigt die folgende URL nur eine Zeile aus der EMP-Tabelle an.
You can apply filter criteria to the URI; use XPath notation for this. But keep in mind that this particular DBURI Servlet does not support 100% of XPath. The XML functions in the database(like EXISTSNODE or EXTRACTVALUE) at the other hand do fully support XPath.
http://[host]:[port]/oradb/SCOTT/EMP/ROW[EMPNO=7839]
Auch andere Kriterien sind möglich; wenn mehrere Zeilen selektiert werden, ist jedoch ein zusätzlicher Parameter rowsettag nötig, sonst gibt es eine Fehlermeldung.
Other criteria is also possible - but use the rowsettag parameter when you expect more then one row - an error is raised otherwise.
http://[host]:[port]/oradb/SCOTT/EMP/ROW[JOB="CLERK"]?rowsettag=QUERY
Mit der Funktion SYS_DBURIGEN könnt Ihr euch URLs generieren lassen. Damit wird es möglich, auf eine bestimmte Tabellenspalte in einer bestimmten Zeile mit genau einer Zeichenkette, eben der URI zu verweisen.
The SYS_DBURIGEN function allows to generate such URI. An URI is (expressed otherwise) a pointer to a single value in the database - as the following example illustrates.
SQL> select sys_dburigen(ENAME, SAL) from partner.emp where empno=7844;

SYS_DBURIGEN(ENAME,SAL)(URL, SPARE)
--------------------------------------------------------------------------------
DBURITYPE('/PARTNER/EMP/ROW[ENAME=''TURNER'']/SAL', NULL)
Setzt man nun Hostname und Port und das Schlüsselwort oradb davor, so kann man sich das Ergebnis im Browser ansehen ... aber auch in SQL können diese URI verwendet werden. Dazu gibt es den Objekttypen DBURITYPE.
Prefix this with the hostname, the TCP/IP-Port of the HTTP listener and the oradb keyword and you can (again) bnavigate to this value with the browser. But the DBURIs can also be used in SQL queries - the DBURITYPE object type is there for this.
SQL> select dburitype('/PARTNER/EMP/ROW[ENAME=''TURNER'']/SAL').getxml() from dual;

DBURITYPE('/PARTNER/EMP/ROW[ENAME=''TURNER'']/SAL').GETXML()
--------------------------------------------------------------------------------
<?xml version="1.0"?>
<SAL>1501</SAL>
Probiert es mal aus ... insbesondere die Variante über den Browser kann sehr interessant sein. Wenn man nun noch berücksichtigt, dass Kommandozeilenwerkzeugen wie wget es erlauben, diese Funktionalität in Batchläufen zu nutzen, dann wird es sehr einfach, XML von der Datenbank in andere Systeme zu übertragen. Einfacher geht es nun wirklich nicht ...
Give it a try. The simple browser access might be of particluar interest if you need to provide XML data from the database in a short timeframe. Consider the wget commandline utility which allows to use this feature in batch processes. Transferring XML data between the database and other systems is then a very simple task.
Mehr Informationen zu den DB URIs findet Ihr im XML DB Handbuch. Darin enthalten sind auch Informationen über zusätzliche HTTP-Parameter, die Ihr verwenden könnt - so kann transform eine XSLT-Transformation auslösen ... schaut einfach mal rein.
More information is contained in the XML DB documentation. This also contains additional parameters which can be applied to the HTTP URL's (e.g. transform for Stylesheet (XSLT)-transformations).

Kommentare:

Carsten hat gesagt…

Hallo Carsten,

super Beitrag (wie immer :-)). Ich könnte mir vorstellen, eine Art Webservice mit aktuellen Daten bereitzustellen. APEX selber bietet sowas ja leider nicht an.

Nur wenn du wget vorschlägst der XML Output aber ein Passwort verlangt, hast du das mal zusammen probiert? ich weiß ja, dass man wget Benutzerdaten übergeben kann.

Carsten Czarski hat gesagt…

Hallo Carsten,

hier ein wget-Aufruf, der funktioniert ...

$ wget
  --proxy=off
  --http-user=scott
  --http-passwd=tiger
  -O EMP.xml
  --no-http-keep-alive
  http://192.168.2.140:8081/oradb/SCOTT/EMP

Michael hat gesagt…

Hallo Carsten,

tolle Sache, gibt es eine einfache Möglichkeit, damit dies auch mit Daten, die Umlaute (oder anderen Sonderzeichen) enthalten funktioniert?

Carsten Czarski hat gesagt…

Hallo Michael,

das ist ein bißchen ein wunder Punkt ...

Die Datenbank liefert das XML stets im Zeichensatz der Datenbank aus; der "XML-Prolog" wird allerdings kein Zeichensatz deklariert.

Nach dem Standard bedeutet "kein Zeichensatz" gleich Unicode. Es gibt demnach keine Probleme, wenn die Datenbank mit dem Unicode-Zeichensatz arbeitet (AL32UTF8). Bei anderen Datenbanken müsste vor einer Weiterbearbeitung der XML-Prolog angepasst werden ...

Viele Grüße

-Carsten

Carsten hat gesagt…

Hallo Carsten,

ich habe den Listener jetzt von meinem DBA auf meiner Abnahme-DB aktivieren lassen.

Wenn ich aber ein Tabelle per URL aufrufe, erhalte ich folgenden Fehler:

ORA-19202: Error occurred in XML processing ORA-00942: table or view does not exist

Die Tabelle ist aber definitiv vorhanden und die Berechtigung passt auch.

Carsten Czarski hat gesagt…

Hallo Carsten,

welche URL hast Du denn im Browser verwendet ...?

-Carsten

Carsten hat gesagt…

Hallo Carsten,

ich 2 Versionen probiert:

http://ip_adresse:4488/oradb/schema/tabellenname

http://name_des_servers:4488/oradb/schema/tabellenname

Wenn du es genau wissen willst, würde ich es per Mail an dich schicken (Datenschutz:-) ). Bei beiden kommt die Aufforderung, Benutzername/Passwort einzugeben. Nur dann eben die o.g. Fehlermeldung

Carsten Czarski hat gesagt…

Hallo Carsten,

schick' mir die tatsächlichen URL gerne per Email ... ein allgemeiner Hinweis noch: Schema- und Tabellenname müssen normalerweise groß geschrieben werden. Im gegensatz zu SQL*Plus macht das DBUriServlet das nicht automatisch ...

Grüße

-Carsten

Carsten hat gesagt…

Hallo Carsten,

das war der entscheidende Hint. Großschreibung beachten und schon bekomme ich meine Daten.

Danke dir und ein schönes Wochenende!

Anonym hat gesagt…

Hallo Carsten,
es scheint, zumindest beim DBURIType, noch einen zweiten wunden Punkt zu geben: Die Unfähigkeit, mehr als eine Zeile (aber eben nicht eine ganze Tabelle) zurückzuliefern. Der Parameter rowsettag ist bei DBURIType ja wohl nicht zu setzen...

Beliebte Postings