Prev: How to control child windows move with parent window?
Next: Is there a way to force TCL to stay interactive even when invoking it with a script?
From: max vorticity on 23 Feb 2010 13:42 I would like to reorder rows in an html table so I thought it might be good time to learn how to use tdom instead of brute force parsing of the html with string commands, but now I've spent a bit more time than I should have to do this. I can get a list of nodes in the order I want, but I'm not sure how to change the parent's child list to be in this order. Do I first clone the parent node and add in each child in order, use insertBefore or replaceChild? For the latter two, I was unsure if I needed to be concerned with the document fragment list the documentation mentions. I sure this is fairly straight forward, but I don't really have much knowledge of working with trees or DOM.
From: Hai Vu on 23 Feb 2010 15:48 On Feb 23, 10:42 am, max vorticity <max.vortic...(a)verizon.net> wrote: > I would like to reorder rows in an html table so I thought it might be > good time to learn how to use tdom instead of brute force parsing of > the html with string commands, but now I've spent a bit more time than > I should have to do this. I can get a list of nodes in the order I > want, but I'm not sure how to change the parent's child list to be in > this order. Do I first clone the parent node and add in each child in > order, use insertBefore or replaceChild? For the latter two, I was > unsure if I needed to be concerned with the document fragment list the > documentation mentions. I sure this is fairly straight forward, but > I don't really have much knowledge of working with trees or DOM. Check out removeChild insertChild, and appendChild. You can use these to reorder the child nocdes. Here is a short sample: ----- package require tdom set xmltext { <root> <node1>this is node1</node1> <node2>this is node2</node2> </root> } set doc [dom parse $xmltext]; # Turn XML text into dom set root [$doc documentElement]; # The root node puts "Before:" puts [$root asXML] # Swap node1 and node2 set node1 [$root firstChild]; # node1 $root removeChild $node1; # Remove node1 from root $root appendChild $node1; # Put node1 after node2 puts "After:" puts [$root asXML]
From: MartinLemburg on 24 Feb 2010 04:34 Hi, since there seems to be no way to sort the DOM tree in tdom, what's about this: proc sortCommand {nodeValueCommand options node1 node2} { # get the values to compare # set value1 [{*}[string map [list %N $node1] $nodeValueCommand]]; set value2 [{*}[string map [list %N $node2] $nodeValueCommand]]; # care for the nocase option # if {"-nocase" in $options} { set value1 [string tolower $value1]; set value2 [string tolower $value2]; } # compare in dictionary style # if {"-dictionary" in $options} { if {$value1 eq $value2} { return 0; } set list [lsort -dictionary [list $value1 $value2]]; if {$value1 eq [lindex $list 0]} { return -1; } return 1; } # compare non-numerical values # if { ("-real" ni $options && "-integer" ni $options) || ![string is double -strict $value1] || ![string is double -strict $value2]} { return [string compare $value1 $value2]; } # compare numerical values # if {$value1 == $value2} { return 0; } elseif {$value1 > $value2} { return 1; } return -1; } proc sortNodesByCommand {parentNode nodeValueCommand args} { # get the child nodes and sort them # set childNodes [$parentNode childNodes]; set sortedNodes [lsort \ {*}$args \ -command [list sortCommand $nodeValueCommand $args] \ $childNodes \ ]; if {$sortedNodes eq $childNodes} { return; } # remove all child nodes from the parent node # foreach childNode $childNodes { $parentNode removeChild $childNode; } # add the child nodes in the new order # foreach childNode $sortedNodes { $parentNode appendChild $childNode; } return; } proc sortNodesByName {parentNode args} { sortNodesByCommand $parentNode {%N nodeName} {*}$args - dictionary; } proc sortNodesByValue {parentNode args} { sortNodesByCommand $parentNode {%N nodeValue} {*}$args; } proc sortNodesByText {parentNode args} { sortNodesByCommand $parentNode {%N text} {*}$args -dictionary; } proc sortNodesByAttribute {parentNode attribute args} { sortNodesByCommand $parentNode {%N getAttribute $attribute} {*} $args; } # examples # package require tdom; set dom [dom parse -html [tDOM::xmlReadFile $htmlFile]]; set doc [$dom documentElement]; set head [$doc firstChild]; sortNodesByName $head; sortNodesByCommand $body {llength [%N childNodes]}; I've put this to the wiki, too: http://wiki.tcl.tk/25772 Best regards, Martin On 23 Feb., 19:42, max vorticity <max.vortic...(a)verizon.net> wrote: > I would like to reorder rows in an html table so I thought it might be > good time to learn how to use tdom instead of brute force parsing of > the html with string commands, but now I've spent a bit more time than > I should have to do this. I can get a list of nodes in the order I > want, but I'm not sure how to change the parent's child list to be in > this order. Do I first clone the parent node and add in each child in > order, use insertBefore or replaceChild? For the latter two, I was > unsure if I needed to be concerned with the document fragment list the > documentation mentions. I sure this is fairly straight forward, but > I don't really have much knowledge of working with trees or DOM.
From: max vorticity on 24 Feb 2010 13:57 On Feb 24, 4:34 am, "MartinLemburg(a)Siemens-PLM" <martin.lemburg.siemens-...(a)gmx.net> wrote: > Hi, > > since there seems to be no way to sort the DOM tree in tdom, what's > about this: > > proc sortCommand {nodeValueCommand options node1 node2} { > # get the values to compare > # > set value1 [{*}[string map [list %N $node1] > $nodeValueCommand]]; > set value2 [{*}[string map [list %N $node2] > $nodeValueCommand]]; > > # care for the nocase option > # > if {"-nocase" in $options} { > set value1 [string tolower $value1]; > set value2 [string tolower $value2]; > } > > # compare in dictionary style > # > if {"-dictionary" in $options} { > if {$value1 eq $value2} { > return 0; > } > > set list [lsort -dictionary [list $value1 $value2]]; > > if {$value1 eq [lindex $list 0]} { > return -1; > } > > return 1; > } > > # compare non-numerical values > # > if { ("-real" ni $options && "-integer" ni $options) > || ![string is double -strict $value1] > || ![string is double -strict $value2]} { > return [string compare $value1 $value2]; > } > > # compare numerical values > # > if {$value1 == $value2} { > return 0; > } elseif {$value1 > $value2} { > return 1; > } > > return -1; > } > > proc sortNodesByCommand {parentNode nodeValueCommand args} { > # get the child nodes and sort them > # > set childNodes [$parentNode childNodes]; > set sortedNodes [lsort \ > {*}$args \ > -command [list sortCommand $nodeValueCommand $args] \ > $childNodes \ > ]; > > if {$sortedNodes eq $childNodes} { > return; > } > > # remove all child nodes from the parent node > # > foreach childNode $childNodes { > $parentNode removeChild $childNode; > } > > # add the child nodes in the new order > # > foreach childNode $sortedNodes { > $parentNode appendChild $childNode; > } > > return; > } > > proc sortNodesByName {parentNode args} { > sortNodesByCommand $parentNode {%N nodeName} {*}$args - > dictionary; > } > > proc sortNodesByValue {parentNode args} { > sortNodesByCommand $parentNode {%N nodeValue} {*}$args; > } > > proc sortNodesByText {parentNode args} { > sortNodesByCommand $parentNode {%N text} {*}$args -dictionary; > } > > proc sortNodesByAttribute {parentNode attribute args} { > sortNodesByCommand $parentNode {%N getAttribute $attribute} {*} > $args; > } > > # examples > # > package require tdom; > > set dom [dom parse -html [tDOM::xmlReadFile $htmlFile]]; > set doc [$dom documentElement]; > set head [$doc firstChild]; > > sortNodesByName $head; > sortNodesByCommand $body {llength [%N childNodes]}; > > I've put this to the wiki, too:http://wiki.tcl.tk/25772 > > Best regards, > > Martin > > On 23 Feb., 19:42, max vorticity <max.vortic...(a)verizon.net> wrote: > > > I would like to reorder rows in an html table so I thought it might be > > good time to learn how to use tdom instead of brute force parsing of > > the html with string commands, but now I've spent a bit more time than > > I should have to do this. I can get a list of nodes in the order I > > want, but I'm not sure how to change the parent's child list to be in > > this order. Do I first clone the parent node and add in each child in > > order, use insertBefore or replaceChild? For the latter two, I was > > unsure if I needed to be concerned with the document fragment list the > > documentation mentions. I sure this is fairly straight forward, but > > I don't really have much knowledge of working with trees or DOM. > > I found that just reusing the node with appendChild reordered the nodes. So if $nodes is a list of the nodes in the desired order: foreach n $nodes {$parent appendChild $n} The above worked in my case but I don't know if this is really a safe way to reoder the nodes.
From: Rolf Ade on 4 Mar 2010 08:15
max vorticity <max.vorticity(a)verizon.net> wrote: >> On 23 Feb., 19:42, max vorticity <max.vortic...(a)verizon.net> wrote: >> >> > I would like to reorder rows in an html table so I thought it might be >> > good time to learn how to use tdom instead of brute force parsing of >> > the html with string commands, but now I've spent a bit more time than >> > I should have to do this. �I can get a list of nodes in the order I >> > want, but I'm not sure how to change the parent's child list �to be in >> > this order. �Do I first clone the parent node and add in each child in >> > order, �use insertBefore or replaceChild? �For the latter two, I was >> > unsure if I needed to be concerned with the document fragment list the >> > documentation mentions. � I sure this is fairly straight forward, but >> > I don't really have much knowledge of working with trees or DOM. >> >> > >I found that just reusing the node with appendChild reordered the >nodes. So if $nodes is a list of the nodes in the desired order: > >foreach n $nodes {$parent appendChild $n} > >The above worked in my case but I don't know if this is really a safe >way to reoder the nodes. That should be save and work. If not, report as bug. The appendChild subcommand unlinks the node to append from its current place in the tree and appends it as last child of $parent. So, a receipt to reorder childs is: get the childs with [$parent childNodes], reorder the returned list of nodes as you need and bring the childs in the tree into the new order as shown above. A note for the second step: Using lsort -command can be slow, which is well known. Depending on what you want to sort the childs, a usual advice is: build up a sort list like set sortlist [list] foreach node $childlist { lappend sortlist [list [$node text] $node] } set sortedlist [lsort -index 0 <maybe more options> $sortlist] set sortedchilds [list] foreach lelm $sortedlist { lappend sortedchilds [lindex $lelm 1] } rolf |