Generate XML out of XPath Expressions
import module namespace mem = "http://xqdev.com/in-mem-update" | |
at "/MarkLogic/appservices/utils/in-mem-update.xqy" ; | |
declare variable $DEBUG as xs:boolean := fn:true() ; | |
(: hack because the inmem update looses the right focus | |
: if you have an idea on a workaround, please let me know | |
:) | |
declare variable $redo as xs:string* := (); | |
(: functional ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::) | |
declare function local:fst( $l ) { $l[1] } ; | |
declare function local:snd( $l ) { $l[2] } ; | |
declare function local:head( $l ) { local:fst( $l ) } ; | |
declare function local:tail( $l ) { fn:subsequence( $l, 2 ) } ; | |
declare function local:fold($f, $z, $l) { | |
if( fn:empty( $l ) ) then $z else | |
local:fold( $f, | |
xdmp:apply( $f, $z, local:head( $l ) ), | |
local:tail( $l ) ) } ; | |
declare function local:head-two( $l ) { fn:subsequence( $l, 1, 2 ) } ; | |
declare function local:tail-two( $l ) { fn:subsequence( $l, 3 ) } ; | |
declare function local:fold2($f, $z, $l) { | |
if( fn:empty( $l ) ) then $z else | |
local:fold2( $f, | |
xdmp:apply( $f, $z, local:head-two( $l ) ), | |
local:tail-two( $l ) ) } ; | |
(:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::) | |
declare function local:log( $string ) { | |
if ($DEBUG) then xdmp:log ( $string ) else () } ; | |
declare function local:replace-value( $node, $value ) { | |
if( xdmp:node-kind($node) = "attribute" ) | |
then mem:node-replace( $node, | |
attribute { fn:node-name( $node ) } { $value } ) | |
else mem:node-replace( $node, | |
element { fn:node-name( $node ) } { $value } ) } ; | |
declare function local:insert-child( $parent, $child ) { | |
if( xdmp:node-kind($child) = "attribute" ) | |
then mem:node-insert-before( ($parent/*)[1] , $child ) | |
else mem:node-insert-child( $parent , $child ) } ; | |
declare function local:create-nodes( $current-node, $xpath-step ) { | |
let $current-node-name := $current-node /fn:local-name(.) | |
let $new-node := | |
if ( fn:starts-with( $xpath-step, "@") ) | |
then attribute { fn:substring( $xpath-step, 2 ) } {} | |
else element { $xpath-step } {} | |
let $new-node-name := $new-node /fn:local-name(.) | |
let $steps := fn:string-join( local:tail( $redo ), "/" ) | |
let $child := | |
if( $steps ) | |
then | |
let $_ := xdmp:log( " ~~steps" ) | |
return xdmp:unpath( fn:concat( "$current-node/", $steps ) ) | |
else | |
let $_ := xdmp:log( " ~~no-steps" ) | |
return xdmp:unpath( fn:concat( "$current-node/", $xpath-step ) ) | |
let $_ := xdmp:set( $redo, ( $redo, $xpath-step ) ) | |
let $_ := local:log( " .................." ) | |
let $_ := local:log( " local:create-nodes" ) | |
let $_ := local:log( fn:concat(" r=", $steps ) ) | |
let $_ := local:log( fn:concat(" c=", xdmp:quote($current-node)) ) | |
let $_ := local:log( fn:concat(" s=", $xpath-step) ) | |
let $_ := local:log( fn:concat(" cn=", xdmp:quote( $current-node-name ) ) ) | |
let $_ := local:log( fn:concat(" n=", xdmp:quote( $new-node ) ) ) | |
let $_ := local:log( fn:concat(" nn=", xdmp:quote( $new-node-name ) ) ) | |
let $_ := local:log( fn:concat(" t=", $steps ) ) | |
let $_ := local:log( fn:concat(" ch=", xdmp:quote( $child ) ) ) | |
return if( fn:empty( $current-node ) ) | |
then $new-node | |
else if( $current-node-name = $new-node-name ) | |
then $current-node | |
else | |
if ( $steps ) | |
then | |
if ( $child ) | |
then local:insert-child( $child , $new-node ) | |
else local:insert-child( $current-node , $new-node ) | |
else | |
if( $child ) | |
then $child | |
else local:insert-child( $current-node , $new-node ) } ; | |
declare function local:generate-tree-step( $current-tree, $xpath ) { | |
let $_ := local:log( " ..................." ) | |
let $_ := local:log( " local:generate-tree-step" ) | |
let $_ := local:log( fn:concat( " z=", xdmp:quote($current-tree) ) ) | |
let $_ := local:log( fn:concat( " p=", fn:string-join($xpath, " ") ) ) | |
let $_ := xdmp:set($redo, ()) | |
let $f := xdmp:function( xs:QName( 'local:create-nodes' ) ) | |
return local:fold( $f, $current-tree, | |
local:tail( fn:tokenize( $xpath, "/" ) ) ) } ; | |
declare function local:populate-tree-step ( $current-tree, $pair ) { | |
let $xpath := local:fst( $pair ) | |
let $value := local:snd( $pair ) | |
let $relative-path := fn:replace($xpath, "^/\w+(/.*)", "$1") | |
let $selected := | |
xdmp:unpath( fn:concat( "$current-tree", $relative-path ) ) | |
let $_ := local:log( fn:concat( " -x = ", $xpath ) ) | |
let $_ := local:log( fn:concat( " -s = ", xdmp:quote($selected) ) ) | |
let $_ := local:log( fn:concat( " -v = ", $value ) ) | |
let $updated := local:replace-value( $selected, $value ) | |
let $_ := local:log( fn:concat( " -u= ", xdmp:quote($updated) ) ) | |
return $updated } ; | |
declare function local:generate-tree( $xpaths ) { | |
let $_ := local:log( " local:generate-tree" ) | |
let $_ := local:log( fn:concat( " lst=", fn:string-join( $xpaths, ", ") ) ) | |
let $f := xdmp:function( xs:QName( 'local:generate-tree-step' ) ) | |
return local:fold( $f, (), $xpaths ) } ; | |
declare function local:populate-tree( $tree, $xpaths, $values ) { | |
let $pairs := for $xpath at $i in $xpaths return ( $xpath, $values[$i] ) | |
let $f := xdmp:function( xs:QName( 'local:populate-tree-step' ) ) | |
let $_ := local:log( " local:populate-tree" ) | |
let $_ := local:log( fn:concat( " t=", xdmp:quote($tree) ) ) | |
let $_ := local:log( fn:concat( " p=", fn:string-join( $pairs, ", ") ) ) | |
return document { local:fold2( $f, $tree, $pairs ) } } ; | |
declare function local:process-fields( $xpaths, $values ) { | |
let $_ := local:log( "# start ############################################" ) | |
let $tree := local:generate-tree( $xpaths ) | |
return local:populate-tree( $tree, $xpaths, $values ) } ; | |
local:process-fields( | |
( "/person/name", "/person/address/zipcode", "/person/address/street", "/person/phone", "/person/@id" ), | |
( "John Doe", "10020", "barker", "555 432-4533", "555" ) ) |
import module namespace mem = "http://xqdev.com/in-mem-update" | |
at "/MarkLogic/appservices/utils/in-mem-update.xqy" ; | |
(: hack because the inmem update looses the right focus | |
: if you have an idea on a workaround, please let me know | |
:) | |
declare variable $redo as xs:string* := (); | |
(: functional ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::) | |
declare function local:fst( $l ) { $l[1] } ; | |
declare function local:snd( $l ) { $l[2] } ; | |
declare function local:head( $l ) { local:fst( $l ) } ; | |
declare function local:tail( $l ) { fn:subsequence( $l, 2 ) } ; | |
declare function local:fold($f, $z, $l) { | |
if( fn:empty( $l ) ) then $z else | |
local:fold( $f, | |
xdmp:apply( $f, $z, local:head( $l ) ), | |
local:tail( $l ) ) } ; | |
declare function local:head-two( $l ) { fn:subsequence( $l, 1, 2 ) } ; | |
declare function local:tail-two( $l ) { fn:subsequence( $l, 3 ) } ; | |
declare function local:fold2($f, $z, $l) { | |
if( fn:empty( $l ) ) then $z else | |
local:fold2( $f, | |
xdmp:apply( $f, $z, local:head-two( $l ) ), | |
local:tail-two( $l ) ) } ; | |
(:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::) | |
declare function local:replace-value( $node, $value ) { | |
if( xdmp:node-kind($node) = "attribute" ) | |
then mem:node-replace( $node, | |
attribute { fn:node-name( $node ) } { $value } ) | |
else mem:node-replace( $node, | |
element { fn:node-name( $node ) } { $value } ) } ; | |
declare function local:insert-child( $parent, $child ) { | |
if( xdmp:node-kind($child) = "attribute" ) | |
then mem:node-insert-before( ($parent/*)[1] , $child ) | |
else mem:node-insert-child( $parent , $child ) } ; | |
declare function local:create-nodes( $current-node, $xpath-step ) { | |
let $current-node-name := $current-node /fn:local-name(.) | |
let $new-node := | |
if ( fn:starts-with( $xpath-step, "@") ) | |
then attribute { fn:substring( $xpath-step, 2 ) } {} | |
else element { $xpath-step } {} | |
let $new-node-name := $new-node /fn:local-name(.) | |
let $steps := fn:string-join( local:tail( $redo ), "/" ) | |
let $child := | |
if( $steps ) | |
then xdmp:unpath( fn:concat( "$current-node/", $steps ) ) | |
else xdmp:unpath( fn:concat( "$current-node/", $xpath-step ) ) | |
let $_ := xdmp:set( $redo, ( $redo, $xpath-step ) ) | |
return if( fn:empty( $current-node ) ) | |
then $new-node | |
else if( $current-node-name = $new-node-name ) | |
then $current-node | |
else | |
if ( $steps ) | |
then | |
if ( $child ) | |
then local:insert-child( $child , $new-node ) | |
else local:insert-child( $current-node , $new-node ) | |
else | |
if( $child ) | |
then $child | |
else local:insert-child( $current-node , $new-node ) } ; | |
declare function local:generate-tree-step( $current-tree, $xpath ) { | |
let $_ := xdmp:set($redo, ()) | |
let $f := xdmp:function( xs:QName( 'local:create-nodes' ) ) | |
return local:fold( $f, $current-tree, | |
local:tail( fn:tokenize( $xpath, "/" ) ) ) } ; | |
declare function local:populate-tree-step ( $current-tree, $pair ) { | |
let $xpath := local:fst( $pair ) | |
let $value := local:snd( $pair ) | |
let $relative-path := fn:replace($xpath, "^/\w+(/.*)", "$1") | |
let $selected := | |
xdmp:unpath( fn:concat( "$current-tree", $relative-path ) ) | |
let $updated := local:replace-value( $selected, $value ) | |
return $updated } ; | |
declare function local:generate-tree( $xpaths ) { | |
let $f := xdmp:function( xs:QName( 'local:generate-tree-step' ) ) | |
return local:fold( $f, (), $xpaths ) } ; | |
declare function local:populate-tree( $tree, $xpaths, $values ) { | |
let $pairs := for $xpath at $i in $xpaths return ( $xpath, $values[$i] ) | |
let $f := xdmp:function( xs:QName( 'local:populate-tree-step' ) ) | |
return document { local:fold2( $f, $tree, $pairs ) } } ; | |
declare function local:process-fields( $xpaths, $values ) { | |
let $tree := local:generate-tree( $xpaths ) | |
return local:populate-tree( $tree, $xpaths, $values ) } ; | |
local:process-fields( | |
( "/person/name", "/person/address/zipcode", "/person/address/street", "/person/phone", "/person/@id" ), | |
( "John Doe", "10020", "barker", "555 432-4533", "555" ) ) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment