Friday, February 25, 2011

‘Recursive’ includes in Oracle UCM idoc script

 

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