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]
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
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