Processors - XML Databases

Introduction

XML databases allow you to easily store, index and query XML documents. They are especially useful when dealing with document-centric applications, where the structure cannot be mapped naturally to a relational database.

Orbeon Forms provides processors to integrate with Tamino XML Server databases as well as databases that support the XML:DB API, such as eXist.

NOTE: You are encouraged to use REST APIs instead of these processors whenever possible, either directly from XForms (typically using XForms' <xforms:submission>, which supports REST since XForms 1.1) or with the XForms Submission processor, which exposes <xforms:submission> to XML pipelines. The eXist XML database, for example, exposes a REST API.

eXist

API

The eXist database can be accessed through the XML:DB API or through a REST Web API:

  • The REST API is a web API to access the database through HTTP with the methods GET, POST, PUT, and DELETE. You can call the eXist REST API directly from XForms. You can also call the eXist REST API from XPL using the XForms Submission processor.
  • The XML:DB API is a Java API, which you can call from XPL using the XML:DB processors provided by Orbeon Forms.

The REST API from XPL

The example below uses XForms Submission processor to call to the eXist REST API from XPL:

<p:processor xmlns:p="http://www.orbeon.com/oxf/pipeline" xmlns:xforms="http://www.w3.org/2002/xforms" xmlns:xdb="http://orbeon.org/oxf/xml/xmldb" name="oxf:xforms-submission">
<p:input name="submission">
<xforms:submission method="post" action="http://localhost:8080/ops/direct/xforms-translate/post"/>
</p:input>
<p:input name="request">
<translation>
<source>This is a table.</source>
<language-pair>en|fr</language-pair>
</translation>
</p:input>
<p:output name="response" ref="data"/>
</p:processor>

The xml:db API

XML:DB is a Java API for XML databases, just like JDBC is a Java API for relational databases. The XML:DB processor interface with the XML:DB API and so may be used with any XML databases that implements XML:DB, including eXist.

There are 4 different XML:DB processors, for querying, updating, deleting, and inserting data in the database. All 4 processors take 2 inputs: datasource and query. The datasource input points to a description of the database. For instance, to connect to an embedded eXist, use:

<datasource>
<driver-class-name>org.exist.xmldb.DatabaseImpl</driver-class-name>
<uri>xmldb:exist:///</uri>
<username>admin</username>
<password>admin</password>
</datasource>

To connect to eXist deployed as a servlet, use:

<datasource>
<driver-class-name>org.exist.xmldb.DatabaseImpl</driver-class-name>
<uri>xmldb:exist://localhost:9999/exist/xmlrpc</uri>
<username>admin</username>
<password>admin</password>
</datasource>

The 4 examples below show how to use the XML:DB query, update, delete, and insert processors.

<p:processor xmlns:xdb="http://orbeon.org/oxf/xml/xmldb" name="oxf:xmldb-query">
<p:input name="datasource" href="datasource.xml"/>
<p:input name="query">
<xdb:query collection="/db/orbeon/blog-example/blogs" create-collection="true">
xquery version "1.0";
<company>
{
for $d in /company/department return
<department employee-count="{count($d/employee)}"/>
}
</company>
</xdb:query>
</p:input>
<p:output name="data" ref="categories"/>
</p:processor>
<p:processor xmlns:xdb="http://orbeon.org/oxf/xml/xmldb" name="oxf:xmldb-update">
<p:input name="datasource" href="datasource.xml"/>
<p:input name="query">
<xdb:update collection="/db/orbeon/bizdoc-example">
<xu:modifications version="1.0">
<xu:update select="/document-info[document-id = '123']/document">
<something/>
</xu:update>
</xu:modifications>
</xdb:update>
</p:input>
</p:processor>
<p:processor xmlns:xdb="http://orbeon.org/oxf/xml/xmldb" name="oxf:xmldb-delete">
<p:input name="datasource" href="datasource.xml"/>
<p:input name="query">
<xdb:delete collection="/db/ops/dmv-example">
/document-info[document-id = '123']
</xdb:delete>
</p:input>
</p:processor>
<p:processor xmlns:xdb="http://orbeon.org/oxf/xml/xmldb" name="oxf:xmldb-insert">
<p:input name="datasource" href="datasource.xml"/>
<p:input name="query">
<xdb:insert collection="/db/ops/dmv-example"/>
</p:input>
<p:input name="data" href="#document-info"/>
</p:processor>

How-to

Create a named file with the xml:db processor

When using the insert processor, you cannot specify the name of the "file" that gets created in eXist. The XML:DB API does not provide a facility to specify the name of the resource that gets created in the database. So when using XML:DB, you need to call the oxf:xmldb-query processor and the xmldb:store() extension function in your query. If the collection where you want to add the document does not exist yet, you will also need to use the xmldb-create-collection() function.

Calling the oxf:xmldb-query processor as in the code below will create a collection myCollection and a file in that collection called myFile.xml. The file will just have a root element <root/>.

<p:processor xmlns:xdb="http://orbeon.org/oxf/xml/xmldb" name="oxf:xmldb-query">
<p:input name="datasource" href="datasource.xml"/>
<p:input name="query">
<xdb:query>
xmldb:create-collection('/db', 'myCollection'),
xmldb:store('/db/myCollection', 'myFile.xml', <gaga/>)
</xdb:query>
</p:input>
<p:output name="data" ref="categories"/>
</p:processor>

Create a named file with the rest api

With the REST API, to create a "file" /db/myCollection/myFile.xml, you PUT the XML data for you file to the URL /db/myCollection/myFile.xml. You can do this with an XForms submission, directly from XForms, or by calling the XForms submission processor, as in the example below:

<p:config xmlns:xdb="http://orbeon.org/oxf/xml/xmldb">
<p:processor name="oxf:xforms-submission">
<p:input name="submission">
<xforms:submission method="put" action="/exist/rest/db/myCollection/myFile.xml"/>
</p:input>
<p:input name="request">
<gaga/>
</p:input>
<p:output name="response" id="dummy"/>
</p:processor>
<p:processor name="oxf:null-serializer">
<p:input name="data" href="#dummy"/>
</p:processor>
</p:config>

Execute queries from the command line

It is sometimes convenient to run queries from the command line. The method below uses the eXist REST API, the same that is used if you access eXist directly from XForms.

  • You first need to install curl. If you are running UNIX, curl might already be installed, and if it isn't, look for the curl package for your UNIX distribution. On Windows, you can download an executable with no dependencies of any library (no need for cygwin).
  • Create an XML file that contains your query, for instance:
    <exist:query xmlns:exist="http://exist.sourceforge.net/NS/exist" max="0">
    <exist:text>

    declare namespace SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/";
    count(/*)

    </exist:text>
    </exist:query>
  • Assuming the context for your application is /ops, the file that contains your query is query.xml, the web server is running on port 8080, and you want to run the query on the collection yourCollection, execute the command line:

    curl http://localhost:8080/ops/exist/rest/db/yourCollection -H "Content-Type: application/xml" --data-binary @query.xml

For more on curl, see the curl man page.

Tamino XML server 4.1

Software AG's Tamino provides a complete XML storage solution. Orbeon Forms allows you to easily store, query, update, and delete documents in Tamino. The following sections describe the four Orbeon Forms processors for Tamino.

Configuration

All Tamino processors have a common config input, describing the database connection, collection and how it is handled.

The configuration of the Tamino processors can be done in two ways: either system-wide via the Properties, or locally for a specific instance of the processor through the config input. The local configuration takes precedence if available.

NOTE: The collection configuration elements cannot be specified system-wide.

config Input

The config input document specifies the URL of the Tamino server, the credentials to use when connecting, the collection to access, isolation degree and locking modes. The following table describes the configuration elements.

Name Description
url Tamino database URL.
username Username to authenticate with the server
password Password to authenticate with the server
collection XML Collection to use
isolation-degree Type of isolation degree used (optional). One of
uncommittedDocument
committedCommand
serializable
stableDocument
stableCursor
lock-mode Type of locking mode used (optional). One of
protected
shared
unprotected
lock-wait 'yes' if the query should wait for locked records to become free. (optional)

This RelaxNG schema describes the expected document.

<element datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
<interleave>
<optional>
<element name="url">
<data type="anyURI"/>
</element>
</optional>
<optional>
<element name="username">
<data type="string"/>
</element>
</optional>
<optional>
<element name="password">
<data type="string"/>
</element>
</optional>
<element name="collection">
<data type="string"/>
</element>
<optional>
<element name="isolation-degree">
<choice>
<value>uncommittedDocument</value>
<value>committedCommand</value>
<value>stableCursor</value>
<value>stableDocument</value>
<value>serializable</value>
</choice>
</element>
</optional>
<optional>
<element name="lock-mode">
<choice>
<value>unprotected</value>
<value>shared</value>
<value>protected</value>
</choice>
</element>
</optional>
<optional>
<element name="lock-wait">
<choice>
<value>yes</value>
<value>no</value>
</choice>
</element>
</optional>
</interleave>
</element>

System-wide configuration

The Tamino processors can be configured in the properties file, allowing all instances to share the same configuration. The following processor properties are allowed:

Name Type Description
url anyURI Tamino Server URL.
username string Username to authenticate with the server.
password string Password to authenticate with the server.

These properties are set as follows:

<property as="xs:anyURI" processor-name="oxf:tamino-query" name="url" value="http://localhost/tamino/welcome_4_1_4"/>
<property as="xs:string" processor-name="oxf:tamino-query" name="username" value="..."/>
<property as="xs:string" processor-name="oxf:tamino-query" name="password" value="..."/>

The following global properties are allowed:

Name Type Description
oxf.tamino.isolation-degree string Isolation degree. Possible values are: uncommittedDocument, committedCommand, stableCursor, stableDocument, serializable. See the Tamino documentation for more details on the isolation degree.
oxf.tamino.lock-mode string Lock mode. Possible values are unprotected, shared, protected. See the Tamino documentation for more details on the lock mode.
oxf.tamino.lock-wait string Lock Wait Mode. If 'yes' then the query will wait for locked records to become free before returning the results.

These properties as set as follows:

<property as="xs:string" name="oxf.tamino.isolation-degree" value="..."/>
<property as="xs:string" name="oxf.tamino.lock-mode" value="..."/>
<property as="xs:string" name="oxf.tamino.lock-wait" value="..."/>

Queries

The oxf:tamino-query processor processes queries either using Tamino's X-Query or W3C XQuery.

data Input

The data input contains only the root element and the query. The root element is either query for an X-Query query, or xquery for an XQuery query.

data Output

The processor sends the result of the query in the data output. The root element is always result.

X-Query example

<p:processor name="oxf:tamino-query">
<p:input name="config">
<config>
<url>http://localhost/tamino/welcome_4_1_4</url>
<username>tamino</username>
<password>password</password>
<collection>encyclopedia</collection>
</config>
</p:input>
<p:input name="data">
<query>
/jazzMusician[@ID="ParkerCharlie"]
</query>
</p:input>
<p:output name="data" id="result"/>
</p:processor>

XQuery example

<p:processor name="oxf:tamino-query">
<p:input name="config">
<config>
<url>http://localhost/tamino/welcome_4_1_4</url>
<username>tamino</username>
<password>password</password>
<collection>encyclopedia</collection>
</config>
</p:input>
<p:input name="data">
<xquery>
for $m in input()/jazzMusician,
$c in input()/collaboration,
$a in input()/album
where $m/@ID= $c/jazzMusician and $c/result = $a/productNo
return
<musician>
{$m/name}
<album>{$a/title}</album>
</musician>

</xquery>
</p:input>
<p:output name="data" id="result"/>
</p:processor>

Insertions

The oxf:tamino-insert processor allows you to insert a document in Tamino.

NOTE: You need to make sure that the document conforms to one of the registered schemas in the current collection. If Tamino can't validate the document, an exception is thrown.

data Input

The data input contains the document to insert.

Example

<p:processor name="oxf:tamino-insert">
<p:input name="config">
<config>
<url>http://localhost/tamino/welcome_4_1_4</url>
<username>tamino</username>
<password>password</password>
<collection>encyclopedia</collection>
</config>
</p:input>
<p:input name="data">
<jazzMusician ID="DavisMiles" type="instrumentalist">
<name>
<first>Miles</first>
<last>Davis</last>
</name>
<birthDate>1926-05-26</birthDate>
<instrument>trumpet</instrument>
</jazzMusician>
</p:input>
</p:processor>

Deletions

The oxf:tamino-delete processor allows you to remove documents from Tamino.

data Input

The data input contains the X-Query to select the document(s) to be removed.

Example

<p:processor name="oxf:tamino-delete">
<p:input name="config">
<config>
<url>http://localhost/tamino/welcome_4_1_4</url>
<username>tamino</username>
<password>password</password>
<collection>encyclopedia</collection>
</config>
</p:input>
<p:input name="data">
<query>
/jazzMusician[@ID="DavisMiles"]
</query>
</p:input>
</p:processor>

Updates

The oxf:tamino-update processor allows you to update parts of documents directly inside Tamino. An extension of XQuery is used for that purpose. Refer to the Tamino documentation for more information.

data Input

The data input contains the XQuery expression to update one or multiple nodes.

Example

<p:processor name="oxf:tamino-update">
<p:input name="config">
<config>
<url>http://localhost/tamino/welcome_4_1_4</url>
<username>tamino</username>
<password>password</password>
<collection>encyclopedia</collection>
</config>
</p:input>
<p:input name="data">
<query>
update replace input()/jazzMusician[@ID="ParkerCharlie"]/instrument
with <instrument>piano</instrument>
</query>
</p:input>
</p:processor>

Transactions

Orbeon Forms initiates a transaction for every HTTP request, and commits the transaction when the pipeline is executed normally. If an exception occurs in the pipeline, the transaction in rolled back.

Comments