How to Install and Use Oracle XQuery Processor for Java

Use XQuery to Query, Update and Modify XML Documents

“Trees that are slow to grow bear the best fruit.” ― Molière

1. Introduction

As a Java Programmer, if you work in any way with XML, you should learn about XQuery and how to use it.

XQuery is a query language for XML. It is similar to XPath in that it uses the same or similar constructs to identify specific parts of an XML document.

XQuery offers facilities to update and modify XML documents. It does this using a language similar (at least in concept if not in form) to SQL for databases.

It is easy to work with XPath in java due to the availability of the XPath engine within the java SDK. Working with XQuery is more challenging because you have to integrate the XQuery processor into your java toolset. This article shows you how to do that.

There are several implementations of XQuery available on the web, some of which are open-source while others are closed-source and proprietary. In this article, we show you how to obtain and use Oracle’s XQuery Processor for Java.

The XQuery API is defined by JSR-225 XQuery API for Java. And here is the link to Oracle XQuery Processor javadocs.

XQuery language itself is defined by XQuery 3.0: An XML Query Language

2. Obtaining Oracle XQuery Processor for Java

Finding the Oracle XQuery Processor for Java is somewhat hard. It seems they have hidden it well. It is included as a part of the Oracle Database (though not in the XE version), but who wants to install the Oracle Database just to get at the XQuery processor?

A better place to find the XQuery processor is the Oracle Big Data Connectors. Head on to this page and click on the Oracle XQuery for Hadoop link. Agree with the presented license agreement, register for a free account, and download the toolkit. It should contain all you need for using the XQuery processor.

3. Installing the Jars for Maven

We are using Maven so we need to extract the jars from the downloaded package and install them. We need the following jars (shown with the full path in the package):

  • oxh-4.9.0-cdh5.0.0/hive/lib/oxquery.jar
  • oxh-4.9.0-cdh5.0.0/hive/lib/xqjapi.jar
  • oxh-4.9.0-cdh5.0.0/hive/lib/orai18n-mapping.jar
  • oxh-4.9.0-cdh5.0.0/hive/lib/xmlparserv2_sans_jaxp_services.jar
  • oxh-4.9.0-cdh5.0.0/hive/lib/apache-xmlbeans.jar

Install the jars so Maven can find it with the following commands. Since the version of these jars are unknown, we use a generic version of 0.1 for all of them.

#!/bin/bash

xqj_dir=oxh-4.9.0-cdh5.0.0/hive/lib/

mvn install:install-file \
   -Dfile=${xqj_dir}/oxquery.jar \
   -DgroupId=com.oracle.xqj \
   -DartifactId=oxquery \
   -Dversion=0.1 \
   -Dpackaging=jar \
   -DgeneratePom=true

mvn install:install-file \
   -Dfile=${xqj_dir}/xqjapi.jar \
   -DgroupId=com.oracle.xqj \
   -DartifactId=xqjapi \
   -Dversion=0.1 \
   -Dpackaging=jar \
   -DgeneratePom=true

mvn install:install-file \
   -Dfile=${xqj_dir}/orai18n-mapping.jar \
   -DgroupId=com.oracle.xqj \
   -DartifactId=orai18n-mapping \
   -Dversion=0.1 \
   -Dpackaging=jar \
   -DgeneratePom=true

mvn install:install-file \
   -Dfile=${xqj_dir}/xmlparserv2_sans_jaxp_services.jar \
   -DgroupId=com.oracle.xqj \
   -DartifactId=xmlparserv2 \
   -Dversion=0.1 \
   -Dpackaging=jar \
   -DgeneratePom=true

mvn install:install-file \
   -Dfile=${xqj_dir}/apache-xmlbeans.jar \
   -DgroupId=com.oracle.xqj \
   -DartifactId=apache-xmlbeans \
   -Dversion=0.1 \
   -Dpackaging=jar \
   -DgeneratePom=true

4. Updates to POM.XML

To build the software, we need the following dependencies in the POM.

<project xmlns="http://maven.apache.org/POM/4.0.0"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
                 http://maven.apache.org/maven-v4_0_0.xsd">
    ...
    <dependency>
      <groupId>com.oracle.xqj</groupId>
      <artifactId>oxquery</artifactId>
      <version>0.1</version>
    </dependency>
    <dependency>
      <groupId>com.oracle.xqj</groupId>
      <artifactId>xqjapi</artifactId>
      <version>0.1</version>
    </dependency>
    <dependency>
      <groupId>com.oracle.xqj</groupId>
      <artifactId>orai18n-mapping</artifactId>
      <version>0.1</version>
    </dependency>
    <dependency>
      <groupId>com.oracle.xqj</groupId>
      <artifactId>xmlparserv2</artifactId>
      <version>0.1</version>
    </dependency>
    <dependency>
      <groupId>com.oracle.xqj</groupId>
      <artifactId>apache-xmlbeans</artifactId>
      <version>0.1</version>
    </dependency>
    ...

To make a fat JAR (or uber jar) which can be run easily, use the maven-assembly-plugin:

     ...
      <plugin>
        <artifactId>maven-assembly-plugin</artifactId>
        <configuration>
          <descriptorRefs>
            <descriptorRef>jar-with-dependencies</descriptorRef>
          </descriptorRefs>
          <archive>
            <manifest>
              <mainClass>sample.sample1</mainClass>
            </manifest>
          </archive>
        </configuration>
        <executions>
          <execution>
            <id>make-my-jar-with-dependencies</id>
            <phase>package</phase>
            <goals>
              <goal>single</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
     ...

And with these updates to the POM, let us move on to the code to run XQuery from inside java.

5. A Simple Hello World XQuery Program

Let us begin by building a simple hello-world program which prints the following to stdout:

<hello-world>2</hello-world>

5.1. Java Imports

We need the following java imports:

import java.io.File;
import java.io.FileInputStream;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.nio.file.Paths;
import java.util.Arrays;
import java.net.URI;
import javax.xml.xquery.XQConnection;
import javax.xml.xquery.XQException;
import javax.xml.xquery.XQPreparedExpression;
import javax.xml.xquery.XQSequence;
import javax.xml.xquery.XQStaticContext;
import oracle.xml.xquery.OXQDataSource;
import oracle.xml.xquery.OXQEntityResolver;
import oracle.xml.xquery.OXQEntityKind;
import oracle.xml.xquery.OXQEntityLocator;
import oracle.xml.xquery.OXQEntityResolverRequestOptions;
import oracle.xml.xquery.OXQEntity;
import oracle.xml.xquery.OXQConnection;
import oracle.xml.xquery.OXQView;

5.2. Entity Resolver class

The following class is an entity resolver class defined as an inner class, and is used by the XQuery processor to resolve file: type URLs .

public class sample
{
    ...
    private static class MyEntityResolver extends OXQEntityResolver {
        @Override
        public OXQEntity resolveEntity(OXQEntityKind kind,
                                       OXQEntityLocator locator,
                                       OXQEntityResolverRequestOptions options)
            throws java.io.IOException
        {
            if (kind == OXQEntityKind.DOCUMENT) {
                URI systemId = locator.getSystemIdAsURI();
                if ("file".equals(systemId.getScheme())) {
                    File file = new File(systemId);
                    FileInputStream input = new FileInputStream(file);
                    OXQEntity result = new OXQEntity(input);
                    result.enlistCloseable(input);
                    return result;
                }
            }
            return null;
        }
    }
    ...
}

5.3. The Main Program

And finally the main() function which runs a snippet of XQuery code.

public class sample
{
    ...
    static private void ex1(String[] args)
        throws javax.xml.xquery.XQException
    {
        OXQDataSource ds = new OXQDataSource();
        XQConnection con = ds.getConnection();
        String query = "<hello-world>{1 + 1}</hello-world>";
        XQPreparedExpression expr = con.prepareExpression(query);
        XQSequence result = expr.executeQuery();

        System.out.println(result.getSequenceAsString(null));
        
        result.close();
        expr.close();
        con.close();
    }
    ...
}

Compile and run this class to get the output of adding 1 + 1 embedded within the XML output.

<hello-world>2</hello-world>

6. Running XQuery code From a File

The above example showed how to run a snippet of XQuery code in a string. It also does not read any XML. To be able to run XQuery code from a file, use the following. Note that we set the base URI using XQStaticContext.setBaseURI() so relative XML file references are properly resolved.

OXQDataSource ds = new OXQDataSource();
XQConnection con = ds.getConnection();
 
// OXQView is used to access Oracle extensions on XQJ objects.
OXQConnection ocon = OXQView.getConnection(con);
ocon.setEntityResolver(new MyEntityResolver());
 
File query = new File(xqFile);
        
// Relative URIs are resolved against the base URI before
// invoking the entity resolver.  The relative URI 'books.xml'
// used in the query will be resolved against this URI.
XQStaticContext ctx = con.getStaticContext();
ctx.setBaseURI(query.toURI().toString());
 
FileInputStream in = new FileInputStream(query);
XQPreparedExpression expr = con.prepareExpression(in, ctx);
in.close();
XQSequence result = expr.executeQuery();
System.out.println(result.getSequenceAsString(null));
        
result.close();
expr.close();
con.close();

Let us execute a sample XQuery file. Here is a part of a sample XML file books.xml:

<?xml version="1.0"?>
<catalog>
   <book id="bk101">
      <author>Gambardella, Matthew</author>
      <title>XML Developer's Guide</title>
      <genre>Computer</genre>
      <price>44.95</price>
      <publish_date>2000-10-01</publish_date>
      <description>An in-depth look at creating applications 
      with XML.</description>
   </book>
   <book id="bk102">
      <author>Ralls, Kim</author>
      <title>Midnight Rain</title>
      <genre>Fantasy</genre>
      <price>5.95</price>
...

The books.xml is referenced by the following XQuery example:

doc("books.xml")/catalog/book[price > 30]

On executing this XQuery example, the result is as shown. Note that only those book elements whose price is greater than 30 are selected.

le.sample1 run ex1.xq
<book id="bk101">
      <author>Gambardella, Matthew</author>
      <title>XML Developer's Guide</title>
      <genre>Computer</genre>
      <price>44.95</price>
      <publish_date>2000-10-01</publish_date>
      <description>An in-depth look at creating applications
      with XML.</description>
   </book><book id="bk110">
      <author>O'Brien, Tim</author>
      <title>Microsoft .NET: The Programming Bible</title>
      <genre>Computer</genre>
      <price>36.95</price>
...

Conclusion

This article showed you how to integrate XQuery into your java application. XQuery is very powerful and can be used for a variety of XML query and update tasks which would otherwise be very cumbersome. In the next series of articles, we shall cover how to use XQuery for these tasks and more.