2013-07-22 42 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非常相似,但速度更快,功能更多,維護性更好。