我做了这样的练习,如何通过XML :: Simple计算折叠成数组的XML元素的数量,这样我就不必硬编码元素了? 我计划使用代码来解析更大的xml文件。我不想通过手册来宣传这些元素。
我可以使用一些计数来替换幻数,有点像person.count
或hobbie.length
等。据我所知,我可以方便地在C#中使用这种语句。
#!/usr/bin/perl -w
use strict;
use XML::Simple;
use Data::Dumper;
my $tree = XMLin('./t1.xml');
print Dumper($tree);
print "\n";
for (my $i = 0; $i < 2; $i++) # magic number '2'
{
print "$tree->{person}->[$i]->{first_name} $tree->{person}->[$i]->{last_name}\n";
print "\n";
for (my $j = 0; $j < 3; $j++) # magic number '3'
{
print $tree->{person}->[$i]->{hobbie}->[$j], "\n";
}
print "\n";
}
Out put:
could not find ParserDetails.ini in C:/Perl/site/lib/XML/SAX
$VAR1 = {
'person' => [
{
'hobbie' => [
'bungy jumping',
'sky diving',
'knitting'
],
'last_name' => 'Bloggs',
'first_name' => 'Joe'
},
{
'hobbie' => [
'Swim',
'bike',
'run'
],
'last_name' => 'LIU',
'first_name' => 'Jack'
}
]
};
Joe Bloggs
bungy jumping
sky diving
knitting
Jack LIU
Swim
bike
run
我的Xml源文件如下
<Document>
<person>
<first_name>Joe</first_name>
<last_name>Bloggs</last_name>
<hobbie>bungy jumping</hobbie>
<hobbie>sky diving</hobbie>
<hobbie>knitting</hobbie>
</person>
<person>
<first_name>Jack</first_name>
<last_name>LIU</last_name>
<hobbie>Swim</hobbie>
<hobbie>bike</hobbie>
<hobbie>run</hobbie>
</person>
</Document>
答案 0 :(得分:5)
由于XML :: Simple会为您生成一个数组,因此很容易计算它的长度。
E.g。 $tree->{person}
是一个数组 - 或者更确切地说是一个数组引用(即使只有一个人,也要使用XML :: Simple的ForceArray选项确保它是一个)。
您可以通过首先将其取消引用到数组本身(使用@{}
数组取消引用)来获取其长度:@{ $tree->{person} }
然后在标量上下文中使用结果数组,该上下文计算数组中的元素数(换句话说,其他语言中的a.lenth
/ a.count
函数转换为Perl成语scalar(@a)
如果标量上下文已经应用,则scalar()
函数是可选的。
在这种情况下,数字比较运算符"<"
将强制使用标量上下文,但如果不是这种情况,则可以使用scalar()
函数。
示例:
# Don't forget ForceArray option of XML::Simple to ensure person and hobbie are array refs
for (my $i = 0; $i < scalar( @{ $tree->{person} } ); $i++) { # scalar() is optional here
print "$tree->{person}->[$i]->{first_name} $tree->{person}->[$i]->{last_name}\n";
print "\n";
for (my $j = 0; $j < @{ $tree->{person}->[$i]->{hobbie} }; $j++) {
print $tree->{person}->[$i]->{hobbie}->[$j], "\n";
}
print "\n";
}
注意,计算Perl数组长度的一种稍微不同的方法是$#a
构造,它返回数组最后一个元素的索引 - 例如1比数组中的元素数量少。我不知道使用这两种方法之间有任何性能差异,所以如果你发现两者同样可读,请在适当时使用它们(例如,如果你需要得到最后一个元素的索引,请使用$#a
;如果#of元素,根据需要使用@a
或scalar(@a)
。
答案 1 :(得分:3)
for my $person (@{ $tree->{person} }) {
print "$person->{first_name} $person->{last_name}\n\n";
for my $hobby (@{ $person->{hobbie} }) {
print $hobby, "\n";
}
print "\n";
}
正如DVK所说,请确保您的XMLin选项中有ForceArray => [qw/Person Hobby/]
,否则如果您只有一个人或任何人只有一个爱好,事情将无法解决。
答案 2 :(得分:1)
如果您使用'C'样式for循环,您只需要知道数组中的项目数。相反,您可以使用更多perlish版本:foreach my $val ( @list )
#!/usr/bin/perl
use strict;
use warnings;
use XML::Simple qw(:strict XMLin);
use Data::Dumper;
my $tree = XMLin('./t1.xml', KeyAttr => { }, ForceArray => [ 'person', 'hobbie' ]);
foreach my $person ( @{ $tree->{person} } ) {
print "$person->{first_name} $person->{last_name}\n";
foreach my $hobbie ( @{ $person->{hobbie} } ) {
print "$hobbie\n";
}
}
为了更安全(并且更具可读性),您可能需要检查<person>
是否包含任何<hobbie>
个元素,然后再尝试循环它们:
foreach my $person ( @{ $tree->{person} } ) {
print "$person->{first_name} $person->{last_name}\n";
if(my $hobbies = $person->{hobbie}) {
foreach my $hobbie ( @$hobbies ) {
print "$hobbie\n";
}
}
}