Skip Headers
Oracle® XML DB Developer's Guide
11g Release 1 (11.1)

B28369-04
Go to Documentation Home
Home
Go to Book List
Book List
Go to Table of Contents
Contents
Go to Index
Index
Go to Master Index
Master Index
Go to Feedback page
Contact Us

Go to previous page
Previous
Go to next page
Next
PDF · Mobi · ePub

14 Java DOM API for XMLType

This chapter describes how to use XMLType in Java, including fetching XMLType data through Java Database Connectivity (JDBC).

This chapter contains these topics:

Overview of Java DOM API for XMLType

Oracle XML DB supports the Java Document Object Model (DOM) Application Program Interface (API) for XMLType. This is a generic API for client and server, for both XML schema-based and non-schema-based documents. It is implemented using Java package oracle.xml.parser.v2. DOM is an in-memory tree-based object representation of XML documents that enables programmatic access to their elements and attributes. The DOM object and interface are part of a W3C recommendation. DOM views the parsed document as a tree of objects.

To access XMLType data using JDBC, use the class oracle.xdb.XMLType.

For XML documents that do not conform to any XML schema, use the Java DOM API for XMLType, because it can handle any valid XML document.

Java DOM API for XMLType

Java DOM API for XMLType handles all kinds of valid XML documents, irrespective of how they are stored in Oracle XML DB. It presents to the application a uniform view of the XML document, whether it is XML schema-based or non-schema-based and whatever the underlying storage model. Java DOM API works on both client and server.

As discussed in Chapter 12, "PL/SQL APIs for XMLType", the Oracle XML DB DOM APIs are compliant with the W3C DOM Level 1.0 and Level 2.0 Core Recommendation.

The Java DOM API for XMLType can be used to construct an XMLType instance from data encoded in different character sets. It also provides method getBLOBVal() to retrieve the XML contents in the requested character set.

You can use the Java DOM API for XMLType to access XML documents stored in Oracle XML DB Repository from Java applications. Naming conforms to the Java binding for DOM as specified by the W3C DOM Recommendation. The repository can contain both XML schema-based and non-schema-based documents.

Using JDBC to Access XMLType Data

This is a SQL-based approach for Java applications to access any data in Oracle Database, including XML documents in Oracle XML DB. Use Java class oracle.xdb.XMLType, method createXML().

How Java Applications Use JDBC to Access XML Documents in Oracle XML DB

JDBC users can query an XMLType table to obtain a JDBC XMLType interface that supports all methods supported by SQL data type XMLType. The Java (JDBC) API for XMLType interface can implement the DOM document interface.

Example 14-1 XMLType Java: Using JDBC to Query an XMLType Table

The following is an example that illustrates using JDBC to query an XMLType table:

import oracle.xdb.XMLType; 
            ... 
   OraclePreparedStatement stmt = (OraclePreparedStatement)
 conn.prepareStatement("select e.poDoc from po_xml_tab e"); 
       ResultSet rset = stmt.executeQuery(); 
       OracleResultSet orset = (OracleResultSet) rset; 

while(orset.next())
        { 
       // get the XMLType 
       XMLType poxml = XMLType.createXML(orset.getOPAQUE(1)); 
       // get the XMLDocument as a string... 
Document podoc = (Document)poxml.getDOM(); 
        }

Example 14-2 XMLType Java: Selecting XMLType Data

You can select the XMLType data in JDBC in one of two ways:

  • Use method getCLOBVal(), getStringVal() or getBLOBVal(csid) in SQL, and obtain the result as an oracle.sql.CLOB, java.lang.String or oracle.sql.BLOB in Java. The following Java code snippet shows how to do this:

    DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver());
    
     Connection conn = 
        DriverManager.getConnection("jdbc:oracle:oci8:@", "QUINE", "CURRY");
    
     OraclePreparedStatement stmt = 
        (OraclePreparedStatement) conn.prepareStatement(
              "select e.poDoc.getCLOBVal() poDoc, "+
                      "e.poDoc.getStringVal() poString "+
              " from po_xml_tab e");
    
    ResultSet rset = stmt.executeQuery();
    OracleResultSet orset = (OracleResultSet) rset;
    
    while(orset.next())
            {
    // the first argument is a CLOB
    oracle.sql.CLOB clb = orset.getCLOB(1);
    
    // the second argument is a string..
    String poString = orset.getString(2);
    
    // now use the CLOB inside the program
            }
    
  • Call method getOPAQUE() in the PreparedStatement to obtain the whole XMLType instance, and use the XMLType constructor to construct an oracle.xdb.XMLType class out of it. Then you can use the Java functions on the XMLType class to access the data.

    import oracle.xdb.XMLType;
    ...
    
     OraclePreparedStatement stmt = 
        (OraclePreparedStatement) conn.prepareStatement(
              "select e.poDoc from po_xml_tab e");
    
    ResultSet rset = stmt.executeQuery();
    OracleResultSet orset = (OracleResultSet) rset;
    
    // get the XMLType
    XMLType poxml = XMLType.createXML(orset.getOPAQUE(1));
    
    // get the XML as a string...
    String poString = poxml.getStringVal();
    

Example 14-3 XMLType Java: Directly Returning XMLType Data

This example shows the use of method getObject() to directly get the XMLType from the ResultSet. This code snippet is the easiest way to get the XMLType from the ResultSet.

import oracle.xdb.XMLType;
...
PreparedStatement stmt =  conn.prepareStatement(
          "select e.poDoc from po_xml_tab e"); 
ResultSet rset = stmt.executeQuery(); 
while(rset.next())
{ 
// get the XMLType 
XMLType poxml = (XMLType)rset.getObject(1); 

// get the XML as a string...
String poString = poxml.getStringVal();
 }

Example 14-4 XMLType Java: Returning XMLType Data

This example illustrates how to bind an OUT variable of XMLType to a SQL statement. The output parameter is registered as data type XMLType.

public void doCall (String[] args) 
  throws Exception 
  { 
 
//  CREATE OR REPLACE FUNCTION getPurchaseOrder(reference VARCHAR2) 
//  RETURN XMLTYPE 
//  AS 
//    xml XMLTYPE; 
//  BEGIN 
//    SELECT OBJECT_VALUE INTO xml 
//      FROM purchaseorder 
//      WHERE extractValue(OBJECT_VALUE,'/PurchaseOrder/Reference') = reference; 
//      RETURN xml; 
//  END; 
 
    String SQLTEXT = "{? = call getPurchaseOrder('BLAKE-2002100912333601PDT')}"; 
    CallableStatement sqlStatement = null; 
    XMLType xml = null; 
    super.doSomething(args); 
    createConnection(); 
    try 
    { 
      System.out.println("SQL := " + SQLTEXT); 
      sqlStatement = getConnection().prepareCall(SQLTEXT); 
      sqlStatement.registerOutParameter (1, OracleTypes.OPAQUE,"SYS.XMLTYPE"); 
      sqlStatement.execute(); 
      xml = (XMLType) sqlStatement.getObject(1); 
      System.out.println(xml.getStringVal()); 
    } 
    catch (SQLException SQLe) 
    { 
      if (sqlStatement != null) 
      { 
        sqlStatement.close(); 
        throw SQLe; 
      } 
    } 

Using JDBC to Manipulate XML Documents Stored in a Database

You can also update, insert, and delete XMLType data using Java Database Connectivity (JDBC).


Note:

XMLType methods extract(), transform(), and existsNode() work only with the thick JDBC driver.

Not all oracle.xdb.XMLType functions are supported by the thin JDBC driver. If you do not use oracle.xdb.XMLType classes and the OCI driver, you could lose performance benefits associated with the intelligent handling of XML.


Example 14-5 XMLType Java: Updating, Inserting, or Deleting XMLType Data

You can update, insert, or delete XMLType data in two ways:

  • Bind a CLOB instance or a string to an INSERT, UPDATE, or DELETE statement, and use the XMLType constructor inside SQL to construct the XML instance:

    OraclePreparedStatement stmt = 
        (OraclePreparedStatement) conn.prepareStatement(
            "update po_xml_tab set poDoc = XMLType(?) ");
    
    // the second argument is a string..
    String poString = "<PO><PONO>200</PONO><PNAME>PO_2</PNAME></PO>";
    
    // now bind the string..
    stmt.setString(1,poString);
    stmt.execute();
    
  • Use setObject() or setOPAQUE() in the PreparedStatement to set the entire XMLType instance:

    import oracle.xdb.XMLType;
    ...
    OraclePreparedStatement stmt = 
        (OraclePreparedStatement) conn.prepareStatement(
            "update po_xml_tab set poDoc = ? ");
    
    // the second argument is a string
    String poString = "<PO><PONO>200</PONO><PNAME>PO_2</PNAME></PO>";
    XMLType poXML = XMLType.createXML(conn, poString);
    
    // now bind the string..
    stmt.setObject(1,poXML);
    stmt.execute();
    

Example 14-6 XMLType Java: Getting Metadata on XMLType

When selecting XMLType values, JDBC describes the column as an OPAQUE type. You can select the column type name and compare it with XMLTYPE to check if you are dealing with an XMLType instance:

import oracle.sql.*;
import oracle.jdbc.*;
...
OraclePreparedStatement stmt = 
    (OraclePreparedStatement) conn.prepareStatement(
        "select poDoc from po_xml_tab");

OracleResultSet rset = (OracleResultSet)stmt.exuecuteQuery();

// Now, we can get the resultset metadata
OracleResultSetMetaData mdata = 
        (OracleResultSetMetaData)rset.getMetaData();

// Describe the column = the column type comes out as OPAQUE
// and column type name comes out as XMLTYPE
if (mdata.getColumnType(1) == OracleTypes.OPAQUE && 
    mdata.getColumnTypeName(1).compareTo("SYS.XMLTYPE") == 0)
{
   // we know it is an XMLtype
}

Example 14-7 XMLType Java: Updating an Element in an XMLType Column

This example updates the discount element inside PurchaseOrder stored in an XMLType column. It uses Java Database Connectivity (JDBC) and the oracle.xdb.XMLType class. This example also shows you how to insert, update, or delete XMLTypes using Java (JDBC). It uses the parser to update an in-memory DOM tree and write the updated XML value to the column.

-- create po_xml_hist table to store old PurchaseOrders
CREATE TABLE po_xml_hist (
 xpo XMLType
);

/*
   DESCRIPTION
    Example for oracle.xdb.XMLType

   NOTES
   Have xmlparserv2.jar and xdb.jar in CLASSPATH

*/

import java.sql.*;
import java.io.*;

import oracle.xml.parser.v2.*;
import org.xml.sax.*;
import org.w3c.dom.*;

import oracle.jdbc.driver.*;
import oracle.sql.*;

import oracle.xdb.XMLType;

public class tkxmtpje
{

  static String conStr = "jdbc:oracle:oci8:@";
  static String user = "QUINE";
  static String pass = "CURRY";
  static String qryStr = 
        "SELECT x.poDoc from po_xml_tab x "+
        "WHERE  x.poDoc.extract('/PO/PONO/text()').getNumberVal()=200";

 static String updateXML(String xmlTypeStr)
  {
     System.out.println("\n===============================");
     System.out.println("xmlType.getStringVal():");
     System.out.println(xmlTypeStr);
     System.out.println("===============================");
     String outXML = null;
     try{
        DOMParser parser  = new DOMParser();
        parser.setValidationMode(false);
        parser.setPreserveWhitespace (true);    

        parser.parse(new StringReader(xmlTypeStr));
        System.out.println("xmlType.getStringVal(): xml String is well-formed");

        XMLDocument doc = parser.getDocument();

        NodeList nl = doc.getElementsByTagName("DISCOUNT");

        for(int i=0;i<nl.getLength();i++){
           XMLElement discount = (XMLElement)nl.item(i);
           XMLNode textNode = (XMLNode)discount.getFirstChild();
           textNode.setNodeValue("10");
        }

       StringWriter sw = new StringWriter();
       doc.print(new PrintWriter(sw));

       outXML = sw.toString();

      //print modified xml
       System.out.println("\n===============================");
       System.out.println("Updated PurchaseOrder:");
       System.out.println(outXML);
       System.out.println("===============================");
      }
    catch (Exception e)
    {
      e.printStackTrace(System.out);
    }
    return outXML;
  }

 public static void main(String args[]) throws Exception
  {
    try{

        System.out.println("qryStr="+ qryStr);

        DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver());

        Connection conn = 
          DriverManager.getConnection("jdbc:oracle:oci8:@", user, pass);

        Statement s = conn.createStatement();
        OraclePreparedStatement stmt;

        ResultSet rset = s.executeQuery(qryStr);
        OracleResultSet orset = (OracleResultSet) rset;

        while(orset.next()){

        //retrieve PurchaseOrder xml document from database
         XMLType xt = XMLType.createXML(orset.getOPAQUE(1));
         
         //store this PurchaseOrder in po_xml_hist table
         stmt = (OraclePreparedStatement)conn.prepareStatement(
                   "insert into po_xml_hist values(?)");

         stmt.setObject(1,xt);  // bind the XMLType instance
         stmt.execute();

         //update "DISCOUNT" element
         String newXML = updateXML(xt.getStringVal());

         // create a new instance of an XMLtype from the updated value
         xt = XMLType.createXML(conn,newXML);

        // update PurchaseOrder xml document in database
         stmt = (OraclePreparedStatement)conn.prepareStatement(
           "update po_xml_tab x set x.poDoc =? where "+
             "x.poDoc.extract('/PO/PONO/text()').getNumberVal()=200");

         stmt.setObject(1,xt);  // bind the XMLType instance
         stmt.execute();

         conn.commit();
         System.out.println("PurchaseOrder 200 Updated!");

        }

       //delete PurchaseOrder 1001
        s.execute("delete from po_xml x"+
           "where x.xpo.extract"+
              "('/PurchaseOrder/PONO/text()').getNumberVal()=1001");
        System.out.println("PurchaseOrder 1001 deleted!");
    }
    catch(Exception e)
    {
      e.printStackTrace(System.out);
    }
  }
}

---------------------- 
-- list PurchaseOrders
----------------------

SELECT x.xpo.getCLOBVal()
FROM po_xml x;

Here is the resulting updated purchase order in XML:

<?xml version = "1.0"?>
<PurchaseOrder>
  <PONO>200</PONO>
  <CUSTOMER>
   <CUSTNO>2</CUSTNO>
   <CUSTNAME>John Nike</CUSTNAME>
   <ADDRESS>
    <STREET>323 College Drive</STREET>
    <CITY>Edison</CITY>
    <STATE>NJ</STATE>
    <ZIP>08820</ZIP>
   </ADDRESS>
   <PHONELIST>
    <VARCHAR2>609-555-1212</VARCHAR2>
    <VARCHAR2>201-555-1212</VARCHAR2>
   </PHONELIST>
  </CUSTOMER>
  <ORDERDATE>20-APR-97</ORDERDATE>
  <SHIPDATE>20-MAY-97 12.00.00.000000 AM</SHIPDATE>
  <LINEITEMS>
   <LINEITEM_TYP LineItemNo="1">
    <ITEM StockNo="1004">
     <PRICE>6750</PRICE>
     <TAXRATE>2</TAXRATE>
    </ITEM>
    <QUANTITY>1</QUANTITY>
    <DISCOUNT>10</DISCOUNT>
   </LINEITEM_TYP>
   <LINEITEM_TYP LineItemNo="2">
    <ITEM StockNo="1011">
     <PRICE>4500.23</PRICE>
     <TAXRATE>2</TAXRATE>
    </ITEM>
    <QUANTITY>2</QUANTITY>
    <DISCOUNT>10</DISCOUNT>
   </LINEITEM_TYP>
  </LINEITEMS>
  <SHIPTOADDR>
   <STREET>55 Madison Ave</STREET>
   <CITY>Madison</CITY>
   <STATE>WI</STATE>
   <ZIP>53715</ZIP>
  </SHIPTOADDR>
</PurchaseOrder>

Example 14-8 Manipulating an XMLType Column

This example performs the following:

  • Selects an XMLType instance from an XMLType table

  • Extracts portions of the XMLType instance, based on an XPath expression

  • Checks for the existence of elements

  • Transforms the XMLType instance to another XML format based on XSL

  • Checks the validity of the XMLType document against an XML schema

import java.sql.*;
import java.io.*;
import java.net.*;
import java.util.*;

import oracle.xml.parser.v2.*;
import oracle.xml.parser.schema.*;
import org.xml.sax.*;
import org.w3c.dom.*;

import oracle.xml.sql.dataset.*;
import oracle.xml.sql.query.*;
import oracle.xml.sql.docgen.*;
import oracle.xml.sql.*;

import oracle.jdbc.driver.*;
import oracle.sql.*;

import oracle.xdb.XMLType;

public class tkxmtpk1
{

  static String conStr = "jdbc:oracle:oci8:@";
  static String user = "tpjc";
  static String pass = "tpjc";
  static String qryStr = "select x.resume from t1 x where id<3";
  static String xslStr =
                "<?xml version='1.0'?> " +
                "<xsl:stylesheet version='1.0' xmlns:xsl='http://www.w3.org/1
999/XSL/Transform'> " +
                "<xsl:template match='ROOT'> " +
                "<xsl:apply-templates/> " +
                "</xsl:template> " +
                "<xsl:template match='NAME'> " +
                "<html> " +
                "  <body> " +
                "      This is Test " +
                "  </body> " +
                "</html> " +
                "</xsl:template> " +
                "</xsl:stylesheet>";

  static void parseArg(String args[])
  {
    conStr = (args.length >= 1 ? args[0]:conStr);
    user = (args.length >= 2 ? args[1].substring(0, args[1].indexOf("/")):user);
    pass = (args.length >= 2 ? args[1].substring(args[1].indexOf("/")+1):pass);
    qryStr = (args.length >= 3 ? args[2]:qryStr);
  }
  /**
   * Print the byte array contents
   */
  static void showValue(byte[] bytes) throws SQLException
  {
    if (bytes == null)
      System.out.println("null");
    else if (bytes.length == 0)
      System.out.println("empty");
    else
    {
      for(int i=0; i<bytes.length; i++)
        System.out.print((bytes[i]&0xff)+" ");
      System.out.println();
    }
  }

public static void main(String args[]) throws Exception
{
 tkxmjnd1 util = new tkxmjnd1();

 try{

     if(args != null)
         parseArg(args);

     //      System.out.println("conStr=" + conStr);
     System.out.println("user/pass=" + user + "/" +pass );
     System.out.println("qryStr="+ qryStr);

     DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver());

     Connection conn = DriverManager.getConnection(conStr, user, pass);
     Statement s = conn.createStatement();

     ResultSet rset = s.executeQuery(qryStr);
     OracleResultSet orset = (OracleResultSet) rset;
     OPAQUE xml;

     while(orset.next()){
      xml = orset.getOPAQUE(1);
      oracle.xdb.XMLType xt = oracle.xdb.XMLType.createXML(xml);

      System.out.println("Testing getDOM() ...");
      Document doc = xt.getDOM();
      util.printDocument(doc);

      System.out.println("Testing getBytesValue() ...");
      showValue(xt.getBytesValue());

      System.out.println("Testing existsNode() ...");
      try {
        System.out.println("existsNode(/)" + xt.existsNode("/", null));
      }
      catch (SQLException e) {
        System.out.println("Thin driver Expected exception: " + e);
      }

      System.out.println("Testing extract() ...");
      try {
        XMLType xt1 = xt.extract("/RESUME", null);
        System.out.println("extract RESUME: " + xt1.getStringVal());
        System.out.println("should be Fragment: " + xt1.isFragment());
      }
      catch (SQLException e) {
        System.out.println("Thin driver Expected exception: " + e);
      }

      System.out.println("Testing isFragment() ...");
      try {
        System.out.println("isFragment = " + xt.isFragment());       }
          catch (SQLException e) 
     {
        System.out.println("Thin driver Expected exception: " + e);
      }

     System.out.println("Testing isSchemaValid() ...");
      try {
     System.out.println("isSchemaValid(): " + xt.isSchemaValid(null,"RES UME"));
      }
      catch (SQLException e) {
        System.out.println("Thin driver Expected exception: " + e);
      }

      System.out.println("Testing transform() ...");
      System.out.println("XSLDOC: \n" + xslStr + "\n");
      try {
      /*  XMLType xslDoc = XMLType.createXML(conn, xslStr);
      System.out.println("XSLDOC Generated");
      System.out.println("After transformation:\n" + (xt.transform(xslDoc,
            null)).getStringVal()); */
      System.out.println("After transformation:\n" + (xt.transform(null, 
            null)).getStringVal());
          }
      catch (SQLException e) {
        System.out.println("Thin driver Expected exception: " + e);
      }

      System.out.println("Testing createXML(conn, doc) ...");
      try {
        XMLType xt1 = XMLType.createXML(conn, doc);
        System.out.println(xt1.getStringVal());
      }
     catch (SQLException e) {
        System.out.println("Got exception: " + e);
      }

    }
}
catch(Exception e)
{
  e.printStackTrace(System.out);
}
}
}

Loading a Large XML Document into the Database with JDBC

If a large XML document (greater than 4000 characters, typically) is inserted into an XMLType table or column using a String object in JDBC, this run-time error occurs:

"java.sql.SQLException: Data size bigger than max size for this type"

This error can be avoided by using a Java CLOB object to hold the large XML document. Example 14-9 demonstrates this technique, loading a large document into an XMLType column; the same approach can be used for XMLType tables. The CLOB object is created using class oracle.sql.CLOB on the client side. This class is the Oracle JDBC driver implementation of the standard JDBC interface java.sql.Clob.

Example 14-9 Loading a Large XML Document

In this example, XMLType method insertXML() inserts a large XML document into the purchaseOrder XMLType column of table poTable. It uses a CLOB object containing the XML document to do this. The CLOB object is bound to a JDBC prepared statement, which inserts the data into the XMLType column.

Prerequisites for running this example are as follows:

  • Oracle Database, version 9.2.0.1 or later.

  • The target database table. Execute the following SQL before running the example:

    CREATE TABLE poTable (purchaseOrder XMLType);

The formal parameters of XMLType method insertXML() are as follows:

  • xmlData – XML data to be inserted into the XMLType column

  • conn – database connection object (Oracle Connection Object)

...
import oracle.sql.CLOB; 
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.PreparedStatement;
... 
 
private void insertXML(String xmlData, Connection conn) {
  CLOB clob = null;
  String query;
    // Initialize statement Object
  PreparedStatement pstmt = null;
  try{
    query = "INSERT INTO potable (purchaseOrder) VALUES (XMLType(?)) ";
    // Get the statement Object
    pstmt = conn.prepareStatement(query);
 
    // xmlData is the string that contains the XML Data.
    // Get the CLOB object using the getCLOB method.
    clob = getCLOB(xmlData, conn);
    // Bind this CLOB with the prepared Statement
    pstmt.setObject(1, clob);
    // Execute the Prepared Statement
    if (pstmt.executeUpdate () == 1) {
    System.out.println ("Successfully inserted a Purchase Order");
    }
  } catch(SQLException sqlexp){
    sqlexp.printStackTrace();
  } catch(Exception exp){
    exp.printStackTrace();
  }
}

Method insertXML() calls method getCLOB() to create and return the CLOB object that holds the XML data. The formal parameters of getCLOB() are as follows:

  • xmlData – XML data to be inserted into the XMLType column

  • conn – database connection object (Oracle Connection Object)

...
import oracle.sql.CLOB; 
import java.sql.Connection;
import java.sql.SQLException;
import java.io.Writer;
... 
 
private CLOB getCLOB(String xmlData, Connection conn) throws SQLException{
  CLOB tempClob = null;
  try{
    // If the temporary CLOB has not yet been created, create one
    tempClob = CLOB.createTemporary(conn, true, CLOB.DURATION_SESSION); 
 
    // Open the temporary CLOB in readwrite mode, to enable writing
    tempClob.open(CLOB.MODE_READWRITE); 
    // Get the output stream to write
    Writer tempClobWriter = tempClob.getCharacterOutputStream(); 
    // Write the data into the temporary CLOB
    tempClobWriter.write(xmlData); 
 
    // Flush and close the stream
    tempClobWriter.flush();
    tempClobWriter.close(); 
 
    // Close the temporary CLOB 
    tempClob.close();    
  } catch(SQLException sqlexp){
    tempClob.freeTemporary(); 
    sqlexp.printStackTrace();
  } catch(Exception exp){
    tempClob.freeTemporary(); 
    exp.printStackTrace();
  }
  return tempClob; 
}

Java DOM API for XMLType Features

When you use the Java DOM API to retrieve XML data from Oracle XML DB:

Both XMLDocument and XDBDocument (which is deprecated) are instances of the W3C Document Object Model (DOM) interface. From this document interface you can access the document elements and perform all the operations specified in the W3C DOM Recommendation. The DOM works on:

The Java DOM API for XMLType supports deep and shallow searching in the document to retrieve children and properties of XML objects such as name, namespace, and so on. Conforming to the DOM 2.0 recommendation, Java DOM API for XMLType is namespace aware.

The Java API for XMLType also lets applications create XML documents programmatically, even on the fly (dynamically). Such documents can conform to a registered XML schema or not.

Creating XML Schema-Based Documents

To create XML schema-based documents, Java DOM API for XMLType uses an extension to specify which XML schema URL to use. For XML schema-based documents, it also verifies that the DOM being created conforms to the specified XML schema, that is, that the appropriate children are being inserted under the appropriate documents.

Note:

The Java DOM API for XMLType does not perform type and constraint checks.

Once the DOM object has been created, it can be saved to Oracle XML DB Repository using the Oracle XML DB resource API for Java. The XML document is stored in the appropriate format:

  • As a BLOB instance for non-schema-based documents.

  • In the format specified by the XML schema for XML schema-based documents.

Example 14-10 Creating a DOM Object with the Java DOM API

The following example shows how you can use Java DOM API for XMLType to create a DOM object and store it in the format specified by the XML schema. Note that the validation against the XML schema is not shown here.

import oracle.xdb.XMLType;
...
OraclePreparedStatement stmt = 
    (OraclePreparedStatement) conn.prepareStatement(
        "update po_xml_XMLTypetab set poDoc = ? ");

// the second argument is a string
String poString = "<PO><PONO>200</PONO><PNAME>PO_2</PNAME></PO>";
XMLType poXML = XMLType.createXML(conn, poString);
Document poDOM = (Document)poXML.getDOM();

Element rootElem = poDOM.createElement("PO");
poDOM.insertBefore(poDOM, rootElem, null);

// now bind the string..
stmt.setObject(1,poXML);
stmt.execute();

JDBC or SQLJ

An XMLType instance is represented in Java by oracle.xdb.XMLType. When an instance of XMLType is fetched using JDBC, it is automatically manifested as an object of the provided XMLType class. Similarly, objects of this class can be bound as values to Data Manipulation Language (DML) statements where an XMLType is expected. The same action is supported in SQLJ clients.

Java DOM API for XMLType Classes

Oracle XML DB supports the W3C DOM Level 2 Recommendation. In addition to the W3C Recommendation, Oracle XML DB DOM API also provides Oracle-specific extensions, to facilitate your application interfacing with Oracle XDK for Java. A list of the Oracle extensions is found at:

http://www.oracle.com/technology/tech/xml/

XMLDocument is a class that represents the DOM for the instantiated XML document. You can retrieve the XMLType value from the XML document using the constructor XMLType constructor that takes a Document argument:

XMLType createXML(Connection conn, Document domdoc)

Table 14-1 lists the Java DOM API for XMLType classes and the W3C DOM interfaces they implement. The Java DOM API classes are all in package oracle.xml.parser.v2.

Table 14-1 Java DOM API for XMLType: Classes

Java DOM API for XMLType Class W3C DOM Interface Recommendation Class
XMLDocument
org.w3c.dom.Document 
XMLCDATA
org.w3c.dom.CDataSection 
XMLComment
org.w3c.dom.Comment 
XMLPI
org.w3c.dom.ProcessingInstruction 
XMLText 
org.w3c.dom.Text 
XMLEntity
org.w3c.dom.Entity 
DTD
org.w3c.dom.DocumentType 
XMLNotation
org.w3c.dom.Notation 
XMLNodeList
org.w3c.dom.NodeList 
XMLAttr
org.w3c.dom.Attribute 
XMLDomImplementation
org.w3c.dom.DOMImplementation 
XMLElement
org.w3c.dom.Element 
XMLAttrList
org.w3c.dom.NamedNodeMap 
XMLNode 
org.w3c.dom.Node 

Java Methods That Are Deprecated or Not Supported

The following are methods documented in release 2 (9.2.0.1) but not currently supported:

  • XDBDocument.getElementByID

  • XDBDocument.importNode

  • XDBNode.normalize

  • XDBNode.isSupported

  • XDBDomImplementation.hasFeature

In addition, in releases prior to Oracle Database 11g release 1, a different API, in package oracle.xdb.dom, was used for the Java DOM. Please refer to the documentation for such releases for more information on that deprecated API. The following classes in oracle.xdb.dom have been deprecated; use the oracle.xml.parser.v2 classes instead.

  • XDBAttribute – use XMLAttr

  • XDBBinaryDocument

  • XDBCData – use XMLCDATA

  • XDBComment – use XMLComment

  • XDBDocFragment – use XMLDocumentFragment

  • XDBDocument – use XMLDocument

  • XDBDocumentType – use DTD

  • XDBDOMException – use XMLDomException

  • XDBDomImplementation – use XMLDomImplementation

  • XDBElement – use XMLElement

  • XDBEntity – use XMLEntity

  • XDBEntityReference – use XMLEntityReference

  • XDBNamedNodeMap – use XMLAttrList

  • XDBNode – use XMLNode

  • XDBNodeList – use XMLNodeList

  • XDBNotation – use XMLNotation

  • XDBProcInst – use XMLPI

  • XDBText – use XMLText

Using Java DOM API for XMLType

Figure 14-1 illustrates how to use the Java DOM API for XMLType.Foot 1  These are the steps:

  1. Retrieve the XML data from the XMLType table or XMLType column in the table. When you fetch XML data, Oracle creates an instance of an XMLType. You can then use method getDocument() to retrieve a Document instance. You can then manipulate elements in the DOM tree using Java DOM API for XMLType.

  2. Use the Java DOM API for XMLType to manipulate elements of the DOM tree. The XMLType instance holds the modified data, but the data is sent back using a JDBC update.

The XMLType and XMLDocument instances should be closed using method close() in the respective classes. This releases any underlying memory that is held.

Figure 14-1 Using Java DOM API for XMLType

Description of Figure 14-1 follows
Description of "Figure 14-1 Using Java DOM API for XMLType"

Handling Large Nodes Using Java

Prior to Oracle Database 11g Release 1 (11.1), there were restrictions on the size of nodes to less than 64 KB, because the Java methods to set and get a node value supported only arguments of type java.lang.String. The maximum size of a string is dependent on the implementation of the Java VM, but it is bounded. Prior to Release 11.1, the Java DOM APIs to manage a node value, contained within class oracle.xdb.dom.XDBNode.java, were these:

public String getNodeValue ();
public void setNodeValue (String value);

The Java DOM APIs to manage an attribute, contained within class oracle.xdb.dom.XDBAttribute.java, were these:

public String getValue ();
public void setValue (String value);

Package oracle.xdb.dom is deprecated, starting with Oracle Database 11g Release 1 (11.1). Java classes XDBNode and XDBAttribute in that package are replaced by classes XMLNode and XMLAttr, respectively, in package oracle.xml.parser.v2. In addition, these DOM APIs were extended in Release 11.1 to support text and binary node values of arbitrary size.

Note:

The large-node feature works only with a thick or kprb connection; it does not work with a thin connection.

See Also:

Stream Extensions to Java DOM

All Java String, Reader, and Writer data are represented in UCS2. This may not be the same as the database character set. Additionally, node character data is tagged with a character set id, set at the time the node value is populated.

The following methods of oracle.xml.parser.v2.XMLNode.java allow access to nodes of size greater than 64 KB. These APIs will throw exceptions if you try to get or set a node which is not a leaf node (attribute, PI, CDATA, and so on). Also, be sure to use close() which actually writes the value and frees resources used to maintain the state for streaming access to nodes.

Get-Pull Model

For a binary input stream:

public java.io.InputStream getNodeValueAsBinaryStream () 
       throws java.io.IOException, DOMException;

This method returns an instance of java.io.InputStream that can be read using the defined methods for this class. The data type of the node must be RAW or BLOB. If not, an IOException is thrown. The following example fragment illustrates reading the value of a node in binary 50-byte segments:

...
oracle.xml.parser.v2.XMLNode node = null;
...
 
java.io.InputStream value = node.getNodeValueAsBinaryStream ();
// now read InputStream...
byte buffer [] = new byte [50];
int returnValue = 0;
while ((returnValue = value.read (buffer)) != -1)
{
   // process next 50 bytes of node
}
...

For a character input stream:

public java.io.Reader getNodeValueAsCharacterStream() 
       throws java.io.IOException, DOMException;

This method returns an instance of java.io.Reader that can be read using the defined methods for this class. If the data type of the node is neither character nor CLOB, the node data is first converted to character. All node data is ultimately in character format and is converted to UCS2, if necessary. The following example fragment illustrates reading the node value in segments of 50 characters:

...
oracle.xml.parser.v2.XMLNode node = null;
...
 
java.io.Reader value = node.getNodeValueAsCharacterStream ();
// now read InputStream
char buffer [] = new char [50];
int returnValue = 0;
while ((returnValue = value.read (buffer)) != -1)
{
   // process next 50 characters of node
}
...

Get-Push Model

For a binary output stream:

public void getNodeValueAsBinaryStream (java.io.OutputStream pushValue) 
       throws java.io.IOException,  DOMException;

The state of the java.io.OutputStream specified by pushValue must be open. The data type of the node must be RAW or BLOB. If not, an IOException is thrown. The node binary data is written to pushValue using the write() method of OutputStream, and the close() method is called when the node value has been completely written to the stream.

For a character output stream:

public void getNodeValueAsCharacterStream (java.io.Writer pushValue) 
       throws java.io.IOException, DOMException;

The state of the java.io.Writer specified by pushValue must be open. If the data type of the node is neither character nor CLOB, then the data is first converted to character. The node data, always in character format, is converted, as necessary, to UCS2 and then pushed into the java.io.Writer.

Set-Pull Model

For a binary input stream:

public void setNodeValueAsBinaryStream (java.io.InputStream pullValue) 
       throws java.io.IOException, DOMException;

The state of the java.io.InputStream specified by pullValue must be open. The data type of the node must be RAW or BLOB. If not, an IOException is thrown. The binary data from pullValue is read in its entirety using the read() method of InputStream and replaces the node value.

import java.io.InputStream;
import oracle.xml.parser.*;
...
oracle.xml.parser.v2.XMLNode node = null;
...
byte [] buffer = new byte [500];
java.io.InputStream  istream; //user-defined input stream
node.setNodeValueAsBinaryStream (istream);

For a character input stream:

public void setNodeValueAsCharacterStream (java.io.Reader pullValue) 
       throws java.io.IOException, DOMException;

The state of the java.io.Reader specified by pullValue must be open. If the data type of the node is neither character nor CLOB, the character data is converted from UCS2 to the node data type. If the data type of the node is character or CLOB, then the character data read from pullValue is converted from UCS2 to the character set of the node.

Set-Push Model

For a binary output stream:

public java.io.OutputStream setNodeValueAsBinaryStream () 
     throws java.io.IOException, DOMException;

This method returns an instance of java.io.OutputStream, into which the caller can write the node value. The data type of the node must be RAW or BLOB. Otherwise, an IOException is raised. The following example fragment illustrates setting the value of a node to binary data by writing to the implementation of java.io.OutputStream provided by Oracle XML DB or Oracle XDK.

For a character output stream:

public java.io.Writer setNodeValueAsCharacterStream () 
       throws java.io.IOException, DOMException;

This method returns an instance of java.io.Writer into which the caller can write the node value. The character data written is first converted from UCS2 to the node character set, if necessary. If the data type of the node is neither character nor CLOB, then the character data is converted to the node data type. Similarly, the following example fragment illustrates setting the value of a node to character data by writing to the implementation of java.io.Writer provided by Oracle XML DB or Oracle XDK.

import java.io.Writer;
import oracle.xml.parser.*;
...
oracle.xml.parser.v2.XMLNode node = null;
...
char [] buffer = new char [500];
java.io.Writer  writer = node.setNodeValueAsCharacterStream ();
for (int k = 0; k < 10; k++)
  {
    byte segment [] = new byte [50];
    // copy next subset of buffer into segment
    writer.write (segment);
  }
writer.flush ();
writer.close();

See Also:

Oracle XML DB creates a writer or OutputStream and passes it to the user who calls the write() method repeatedly until the complete node value has been written. The new node value is reflected only when the user calls the close() method.

Using the Java DOM API and JDBC With Binary XML

XML data can be stored in Oracle XML DB using XMLType, and one of the storage models for this abstract data type is binary XML. Binary XML is a compact, XML Schema-aware encoding of XML data. You can use it as a storage model for XMLType in the database, but you can also use it for XML data located outside the database. Client-side processing of XML data can involve data stored in Oracle XML DB or transient data that resides outside the database.

You can use the Java DOM API for XML to read or write XML data that is encoded as binary XML from or to Oracle XML DB. Doing so involves the usual read and write procedures.

Binary XML is XML Schema-aware and can use various encoding schemes, depending on your needs and your data. Because of this, in order to manipulate binary XML data, you must have both the data and this metadata about the relevant XML schemas and encodings.

For XMLType data stored in the database, this metadata is also stored in the database. However, depending on how your database and data are set up, the metadata might not be on the same server as the data it applies to. If this is the case, then, before you can read or write binary XML data from or to the database, you must carry out these steps:

  1. Create a context instance for the metadata.

  2. Associate this context with a data connection that you use to access binary XML data in the database. A data connection can be a dedicated connection or a connection pool. You use methods getDedicatedConn() and getConnPool() in class java.sql.Connection to obtain handles to these two types of connection, respectively.

Then, when your application needs to encode or decode binary XML data on the data connection, it will automatically the fetch the metadata needed to do that. The overall sequence of actions is thus as follows:

  1. Create an XML data connection object, in class java.sql.Connection.

  2. Create one or more metadata contexts, as needed, using method BinXMLMetadataProviderFactory.createDBMetadataProvider() in package oracle.xml.binxml. A metadata context is sometimes referred to as a metadata repository. You can create a metadata context from a dedicated connection or from a connection pool.

  3. Associate the metadata context(s) with the binary XML data connection(s). Use method DBBinXMLMetadataProvider.associateDataConnection() in package oracle.xml.binxml to do this.

  4. (Optional) If the XML data originated outside of the database, use method oracle.xdb.XMLType.setFormatPref() to specify that XML data to be sent to the database from now on will be in binary XML format. This applies to a DOM document (class oracle.xdb.XMLType). If you do not specify binary XML, the data will be stored as text (CLOB).

  5. Use the usual Java methods to read and write XML data from and to the database. Whenever it is needed for encoding or decoding binary XML documents, the necessary metadata is fetched automatically using the metadata context.

    Use the Java DOM API for XML to operate on the XML data at the client level.

Example 14-11 illustrates this.

Example 14-11 Using the Java DOM API With Binary XML

import java.sql.*;
import oracle.jdbc.*;
import oracle.jdbc.pool.OracleDataSource;
import oracle.xdb.XMLType;
import oracle.xml.binxml.*;
 
class tdadxdbxdb11jav001 {
  public static void printBinXML() throws SQLException, BinXMLException
  {
    // Create datasource to connect to local database
    OracleDataSource ods = new OracleDataSource();
    ods.setURL("jdbc:oracle:kprb");
    System.out.println("Starting Binary XML Java Example");
    // Create data connection
    Connection conn = ods.getConnection();
    // Create binary XML metadata context, using connection pool
    DBBinXMLMetadataProvider repos =
      BinXMLMetadataProviderFactory.createDBMetadataProvider();
    repos.setConnectionPool(ods);
    // Associate metadata context with data connection
    repos.associateDataConnection(conn);
    // Query XML data stored in XMLType column as binary XML
    Statement stmt = conn.createStatement();
    ResultSet rset = stmt.executeQuery("SELECT doc FROM po_binxmltab");
    // Get the XMLType object
    while (rset.next())
    {
      XMLType xmlobj = (XMLType) rset.getObject(1);
      // Perform XMLType operation
      String xmlvalue = xmlobj.getStringVal();
      System.out.println(xmlvalue);
    }
    // Close result set, statement, and connection
    rset.close();
    stmt.close();
    conn.close();
    System.out.println("Completed Binary XML Java Example");
  }
}


Footnote Legend

Footnote 1: This assumes that your XML data is pre-registered with an XML schema, and that it is stored in an XMLType column.