Due to the semantics of XQuery, all child nodes need to be copied if they are wrapped by a new parent node. This is demonstrated by the following query, which compares the node identity of the original and copied node. It will yield false
:
let $node := <node/>
let $parent := <parent>{ $node }</parent>
return $parent/node is $node
As copying millions of nodes is expensive, this inevitably leads to an out-of-memory error.
If you write results to files, here is a pragmatic solution to get around this restriction:
(:~
: Writes element to a file, wrapped by a root node.
: @param $path path to file
: @param $elements elements to write
: @param $name name of root node
:)
declare function local:write-to(
$path as xs:string,
$elements as element()*,
$name as xs:string
) as empty-sequence() {
file:write-text($path, '<' || $name || '>'),
file:append($path, $elements),
file:append-text($path, '</' || $name || '>')
};
local:write-to('result.xml', <result/>, 'root')
To anticipate criticism: This is a clear hack. For example, the approach conflicts with various non-default serialization parameters of BaseX (the result will not be well-formed if an XML declaration needs to be be output, etc.).