Xatapult's XML Blog


XQuery functions with side effects – How to handle?

Filed under: How-to,Tips and trics — xatapult @ 14:12

XQuery is the language for working with XML databases. It can also be used as a general purpose language for working with XML.

If you have functions in XQuery with side effects (e.g. updating a log) that return something you don’t want to use, you have a serious problem. This blog explores this and proposes some solutions.

Don’t leave your litter lying around

In most programming languages, you have to deliberately do something to produce output. For instance, if you write a function in Java and you want to return it’s result, you use the return statement. If you don’t, nothing much will happen. The same is true for the full program: If you don’t specifically add code to create some kind of output (e.g. a file, lines on screen, records in a database) nobody will even notice your code has run.

Not so in XQuery. XQuery will output everything you leave behind. For instance: Let’s assume you have a function that updates a logfile and this function returns true or false, depending on whether the log update was successful. So you might write XQuery code that produces your desired XML output and registers this in the log:

   <Output> … XQuery code to create the right output … </Output>,
   local:UpdateLogFile('Output created')

Now what will be the output of this code fragment? Exactly: A sequence with an <Output> element followed by a boolean value. Probably not what you intended.

Now you might of course refactor local:UpdateLogFile() so it no longer returns a boolean but the empty sequence instead. But if you are interested in its return value sometimes, that’s not an option.

There are a number of ways to work around this. Which one works depends (probably?) on the XQuery processor you use.

An XQuery litter bin 1

The first way around this is to add a FLWOR, assign the function’s return value to a local variable and happily ignore this:

let $ignore := local:UpdateLogFile('Output created')
return <Output> … XQuery code to create the right output … </Output>

Now this approach has two drawbacks:

  • The optimizer might decide that computing the value of $ignore is of no use and never call local:UpdateLogFile(). I know eXist does not do this kind of optimizing and so this code works in an eXist environment. However, Saxon does optimize the local:UpdateLogFile() away and I’m not so sure about other products.
  • When your code interpreter works neatly from top to bottom, the log file will be updated before the output is created. This might or might not be a problem.

An XQuery litter bin 2

A second strategy to cope with this is add a function that does… nothing:

declare function local:Empty( $anything as item()* ) as item()? { () };
   <Output> … XQuery code to create the right output … </Output>,
   local:Empty(local:UpdateLogFile('Output created'))

Again, a smart optimizer might find out that local:Empty() does not do anything with its input and not call local:UpdateLogFile(). The example above works in both eXist and Saxon but if you use something else, test it first.

An XQuery litter bin 3

A third way to cope with the problem at hand is to wrap the function call in an if/then/else statement:

   <Output> … XQuery code to create the right output … </Output>,
   if (local:UpdateLogFile('Output created')) then () else ()

Again, the optimizer is the spoilsport. This works in eXist but not in Saxon.


I’m not sure I’m exactly happy with any of the proposed solutions. They are more like imperfect tricks. A smart optimizer can see through them and wipe the necessary function calls away.

So are there any other solutions to this problem? How can I call a function and discard the result while still being certain the function does gets called? Maybe somebody else knows…



Leave a Comment »

No comments yet.

RSS feed for comments on this post. TrackBack URI

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

Blog at WordPress.com.

%d bloggers like this: