OJXQI - The Oracle Java XQuery API

Introduction to OJXQI

OJXQI is a Java API for XQuery proposed by Oracle.
This page introduces OJXQI, and explains the various extensions that Oracle supports inside the XQuery expression for connecting to the database and for binding values etc..
You can review the javadoc for OJXQI here.

What is OJXQI?

OJXQI is a Java API that can be used to execute and fetch results from XQuery queries. This is similar to JDBC and SQL. OJXQI has a very similar API like JDBC. You can compile XQuery statements and execute them, binding different values each time. Similar to the JDBC result set, the OJXQI provides a XQueryResultSet class which can be used to fetch the results of executing the XQuery.

Here is a simple example of an XQuery usage with OJXQI. This reads the XQuery query from the file exmpl1.xql and then executes the query and prints out the result DOM nodes.

   XQueryContext ctx = new XQueryContext();

   try
   {
     // create a string from the file
     Reader strm = new FileReader("exmpl1.xql");

     // prepare the query
     PreparedXQuery xq = ctx.prepareXQuery(strm);

     // get a resultset
     XQueryResultSet rset = xq.executeQuery();

     while (rset.next())
     {
       XMLNode node = rset.getNode();  // get result nodes
       System.out.println(" NODE "+ node.getNodeName());
       node.print(System.out);
     }
   }
   catch (Exception e)
   {
      // do something..
   }

  • To use the OJXQI API, you would have to first create a context. This context is used to keep prepare multiple XQuery statements later. The context keeps track of metadata such as the Connection to use to connect to the database (if necessary) etc.. In this example, we simply use a default constructor.
  • Next, we create a FileReader stream object to read the XQuery query (We could use a StringReader if the Query was inlined).
  • We prepare the XQuery statement, by calling the prepareXQuery() call. This parses and compiles the XQuery into internal structures.
  • After this, we can call the executeQuery() statement to execute the query. Note that we should have bound values to any bind variable by this time, if our query included bind variables described later. 
  • Executing the query returns a result set which can be used to fetch the data. The return in this example is a DOMNode() which we print out.

Steps for using OJXQI

  • Create a context by using the default constructor or passing in SQL connection information
  • Prepare a XQuery or XQueryX statement by calling prepareXQuery or prepareXQueryX() respectively. This compiles the XQuery statement and returns a PreparedXQuery object.
  • Bind any values to the PreparedXQuery object.
  • Execute the preparedXQuery object. This would return a XqueryResultSet object.
  • Iterate over the result set object (using the next() function) and use the getNode() calls on the XqueryResultSet to get the return values. The iterator iterates over each result from the top level FLWR expression in the XQuery and returns a result. For example, the XQuery,
    • for $i in document("emp.xml")/PurchaseOrder return $i
    would return a list of purchase order nodes. The XQueryResultSet would iterate over these nodes and return a purchaseorder node for each iteration.

Advantages of OJXQI

  • Similar to JDBC hence easy to understand.
  • Support for preparedStatements makes it more scalable, since all queries can be precompiled and used multiple times without having to parse and re-compile.
  • Support for bind variables make it more scalable, when the queries change only with constants. The same query can now be used when the only difference is a constant value.
  • The bind variable allows you to bind DOM objects directly into the XQuery. So you can query transient DOM instances instead of XML stored in files.

Oracle enhancements in OJXQI

Oracle has enhanced the XQuery language to add new functions which provide better integration with the backend database, and to provide for scalable XQuery applications. Oracle enhancements are,
  • Support for SQL queries to be embedded inside XQuery
  • Support for bind variables, so as to not re-execute the XQuery for every constant changes
  • Support for XQueryX - an XML representation of the XQuery language - for ease of mechanical generation and translation of XQuery.

Support for SQL queries

Oracle's XQuery implementation augments the standard to support SQL query results as a document source. A new function called sqlquery is used to identify the SQL query. The result of the sqlquery function is a list of ROW elements each of which is a XML representation of a row of the SQL query result. Further XQuery operations, such as joining the result with other XQuery sources or changing the format of the XML can be done on these elements.
  • For example, the following XQuery gets the results of the employee table in XML and returns the employee element in a different format -
    FOR $i IN sqlquery("select * from scott.emp")/ROW
    RETURN
      <EMP empno="{$i/EMPNO}">
        $i/ENAME,
        $i/SALARY
      </EMP>
     
  • The following XQuery gets the result of the SQL query, and joins that with a local file source. In this case, we get the results from the employee table in SCOTT's schema in the database and join that with the department values stored in a local dept.xml file.
    FOR $i IN sqlquery("select * from scott.emp")/ROW,
        $j IN document("dept.xml")
    WHERE $j/deptno = $i/DEPTNO
    RETURN
      <EMP empno="{$i/EMPNO}" deptno="{$j/deptno}"/>
To execute such XQuery queries that use the sqlquery function, you would need to initialize the Java connection information in the XQueryContext before executing the query. For example, your Java program would be something like this,
  // get the connection (for example, using the thick JDBC Driver)
  DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver());
  Connection conn =
      DriverManager.getConnection("jdbc:oracle:@","scott","tiger");

  // create a context using that connection..
  XQueryContext ctx = new XQueryContext(conn);

  // create a string from the file
  Reader strm = new StringReader(
     "FOR $i IN sqlquery(\"select * from scott.emp\")/ROW "+
     " RETURN <EMP empno=\"{$i/EMPNO}\">$i/ENAME,$i/SALARY</EMP>");

  // prepare the query
  PreparedXQuery xq = ctx.prepareXQuery(strm);

  // get a resultset
  XQueryResultSet rset = xq.executeQuery();

  while (rset.next())
  {
    XMLNode node = rset.getNode();  // get result nodes
    System.out.println(" NODE "+ node.getNodeName());
    node.print(System.out);
  }

Support for URLs in document function

The Oracle's implementation of XQuery supports any arbitrary URLs inside the document function including files. This allows one to point to any web pages containing XML data or to database data when using the XML DB's DBUri and XDB repository.

The XQueryContext also supports a constructor that takes in a baseUrl. This is useful for changing the location from which the document function picks up the files without having to modify the XQuery query itself.

Support for bind variables

Oracle's XQuery implementation supports bind variables as well. This helps in avoiding the overhead of compiling queries. This also helps to query arbitrary DOM nodes, since you can bind DOM nodes into the XQuery.

Example for binding DOM nodes

The following program shows how to execute a query that contains binds involving DOM nodes. It compiles the query and binds the book.xml file as a DOM to the query. Here, after the results are fetched, we can re-bind new values and re-execute the Xquery statement, without having to recompile the whole query.
import java.sql.*;
import oracle.xml.parser.v2.*;
import oracle.xquery.*;
import java.io.*;
import java.util.*;
import oracle.xquery.exec.*;

public class testBindDOM
{
  public static void main(String argv[])
  {
    XQueryContext ctx = new XQueryContext();

    try
    {
      // create a string from the file
      PreparedXQuery xq = ctx.prepareXQuery(
                " for $iN bind('1')/bib/book            "+
                " WHERE $b/publisher = 'Addison-Wesley' "+
                "   AND $b/@year > 1991                 " +
                "    RETURN  <book year={ $b/@year }>   "+
                "            { $b/title }  </book>      ");

      DOMParser prs = new DOMParser();
      InputStream is = Utils.getStream("book.xml");
      prs.parse(is);

      XMLDocument doc = prs.getDocument();
      xq.setNode((new Integer(i)).toString(), doc);

      System.out.println(" Executing Query ");
      XQueryResultSet rset = xq.executeQuery();
      int pos = 0;

      while (rset.next())
     {
       System.out.println(" ---- Fetching Node["+pos+"] ---- ");
       pos ++;

       XMLNode node = rset.getNode();
       System.out.println(" NODE "+ node.getNodeName());
       node.print(System.out);
     }
    }
    catch (Exception e)
    {
        System.out.println(" got exception "+e.getMessage());
    }
  }
}

How are bind values determined?

The bind function takes in a string which indicates the bind name. You can bind the value using that name. You can bind either a String, a DOM node or a simple scalar like integer, float etc..

Example for binding Strings

Here is an XQuery example, which executes the same XQuery, but binds different files. The bind is in the form of a String. This program takes as input the list of files, and executes the same XQuery on each input file.

import java.sql.*;
import oracle.xml.parser.v2.*;
import oracle.xquery.*;
import java.io.*;
import java.util.*;
import oracle.xquery.exec.*;

public class testBindString
{
  public static void main(String argv[])
  {
    XQueryContext ctx = new XQueryContext();

    try
    {
      // create a string from the file
      PreparedXQuery xq = ctx.prepareXQuery(
                " for $iN document(bind(\"filename\"))         "+
                " WHERE $b/publisher = 'Addison-Wesley' "+
                "   AND $b/@year > 1991                 " +
                "    RETURN  <book year={ $b/@year }>   "+
                "            { $b/title }  </book>      ");

 
      // Loop over the input arguments
      for (int i = 0; i < argv.length; i++)
      {
        System.out.println(" Binding value "+i);
        xq.setString("filename", argv[i]);

        System.out.println(" Executing Query... ");
        XQueryResultSet rset = xq.executeQuery();
        int pos = 0;

        while (rset.next())
        {
          System.out.println(" ---- Fetching Node["+pos+"] ---- ");
          pos ++;

          XMLNode node = rset.getNode();
          System.out.println(" NODE "+ node.getNodeName());
          node.print(System.out);
        }
      }
    }
    catch (Exception e)
    {
        System.out.println(" got exception "+e.getMessage());
    }
  }
}

you can execute this program by recompiling it and then supplying the list of filenames,
e.g.

  java testBindString exmpl1.xml exmpl2.xml exmpl3.xml
 
 

E-mail this page
Printer View Printer View
Oracle Is The Information Company About Oracle | Oracle RSS Feeds | Careers | Contact Us | Site Maps | Legal Notices | Terms of Use | Privacy