home *** CD-ROM | disk | FTP | other *** search
/ PC World 2000 December / PCWorld_2000-12_cd.bin / Komunikace / Comanche / xuibuilder / ddom.tcl next >
Text File  |  2000-11-02  |  5KB  |  183 lines

  1. # ddom.tcl 
  2. #
  3. # Different helper methods to make TclDOM API more user friendly
  4.  
  5.  
  6. # dom::getText --
  7. #   Returns the node contents if a text node or the contents of all the text
  8. # children if it is an element. 
  9. #
  10. # Example: getText on <foo>bar</foo> would return "bar"
  11.  
  12. proc ::dom::getText { token } {
  13.     switch [dom::node cget $token -nodeType]  {
  14.     element {
  15.         set result {}
  16.         foreach child [dom::children $token] {
  17.              append result [dom::node cget $child -nodeValue]
  18.         }
  19.         return  $result
  20.     } 
  21.     textNode {
  22.         return [dom::node cget $token -nodeValue]
  23.     } default {
  24.     }
  25.     }
  26. }
  27.  
  28.  
  29. # dom::getElements --
  30. #   Returns a list with all children of type element of a given node
  31.  
  32. proc ::dom::getElements { token } {
  33.     set result {}
  34.     foreach child [dom::children $token] {
  35.     if ![string compare [dom::node cget $child -nodeType] element] {
  36.         lappend result $child
  37.     }
  38.     }
  39.     return $result
  40. }
  41.  
  42.  
  43. # dom::getTagName --
  44. #   Helper function for getting the tag for a node of type element
  45.  
  46. proc ::dom::getTagName {token} {
  47.     switch [dom::node cget $token -nodeType] {
  48.     element {
  49.         return [dom::element cget $token -tagName ]
  50.     } default {
  51.         return /textnode
  52.     }
  53.     }
  54. }
  55.  
  56.  
  57. # dom::rp --
  58. #   Resolve path. Given a node and a path, return the node the path points to
  59. # Path are constructed:
  60. #   tagName<attr1="some value">/tagname2<5>  etc.
  61. #
  62. # Examples:
  63. #   Given the following document
  64. #
  65. #  <puppets>
  66. #    <puppet name="kermit"><color>green</color></puppet>
  67. #    <puppet name="cookie monster"><color>blue</color></puppet>
  68. #  </puppets>
  69. #
  70. # dom::rp $initialToken puppets/puppet<0>   
  71. # will return the first <puppet> element (kermit)
  72. # dom::rp $initialToken puppets/puppet<name="kermit">
  73. # will return the <puppet> element that has attribute name="kermit"(kermit)
  74. #
  75. # dom::rp $initialToken puppets/puppet<0>/color  
  76. # will return the text node that contains the "green" text
  77. #
  78. # TO-DO: more robust error checking
  79.  
  80. proc ::dom::rp {token path} {
  81.     set currentNode $token
  82.     regsub -all {(//*([^/<]+(<[^>]*>)?))} $path { \2} spath
  83.     foreach pathComponent $spath {
  84.     set result {}
  85.     set children [getElementsByTagName $currentNode \
  86.         [getTagFromPath $pathComponent]] 
  87.     set attrs [getAttrsFromPath $pathComponent]
  88.     if  {[lindex $attrs 0] == "</idx>"} {
  89.         set result [lindex $children [lindex $attrs 1]]
  90.     } else {
  91.         foreach ch $children {
  92.         if {[matchesAttrs $ch $attrs]} {
  93.             lappend result  $ch
  94.         }
  95.         }
  96.     }
  97.     switch [llength $result]  {
  98.         0 {
  99.         error "No such element $pathComponent while resolving $path"
  100.         } 1 { 
  101.             set currentNode $result
  102.         } 2 {
  103.         error "Too many elements match $pathComponent in $path"
  104.         }
  105.     }
  106.     }
  107.     return $currentNode
  108. }
  109.  
  110. # dom::matchesAttrs --
  111. #   Check that a certain node has ALL specified attributes
  112.  
  113. proc ::dom::matchesAttrs {node attrs} {
  114.     array set attr $attrs
  115.     foreach attribute [array names attr] {
  116.     if {$attr($attribute) != [getAttribute $node $attribute]} {
  117.         return 0
  118.     }
  119.     }
  120.     return 1
  121. }
  122.  
  123.  
  124. # dom::getTagFromPath --
  125. #  Given a path, return the tagname
  126. #
  127. # Example
  128. #   getAttrsFromPath foo<a="5",b="6">
  129. # returns 
  130. #   "foo"
  131.  
  132. proc ::dom::getTagFromPath {path} {
  133.     regexp {([^<]+)} $path tag
  134.     return $tag
  135. }
  136.  
  137. # dom::getAttrsFromPath --
  138. #  Given a path, return a list of attribute/value pairs
  139. #
  140. # Example
  141. #   getAttrsFromPath foo<a="5",b="6">
  142. # returns
  143. #   {a 5 b 6}
  144. #
  145. # TO-DO : Does we handle correctly attribute values with spaces?
  146.  
  147. proc ::dom::getAttrsFromPath {path} {
  148.     set attrs {}
  149.     regexp {([^<]+)<([^>]*)>} $path whole tag attrs
  150.     if [regexp {^[0-9]+$} $attrs idx ] {
  151.     return [list </idx> $idx]
  152.     }
  153.     regsub -all {([^=]+)(=("[^"]*"))?,?} $attrs {\1 \3 } list 
  154.     return $list 
  155. }
  156.  
  157. # Rename procedures so they are easier to type and we do not have to 
  158. # remember in which interface (node, element, document the node is defined)
  159.  
  160. foreach procedure { insertBefore  replaceChild  \
  161.     removeChild appendChild hasChildNodes \
  162.     clodeNode  children  parent 
  163. } {
  164.     proc dom::$procedure args "eval ::dom::node $procedure \$args"
  165. }
  166.  
  167. foreach procedure { getElementsByTagName createElement createDocumentFragment \
  168.     createTextNode createComment createCDATASection \
  169.     createProcessingInstruction createAttribute createEntity  \
  170.     createEntityReference  createDocTypeDecl cget configure} {
  171.     proc dom::$procedure args "eval ::dom::document $procedure \$args"
  172. }
  173.  
  174. foreach procedure { getAttribute setAttribute removeAttribute\
  175.     getAttributeNode setAttributeNode removeAttributeNode \
  176.         getElementsByTagName normalize 
  177. } {
  178.     proc dom::$procedure args "eval ::dom::element $procedure \$args"
  179. }
  180.  
  181.  
  182.