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