我试图在xml文件中对一组节点进行排序,结果比我想象的要困难得多。我正在使用XML :: DOM,我想根据一个值取一个节点并对一组子节点进行排序,在这种情况下,将成员节点排序为我的成员/ num值
这是一个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);
为此($ fore在foreach之外定义):
$root->appendChild($nodeMem);
我确实获得了正确的输出,但这看起来很奇怪。我写这篇文章可能已经回答了我自己的问题(不是坏事,我想...... :)),但这个解决方案会一直运行吗?如果第二个解决方案是正确的,以及它为什么有效,任何见解?我认为它会添加已排序节点的副本......
另外,任何喜欢的包,用perl来分类xml节点的方法?
答案 0 :(得分:3)
不出所料,我会使用XML :: Twig:
#!/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非常相似,但速度更快,功能更多,维护更好。