Processors - XQuery Processor

Introduction

The XQuery processor is a generic processor that submit XQuery requests to various XQuery processor implementations and returns the result as an XML document.

Note: An undocumented  processor specific to Saxon which is now deprecated has been shipped in the past under the same name. This processor has been replaced by the XQuery processor which have a different API. If you still want to use the Saxon XQuery processor, you can replace the name "oxf:xquery" by "oxf:saxon-xquery-deprecated" in your pipelines.

Help us to improve the support of Oracle in this processor

The support of Oracle is suffering from a number of restrictions that are documented in this document.

If you're an Oracle expert, you can help us by answering to the questions which have been posted on StackOverflow (issue1) and on the Oracle forums (issue1).

XQuery processor implementations

XQuery processor implementations can be identified by two mutually exclusive config elements:

  • The vendor element identifies well known XQuery implementations. As of 2012-05-17, "exist", "oracle" and "saxon" are supported.
  • For other providers, the implementation element identifies the class name of an XQJ XQDataSource implementation. This class is then instantiated and used to submit the query.
Examples:

To submit the query to an Oracle database:

<p:processor name="oxf:xquery">
        <p:input name="config">
            <config>
                <vendor>oracle</vendor>
                ...


To submit the query through the com.example.XQDatasource XQJ implementation:

<p:processor name="oxf:xquery">
        <p:input name="config">
            <config>
                <implementation>com.example.XQDatasource</implementation>
                ...

Connection information

XQJ data sources can be instantiated without parameters, with an user name and a password or with a JDBC connection.

Likewise, the XQuery processor accepts optional username/password or jdbc elements. The jdbc element may include an optional implementation element and a url element.

NOTE: XQJ implementations are free to implement these different constructors and some combinations are not allowed.


Examples:

To connect using username/password elements:

<p:processor name="oxf:xquery">
        <p:input name="config">
            <config>
                <implementation>com.example.XQDatasource</implementation>
                <username>averell</username>
                <password>whendoweeat</password>

To connect using a JDBC connection:
<p:processor name="oxf:xquery">
        <p:input name="config">
            <config>
                <vendor>oracle</vendor>
                          <jdbc>
                    <url>jdbc:oracle:thin:averell/secret@localhost:1521:XE</url>
                </jdbc>

To connect using a JDBC connection using a specific implementation:

<p:processor name="oxf:xquery">
        <p:input name="config">
            <config>
                <implementation>com.example.XQDatasource</implementation>
                <jdbc>
                    <implementation>com.example.JdbcDriver</implementation>
                    <url>jdbc:oracle:thin:averell/secret@localhost:1521:XE</url>
                </jdbc>

In addition to these parameters that are used to instantiate the XQJ data source, properties can be set using property elements:

<p:processor name="oxf:xquery">
        <p:input name="config">
            <config>
                <vendor>exist</vendor>
                <property>
                    <name>serverName</name>
                    <value>localhost</value>
                </property>
                <property>
                    <name>port</name>
                    <value>8080</value>
                </property>
                <property>
                    <name>user</name>
                    <value>averell</value>
                </property>
                <property>
                    <name>password</name>
                    <value/>
                </property>

To submit a query to Saxon which runs in Orbeon Forms and does not require any connection information:
    <p:processor name="oxf:xquery">
        <p:input name="config">
            <config>
                <vendor>saxon</vendor>

In practice...

These parameters are really implementation specific:
  • Oracle: the current (2012-05-17) implementation requires a JDBC URL.
  • eXist: you must specify the serverName, port, user and password properties.
  • Saxon: you have no connection info to provide.
If you use a specific XQJ implementation you need to read its documentation to find out which one should be used. The XQuery processor can help you by displaying the list of methods, constructors and properties that are supported by your implementation. To do so, you need to use an "info" element, for instance:

    <p:processor name="oxf:xquery">
        <p:input name="config">
            <config>
                <implementation>net.xqj.exist.ExistXQDataSource</implementation>
                <info/>
            </config>
        </p:input>
        <p:output name="data" id="results" debug="results"/>
    </p:processor>

Returns:
<info>
    <vendor/>
    <implementation>net.xqj.exist.ExistXQDataSource</implementation>
    <implements>java.io.Serializable</implements>
    <implements>javax.xml.xquery.XQDataSource</implements>
    <constructor>public net.xqj.exist.ExistXQDataSource()</constructor>
    <method>public void net.xqj.exist.ExistXQDataSource.setProperty(java.lang.String,java.lang.String)</method>
    <method>public java.lang.String net.xqj.exist.ExistXQDataSource.getProperty(java.lang.String)</method>
    <method>public int net.xqj.exist.ExistXQDataSource.a()</method>
    .../...
    <method>public final native void java.lang.Object.notifyAll()</method>
    <supported-properties>
        <property>description</property>
        <property>logLevel</property>
        <property>loginTimeout</property>
        <property>serverName</property>
        <property>port</property>
        <property>user</property>
        <property>password</property>
    </supported-properties>
</info>

Restrictions

The Oracle implementation currently relies on embedding XQuery statements within PL-SQL and JDBC. You can help us if you know the answer to this blocking issue : https://forums.oracle.com/forums/thread.jspa?messageID=10338407

The eXist implementation used the xqj.net eXist data source which assumes that the eXist REST API is located at /exist/rest which is the case of default eXist installation but not the case of the eXist instance embedded in Orbeon Forms. This should change in future releases.

Libraries

Depending on the implementation which you are using, you may have to add external libraries:
  • eXist: the XQJ.net implementation is included Orbeon Forms.
  • Oracle: you need to add the following jars: ojdbc6.jar, xdb.jar and xmlparserv2.jar. These are standard client libraries that should be included in your Oracle distribution. If not, they are available from the Oracle download page (click on the "see all" link for your platform and download the "Oracle Database Client".
  • Saxon: Saxon is embedded in Orbeon Forms and no additional libraries are required.
  • Other implementations: you need to add the jars corresponding to these implementations.

Query and parameters

To fight XQuery injection, you should avoid to copy unsafe data into queries and use parameters to pass information to your queries.

To do so, the query element that contains the query can be followed by an optional sequence of parameters. These parameters must be declared as external variables in the query:

    <p:processor name="oxf:xquery">
        <p:input name="config">
            <config>
                <vendor>exist</vendor>
                 <property>
                    <name>serverName</name>
                    <value>localhost</value>
                </property>
                <property>
                    <name>port</name>
                    <value>8080</value>
                </property>
                <property>
                    <name>user</name>
                    <value>admin</value>
                </property>
                <property>
                    <name>password</name>
                    <value/>
                </property>
                <query><![CDATA[
                    declare variable $x as xs:string external;
                    $x
                    ]]></query>
                <parameter>
                    <name>x</name>
                    <value>Hello world!</value>
                </parameter>
            </config>
        </p:input>
        <p:output name="data" id="results" debug="results"/>
    </p:processor>

Returns the following result:
<results>
    <result>Hello world!</result>
</results>

NOTE: The current version does only support parameters with xs:string datatypes.

Restrictions

XQuery update facility (Oracle)

The support of XQuery update facility in Oracle is limited in the current implementation: it can be used to update a copy of an XML fragment but can't be used to update the content of the database.

Referring to pipeline documents (Saxon)

Since [2012-05-19]

When using Saxon, the query is executed within Orbeon Forms and it is often useful to be able to run it against pipeline documents.

To achieve this feature, the XQuery processor supports the "input:" protocol when Saxon is selected:

    <p:processor name="oxf:xquery">
        <p:input name="data">
            <doc>world! </doc>
        </p:input>
        <p:input name="config">
            <config>
                <vendor>saxon</vendor>
                <query><![CDATA[
                    declare variable $x as xs:string external;
                    concat($x, ' ', doc('input:data'))
                    ]]></query>
                <parameter>
                    <name>x</name>
                    <value>Hello</value>
                </parameter>
            </config>
        </p:input>
        <p:output name="data" id="results" debug="results"/>
    </p:processor>

Returns:

<results>
    <result>Hello world!</result>
</results>

Any input name can be used except "config" which is reserved for the configuration.

Note: This feature is not implemented for other implementations that usually run out of the Orbeon Forms pipeline.

Comments