Using xPath and creating XML is interesting in process orchestrations. The primary way of manipulating variables within processes is to use the Set Value service. This uses as its “scripting” language xPath. As a scripting language xPath is limited. It is meant to be a query language and does that very well. For creating XML, however, it can be a blunt tool.
Within a process there are three basic ways to create and edit XML.
- Using xPath within a Set Value service
- Building the XML as text and then deserializing the text into XML. This, too, uses xPath within a Set Value activity. Instead of using xPath to manipulate the XML it is used to manipulate string variables.
- Editing an XML variable within an Execute Script service
Using xPath to Build XML Variables
XML may be created within the Set Value service using the xPath syntax if the XML has schema associated with it.
For example, it is possible to start with an empty XML variable that is associated with a schema and add nodes.
/process_data/node = "" // make sure the XML is empty /process_data/node/resources/resource/@value = "value for first resource" /process_data/node/resources/resource/@id = "id for first resource"
In this example, the variable, node, is now:
<resources> <resource id="itemOne" value="itemTwo"/> </resources>
But what if there is more than one resource node? Let’s add code to set the value of a second resource node:
/process_data/node = "" // make sure the XML is empty /process_data/node/resources/resource/@value = "value for first resource" /process_data/node/resources/resource/@id = "id for first resource" /process_data/node/resources/resource[number(2)]/@id = "id for second resource" /process_data/node/resources/resource[number(2)]/@value = "value for second resource"
This, sadly, fails. To be able to set the value of a node that is referenced by index, the item must already exist.
It is possible to add items to list items using xPath syntax.
/process_data/stringList = empty-list() /process_data/stringList = "item one" /process_data/stringList = "item two"
Now, /process_data/stringList[number(1)] equals “item one” and process_data/stringList[number(2)] equals “item two”
Can we do the same with XML in the xPath syntax? Unfortunately, no. The Set Value service treats Java objects (such as the list) and XML completely different.
/process_data/node = "" // make sure the XML is empty /process_data/node/resources/resource/@value = "value for first resource" /process_data/node/resources/resource/@id = "id for first resource" /process_data/node/resources/resource/@id = "id for second resource" /process_data/node/resources/resource/@value = "value for second resource"
This replaces the value of a node with a new value. The value of XML is now:
<resources> <resource id="id for second resource" value="value for second resource"/> </resources>
Building XML as text
We can build an XML value in a more cumbersome way by building the xml in text.
/process_data/@nodeId = "id for first resource" /process_data/@nodeValue = "value for first resource" /process_data/@stringVariable = "<resources>" // add the start tag to the string /process_data/@stringVariable = concat(/process_data/@stringVariable,"<resource") // add the beginning of the resource tag /process_data/@stringVariable = concat(/process_data/@stringVariable," id='",/process_data/@nodeId,"'") // add the id attribute /process_data/@stringVariable = concat(/process_data/@stringVariable," value='",/process_data/@nodeValue,"'") // add the value attribute /process_data/@stringVariable = concat(/process_data/@stringVariable,"/></resource>") // close tags /process_data/node = deserialize(/process_data/@stringVariable)
Building XML with text may be more cumbersome for simple XML, but it does provide a way to add nodes that xPath does not provide. In addition, a schema is not required. To add another resource to the sample above:
/process_data/@nodeId = "id for second resource" /process_data/@nodeValue = "value for second resource" /process_data/@stringVariable = serialize(/process_data/node) // get existing node as a string /process_data/@stringVariable = string-before(/process_data/@stringVariable,"</resources>") // returns everything but the closing resources tag /process_data/@stringVariable = concat(/process_data/@stringVariable,"<resource") // add the beginning of the new resource tag /process_data/@stringVariable = concat(/process_data/@stringVariable," id='",/process_data/@nodeId,"'") // add the id attribute /process_data/@stringVariable = concat(/process_data/@stringVariable," value='",/process_data/@nodeValue,"'") // add the value attribute /process_data/@stringVariable = concat(/process_data/@stringVariable,"/></resource>") // close tags /process_data/node = deserialize(/process_data/@stringVariable) // turn string back into XML
Building XML using Java
Within orchestrations Java may be used within the Execute Script service. The Execute Script service within Process Management orchestrations uses BeanScript, a scriptable version of Java. Java is much more adapted to complex manipulation of XML data.
Process Management uses the Apache Xerces DOM parser to create and store XML variables within processes. Xerces is a Java implementation of W3C’s Document Object Model specification, http://www.w3.org/DOM/. The DOM specification is a standard way of manipulating XML that has been around since 1998. The Java implementation of Xerces, Xerces-J, supports DOM Level 2 version 1.0.
There is an extended explanation of how to manipulate XML within the Execute Script service within the article, Using the Execute Script Service in LiveCycle Workbench ES2 to build XML data.