我需要使用Perl脚本在XML文件中获取具有给定名称的节点的子节点数据值。 我正在使用XML::LibXML::Simple。
代码段如下所示:
my $booklist = XMLin(path);
foreach my $book (@{$booklist->{detail}}) {
print $book->{name} . "\n";
}
XML文件如下所示:
<?xml version='1.0' encoding='iso-8859-1'?>
<booklist>
<book>
<detail label='label1' status='active' type='none'>
<name>book1</name>
</detail >
<detail label='label2' status='active' type='none'>
<name>book2</name>
</detail >
</book>
</booklist>
当我使用上面的代码时,我收到以下错误消息: “不是ARRAY参考”
任何人都可以帮助我吗?
答案 0 :(得分:2)
下面是在XML中使用的XML :: Simple的解决方案。
use strict;
use warnings;
use XML::Simple;
my $booklist = XMLin($ARGV[0], KeyAttr => [], ForceArray => qr/detail/);
foreach my $book (@{$booklist->{book}->{detail}}) {
print $book->{name} . "\n";
}
这里重要的部分是给予XMLin的选项,强制将“细节”子节点表示为数组。
XML的简单快速入门:: Simple是关于CPAN的文档: http://metacpan.org/pod/XML::Simple
答案 1 :(得分:1)
当你写:
@{ $booklist->{detail} }
...你说$ booklist-&gt; {detail}返回一个数组引用,你希望perl将它取消引用到一个数组中,即'@'。
不要将<name>
用作标记。 XML :: Simple很奇怪地解析它。这是一个例子:
1)
<?xml version='1.0' encoding='iso-8859-1'?>
<booklist>
<book>
<bname>book1</bname>
</book>
<book>
<bname>book2</bname>
</book>
</booklist>
use strict;
use warnings;
use 5.016;
use XML::Simple;
use Data::Dumper;
my $booklist = XMLin('xml.xml');
print Dumper($booklist);
--output:--
$VAR1 = {
'book' => [
{
'bname' => 'book1'
},
{
'bname' => 'book2'
}
]
};
2)现在看看使用<name>
标签时会发生什么:
<?xml version='1.0' encoding='iso-8859-1'?>
<booklist>
<book>
<name>book1</bname>
</book>
<book>
<name>book2</bname>
</book>
</booklist>
--output:--
$VAR1 = {
'book' => {
'book2' => {},
'book1' => {}
}
};
所以用你原来的例子:
<?xml version='1.0' encoding='iso-8859-1'?>
<booklist>
<book>
<detail label='label1' status='active' type='none'>
<bname>book1</bname>
</detail>
<detail label='label2' status='active' type='none'>
<bname>book2</bname>
</detail>
</book>
</booklist>
--output:--
$VAR1 = {
'book' => {
'detail' => [
{
'bname' => 'book1',
'status' => 'active',
'label' => 'label1',
'type' => 'none'
},
{
'bname' => 'book2',
'status' => 'active',
'label' => 'label2',
'type' => 'none'
}
]
}
};
要获取所有bname标记,您可以执行以下操作:
use strict;
use warnings;
use 5.016;
use XML::Simple;
use Data::Dumper;
my $booklist = XMLin('xml.xml');
my $aref = $booklist->{book}{detail};
for my $href (@$aref) {
say $href->{bname};
}
--output:--
book1
book2
答案 2 :(得分:1)
我想是这样......
use strict;
use XML::Twig;
my $text = join '', <DATA>;
my $story_file = XML::Twig->new(
twig_handlers =>{
'name' => \&name,
keep_atts_order => 1,
},
pretty_print => 'indented',
);
$story_file->parse($text);
sub name {
my ($stroy_file, $name) = @_;
print $name->text, "\n";
}
__END__
<?xml version='1.0' encoding='iso-8859-1'?>
<booklist>
<book>
<detail label='label1' status='active' type='none'>
<name>book1</name>
</detail >
<detail label='label2' status='active' type='none'>
<name>book2</name>
</detail >
</book>
</booklist>
答案 3 :(得分:1)
不鼓励在新代码中使用此模块。其他模块可用,提供更直接和一致的接口。特别强烈建议使用XML :: LibXML。
此模块的主要问题是大量选项以及这些选项交互的任意方式 - 通常会产生意外结果。
反正。
在您的代码中,您忽略了书单包含包含详细信息的书籍这一事实。书单没有直接的细节。以下是使用XML::LibXML的简短解决方案:
use strict; use warnings; use 5.010; use XML::LibXML;
my $dom = XML::LibXML->load_xml(IO => \*DATA) or die "Can't load";
for my $detail ($dom->findnodes('/booklist/book/detail')) {
say $detail->findvalue('./name');
}
__DATA__
<?xml version='1.0' encoding='iso-8859-1'?>
<booklist>
<book>
<detail label='label1' status='active' type='none'>
<name>book1</name>
</detail >
<detail label='label2' status='active' type='none'>
<name>book2</name>
</detail >
</book>
</booklist>
正如您在XPATH表达式/booklist/book/detail
中所看到的,我们首先必须在查找详细信息之前查看本书。当然,这可以缩短为//detail
。
通常,如果数据结构不是它看起来的那样,你应该转储它,例如
use Data::Dumper;
print Dumper $booklist;
这将输出:
$VAR1 = {
'book' => {
'detail' => {
'book2' => {
'status' => 'active',
'type' => 'none',
'label' => 'label2'
},
'book1' => {
'status' => 'active',
'type' => 'none',
'label' => 'label1'
}
}
}
};
因此,出于某些原因,book1
和book2
字符串现在是嵌套哈希中的键。帮自己一个忙,并停止在CPAN上使用最复杂的XML模块,即“XML :: Simple”。
答案 4 :(得分:0)
使用XML::Rules的另一种方式(假设要点是'详细'而不是仅打印'name'的内容):
use XML::Rules;
my @rules = (
detail => sub {
print "$_[1]{name}\n";
return;
},
name => 'content',
_default => undef,
);
my $xr = XML::Rules->new(rules => \@rules);
$xr->parsefile("tmp.xml");