XML principles tend to be a bit fractal-like: what's true at the macro level is true at the micro.
In some cases this is first about nesting elements in schemas and then about recursion in XML access code like the following XQuery:
define function tree-walk($node as node()) as node()* {
for $node in $node/element()
return
(
<element>{fn:local-name($node)}
{if (fn:local-name($node) eq "section") then
<section-nesting>{fn:count($node/ancestor::section)}</section-nesting>
else ()
}
</element>,
tree-walk($node)
)
}
let $doc := <section>
<title>this is section 1</title>
<section><title>this is nested once</title>
<section><title>this is 2x nesting</title>
</section>
</section>
</section>
return
tree-walk($doc)
But in some cases a design pattern can be applied as a fractal.
XML is often used as a data interchange format. It's simple, it’s flexible and can accommodate new and complex forms of data.
This is pretty universally accepted as a way to pass data between systems and now that we have XQuery, these systems are even easier than ever to build and maintain.
But it turns out these same principles are very valuable within an XQuery application and are applied in very much the same way.
In the eample above, we are using a user defined function that takes a parameter of type xs:node(). This means that the incoming payload to the function is an XML node any sturcture.
This is data interchange at a micro level: the arguments can be complex or simple depending on the case.
Now that example was a data input. But this gets really useful for controlling input.
One of the great features of MarkLogic Server is it's HTTP server to run XQuery. Like other HTTP servers it features accessors to the request object but these are implemented directly in XQuery.
Since you are usually sending both control and data, you need all of this input and likely you will pass this to your functions.
Here is how it works:
let $params := <params>
{for $i in xdmp:get-request-field-names()
return
for $j in xdmp:get-request-field($i)
return
element {$i} { $j}
}
</params>
return
if ($params/action eq "print") then
print-results($params)
else
menu-item($params)
Now as the app evolves the function signature can stay the same - and only those that require the new parameter need make use of it (function new-thing needs $params/newthing) and the others remain blissfully unaware (print-results doesn't know it exists).
So inside your data interchange XML application you can have functions that now pass . . . data interchange XML. And these functions run other functions and pass XML and so on and so on and so on.
MT
P.S. an interesting aside is the multiple value parameters become a sequence of elements when you access the $params node.
P.P.S. fans of recursion may enjoy the guilty pleasure of Wyrm.