Processors - XUpdate

Availability

The XUpdate processor and associated technologies are deprecated in Orbeon Forms 3.9 and not available in Orbeon Forms 4.0 and newer.

Scope

This section provides an overview of the XUpdate language, the Orbeon Forms XUpdate engine, and the extensions to the XUpdate language supported by the Orbeon Forms XUpdate engine. It also features examples programs written in XUpdate.

For more information on how to use the Orbeon Forms XUpdate engine directly from Java programs, see the XUpdate section in Integration.

About XUpdate

Origin

The XML:DB group has been working on a specification for a language to describes how to update an XML document. The latest version of the XUpdate specification was released in 2000 as a working draft. Since then, XUpdate has been used in a number of situations to update XML documents, in particular in XML databases like eXist, Xindice and X-Hive/DB.

The orbeon forms XUpdate engine

XUpdate does not provide means to declare variables, iterate over a node set, or declare functions. In addition to the XUpdate specification, the Orbeon Forms XUpdate engine implements a set of extensions to allow all of the above.

The XUpdate language was designed to be consistent with XSLT, so it would be natural for developers who are familiar with XSLT to use XUpdate. The extensions to the XUpdate specification implemented in the Orbeon Forms XUpdate engine follow the same design principle as they closely mimic their XSLT counterpart.

Best practices

An XUpdate transformation is similar to an XSLT transformation:

  • As shown in the illustration below, just like XSLT, XUpdate transforms an XML input document into an XML output document based on a "configuration". With XSLT, the configuration is an XSLT stylesheet. With XUpdate, the configuration is a program written in the XUpdate language.
  • The XSLT and XUpdate languages have similar expressive power, they both use XPath as the expression language and share elements names in a consistent way.

Every program written in XSLT could also be written in XUpdate and vice versa. A natural question would be: when is it more appropriate to use XUpdate and when is it more appropriate to use XSLT? XSLT and XUpdate are set apart by their distinctive processing model: in XSLT nodes from the input document trigger the execution of templates that define the output document, while an XUpdate provides the sequence of operations to be performed on the input document to create the output document.

As a rule of thumb, XUpdate is more appropriate when the output document is similar to the input document, while XSLT is more appropriate when the output document is a new document in which values from the input document are inserted. This can be summarized in the table below:

XSLT XUpdate
Execution model Nodes from the input document trigger the execution of templates that define the output document XUpdate provides a sequence of operations to be performed on the input document to create the output document
Most appropriate when When the output document is a new document in which values from the input document are inserted When the output document is similar to the input document
Typical applications XSLT can be used as a template language, for instance to create an HTML page with both dynamic and static data. The input document contains the dynamic data. The stylesheets contains the static data and describes how the dynamic data is inserted in the document. Doing the same thing in XUpdate would be unnecessarily complicated.

XUpdate can be used as an annotation language, for instance to validate elements of an input document and to add an attribute on those elements stating if they are valid or not. Another usage is when annotating an XML document to add calculated values based on existing values. Some of the examples below do exactly that.

Some cases, for instance when a parent elements has to be updated based on updates previously done to child elements, cannot be handled with XSLT 1.0 without using XSLT extensions or pipelining multiple stylesheets.

Language reference

All the XUpdate elements mentioned here must be in the http://www.xmldb.org/xupdate namespace and for brevity we use the xu prefix.

Standard elements

The elements below are defined in the XUpdate specification.

  • <xu:modifications version="1.0">
  • <xu:value-of select="expression">
  • <xu:if test="expression">
  • <xu:insert-before select="expression">
  • <xu:insert-after select="expression">
  • <xu:append select="expression" child="expression">
  • <xu:remove select="expression">
  • <xu:update select="expression">
  • <xu:variable name="qname" select="expression">
  • <xu:element name="qname">
  • <xu:attribute name="qname">

Extensions

  • <xu:function name="qname"> ? Defines a function with the given name. The element can contain <xu:param name="qname" select="expression"> elements that define the parameters of the function. Functions defined with <xu:function> are called from XPath expressions, just like regular XPath functions.

    Functions in XUpdate, just like variables, can be declared anywhere, not only at the top level. In particular, they can also be declared inside other functions. The visibility rules for functions are the same as those for variables: a function has a visibility on the context where it is declared and is visible only inside the block where it is declared.

    Functions in XUpdate are first-class citizen: just like variables they can be passed as arguments and returned by other functions. An example later in this section illustrates how this works.

  • <xu:choose> ? Contains one or more <xu:when test="expression"> elements and an optional <xu:otherwise>. The content of the first <xu:when> where the test condition is true is executed. If none is true, the content of <xu:otherwise> is executed if present.

  • <xu:copy-of select="expression"> ? Performs a copy of what is returned by the select expression. Unlike <xu:value-of>, the result of the expression is not converted to a string before it is returned.

  • <xu:for-each select="expression"> ? Iterates over the node set returned by the select expression and executes the content of the <xu:for-each> for every node in the node set with that node as the current context.

    Note that in the case below, the content of the data variable is updated, not the input document (so in this case, the input document will be left unchanged):

    <xu:modifications xmlns:xu="http://www.xmldb.org/xupdate">
    <xu:variable name="company" select="document('oxf:/xupdate/input.xml')"/>
    <xu:for-each select="$company/company/year">
    <xu:variable name="position" select="position()"/>
    <xu:update select="/company/year[$position]"><xu:value-of select="@id"/>
    </xu:for-each>
    <!-- Statements using $company -->
    </xu:modifications>
  • <xu:while select="expression"> ? Executes the content of the <xu:while> while the condition in the select expression is true.

  • <xu:assign select="expression"> ? Replaces the content of a variable. Once the value of a variable is set, it is possible to update parts of its contents with statements like <xu:update>. However no other statements we'll let you replace the root element of the variable, or the value of the variable if it is a simple type. To do so you need to use <xu:assign>. The new value can be a either specified as an XPath expression with the select attribute, or in the contents of the <xu:update> element.

  • <xu:message> ? Just like <xsl:message>, logs the content of the element. For instance, to log the document being currently updated, use <xu:message><xu:copy-of select="/*"/></xu:message>.

  • <xu:error> ? The XUpdate program is interrupted as an exception is thrown with the result of the evaluation of the element content.

  • <xu:namespace> ? Adds a namespace declaration on the current element, just like the XSLT <xsl:namespace>.

Incompatibilities

  • The <xu:value-of> as described in the XUpdate specification works like the XSLT <xsl:copy-of> but the XUpdate specification provides no equivalent to the XSLT <xsl:value-of>.

    We find this situation both confusing and restrictive. It is confusing because more people know about XSLT than XUpdate and they will be surprised if <xu:value-of> has a different behavior than the one they expected. It is restrictive because the XUpdate specification provides no equivalent to the XSLT <xsl:value-of> functionality.

    For these reasons the Orbeon Forms XUpdate engine implements both <xu:value-of> and <xu:copy-of> as in XSLT.

XPath

In a number of places you can use XPath expressions. In addition to standard XPath 1.0, you can use the following list of extension functions:

  • The XPath 2.0 function get-namespace-uri-for-prefix() is supported (the XPath engine is still 1.0 compliant, not 2.0).
  • evaluate(xpath, namespaces, nodeset) ? Evaluates the first string argument as an XPath expression in the context of the third nodeset argument. Any prefix used in the XPath expression must be defined in the second argument, which is a nodeset of namespace nodes.

Using the XUpdate processor

Interface

The XUpdate processor has the same interface as the XSLT processor. It takes two inputs: config, the XUpdate program, and data, the document to update. In XPL, the XUpdate processor can be invoked with:

<p:processor name="oxf:xupdate">
<p:input name="config" href="xupdate.xml"/>
<p:input name="data" href="#data"/>
<p:output name="data" id="output"/>
</p:processor>

Using multiple documents

It is not uncommon that a given document needs to be updated based on information stored in other documents. For example, in the situation illustrated below the document on the left is modified based on three other documents a, b and c.

When calling the XUpdate processor from XPL, this is done by connecting the three documents to the inputs of the XUpdate processor named a, b and c. Then the XUpdate program has access to those documents through XPath expressions with the document() or doc() functions using the URI #a, #b and #c. Note that any name can be chosen except data and config since those are reserved for the document to update and the XUpdate program. Invoking the XUpdate processor in this scenario could be done as follows:

<p:processor name="oxf:xupdate">
<p:input name="config" href="xupdate.xml"/>
<p:input name="data" href="#data"/>
<p:input name="a" href="x.xml"/>
<p:input name="b" href="y.xml"/>
<p:input name="c" href="z.xml"/>
<p:output name="data" id="output"/>
</p:processor>

Examples

Input document

All the examples have been designed to the work on the sample document given below. This document provides numbers reflecting the sales of a company divided by quarter and by year.

<company>
<year id="2000">
<quarter id="1" sales="80"/>
<quarter id="2" sales="56"/>
<quarter id="3" sales="97"/>
<quarter id="4" sales="150"/>
</year>
<year id="2001">
<quarter id="1" sales="20"/>
<quarter id="2" sales="54"/>
<quarter id="3" sales="80"/>
<quarter id="4" sales="90"/>
</year>
<year id="2002">
<quarter id="1" sales="54"/>
<quarter id="2" sales="65"/>
<quarter id="3" sales="96"/>
<quarter id="4" sales="164"/>
</year>
</company>

Leaf to root document annotation

The goal is to add a change attribute to the quarter element with the difference between the numbers for that quarter and the same quarter one year before. We also want to add a change attribute to the year element computed as the sum of the change attributes on its children elements. Obviously no change attribute can be added to the year and quarter elements of the first year. The output document looks like:

<company>
<year id="2000">
<quarter id="1" sales="80"/>
<quarter id="2" sales="56"/>
<quarter id="3" sales="97"/>
<quarter id="4" sales="150"/>
</year>
<year id="2001" change="-139">
<quarter id="1" sales="20" change="-60"/>
<quarter id="2" sales="54" change="-2"/>
<quarter id="3" sales="80" change="-17"/>
<quarter id="4" sales="90" change="-60"/>
</year>
<year id="2002" change="135">
<quarter id="1" sales="54" change="34"/>
<quarter id="2" sales="65" change="11"/>
<quarter id="3" sales="96" change="16"/>
<quarter id="4" sales="164" change="74"/>
</year>
</company>

What is particular in this example is that the most convenient way to implement the requirement is to first add an attribute to a set of elements (quarters) and then to update the parent elements (years) based on the values previously computed. This is typically hard to do in XSLT, but is quite natural in XUpdate:

<xu:modifications xmlns:xu="http://www.xmldb.org/xupdate">
<!-- Add the change attribute to the quarter elements -->
<xu:for-each select="/company/year[position() &gt; 1]">
<xu:variable name="last-year" select="preceding::year"/>
<xu:for-each select="quarter">
<xu:variable name="quarter" select="@id"/>
<xu:append select=".">
<xu:attribute name="change">
<xu:value-of select="@sales - $last-year/quarter[@id = $quarter]/@sales"/>
</xu:attribute>
</xu:append>
</xu:for-each>
</xu:for-each>
<!-- Add the change attribute at the year level by computing -->
<!-- the sum of the changes at the quarter level -->
<xu:for-each select="/company/year[position() &gt; 1]">
<xu:append select=".">
<xu:attribute name="change">
<xu:value-of select="sum(quarter/@change)"/>
</xu:attribute>
</xu:append>
</xu:for-each>
</xu:modifications>

Iterative document annotation

The idea is to add a change attribute to the quarter elements, like in the previous example. In addition, a variation attribute must be added to the quarter elements with the difference between the change value of the current quarter and the change value of the previous quarter. Obviously, the variation attribute cannot be added to the first quarter of the second year. The output document looks like:

<company>
<year id="2000">
<quarter id="1" sales="80"/>
<quarter id="2" sales="56"/>
<quarter id="3" sales="97"/>
<quarter id="4" sales="150"/>
</year>
<year id="2001">
<quarter id="1" sales="20" change="-60"/>
<quarter id="2" sales="54" change="-2" variation="58"/>
<quarter id="3" sales="80" change="-17" variation="-15"/>
<quarter id="4" sales="90" change="-60" variation="-43"/>
</year>
<year id="2002">
<quarter id="1" sales="54" change="34" variation="94"/>
<quarter id="2" sales="65" change="11" variation="-23"/>
<quarter id="3" sales="96" change="16" variation="5"/>
<quarter id="4" sales="164" change="74" variation="58"/>
</year>
</company>

What is special in this example, is that the most natural way to implement the requirement is in a two-pass algorithm: first add the change attribute, then the variation attribute based on the value previously computed. Iterative algorithms can be implemented in XSLT but the exercise adds unnecessary complexity and often requires the use of XSLT extensions or multiple pipelined XSLT stylesheets. Instead, iterative algorithms can be expressed very naturally with XUpdate:

<xu:modifications xmlns:xu="http://www.xmldb.org/xupdate">
<xu:for-each select="/company/year[position() &gt; 1]">
<xu:variable name="last-year" select="preceding::year"/>
<xu:for-each select="quarter">
<xu:variable name="quarter" select="@id"/>
<xu:append select=".">
<xu:attribute name="change">
<xu:value-of select="@sales - $last-year/quarter[@id = $quarter]/@sales"/>
</xu:attribute>
</xu:append>
</xu:for-each>
</xu:for-each>
<xu:for-each select="/company/year/quarter">
<xu:if test="preceding::quarter/@change">
<xu:append select=".">
<xu:attribute name="variation">
<xu:value-of select="@change - preceding::quarter/@change"/>
</xu:attribute>
</xu:append>
</xu:if>
</xu:for-each>
</xu:modifications>

Simple functions

The XUpdate program below adds a change attribute on the quarter elements just like the previous two examples. But, in this case, the logic to add the change attribute to a given element is in a function and that function is called from some code that iterates over the quarters. Here, functions are used in XUpdate just like they would be used in XSLT 2.0.

<xu:modifications xmlns:xu="http://www.xmldb.org/xupdate">
<xu:function name="add-change">
<xu:param name="last-quarter"/>
<xu:param name="this-quarter"/>
<xu:append select="$this-quarter">
<xu:attribute name="change">
<xu:value-of select="$this-quarter/@sales - $last-quarter/@sales"/>
</xu:attribute>
</xu:append>
</xu:function>
<xu:for-each select="/company/year[position() &gt; 1]/quarter">
<xu:variable name="id" select="@id"/>
<xu:value-of select="add-change(preceding::year/quarter[@id = $id], .)"/>
</xu:for-each>
</xu:modifications>

Functions as first-class citizens

The Orbeon Forms XUpdate engine allows for top-level functions called from XPath expressions, like XSLT 2. Additionally:

  • Functions can be declared anywhere in the program, including inside other functions. The visibility rules for functions are the same as those for variables.
  • Functions can be assigned to variables, passed as arguments to other functions and returned by functions. Languages providing this capability are said to treat functions as first-class citizen.

The XUpdate program below adds a change attribute to the quarter elements just like the previous examples. The add-change function is taken from the previous example. In addition, the logic to iterate over the quarters has been coded in a function apply-on-quarter that takes one argument: the function to apply to each quarter.

<xu:modifications xmlns:xu="http://www.xmldb.org/xupdate">
<xu:function name="add-change">
<xu:param name="last-quarter"/>
<xu:param name="this-quarter"/>
<xu:append select="$this-quarter">
<xu:attribute name="change">
<xu:value-of select="$this-quarter/@sales - $last-quarter/@sales"/>
</xu:attribute>
</xu:append>
</xu:function>
<xu:function name="apply-on-quarter">
<xu:param name="f"/>
<xu:for-each select="/company/year[position() &gt; 1]/quarter">
<xu:variable name="id" select="@id"/>
<xu:value-of select="f(preceding::year/quarter[@id = $id], .)"/>
</xu:for-each>
</xu:function>
<xu:value-of select="apply-on-quarter($add-change)"/>
</xu:modifications>

The example below uses the full power of the Orbeon Forms XUpdate engine first-class citizen functions:

<xu:modifications xmlns:xu="http://www.xmldb.org/xupdate">
<xu:function name="double">
<xu:param name="f"/>
<xu:function name="result">
<xu:param name="x"/>
<xu:value-of select="f($x) * 2"/>
</xu:function>
<xu:copy-of select="$result"/>
</xu:function>

<xu:function name="increment">
<xu:param name="x"/>
<xu:value-of select="$x + 1"/>
</xu:function>

<xu:variable name="incrementAndDouble" select="double($increment)"/>
<xu:update select="/">
<result>
<xu:value-of select="incrementAndDouble(2)"/>
</result>
</xu:update>
</xu:modifications>

At the top level, the above XUpdate program defines two functions:

  • increment simply takes a number x as argument and returns x + 1
  • double is more interesting: its argument is not a number but a function f with one argument. double returns a function g such as g(x) = 2*f(x). Note that to return a function from another function, you must use <xu:copy-of> and not <xu:value-of>.

Finally we create a function incrementAndDouble by applying double on increment. As expected the result of incrementAndDouble(2) is 6:

<result xmlns:p="http://www.orbeon.com/oxf/pipeline" xmlns:xforms="http://www.w3.org/2002/xforms">6</result>
Comments