Skip to content

Instantly share code, notes, and snippets.

@joewiz
Last active January 5, 2022 17:03
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save joewiz/b38279b8bd33de6949bb891370f76a04 to your computer and use it in GitHub Desktop.
Save joewiz/b38279b8bd33de6949bb891370f76a04 to your computer and use it in GitHub Desktop.
Merge XML fragments into a composite document
xquery version "3.1";
(:~ Merge XML fragments with the same root node into a composite document.
: Based on a question from the exist-open mailing list.
:
: @see https://markmail.org/message/gdrhscaobyya44we
:)
(: Compare the fragment to the composite document. If the node names match,
: then recursively descend into child nodes to continue the comparison;
: if the fragment does not match, then deposit the non-matching fragment
: node into the composite. :)
declare function local:merge-fragment($fragment-node as node(), $composite-node as node()) {
if ($fragment-node/node-name() eq $composite-node/node-name()) then
element { $fragment-node/node-name() } { local:merge-fragment($fragment-node/node(), $composite-node/node()) }
else
($fragment-node, $composite-node)
};
(: Pass each fragment to the merge-fragment function until we've merged them
: all into the composite document. :)
declare function local:merge-fragments($fragments as node()*, $composite as node()) {
if (exists($fragments)) then
let $fragment-to-merge := head($fragments)
let $updated-composite := local:merge-fragment($fragment-to-merge, $composite)
let $remaining-fragments := tail($fragments)
return
local:merge-fragments($remaining-fragments, $updated-composite)
else
$composite
};
(: Check to make sure the fragments share the same root element,
: since otherwise they can't be merged. If they are mergeable,
: treat the 1st fragment as the initial "composite" that all
: other fragments are merged into. :)
declare function local:merge-fragments($fragments as node()*) {
if (count(distinct-values($fragments/node-name())) gt 1) then
"can't merge these elements - they don't have the same root element"
else
let $initial-composite := head($fragments)
let $initial-fragments := tail($fragments)
return
local:merge-fragments($initial-fragments, $initial-composite)
};
let $var1 := <fileDesc>
<sourceDesc>
<msDesc>
<physDesc>
<objectDesc form=""/>
</physDesc>
</msDesc>
</sourceDesc>
</fileDesc>
let $var2 := <fileDesc>
<sourceDesc>
<msDesc>
<msIdentifier>
<idno/>
</msIdentifier>
</msDesc>
</sourceDesc>
</fileDesc>
let $var3 := <fileDesc>
<titleStmt>
<title/>
</titleStmt>
</fileDesc>
return
local:merge-fragments(($var1, $var2, $var3))
<fileDesc>
<titleStmt>
<title/>
</titleStmt>
<sourceDesc>
<msDesc>
<msIdentifier>
<idno/>
</msIdentifier>
<physDesc>
<objectDesc form=""/>
</physDesc>
</msDesc>
</sourceDesc>
</fileDesc>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment