OPS User Guide
- Getting Started
- Core Technologies Reference
- XForms
- Page Flow
- XML Pipelines (XPL)
- OPS Technologies Reference
- Processors Reference
- API Reference
- Integration
|
XUpdate Processor
1. Scope
This section provides an overview of the XUpdate language, the
OPS XUpdate engine, and the extensions to the XUpdate language
supported by the OPS XUpdate engine. It also features examples
programs written in XUpdate.
For more information on how to use the OPS XUpdate engine
directly from Java programs, see the XUpdate section in
Integration.
2. About XUpdate
2.1. 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.
2.2. The OPS 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 OPS 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 OPS XUpdate engine follow
the same design principle as they closely mimic their XSLT
counterpart.
2.3. 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.
|
3. 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.
3.1. 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">
3.2. 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:update> </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> .
3.3. 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 OPS XUpdate engine implements
both <xu:value-of> and
<xu:copy-of> as in XSLT.
3.4. 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.
4. Using the XUpdate Processor
4.1. 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" xmlns:p="http://www.orbeon.com/oxf/pipeline"> <p:input name="config" href="xupdate.xml"/> <p:input name="data" href="#data"/> <p:output name="data" id="output"/> </p:processor>
4.2. 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" xmlns:p="http://www.orbeon.com/oxf/pipeline"> <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>
5. Examples
5.1. 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>
5.2. 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() > 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() > 1]"> <xu:append select="."> <xu:attribute name="change"> <xu:value-of select="sum(quarter/@change)"/> </xu:attribute> </xu:append> </xu:for-each> </xu:modifications>
5.3. 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() > 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>
5.4. 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() > 1]/quarter"> <xu:variable name="id" select="@id"/> <xu:value-of select="add-change(preceding::year/quarter[@id = $id], .)"/> </xu:for-each> </xu:modifications>
5.5. Functions as First-Class Citizens
The OPS 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() > 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 OPS 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:
|