ONJava.com    
 Published on ONJava.com (http://www.onjava.com/)
 See this if you're having trouble printing code examples


Storing an XML Document in Apache Xindice

by Deepak Vohra
03/08/2006

Apache Xindice is a native XML database in which XML documents may be stored, queried, and modified. The advantage of a native database over a relational database is that mapping of XML to SQL is not required. Instead, XPath is used to query the Xindice database and XML:DB XUpdate is used to update the database. Xindice implements the Java XML:DB API to add, query, update XML documents to the Xindice database. XML documents in the Xindice database are stored in collections; a collection may consist of one or more XML documents. Xindice also provides a command-line tool which has the same functionality as the XML:DB API.

Preliminary Setup

The Xindice database is installed as a web application in a web server. To install the Xindice database, the Xindice API JAR files and the Xindice server web application are required.

  1. Download the Version 1.1b4 binary (JAR), xml-xindice-1.1b4-jar.zip, which has the Xindice XML:DB API JAR files.

  2. Download the Version 1.1b4 binary (webapp), xml-xindice-1.1b4-war.zip, which has the Xindice server web application.

  3. Extract xml-xindice-1.1b4-jar.zip to an installation directory, C:/xindice.

  4. Add the xerces-2.6.0.jar to the beginning of the CLASSPATH variable. Then add the following Xindice JAR files to CLASSPATH, where <Xindice> is the Xindice installation directory.

    Xindice JAR File Description
    <Xindice>/xindice-1.1b4/lib/xerces-2.6.0.jar Xerces XML parser
    <Xindice>/xindice-1.1b4/xindice-1.1b4.jar Core Server API
    <Xindice>/xindice-1.1b4/lib/commons-logging-1.0.3.jar Jakarta Commons Logging API
    <Xindice>/xindice-1.1b4/lib/xalan-2.5.2.jar XPath API
    • <Xindice>/xindice-1.1b4/lib/xmldb-api-20030701.jar
    • <Xindice>/xindice-1.1b4/lib/xmldb-api-sdk-20030701.jar
    • <Xindice>/xindice-1.1b4/lib/xmldb-common-20030701.jar
    • <Xindice>/xindice-1.1b4/lib/xmldb-xupdate-20040205.jar
    Implementations of XML:DB API and XUpdate API
    <Xindice>/xindice-1.1b4/lib/xmlrpc-1.1.jar XML-RPC API
    <Xindice>/xindice-1.1b4/lib/xml-apis.jar DOM API

    Table 1. Xindice JAR files

  5. Add <Xindice>/xindice-1.1b4/bin to the PATH variable.

  6. Add a XINDICE_HOME environment variable with the value <Xindice>/xindice-1.1b4.

  7. Extract xml-xindice-1.1b4-war.zip to an installation directory, C:/xindice.

  8. The Xindice web application is deployed in a web/application server (the WebLogic server 9.0 is used in this tutorial, though another web/application server may also be used). Install the WebLogic Server 9.0. Then create a WebLogic server domain with the WebLogic server Configuration Wizard. The default domain that gets created is base_domain.

Overview

The Xindice database may be accessed and modified with either the XML:DB and XUpdate APIs or the Xindice command-line tool. The XML:DB API includes the XpathQueryService service to query the database with XPath and the XUpdateQueryService service to update the database with XUpdate. The XML:DB/XUpdate APIs and the command-line tool are used to create an Xindice database collection, add XML documents to the database, retrieve XML documents from the database, query the database, and update the database. In each of the following sections, we shall first demonstrate the command-line tool and then the Xindice APIs.

The Xindice command-line tool is accessed with the xindice command. The syntax of the xindice command is:

xindice action [switch] [parameter]

Some of the xindice command action values are listed in Table 2.

Xindice Action Description
ac Adds a collection
dc Deletes a collection
ad Adds a document
dd Deletes a document
lc Lists the collections
rd Retrieves a document
ld Lists documents in a collection
xpath Queries a document with XPath
xupdate Updates a document with XUpdate

Table 2. Xindice command action values

Some of the xindice command switch values are listed in Table 3.

Xindice Switch Description
-c Specifies a collection context.The context syntax is of the form xmldb:xindice://host:port/db
-f Specifies a file path
-n Specifies a name
-q Specifies an XPath query

Table 3. Xindice command switch values

In the following sections refer to Table 2 and Table 3 for the Xindice action or switch used in the xindice command. As an example of the xindice command, list the collections in the Xindice database with the command:

xindice lc -c xmldb:xindice://localhost:7001/db

The result of the xindice command is:

system

meta

Total collections: 2
XPath and XPointer

Related Reading

XPath and XPointer
Locating Content in XML Documents
By John E. Simpson

Configuring Xindice with WebLogic Server

The Xerces parser is required to configure the Xindice 1.1.b4 database. By default, Xindice uses the XML parser configured in the JVM. As the XML parser included in JDK 1.4.2 is the Crimson parser, using Xindice 1.1b4 with JDK 1.4.2 generates the error:

Failed to create SAXParser

org.xml.sax.SAXNotSupportedException: 

Feature: http://xml.org/sax/features/

external-general-entities

Use JDK 5.0 with Xindice 1.1b4. JDK 5.0 includes the Xerces parser. The WebLogic Server 9.0 is used to deploy the Xindice database. You need to use WebLogic version 9.0 instead of 8.1 because version 9.0 supports JDK 5.0.

JDK 1.4.2 may be used with Xindice by adding Xerces implementation classes in Xerces2-j 2.7.1 to the classpath before the Xerces classes in the JDK 1.4.2, via the endorsed standards override mechanism. To use the endorsed standards override mechanism, either define a system property java.endorsed.dirs with the directory in which Xerces2-j is installed (such as <xerces-2_7_1>), or copy the JAR files from the xerces-2_7_1 directory to the <JDK1.4.2>/jre/lib/endorsed directory.

The configuration procedure in this section applies only to WebLogic Server 9.0:

  1. Modify <Xindice>/Xindice-webapp/xindice-1.1b4/xindice-1.1b4.jar to xindice.jar.
  2. Extract the WEB-INF/server.xml configuration file from the xindice.jar file.
  3. In the server.xml file, specify the dbroot attribute value in the root collection element as C:/xindice/db, a directory path in which the Xindice database shall be created.
  4. Delete WEB-INF/system.xml from the xindice.jar file. Add the modified WEB-INF/server.xml to xindice.jar.
  5. Copy the xindice.jar file to the <weblogic>/user_projects/domains/base_domain/autodeploy directory.
  6. Define the JAVA_HOME environment variable as <weblogic>/jdk150_03, where <weblogic> is the directory in which the WebLogic server is installed.
  7. Start the WebLogic server. This starts the Xindice database server in the WebLogic server and opens the default Xindice database, db. The Xindice server web application gets deployed in the WebLogic server. Access the WebLogic server Administration Console with the URL http://localhost:7001/console. Select the base_domain>Deployments node. Select the Xindice web application link and the Testing tab. The Xindice server URL is shown as http://localhost:/7001/xindice.

Creating a Collection in the Database

After configuring the Xindice database server in the WebLogic server, we shall create an Xindice database collection with the command-line tool and the XML:DB API. A collection is a set of XML documents in the Xindice database.

Create a top-level collection, catalog, with the Xindice command:

>xindice ac -c xmldb:xindice://localhost:7001/db -n catalog

The collection context in the example command line command is the db database instance, the default Xindice database instance. The db database may also be referred to as the root collection. This creates the collection catalog in the db database and prints the message:

Created :xmldb:xindice://localhost:7001/db/catalog

The collection created may be deleted with the command:

>xindice dc -c xmldb:xindice://localhost:7001/db -n catalog

This deletes the collection with the message:

Deleted: xmldb:xindice://localhost:7001/db/catalog

Next, we shall create a collection with the XML:DB API. Import the Xindice core server classes and the XML:DB API classes.

import org.apache.xindice.client.xmldb.services.*;
import org.apache.xindice.util.XindiceException;
import org.apache.xindice.xml.dom.*;
import org.xmldb.api.*;
import org.xmldb.api.base.*;
import org.xmldb.api.modules.*;

Create an instance of the Xindice database engine. The XML:DB driver implementation class for the Xindice database is DatabaseImpl. Register the Xindice database with the org.xmldb.api.DatabaseManager, which is used to obtain a collection from a XML:DB database.

String xindiceDriver = 
  "org.apache.xindice.client.xmldb.DatabaseImpl";
org.xmldb.api.base.Database xindiceDatabase = 
  (org.xmldb.api.base.Database)
  ((Class.forName(xindiceDriver)).newInstance());
org.xmldb.api.DatabaseManager.
   registerDatabase(xindiceDatabase);

Next, obtain the db collection from the database.

 String url = "xmldb:xindice://localhost:7001/db";
 org.xmldb.api.base.Collection  collection = 
    DatabaseManager.getCollection(url);

Create a org.apache.xindice.client.xmldb.services.CollectionManager object. A CollectionManager is required to create and delete collections from the database. Specify the XML configuration to create a collection. The XML configurations are not very well documented in Xindice. Create a database collection with the CollectionManager service.

CollectionManager collectionManagerService = 
   (CollectionManager) 
   collection.getService("CollectionManager", "1.0");

String collectionName = "catalog";
String collectionConfig = "<collection compressed=\"true\" " +
  "   name=\"" + collectionName + "\">" +
  " <filer class=\"org.apache.xindice.core.filer.BTreeFiler\"/>" +
  "</collection>";

catalogCollection = 
  collectionManagerService.createCollection
  (collectionName, 
  DOMParser.toDocument(collectionConfig));

This creates collection, catalog in the db database.

Adding an XML Document to the Database

Next, add an example XML document to the database collection, catalog. The example XML document is as follows:

<catalog title="OnJava.com" publisher="OReilly"> 
 <journal date="Sept 2005"> 
  <article>
   <title>What Is a Portlet</title>
   <author> Sunil Patil</author>
  </article>
 </journal>
 <journal date="Sept 2005">
  <article> 
   <title>What Is Hibernate</title>
   <author>James Elliott</author>
  </article>
 </journal>
 <journal date="Oct 2003">
  <article> 
   <title>BCEL Maven and CSS with Swing</title>
   <author>Daniel Steinberg</author>
  </article>
 </journal>
</catalog>

Use the command-line tool to add an XML document to the Xindice database with the command:

>xindice ad -c xmldb:xindice://localhost:7001/db/catalog  
 -f c:/xindice/catalog.xml -n catalog.xml

This adds the catalog.xml document to the catalog collection, printing the confirmation:

Added document 
xmldb:xindice://localhost:7001/db/catalog/catalog.xml

Next, we shall add a collection with the XML:DB API. Import the XML:DB API and core server classes, which are listed in the previous section. Create and register the database driver as in the "Creating a Collection in the Database" section. Obtain the catalog collection from the database:

Collection collection = DatabaseManager.getCollection
  ("xmldb:xindice://localhost:7001/db/catalog");

Obtain a Document object for the XML document to be added to the database.

DocumentBuilderFactory factory = 
  DocumentBuilderFactory.newInstance();
File datafile = new File("c:/Xindice/catalog.xml");
DocumentBuilder builder = factory.newDocumentBuilder();
Document document = builder.parse(datafile);

Create an ID for the XML document resource to be added to the collection. The ID associates the collection with an identifier. Create a org.xmldb.api.modules.XMLResource for the XML document to add from the collection. The XMLResource object represents an XML resource, such as a Document object, in the Xindice database. Set the content of the XMLResource from the Document object. Add the XML resource to the collection.

String  resourceID = collection.createId();

XMLResource resource = (XMLResource) 
 (collection.createResource(resourceID,
              "XMLResource"));
resource.setContentAsDOM(document);
collection.storeResource(resource);

This adds the XML document to the database collection.

Retrieving an XML Document from the Database

Next, retrieve the XML document that was added in the previous section. Retrieve an XML document from the Xindice database with the command:

>xindice rd -c xmldb:xindice://localhost:7001/db/catalog  
  -n catalog.xml

This retrieves the XML document. Next, retrieve the XML document with the XML:DB API. Obtain the catalog collection as in the "Adding an XML Document to the Database" section. Obtain the XML resource for the XML document. Output the XML document in the XML resource.

XMLResource resource = (XMLResource) 
  (collection.getResource(resourceID)); 
System.out.println(resource.getContent());

This retrieves the XML document added in the previous section.

Querying the Database with XPath

Xindice provides the XPath Query engine to query the XML document in the database with XPath. Next, query the XML document in the Xindice database with XPath. First, with the command-line tool, query the Xindice database collection with the xindice command xpath action. For example, retrieve the title of the <article/> in the first <journal/> element.

>xindice xpath -c xmldb:xindice://localhost:7001/db/catalog 
   -q /catalog/journal[1]/article/title

The -q switch specifies the XPath query. The output from the XPath query is:

<title src:col="/db/catalog" src:key="catalog.xml" 
xmlns:src="http://xml.apache.org/xindice/Query">
What Is a Portlet</title>

As another example, retrieve the publisher attribute of the catalog element.

>xindice xpath -c xmldb:xindice://localhost:7001/db/catalog 
    -q /catalog/@publisher

The output from the XPath query is:

<xq:result publisher="OReilly" 
xmlns:xq="http://xml.apache.org/xindice/Query" 
xq:col="/db/catalog" xq:key="catalog.xml" />

Next, query the database with the XML:DB API. Obtain the catalog collection from the database as in the "Adding an XML Document to the Database" section. Next, specify the XPath query string. The following XPath expression finds the title of the article in the first journal element.

String xpath = "/catalog/journal[1]/article/title";

The org.xmldb.api.modules.XpathQueryService service is used to query a database collection. Create an XPathQueryService object. Query the database with the XPathQueryService query() method. The query returns a org.xmldb.api.base.ResourceSet. Iterate over the resource set to obtain the XML document resource org.xmldb.api.base.Resource. Output the XML document in the resource.

XPathQueryService queryService = 
  (XPathQueryService) 
  collection.getService("XPathQueryService","1.0");
ResourceSet resourceSet = queryService.query(xpath);
ResourceIterator iterator = resourceSet.getIterator();
   while (iterator.hasMoreResources()) {
       Resource resource = iterator.nextResource();
       System.out.println(resource.getContent());
   }

The output of the XPath query is:

<title src:col="/db/catalog" 
src:key="022705cf47a9e30900000107728ed85e"
 xmlns:src="http://xml.apache.org/xindice/Query">
What Is a Portlet</title>

Modifying the Database with XUpdate

Xindice implements the XML:DB XUPdate mechanism to update an XML document. Let's update the XML document in the database with XUpdate. First, we'll use the command-line tool. The xindice command xupdate action is used to update an XML document. Some of the XUpdate commands to update an XML document are listed in Table 4.

XUpdate Command Description
xupdate:insert-after Adds a node after the selected node.
xupdate:update Updates the selected node.
xupdate:remove Removes the selected node.

Table 4. XUpdate commands

Adding an Element with the xindice Command

For example, we'll update the catalog.xml file to add a journal element to the XML document. The elements/attributes to be updated/added are specified in the xupdate configuration file, xupdate.xml. The xupdate.xml configuration file to add a journal element is as follows:

<xupdate:modifications version="1.0"
  xmlns:xupdate="http://www.xmldb.org/xupdate">
 <xupdate:insert-after select="/catalog/journal[3]">
  <xupdate:element name="journal">
  <xupdate:attribute name="date">Aug 2005</xupdate:attribute>
   <article> 
    <title>iBatis DAO</title>
    <author>Sunil Patil</author>
   </article>
  </xupdate:element>
 </xupdate:insert-after>
</xupdate:modifications>

Update the XML document with the command:

>xindice xupdate -c 
  xmldb:xindice://localhost:7001/db/catalog -n catalog.xml 
  -f  c:/xindice/xupdate.xml

The xupdate action specifies an XML document is to be updated. The -f switch specifies the xupdate.xml configuration file. This updates XML document with the message:

1 documents updated

Deleting and Modifying an Element with the xindice Command

As another example, remove a journal element and modify the title in another journal element. Let's remove the first journal element and modify the title in the third journal element. Since the first journal element is removed before the third journal element is updated, the journal element to be updated becomes the second journal element. We use xupdate:remove to remove an element and xupdate:update to update an element. Here's the xupdate.xml configuration file for removing and modifying elements:

<xupdate:modifications version="1.0"
  xmlns:xupdate="http://www.xmldb.org/xupdate">
<xupdate:remove select="/catalog/journal[1]"/>
<xupdate:update select="/catalog/journal[2]/article/title">
Maven with Swing</xupdate:update>
</xupdate:modifications>

Update the XML document with the command:

>xindice xupdate -c 
  xmldb:xindice://localhost:7001/db/catalog -n catalog.xml 
  -f  c:/xindice/xupdate.xml

This updates the XML document in the Xindice database.

Adding an Element with XML:DB API

Next, update the example XML document with the XML:DB API. As an example, add a journal element after the third journal element. Obtain the catalog collection from the database as in the "Adding an XML Document to the Database" section. Then specify the XUpdate commands in an XUpdate string.

String xupdate = 
"<xupdate:modifications version=\"1.0\"" +
"    xmlns:xupdate=\"http://www.xmldb.org/xupdate\">" +
"    <xupdate:insert-after select=\"/catalog/journal[3]\">" +
"    <journal date=\"Aug 2005\">" + " <article>" +
"    <title>iBatis DAO</title>" +
"    <author>Sunil Patil</author>" + " </article>" +
"    </journal>" + "    </xupdate:insert-after>" +
"</xupdate:modifications>";

The org.xmldb.api.modules.XUpdateQueryService is used to update the database with XUpdate. Create a XUpdateQueryService object from the collection to update. Update the database with the update() method of the XUpdateQueryService object, as follows:

XUpdateQueryService queryService = 
(XUpdateQueryService) collection.getService("XUpdateQueryService",
                   "1.0");
queryService.update(xupdate);

Deleting an Element with XML:DB API

Similarly, you remove a journal element from the XML document in the database with the xupdate:remove command. To remove the first journal element, you create a XUpdate command, String. Update the XML document with the XUpdate query service:

xupdate = "<xupdate:modifications version=\"1.0\"" +
    "    xmlns:xupdate=\"http://www.xmldb.org/xupdate\">" +
    "    <xupdate:remove select=\"/catalog/journal[1]\"/>" +
    "</xupdate:modifications>"; queryService.update(xupdate);

Modifying an Element with XML:DB API

Next, modify an element with the xupdate:update command. Modify the title of the article in the second journal element. Again, we'll create a XUpdate command String to update the XML document with the XUpdate query service.

xupdate = "<xupdate:modifications version=\"1.0\"" +
"    xmlns:xupdate=\"http://www.xmldb.org/xupdate\">" +
"    <xupdate:update select=\"/catalog/journal[2]/article/title\"> +
"    Maven with Swing</xupdate:update>" +
"</xupdate:modifications>";

queryService.update(xupdate);

Retrieve the modified XML document in the database collection catalog. The modified XML document is listed:

<?xml version="1.0"?>
<catalog publisher="OReilly" title="OnJava.com"> 
 <journal date="Sept 2005">
  <article> 
   <title>What Is Hibernate</title>
   <author>James Elliott</author>
  </article>
 </journal>
 <journal date="Oct 2003">
  <article> 
   <title>Maven with Swing</title>
   <author>Daniel Steinberg</author>
  </article>
 </journal><journal date="Aug 2005">    
  <article>    
   <title>iBatis DAO</title> 
   <author>Sunil Patil</author>   
  </article>    
 </journal>    
</catalog>

Deleting an XML Document

Next, delete an XML document from the database collection. With the command-line tool, delete the XML document with the command:

>xindice dd -c 
  xmldb:xindice://localhost:7001/db/catalog -n catalog.xml

This deletes the XML document catalog.xml in the catalog collection with the message:

DELETED: xmldb:xindice://localhost:7001/db/catalog/catalog.xml

Next, delete the XML document with the XML:DB API. You need to obtain the catalog collection from which an XML document is to be deleted, and obtain the XML resource to delete. Delete the XML resource as follows:

XMLResource resource = (XMLResource) 
  (collection.getResource(resourceID));
collection.removeResource(resource);

This deletes the selected XML document from the database.

The Xindice Java application XIndiceDB.java, used to create a collection, add an XML document, retrieve an XML document, query the database, update the database, and delete an XML document, is available in the xindice-resources.zip file.

Conclusion

In this tutorial, the Xindice database server is configured with the WebLogic server 9.0. Another application server, such as JBoss, may also be used to configure Xindice. JDK 5.0 was used, because JDK 1.4.2 generates an exception with Xindice 1.1b4. WebLogic version 9.0 is used because version 9.0 supports JDK 5.0.

Resources:

Deepak Vohra is a NuBean consultant and a web developer.


Return to ONJava.com.

Copyright © 2009 O'Reilly Media, Inc.