I was trying to sort a group of nodes in an xml file, and it ended up being a lot tougher than I thought. I'm using XML::DOM, and I want to take a node and sort a group of child nodes based on a value, in this case, sort the member nodes my the member/num value
here is an xml file:
<?xml version="1.0"?>
<family>
<member><num>1A</num><name>isashi</name></member>
<member><num>1</num><name>felix</name></member>
<member><num>3</num><name>brandon</name></member>
<member><num>5</num><name>jeremy</name></member>
<member><num>4B</num><name>aaron</name></member>
</family>
and the relevant perl code:
my $instance = 'C:\my\path\perlNodeSortTest.xml';
$instance =~ s#\\#/#g;
# create parser, open file
my $parser = XML::DOM::Parser->new();
my $doc = $parser->parsefile( $instance );
sub readMembers(){
my $members = $doc->getElementsByTagName( 'member' );
# basic idea here is to loop thru nodes, swapping the old sort order node for the new,
# but getting error
my $i = 0;
foreach my $nodeMem(sort mySort @{$members} ){
my $nodeNum = $nodeMem->getElementsByTagName('num')->item(0);
my $numVal = &getTagValue( $nodeNum );
my $parentNode = $nodeMem->getParentNode();
print $parentNode->getNodeName(), "\n";
my $oldNode = $members->item($i);
$parentNode->replaceChild($nodeMem, $oldNode);
print "reading " . $nodeMem->getNodeName() . " num is $numVal\n";
$i++
}
}
# this sort could be a lot more sophisticated, but this is the basic idea
sub mySort(){
my $nodeNumA = $a->getFirstChild();
my $nodeNumB = $b->getFirstChild();
# getTagValue() sub not shown, but it just grabs the value of the node, assuming
# it's a text node and has no child element nodes
my $numA = &getTagValue( $nodeNumA );
my $numB = &getTagValue( $nodeNumB );
if( $numA =~ m/[a-zA-Z]/ || $numB =~ m/[a-zA-Z]/){
return $numA cmp $numB;
} else {
return $numA cmp $numB;
}
}
this code results in an error like:
Can't call method "getNodeName" on an undefined value at sort-nodes-test.pl line 47.
I tried a couple other things, like defining the node outside the foreach loop, but that omits some of the elements in the output, even though all the console output is correct.
when I swapped this line:
$parentNode->replaceChild($nodeMem, $oldNode);
for this ($root defined outside foreach):
$root->appendChild($nodeMem);
I did get proper output, but that seems weird. I may have answered my own Q in writing this out (not a bad thing, I suppose.. :)), but will that solution work all the time? Any insight if the second solution is correct, and why it works? I would think it would add a copy of the sorted node ... .
Also, any favorite packages, methods of sorting xml nodes with perl?