Element constructors: computed and direct

Author: Dave Cassel  |  Category: Software Development

In XQuery, you can build an element one of two ways: computed or direct.

Direct

This is the simpler case, so I’ll take it first. Direct means that your XQuery code has the XML you want to build:

declare namespace blog = "http://davidcassel.net/blog";
<blog:example simple="true">
  <blog:pointless/>
</blog:example>

XML is a natural data structure for XQuery and this is a very simple way to construct it.

Computed

A computed element is less direct, but it has its benefits. Let’s take a look:

declare namespace blog = "http://davidcassel.net/blog";

element { xs:QName("blog:example") } {
  attribute simple { "true" },
  element { xs:QName("blog:pointless") } { }
}

Benefits

The direct method is more concise, so why would we use the computed? There are two reasons why I typically end up using them.

A Conditional Attribute

Sometimes you want to include an attribute only under certain circumstances. The trick is, this doesn’t work:

<blog:example { if ($condition) then simple="true" else () }/>

That’s not valid syntax — the attribute either has to be there or not, though its value can be the result of an XQuery expression. One way we can conditionally include an attribute is to build the element different in the if and else branches of the condition:

if ($condition) then
  <blog:example simple="true"/>
else
  <blog:example/>

As you can imagine, that can be a lousy way to go if the element has some complexity to it, for instance if it has a lot of attributes. This is one place where computed construction makes your life easier:

declare namespace blog = "http://davidcassel.net/blog";

element { xs:QName("blog:example") } {
  if ($condition) then attribute simple { "true" } else (),
  element { xs:QName("blog:pointless") } { }
}

Computing the Name

Another case where the computed version comes in handy is when the name of the element itself will be the result of a computation. Let’s suppose you have a map that you want to turn into a set of elements.

<root>{
  for $key in map:keys($map)
  return element { $key } { map:get($map, $key) }
}</root>

There’s really no other way to do this case, but it’s simple to do this way.

Any other cases you can think of where computed elements are the easier way to go?

Tags: ,

6 Responses to “Element constructors: computed and direct”

  1. Evan Lenz Says:

    Nice post, Dave. Note you also have the option of using a computed attribute constructor with a direct element constructor. So your conditional attribute example could be simplified like this:

    <blog:example>
    { if ($condition) then attribute simple { “true” } else () }
    <blog:pointless/>
    </blog:example>

    In general, I think it’s a good practice to avoid computed constructors except in the cases you describe. Direct constructors are much more readable, like you said.

  2. Dave Cassel Says:

    Good point, Evan. I’ve done that mixed approach accidentally before (trying to include a value, but getting the whole attribute instead), but I don’t tend to think of doing it that way on purpose.

  3. peter Says:

    Thanks for this

    The article (together with the comment) were exactly what I was looking for

  4. Ed Says:

    Thanks Dave, I’m echoing Peter’s comment – a nice easily understood explanation and example

  5. JC Says:

    Exactly what I was struggling with: conditionally adding an attribute. Thank you.

  6. vin Says:

    Thanks David. Great article and real life saver.
    Regards

Leave a Reply