Constructing Dynamic XML Elements in XQuery

This article explains how XQuery dynamically constructs new XML elements and attributes from existing datasets. By leveraging direct and computed constructors alongside FLWOR (For, Let, Where, Order by, Return) expressions, XQuery allows developers to transform, reshape, and generate customized XML structures on the fly based on queried data.

Direct XML Constructors

Direct constructors allow you to write literal XML tags directly within an XQuery expression. Dynamic data from the queried dataset is embedded into the element content or attribute values using curly braces {}. The expression inside the braces is evaluated at runtime, and its result is inserted into the final XML tree.

for $book in doc("library.xml")//book
where $book/price < 30
return
  <discount-item category="{$book/@genre}">
    <title>{$book/title/text()}</title>
    <sale-price>{$book/price * 0.8}</sale-price>
  </discount-item>

In this example, literal tags like <discount-item> and <title> are created directly, while attribute values and inner text nodes are populated dynamically from the source dataset.

Computed XML Constructors

When the element or attribute names cannot be hardcoded and must be determined dynamically from the data, XQuery provides computed constructors using keywords such as element, attribute, text, and comment.

A computed constructor evaluates two expressions: the first determines the QName (element or attribute name), and the second determines the content.

for $node in doc("dataset.xml")//record/*
return
  element { node-name($node) } {
    attribute { "status" } { "processed" },
    attribute { concat("data-", name($node)) } { "valid" },
    $node/text()
  }

Computed constructors are essential when translating dynamic schemas, mapping key-value stores into tag-value structures, or normalizing inconsistent naming conventions across disparate datasets.

Combining Constructors with FLWOR Expressions

The power of dynamic construction comes from pairing constructors with FLWOR expressions. The return clause of a FLWOR expression acts as a factory for generating transformed nodes for each iteration over the source data.

  1. Iteration (for): Iterates through source nodes.
  2. Variable Binding (let): Calculates intermediate values, aggregations, or sequences.
  3. Filtering (where): Selects relevant items.
  4. Ordering (order by): Sorts output sequence order.
  5. Output Generation (return): Constructs the dynamic elements for each item.
<inventory summary-date="{current-date()}">
{
  for $item in doc("stock.xml")//item
  let $totalValue := $item/quantity * $item/unit-cost
  order by $totalValue descending
  return
    element { if ($item/quantity < 10) then "low-stock" else "available-stock" } {
      attribute sku { $item/@id },
      element name { $item/name/text() },
      element total-value { $totalValue }
    }
}
</inventory>

Nesting and Grouping Constructors

XQuery supports full nesting of direct and computed constructors. In modern XQuery specifications (3.0 and later), the group by clause can be used to aggregate data dynamically into hierarchical structures:

<departments>
{
  for $emp in doc("employees.xml")//employee
  group by $dept := $emp/department
  return
    <department name="{$dept}">
      <headcount>{count($emp)}</headcount>
      <staff>
      {
        for $e in $emp
        return <name>{$e/name/text()}</name>
      }
      </staff>
    </department>
}
</departments>

By combining direct constructors for static structures with computed constructors for schema-driven naming, XQuery provides a complete declarative engine for shaping and constructing dynamic XML documents from any queried source.