::xox
Class XmlNodeReader

Heritage:
::xotcl::Object
  |
  +--::xox::XmlReader
Associated Test:
::xox::test::TestXmlNodeReader

Class XmlNodeReader
superclass ::xox::XmlReader,
XmlNodeReader is a library of methods that will convert
 specially built XML into a tree of ::xox::Node objects.
 The schema for the XML is defined by the operations of
 the ::xox::XmlNodeWriter class.  Thus XML written by
 ::xox::XmlNodeWriter from a ::xox::Node tree can be
 read back into a ::xox::Node tree using this class.

 The primary methods in this class are buildTree and buildNodes.
Variables
NameDefault ValueClassComment
externalRootNodes    ::xox::XmlNodeReader
 OPTIONAL, Other root nodes that may be found in the XML
rootNode    ::xox::XmlNodeReader
 ACCESSOR, The rootNode to build the ::xox::Node tree upon.
 
Methods
NameComment
addMixin {parentNode subTdomNode}   Adds a mixin given in the value of subTdomNode to parentNode
buildNode {parentNode subTdomNode}   Recurisvley build a subtree of ::xox::Nodes from a corresponding DOM subtree
buildNodes {rootNode xml}   Build a tree of ::xox::Nodes and add them to the node, rootNode, from the given xml
buildNodesFromTdom {parentNode tdomNode}   Builds the subnodes of the tdomNode into ::xox::Nodes
buildTree {rootNode treeFiles}   Adds a tree of ::xox::Nodes to rootNode from set of tree files that are the format created by ::xox::XmlNodeWriter
getPathNode {path}   Finds the object given by the path, path
isclassAndLoad {name}  
lookupIndexPathAndSetValues {}   Finds object specified by path variables and sets those variables to the handles of the found objects
lookupPathAndSetValues {}   Finds object specified by path variables and sets those variables to the handles of the found objects
lookupPathsAndSetValues {}   Finds object specified by path variables and sets those variables to the handles of the found objects
savePathForSecondProcess {node variable value}   Save the node, variable, and path value for the second phase processing
savePathsForSecondProcess {node variable value}   Save the node, variable, and paths value for the second phase processing
setArrayIndexValue {parentNode valueNode name index}   Sets the value of the array variable given as the name of the subTdomNode on the parentNode
setArrayValue {parentNode subTdomNode}   Sets the value of the array variable given as the name of the subTdomNode on the parentNode
setNodeValue {node tdomNode variableName}   Sets the value of the variable, variableName, on node to the value found in the DOM node, tdomNode
setPathValue {parentNode subTdomNode}   Extracts the path value from subTdomNode and saves the value for second phase processing
setPathsValue {parentNode subTdomNode}   Extracts the paths value from subTdomNode and saves the value for second phase processing
setValues {parentNode subTdomNode}   Sets the value of the variable given as the name of the subTdomNode on the parentNode
   
Methods from ::xotcl::Object
#, ., ?, ?code, ?methods, ?object, abstract, copy, coverageFilter, defaultmethod, extractConfigureArg, filterappend, garbageCollect, get#, getClean#, hasclass, init, methodTag, mixinappend, move, profileFilter, self, setParameterDefaults, shell, tclcmd, traceFilter,
 
Instproc Detail

addMixin

Description:
 Adds a mixin given in the value of subTdomNode to parentNode.

 Arguments:

 parentNode - the ::xox::Node instance to add the mixin to.
 subTdomNode - the subTdomNode that holds the class name of the mixin
Arguments:
Code:
  ::xox::XmlNodeReader instproc addMixin {parentNode subTdomNode}  {
   

       set mixin [ my extractValue $subTdomNode ]
       $parentNode mixin add $mixin
   
}

buildNode

Description:
 Recurisvley build a subtree of ::xox::Nodes from a corresponding DOM subtree.

 Arguments:

 parentNode - The parent ::xox::Node to add the new ::xox::Node subtree to.
 subTdomNode - The DOM subtree that holds the information for the new subtree of Nodes.
Arguments:
Code:
  ::xox::XmlNodeReader instproc buildNode {parentNode subTdomNode}  {
   

       set class [ $subTdomNode nodeName ]

       #my debug $class

       set childName ""

       foreach subSubNode [ $subTdomNode childNodes ] {

           set name [ $subSubNode nodeName ]
           if [ my isclassAndLoad $name ] { continue }
           set value ""
           catch { set value [ my extractValue $subSubNode ] }
           set childParameters($name) $value
           
           if { "$name" == "nodeName" } { 
               set childName $value
           }
       }

       if { ""  == "$childName" } {

           set node [ $parentNode createAutoNamedChild $class -noinit ]
           my buildNodesFromTdom $node $subTdomNode
           return
       } 

       if [ $parentNode hasNode $childName ] {

           set node [ $parentNode getNode $childName ]
           my buildNodesFromTdom $node $subTdomNode

       } else {

           set node [ $parentNode createChild $childName $class -noinit ]
           my buildNodesFromTdom $node $subTdomNode
       }
   
}

buildNodes

Description:
 Build a tree of ::xox::Nodes and add them to the node, rootNode, from the
 given xml.

 Arguments:

 rootNode - The root node to add the tree of Nodes to.
 xml - The XML that will be converted to the tree of Nodes.
Arguments:
Code:
  ::xox::XmlNodeReader instproc buildNodes {rootNode xml}  {
   

       my rootNode $rootNode

       set document [dom parse $xml]
       set root     [$document documentElement]

       if [ $root hasAttribute package ] {

           package require [ $root getAttribute package ]
       }

       #puts $xml

       my array unset path
       my array unset paths
       my array unset indexPath
       my array unset indexPaths

       my buildNodesFromTdom $rootNode $root

       #my debug [ $rootNode dumpTreeData ]

       my lookupIndexPathAndSetValues
       my lookupPathAndSetValues
       my lookupPathsAndSetValues
   
}

buildNodesFromTdom

Description:
 Builds the subnodes of the tdomNode into ::xox::Nodes.

 If the name of the subnode is a class name then it will
 create a new object from that class name otherwise it
 If the name of the subnode is not a class name then it
 assumes the name is a variable.  The value of the variable
 is extracted from the subnode and set on the parentNode
Arguments:
Code:
  ::xox::XmlNodeReader instproc buildNodesFromTdom {parentNode tdomNode}  {
   

       set subTdomNodes [ $tdomNode childNodes ]
       set parameterList ""

       foreach subTdomNode $subTdomNodes {

           #my debug "node: [ $subTdomNode nodeName ]"

           set classOrParameter [ $subTdomNode nodeName ]

           if { ![ my isclassAndLoad $classOrParameter ] } {

               my setValues $parentNode $subTdomNode

           } else { 

               my buildNode $parentNode $subTdomNode 
           }
       }
   
}

buildTree

Description:
 Adds a tree of ::xox::Nodes to rootNode from set of tree files that
 are the format created by ::xox::XmlNodeWriter.

 Arguments:

 rootNode - The rootNode to add the tree of nodes created from on
     of the tree files in treeFiles. This node must have the same name
     as the root node written to the tree files.

 treeFiles - A list of files to read in and convert to ::xox::Node instances.
Arguments:
Code:
  ::xox::XmlNodeReader instproc buildTree {rootNode treeFiles}  {
   

        foreach treeFile $treeFiles {

            if [ catch {

            set xml [ read [ open $treeFile ] ]
            my buildNodes $rootNode $xml

            } result ] {

                global errorInfo

                error "XmlNodeReader buildTree $treeFile\n$errorInfo"
            }
        }

        return $rootNode
    
}

getPathNode

Description:
 Finds the object given by the path, path.  This method
 will look on rootNode and the externalRootNodes depending
 on the name of the root element in the path, path. 

 Arguments: 

 path - The path to the Node.

 Returns:

 The ::xox::Node instance found by the path.

 Throws:

 An error if the Node is not found.
Arguments:
Code:
  ::xox::XmlNodeReader instproc getPathNode {path}  {
   

       my instvar rootNode externalRootNodes

       set root [ lindex $path 0 ]
       set subPath [ lrange $path 1 end ]

       if { "$root" == "[ $rootNode nodeName ]" } {

           return [ eval $rootNode $subPath ]
       }

       if [ my exists externalRootNodes ] { 
       foreach externalRootNode $externalRootNodes {

           if { "[ $externalRootNode getNodeName ]" == "$root" } {

               return [ eval $externalRootNode $subPath ]
           }
       }
       }

       puts "Warning: Path, $path, has unknown root, $root\n Expected: [ $rootNode nodeName ]\n Actual: $root\n"

       return $path
   
}

isclassAndLoad

Description:
 
Arguments:
Code:
  ::xox::XmlNodeReader instproc isclassAndLoad {name}  {
   

        if [ Object isclass $name ] {

            return 1
        }

        set current [ ::xox::Package getPackageFromClass $name ]

        while { "" != "$current" } {

            catch { package require $current }

            if [ Object isclass $name ] { 

                return 1
            }

            set current [ ::xox::Package getPackageFromClass $current ]
        }

        return 0
   
}

lookupIndexPathAndSetValues

Description:
 Finds object specified by path variables and sets those variables
 to the handles of the found objects.

 This method finds objects specified in array indexes.
Code:
  ::xox::XmlNodeReader instproc lookupIndexPathAndSetValues {}  {
   

       foreach { name value } [ my array get indexPath ] {

           set object [ lindex $name 0 ]
           set variable [ lrange $name 1 end ]

           set index [ lindex $value 0 ]
           set domNode [ lindex $value 1 ]

           #my debug "path: $object set $variable $value"

           set indexNode [ my getPathNode $index ]

           #my debug "$object $variable $index $domNode $indexNode"
           set valueNode [ my getFirstChildNamed $domNode value ]
           my setArrayIndexValue $object $valueNode $variable $indexNode
       }
   
}

lookupPathAndSetValues

Description:
 Finds object specified by path variables and sets those variables
 to the handles of the found objects.

 This method finds objects specified as a path.
Code:
  ::xox::XmlNodeReader instproc lookupPathAndSetValues {}  {
   

       foreach { name value } [ my array get path ] {

           set object [ lindex $name 0 ]
           set variable [ lrange $name 1 end ]
           set arrayName [ lindex [ split $variable "\(" ] 0 ]

           if { "parentNode" == "$variable" } { continue }
           if { "nodes" == "$variable" } { continue }
           if { "nameToNodes" == "$arrayName" } { continue }

           #my debug "path: $object set $variable $value"

           $object set $variable [ my getPathNode $value ]
       }
   
}

lookupPathsAndSetValues

Description:
 Finds object specified by path variables and sets those variables
 to the handles of the found objects.

 This method finds objects specified as paths.
Code:
  ::xox::XmlNodeReader instproc lookupPathsAndSetValues {}  {
   

       foreach { name value } [ my array get paths ] {

           set object [ lindex $name 0 ]
           set variable [ lindex $name 1 ]
           set arrayName [ lindex [ split $variable "\(" ] 0 ]

           if { "parentNode" == "$variable" } { continue }
           if { "nodes" == "$variable" } { continue }
           if { "nameToNodes" == "$arrayName" } { continue }

           foreach path $value {

               $object lappend $variable [ my getPathNode $path ]
           }
       }
   
}

savePathForSecondProcess

Description:
 Save the node, variable, and path value for the second phase processing.
 Paths must be saved to be processed in the second phase after all the objects are built.
Arguments:
Code:
  ::xox::XmlNodeReader instproc savePathForSecondProcess {node variable value}  {
   

       my set "path($node $variable)" $value
   
}

savePathsForSecondProcess

Description:
 Save the node, variable, and paths value for the second phase processing.
 Paths must be saved to be processed in the second phase after all the objects are built.
Arguments:
Code:
  ::xox::XmlNodeReader instproc savePathsForSecondProcess {node variable value}  {
   

       my set "paths($node $variable)" $value
   
}

setArrayIndexValue

Description:
 Sets the value of the array variable given as the name of the subTdomNode
 on the parentNode.
Arguments:
Code:
  ::xox::XmlNodeReader instproc setArrayIndexValue {parentNode valueNode name index}  {
   

       #my debug "$parentNode $valueNode $name $index"

       set value [ my extractValue $valueNode ]
       set variableName "${name}\($index\)"
       if [ $valueNode hasAttribute type ] {
           set type [ $valueNode getAttribute type ]
           switch $type {
               path { my savePathForSecondProcess $parentNode $variableName $value }
               paths { my savePathsForSecondProcess $parentNode $variableName $value }
               default { error "Unsupported type $type" }
           }
           return

       } else {
           
           #my debug "$parentNode set $variableName $value"
           $parentNode set $variableName $value
       }
   
}

setArrayValue

Description:
 Sets the value of the array variable given as the name of the subTdomNode
 on the parentNode.
Arguments:
Code:
  ::xox::XmlNodeReader instproc setArrayValue {parentNode subTdomNode}  {
   

       set name [ $subTdomNode nodeName ]

       set indexNode [ my getFirstChildNamed $subTdomNode index ]
       #my debug [ $indexNode asXML ]
       set index [ my extractValue $indexNode ]
       if [ $indexNode hasAttribute type ] {
           set type [ $indexNode getAttribute type ]
           switch $type {
               path { my set "indexPath($parentNode $name)" [ list $index $subTdomNode ] }
               paths { my set "indexPaths($parentNode $name)" [ list $index $subTdomNode ] }
               default { error "Unsupported type $type" }
           }
           return
       }

       set valueNode [ my getFirstChildNamed $subTdomNode value ]
       my setArrayIndexValue $parentNode $valueNode $name $index
   
}

setNodeValue

Description:
 Sets the value of the variable, variableName, on node to the
 value found in the DOM node, tdomNode.

 Arguments:

 node - The ::xox::Node instance to set value of variableName on.
 tdomNode - The DOM node to extract the value of variableName from.
 variableName - The variable name to set the value on node.
Arguments:
Code:
  ::xox::XmlNodeReader instproc setNodeValue {node tdomNode variableName}  {
   

       set value [ my extractValue $tdomNode ]
       $node set $variableName $value
   
}

setPathValue

Description:
 Extracts the path value from subTdomNode and saves the value for second phase processing.
Arguments:
Code:
  ::xox::XmlNodeReader instproc setPathValue {parentNode subTdomNode}  {
   

       set variableName [ $subTdomNode nodeName ]

       if { "" != "[ $subTdomNode childNodes ]" } {
           set value [ my extractValue $subTdomNode ]
           my savePathForSecondProcess $parentNode $variableName $value
       } 
   
}

setPathsValue

Description:
 Extracts the paths value from subTdomNode and saves the value for second phase processing.
Arguments:
Code:
  ::xox::XmlNodeReader instproc setPathsValue {parentNode subTdomNode}  {
   

       set variableName [ $subTdomNode nodeName ]

       if { "" != "[ $subTdomNode childNodes ]" } {
           set value [ my extractValue $subTdomNode ]
           my savePathsForSecondProcess $parentNode $variableName $value
       } 
   
}

setValues

Description:
 Sets the value of the variable given as the name of the subTdomNode
 on the parentNode.
Arguments:
Code:
  ::xox::XmlNodeReader instproc setValues {parentNode subTdomNode}  {
   

       set name [ $subTdomNode nodeName ]

       #my debug "name: $name"
       #my debug "[ $subTdomNode asXML ]"

       if [ $subTdomNode hasAttribute type ] {

           set variableName $name 

           set type [ $subTdomNode getAttribute type ]
           #my debug "type: $type"
           switch $type {

               path { my setPathValue $parentNode $subTdomNode }
               paths { my setPathsValue $parentNode $subTdomNode }
               mixin { my addMixin $parentNode $subTdomNode }
               array { my setArrayValue $parentNode $subTdomNode }
               default { error "[ my info class ] Unsupported type $type" }
           }

           return
       }

       my setNodeValue $parentNode $subTdomNode $name
   
}