2013-07-22 40 views
1

我试图在xml文件中对一组节点进行排序,结果比我想象的要困难得多。我正在使用XML :: DOM,并且我想根据一个值取一个节点并对一组子节点排序,在这种情况下,对成员节点进行排序,我的成员/ num值为通过使用XML的子节点的值对XML节点进行排序的最佳方法:: DOM

这里是一个xml文件:

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

和有关Perl代码:

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

该代码会导致类似的错误:

Can't call method "getNodeName" on an undefined value at sort-nodes-test.pl line 47. 

我尝试了一些其他的东西,比如在foreach循环外定义节点,但是忽略了输出中的一些元素,即使所有的控制台输出都是正确的。

当我换这条线:

$parentNode->replaceChild($nodeMem, $oldNode); 

这个(外的foreach定义$根):

$root->appendChild($nodeMem); 

我没有得到正确的输出,但似乎不可思议。我可能已经回答了我自己的问题(不是坏事,我想......)),但是这个解决方案会一直工作吗?任何洞察,如果第二个解决方案是正确的,为什么它的作品?我会认为它会添加已排序节点的副本...。

此外,任何最喜欢的软件包,用Perl来排序XML节点的方法?

+1

XSLT可以排序。您将需要使用XML :: LibXSLT。 – runrig

回答

3

不出所料,我会用XML ::嫩枝:

#!/usr/bin/perl 

use strict; 
use warnings; 

use XML::Twig; 

my $t= XML::Twig->new(pretty_print => 'record_c')->parsefile($ARGV[0]); 
$t->root->sort_children_on_field('num'); 
$t->print; 

在任何情况下,我会尽力避免XML DOM ::。 XML :: LibXML非常相似,但速度更快,功能更多,维护性更好。