Although I have acquired quite some experience in the past years using Oracle’s Service Bus and XQueries for transformations, there are still a lot of things I do not know … Some time ago, one of my colleagues mentioned a neat trick using Service Bus 11g to act as a shorthand for a conditional construct, <MyTagName?>.
Setup
This construct can be used in Service Bus 11g, for optional elements:
<MyTagName?>{SomeXQExpression}</MyTagName>
Whenever the XQuery expression “SomeXQExpression” exists, the element will be created in the output stream; otherwise, the element will not be created.
For demonstration purposes, I have created a very silly 11g Service Bus project whose sole purpose is to demonstrate this behaviour, effectively copying elements from the source XML (having English element names) to the target XML structure (having Dutch element names). The optional field for the LastNamePrefix is copied using the construct described above:
(:: pragma bea:global-element-parameter parameter="$req" element="ns0:HelloWorldRequest" location="../schemas/HelloWorld.xsd" ::) (:: pragma bea:global-element-return element="ns0:HelloWorldResponse" location="../schemas/HelloWorld.xsd" ::) declare namespace ns0 = "http://xmlns.syntouch.nl/HelloWorld"; declare namespace xf = "http://tempuri.org/HelloWorld/transforms/DoNiftyTransforms/"; declare function xf:DoNiftyTransforms($req as element(ns0:HelloWorldRequest)) as element(ns0:HelloWorldResponse) { <ns0:HelloWorldResponse> <ns0:Voornaam>{ data($req/ns0:FirstName) }</ns0:Voornaam> <ns0:Tussenvoegsel?>{ data($req/ns0:LastNamePrefix) }</ns0:Tussenvoegsel> <ns0:Achternaam>{ data($req/ns0:LastName) }</ns0:Achternaam> </ns0:HelloWorldResponse> }; declare variable $req as element(ns0:HelloWorldRequest) external; xf:DoNiftyTransforms($req)
Apart from the XQuery, the project contains a proxy and a WSDL/XSD — see the code at https://github.com/mnuman/XQueryOptionals.
Running the example on 11g
When running this example with an optional source element “LastNamePrefix”, the target element “Tussenvoegsel” is created in the output document:
However, without the optional element the conditional shorthand suppresses the optional element from the output document:
Export/Import to 12c
The easiest way to transfer this code to the 12c platform, is to export the project from an 11g runtime into a Service Bus configuration JAR and import this JAR into a 12c runtime:
After importing the projet, the 12c Service Bus will inform you about the changes it has made (if any) to the resources imported; in this case, it will split an existing 11g proxy into a 12c proxy + pipeline and insert an explicit version number into the XQuery resource:
Inspecting the imported XQuery reveals that Service Bus 12c has added an explicit XQuery version declaration, specifying that it should be executed using the XQuery 2004 specification/engine:
Running on 12c (2004-draft)
When running the XQuery using the 2004-draft version specification, the results are similar to the results obtained on 11g
Omitting the optional element, the output element is missing from the output document:
Running 12c using XQuery 1.0
Normally, I might have left it here and have concluded that this is indeed a nice shorthand to an if-then-else construct in XQuery. However, at the time we were experiencing some (severe) performance degradations on the 12c Service Bus environment of my customer. As the symptoms pointed to some resource leakage we could not pinpoint any further, the Oracle A-Team was brought in to help us in diagnosing the issue:
One of the recommendations made by the A-Team was to upgrade all of our XQueries (which had come from 11g and hence were XQuery 2004-draft) to XQuery 1.0 as it was suspected some of the resource leakage and contention problems were caused by the XQuery 2004 engine. As such, I decided to also test this shorthand by upgrading my entire project (which was imported from 11g) to XQuery 1.0:
At first sight, the conversion seems to complete smoothly:
However, upon activating the changes, it turned out that the conditional shorthand was not acceptable in XQuery 1.0:
When the shorthand is replaced by a “proper” if-then-else construct, the XQuery becomes valid again and can be executed from 12c.
An alternative ?
According to My Oracle Support (note 2068809.1), there is a different but equivalent Oracle extension, wrapping the optional element in (#ora-ext:if-exists-content#) { <tag>{Expression}</tag> }
… but I could not get this to work on SB 12.2.1.
Bottom Line
The bottom line for me from this experience is to stay away from relying on non-standard constructs — unless there is no alternative. It feels a bit like the suspicion Laocoön voiced in Aneid’s Virgil about the horse the Greeks left outside Troy’s city walls … “Timeo Danaos et dona ferentes“, but fortunately in this case it does not bring about such dire consequences!