xquery version "3.1"; (:~ : represant sequence of path strings as sequence of xml trees :) module namespace tree = 'quodatum.data.tree'; (:~ : convert path(s) to tree :) declare function tree:build($paths as xs:string*,$del as xs:string) { fn:fold-right($paths, (), function($this,$acc){ tree:merge($acc,tree:nest($this,$del)) } ) }; (:~ convert a path to xml :) declare function tree:nest($path as xs:string,$del as xs:string) as element(*) { let $path:=if(starts-with($path,$del)) then $path else $del || $path let $parts:=fn:tokenize(($path),"\" || $del) return fn:fold-right(subsequence($parts,1,count($parts)-1), , tree:wrap#2 ) }; declare function tree:wrap($this as xs:string,$acc) as element(*) { {$acc} }; declare function tree:merge($a1 as element(*)?,$a2 as element(*)?) as element(*)* { if($a1/@name=$a2/@name) then let $n1:=$a1/* let $n2:=$a2/* let $t:=( for $x in fn:distinct-values($n1/@name[.=$n2/@name]) (:both:) return tree:merge($a1/*[@name=$x],$a2/*[@name=$x]), for $x in fn:distinct-values($n1/@name[fn:not(.=$n2/@name)]) (:only $a1 :) return $a1/*[@name=$x], for $x in fn:distinct-values($n2/@name[fn:not(.=$n1/@name)]) (:only $a2 :) return $a2/*[@name=$x] ) return tree:wrap($a1/@name,for $x in $t order by $x/@name return $x) else ($a1,$a2) };