Recently I have been doing some coding in idoc script, the default scripting language for Oracle UCM. It’s main use as a scripting language is for generating html server-side. Using it can be frustrating as it does not have procedures and has very limited scoping of variables.
One of the fragments I wrote was a depth first enumeration of the website nodes. A recursive function is the most natural to do this, however because idoc it doesn’t have procedures and a stack this cannot be done in the normal way. The solution was to keep a counter to the current recursion depth in a global variable and store the ‘scoped’ variable at each level in another global variable which was suffixed with the current level:
<@dynamichtml diagonal.page.utility.getallnodes@>
<$c="***********************************"$>
<$c=" Retrieves a complete list of nodes for a website in depth first search order (recursive)"$>
<$c="Input variables:"$>
<$c=" siteId : the site to search"$>
<$c=" currentNode : the node to start from"$>
<$c=" AllNodesRs : a result set with one column (nodeId) to add the nodes to"$>
<$c=" level : current level of the depth first search"$>
<$c="Ouput variables:"$>
<$c=" AllNodesRs"$>
<$c="*************************************"$>
<$rsAppendRowValues("AllNodesRs",currentNode)$>
<$setValue("#local","tmpNode"&level, currentNode)$>
<$currentNode=ssGetRelativeNodeId(siteId,currentNode,"child")$>
<$if not strEquals(currentNode,"")$>
<$level=level+1$>
<$include diagonal.page.utility.getallnodes$>
<$level=level-1$>
<$endif$>
<$currentNode=ssGetRelativeNodeId(siteId,getValue("#local","tmpNode"&level),"next")$>
<$if not strEquals(currentNode,"")$>
<$include diagonal.page.utility.getallnodes$>
<$endif$>
<@end@>
And to use this:
<$currentNode=ssGetFirstNodeId(siteId)$>
<$level=0$>
<$rsCreateResultSet("AllNodesRs","node")$>
<$c="We have to set this to ensure we enumerate sections that are set to 'Contributor Only'"$>
<$SSContributor=1$>
<$include diagonal.page.utility.getallnodes$>
<$SSContributor=0$>
The two key lines which store and retrieve the current node for each level of the recursion are:
<$setValue("#local","tmpNode"&level, currentNode)$>and
<$currentNode=ssGetRelativeNodeId(siteId,getValue("#local","tmpNode"&level),"next")$>
Of course you can write an imperative version of any algorithm but some things are more naturally written as a recursion.
NB: for deep sites you can produce a ‘stack overflow’ due to the large number of nested idoc includes.
No comments:
Post a Comment