Troubleshooting
Problem
When you use XPath expressions with the Message Filter Primitive, it does not always produce the expected results. This document explains these results, and tells you how to construct expressions which result in the expected output.
Symptom
The documentation for WebSphere ESB and WebSphere Process Server states that some mediation primitives have properties, which are specified using an XPath 1.0 expression. However, with the Message Filter primitive, using particular XPath expressions do not always yield the expected output. This situation occurs because XPath expressions used in mediation primitives are evaluated over an SDO view of the message rather than directly against XML. The following three examples illustrate this.
Example 1: Accessing attribute nodes
The following XML fragment represent the body element of a Service Message Object (SMO) at the entry point to a Message Element Setter primitive:
- <body xsi:type="xml:operation1RequestMsg">
- <myns:operation1>
- <inputBO fruitFamily="apple">
- <variety>Golden Delicious</variety>
<variety>Granny Smith</variety>
<variety>Royal Gala</variety>
You might want to use an XPath expression such that a match terminal is triggered whenever the "inputBO" element's attribute "fruitFamily" has the value "apple", the element highlighted in bold in the XML fragment. To achieve this, you might construct an XPath expression of the following form, which you expect to be evaluated as true whenever this attribute has the desired value:
- /body/operation1/inputBO[@fruitFamily='apple']
At runtime however, when this message is processed by the Message Filter primitive, the match terminal for this expression is not fired. The following XPath expression does cause the match terminal to fire:
- /body/operation1/inputBO/@fruitFamily='apple'
This situation is expected because it implies that the message filter primitive found the fruitFamily attribute as a child member of the element "inputBO", which is not how it exists in the XML fragment.
Example 2: Referencing "xsi:type" attributes
The following body XML fragment represents the body of the SMO on the input terminal of the Message Element Setter:
- <body xsi:type="xml:operation1RequestMsg">
- <myns:operation1>
- <fruit xsi:type="apple">
- <variety>Golden Delicious</variety>
<fruit xsi:type="banana">
- <variety>Cavendish</variety>
The element that we want to match on is highlighted in bold text, the <fruit> element with an xsi:type attribute value of "apple". We might use a XPath expression of the following form to match on this element:
- /body/operation1/fruit[@*[local-name()='type' and contains(., 'apple')]]
As with example 1, at runtime this XPath expression does not result in the match terminal being fired when this message is processed.
Example 3: Using the "text()" XPath function
Consider the following body XML fragment:
- <body xsi:type="xml:operation1RequestMsg">
- <myns:operation1>
- <fruit>apple</fruit>
If you want to trigger the match terminal whenever the value of the "/body/operation1/fruit" element is 'apple', you might consider using an XPath expression, which makes use of the "text()" function to access the node's textual content. For example:
- boolean(/body/operation1/fruit[text()='apple'])
However, at runtime, the match terminal is not triggered.
Cause
The cause of these non-matching XPath expression issues is the way the data is represented within the Service Message Object. Although it is often useful to think of this data being represented as an XML document, in reality it is a series of Java™ Service Data Objects (SDO).
In most circumstances, you can treat these DataObjects in the Message Filter primitive as their serialized XML form and construct XPath expressions accordingly. However, there are a number of cases where the evaluation of an XPath against the SDO view of the data in a mediation primitive gives different results from those that would occur if the XPath were evaluated directly against its XML representation. This situation might result in the match terminal of the MessageFilter primitive not being fired as expected.
Resolving The Problem
(1) Attribute nodes are represented as child elements in SDO
In SDO, all attribute values are treated as child elements of the context node. In the first example above, note that if you use the following XPath expression the match terminal fires when the message is processed:
- /body/operation1/inputBO/@fruitFamily='apple'
Here, you explicitly instructed XPath to look for the attribute value as a child of the context node, in this case <inputBO>.
Subsequently, if you want to use an XPath expression, which includes a reference to attribute data, you need to specify the XPath expression in this format. That is, the expression defines the attributes as children of the context node.
(2) 'xsi:type' attribute values do not exist in SDO
The concept of the 'xsi:type' attribute in an XML document is used to explicitly define the type of the element. However, in SDO, the Java objects implicitly know their type definition without the use of such an attribute. Subsequently, the 'xsi:type' attribute should not be referenced when constructing the XPath expression.
Depending on the structure of your message, you might be able to use an alternative XPath expression, which gives you the equivalent logical output. For example, if you want to fire a match terminal whenever you have a "banana" type element with a <variety> element with the value "Cavendish", you can use an expression of the form:
- /body/operation1/fruit/variety='Cavendish'
However this type of construct might not always be appropriate given the structure of your message and intent of your business logic. If you must access this type information in order to perform your logical matching, then (for versions up to, and including, version 6.2 of the product) you must use an alternative mediation flow primitive, such as the Custom primitive. In the Custom primitive, you can use the SDO API to query this type information, and process your message flow accordingly.
(3) The XPath 'text()' function:
The XPath function 'text()' selects all text node children of the context node. Therefore, its use in the example 3 XML document snippet should return the text "apple" when used within the Message Filter primitive.
However, a limitation in the product's implementation of XPath against SDO means that the function returns 'null' instead of the textual content. Similarly, the following expressions all fail to return the correct value when evaluated against the example XML document:
- /body/operation1/fruit/text()='Apple'
- boolean(//fruit[text()='Apple'])
This limitation applies to all versions of the product (up to version 6.2 at the time of writing).
To work around this issue, it is usually possible to construct an alternative XPath expression that returns the same logical result. For example, the following three expressions all return true when evaluated against the XML snippet, which would result in the match terminal firing when used in conjunction with the Message Filter primitive:
- boolean(/body/operation1/fruit[.='Apple'])
boolean(/body/operation1/fruit='Apple')
boolean(//fruit[.='Apple'])
Was this topic helpful?
Document Information
Modified date:
15 June 2018
UID
swg21317934