Created
April 13, 2010 06:01
-
-
Save dscape/364356 to your computer and use it in GitHub Desktop.
Generate XML out of XPath Expressions
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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" ) ) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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