In this section we will discuss some of the special features provided by Oracle.
Oracle9i introduces new URIType object types that represent URIs (Uniform Resource Identifiers). A URI generalizes the concept of URL. A URI references not only HTML and XML documents, it also possesses "pointer" semantics to point into a document. Hence, a URI consists of two parts:
A URL referencing a document
A fragment that identifies a fragment within that document
A typical example for a URI is http://www.xml.com/xml_doc#//Customer/Address/Zip'. The part in front of the number sign (#) identifies the place of the document, while the final part references a fragment in the document. This mechanism follows the W3C XPointer specification. Oracle provides four object types to support the URI concept:
UriType is an abstract object type that supplies the basic mechanisms.
The subtype HttpUriType implements the HTTP protocol for accessing (external) Web pages.
DBUriType is another subtype that allows referencing data in the database, so to speak, by means of intra-database references.
The purpose of class UriFactoryType is to create those UriType objects.
The UriType object types are ordinary Oracle attribute domains. An object of that type holds a URI to an external document or to database data. Moreover, further subtypes of UriType can be added to support and implement other protocols such as gopher.
The subtype DBUriType, in particular, can be understood as a pointer to one entry in the database, which might be a table, a single row, a value, maybe complexly structured. The basis for referencing data via DBUriType is the implicit XML representation of a database shown in Listing 6.38.
<?xml version="1.0"?> <oradb SID="mydb"> <PUBLIC> <ALL_TABLES> . . . </ALL_TABLES> <EMP> <ROW> <EMPNO>1001</EMPNO> <ENAME>John</ENAME> . . . </ROW> <ROW> <EMPNO>1002</EMPNO> <ENAME>Mary</ENAME> . . . </ROW> </EMP> </PUBLIC> <SCOTT> <CUSTOMER> <ROW> <CNO>10</CNO> <NAME>Lucky Luke</NAME> <ADDRESS> <ZIP>12345</ZIP> <CITY>Bull</CITY> <STREET>Cows Xing</STREET> <HOUSENO>8</HOUSENO> </ADDRESS> . . . </ROW> </SCOTT> </oradb>
The organization of this virtual XML database document reflects the hierarchy of database concepts:
<oradb> with the Oracle system identifier (SID) as attribute
Database schema (e.g., <PUBLIC> and <SCOTT>)
Table in the schema (e.g., <EMP>, <CUSTOMER>)
Tuple in the table (<ROW>)
Attribute value (<CNO>)
Complex attribute values are handled as in XSU. For instance, the "virtual" XML document presents an object-valued attribute Address being structured as <ADDRESS> <ZIP> 12345 </ZIP> <CITY> . . . </HOUSENO> </ZIP>.
The virtual XML document takes into account the access privileges that are valid at the time of access. Hence, only those tables that are accessible by the user become part of the document. NULL values are not displayed, and the whole element for the attribute value is absent. In the future, the special null attribute <xsi null="true"> will be used to this end.
A DBUri path refers to exactly one element in the "database document"?that is, an attribute value, a single tuple, or the whole table. The path is specified in a simplified XPath format.
/SCOTT/CUSTOMER denotes the whole table.
/SCOTT/CUSTOMER/ROW[ CNO="10"] determines a tuple by means of a predicate.
/SCOTT/CUSTOMER/ROW[ CNO="10"] /NAME refers to an attribute value of a tuple.
/SCOTT/CUSTOMER/ROW[ CNO="10"] /ADDRESS/ZIP points to a value of an object.
In any case, the predicate has to determine exactly one tuple. It does not need to include the key of the table. Logical operators and, or, and not(), the usual comparisons, and some arithmetic operators are allowed. Not all features of XPath and XPointer are supported. For example, the wildcard "*" and the operator "//" are missing. The only XPath-function being allowed is text(). This function eliminates embedding tags and references just the text itself. Hence, the DBUri /SCOTT/CUSTOMER/ROW[ CNO="10"] /NAME/text() qualifies the text "Lucky Luke" instead of the element <NAME> Lucky Luke </NAME>.
DBUriType objects are accessible from a browser or a Web server. Certainly, a servlet must be called being able to transform a DBUri. A Java servlet oracle.xml.uri.OraDbUriServlet can execute the DBUri reference and return the value. However, the servlet can run only on the Oracle Servlet Engine (OSE). Anyway, anybody can implement such a servlet and plug it into a Web server. Using the Oracle servlet, the following URL returns the name of customer 10:
http://machine.oracle.com:8080/oradb/SCOTT/CUSTOMER/ROW[ CNo=10] /Name/text()
The servlet engine runs on the machine machine.oracle.com with a Web service at port 8080 listening to requests. The appended DBUri is then executed by the servlet. The result of this "query," the name of customer 10, is visualized in the browser. Note that a non-SQL programmer can now easily access data and documents stored in the database.
The MIME type of the generated document is chosen automatically. In the case the DBUri ends in a text() function, then "text/plain" is used, else an XML document is produced with the mime type "text/xml".
DBUriType objects are useful in several scenarios:
Links to other related documents can be held in the database, as some kind of intra-database link.
A "lazy fetching" of documents can be implemented: Only the first few characters of a document are stored in a table, the complete document is referenced by a URI in the database.
XSL style sheets can be stored in the database and referenced during parsing with import/include.
The URIType object types encapsulate in principle a VARCHAR value that holds the URI string. URIType possesses the following methods:
CLOB getClob(): Returns the value pointed to by the URI as a CLOB.
VARCHAR getUrl(): Returns the URL that is stored in the URIType object.
VARCHAR getExternalUrl(): Is similar to getUrl; however, it calls the escape mechanism (e.g., to convert white spaces into "%20").
The type UriFactory should be used to create UriType objects. Let us assume a table UrlTab(id INTEGER, uri URIType). A URI can be stored as shown in Listing 6.39.
INSERT INTO UrlTab VALUES (1,SYS.UriFactory.getUri('http://www.oracle.com/CUSTOMER/ROW [ CNo=10] /Name'))
The method getUri(VARCHAR) takes a string and creates a URIType object in the following manner:
If the prefix is "http://", then the object will be of type HttpUriType.
If the prefix is "/oradb/" or unknown, then an object of type DBUriType is created.
In principle, new protocols can be added as further subtypes of UriType. Any subtype must be registered in UriFactory by means of a method registerHandler. Afterwards the protocol is recognized by getUri in the same way.
Oracle's SQL possesses a standalone function SYS_DBURIGen that simplifies creating a DBUriType object. URIs are defined in a descriptive manner in Listing 6.40 instead of specifying an XPath, which is useful to generate a DBUri dynamically for given target columns.
SELECT SYS_DBURIGen(CNo, Name) FROM Customer WHERE CNo=10
This query produces a URI "/SCOTT/CUSTOMER/ROW[ CNO="10"] /NAME", which references the name of the customer with CNo=10. The first parameter CNo characterizes the key of the object to be referenced, while the second parameter determines the target?that is, the Name value. The key may consist of several attributes, which are all listed in the parameter list. All the parameters except the last one are considered the key. The last parameter always specifies the database object to be referenced.
The generated URI points to an element?that is, including tags like <ROW> . . . </ROW>. If the URI refers to the text, then 'text()' can be applied as the last parameter.
The following generates a URI /SCOTT/CUSTOMER/ROW[ CNO='10'] /NAME/ text():
SELECT SYS_DBURIGen(CNo, Name, 'text()') FROM Customer WHERE CNo=10
The scenario in Listing 6.41 presents an application for URIs. Given a table ClobTab(id INTEGER, doc CLOB), we are able to define a view Shorttext(id, header, link), which presents the first 20 characters of doc in a column named header and maintains a link to the real CLOB document.
CREATE VIEW Shorttext AS SELECT id, shorten(doc) AS header, SYS_DBURIGen(id,doc,'text()') AS link FROM ClobTab
The view uses a user-defined function shorten that extracts the first 20 characters.
Oracle9i provides several components, utilities, and interfaces to provide the advantages of XML technology in building Web-based database applications. Most of them are summarized in the XDK (XML Development Kit). XDKs are available for Java, C/C++, and PL/SQL, containing building blocks for reading, manipulating, transforming, and viewing XML documents. The XDK for Java is composed of the following components:
An XML parser parses and creates XML documents using industry standard DOM and SAX interfaces. The SAX and DOM interfaces conform to the W3C recommendations version 2.0.
The parser includes an integrated XSL Transformation (XSLT) processor for transforming XML data using style sheets. Using the XSLT processor, XML documents can be transformed from XML to any text-based format, such as XML, WML, or HTML.
Moreover, the parser is able to validate a document against a DTD or an XML schema.
XDK supports XML1.0, DOM1.0, 2.0, SAX1.0, 2.0, and XSLT1.0. As Java is one possible language for implementing stored procedures in Oracle, the XDK allows plugging applications with XML processing into the database server.
An XML Class Generator creates source files from an XML DTD or XML Schema definition. Given a DTD or XML Schema, a class generator produces a set of Java or C++ classes. These classes enable one to construct XML documents in a program incrementally by calling constructors and methods. This is useful, for instance, when a Java program has to create an XML document that confirms a customer's order.
Here we want to explain only the general principle for the Java class generation in case of DTDs. For each element of a DTD, a corresponding Java class is generated. The class possesses constructors to initialize the XML element. Methods represent the DTD rules; for each element E on the right side is a corresponding addNode method to add parts. In addition to these basic mechanisms for constructing documents, further methods such as print(OutputStream) and validateContent() validate the constructed document. Listing 6.42 shows how to build an XML document.
CNo id = new CNo("1"); Firstname f = new Firstname ("Lucky"); Lastname l = new Lastname ("Luke"); Name name = new Name; name.addNode(f); name.addNode(l); // Name element is ready now Zip z = new Zip("12345"); City c = new City("Bull"); Street str = new Street ("Cows Xing"); Houseno hno = new Houseno("8"); Address addr = new Address(); addr.addNode(z); addr.addNode(c); addr.addNode(str); addr.addNode(hno); // Address element is ready now Phone ph1 = new Phone ("012/3456"); Phone ph2 = new Phone ("023/4567"); Price pr = new Price("1.11"); pr.setCURRENCY(CURRENCY_Dollar); // attribute of Price Position p = new Position ("1"); p.addNode(pr); . . . Order ord = new Order("4711"); . . . Customer c = new Customer(); c.addNode(id); c.addNode(name); c.addNode(addr); c.addNode(ph1); c.addNode(ph2); c.addNode(ord); c.validateContent(); // validate the document c.print(System.out); // print the document
Using the generated Java classes, XML documents can be constructed gradually in a Java program. At first, the leaves of the document tree are created by using constructors of CNo, Firstname, Lastname, and so on. Higher elements like Name or Address are then built. The addNode method adds either a component to an element or a repetitive element such as Phone. The validateContent method finally checks the validity of the constructed document, which is useful as the methods themselves do not guarantee valid documents. For instance, exchanging addNode(f) with addNode(1), an invalid document would emerge.
A command-line utility for the class generator offers the same functionality.
Most of Oracle's XML functionality is accompanied with Java Beans that encapsulate the concepts presented earlier in this chapter. These Oracle XML TransViewer beans are provided as part of XDK for Java Beans. They facilitate the addition of graphical or visual interfaces to an XML application. The first three beans are nonvisual:
The DOM Builder bean builds a DOM tree from an XML document. It encapsulates the XML parser for Java's DOMParser class with a bean interface and extends the functionality with asynchronous parsing.
The XSL Transformer bean accepts an XML file, applies the transformation specified by an input XSL style sheet, and creates the resulting output file. When integrated with other beans, XSL Transformer enables an application to view the results of transformations immediately.
The DBAccess bean is dedicated to the storage of XML documents. This bean maintains CLOB tables that hold several XML documents. The tables manage filenames and related XML contents. DBAccess can be used by other TransViewer beans as a kind of intermediate XML storage (e.g., keeping XSL style sheets under development and transformation results).
The following beans are visual:
The Treeviewer bean displays XML documents graphically as a tree. The branches and leaves of this tree can be manipulated with a mouse.
The XML SourceView bean allows visualization of XML documents, and the editing. of XML and XSL files is displayed such that syntax is highlighted with color. Thanks to the Java Bean approach, the XML SourceView bean can easily be integrated with DOM Builder bean. Hence, it allows for pre- and post-parsing visualization.
DBViewer is a Java Bean that can be used to display the results of database queries as XML documents in a scrollable swing panel. XSL style sheets can easily be applied to modify the shape of result.
XML Transform Panel is a bean that applies XSL transformations on XML documents and shows the result. It allows the editing of XML and XSL files.