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.
- Iteration (
for): Iterates through source nodes. - Variable Binding (
let): Calculates intermediate values, aggregations, or sequences. - Filtering (
where): Selects relevant items. - Ordering (
order by): Sorts output sequence order. - 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.