我尝试了XML Simple
,但由于它只是将XML读入哈希,因此在针对DTD运行时输出无效。很了解它。
所以我采用了XML::LibXML
,有趣的是我发现XML::Simple
最难实现的要求是最简单的。但是我发现在XML::Simple
中一些更容易做的事情被证明是不可能的(我对DOM的理解不足,以及XML::LibXML
的一些令人困惑的行为)。
以下是XML的示例:
<Metadata>
<ADI Name="movie" />
<App_Data Name="Something I don't care about" value="who cares" />
<App_Data Name="Something I don't care about as well" value="who cares" />
<App_Data Name="ChangeMe" Value="" />
</Metadata>
<Metadata>
<ADI Name="photo" />
<App_Data Name="Something I don't care about" value="who cares" />
<App_Data Name="Something I don't care about as well" value="who cares" />
<App_Data Name="ChangeMe" Value="" />
</Metadata>
<Metadata>
<ADI Name="poster" />
<App_Data Name="Something I don't care about" value="who cares" />
<App_Data Name="Something I don't care about as well" value="who cares" />
<App_Data Name="ChangeMe" Value="" />
</Metadata>
注意:我已将此内容简化为此内容。
所以基本上我必须使用Name
标记中的<ADI>
字段来确认我在DOM的正确区域中,以更改Value
属性<App_Data>
标记Name
是谁ChangeMe
。
这是我提出的代码片段......并且悲惨地失败了。
#!/usr/bin/perl
use strict;
use XML::LibXML;
my $xml2 = XML::LibXML->new();
my $data = $xml2->parse_file("adi.xml");
my $movie;
my $photo;
my $poster;
foreach my $test ($data->findnodes('//Metadata')) {
if ($test->findvalues('./ADI/@Name[.="movie"]')){
$movie = 1;
undef $photo;
undef $poster;
}
elsif ($test->findvalues('./ADI/@Name[.="photo"]')){
undef $movie;
$photo = 1;
undef $poster;
}
elsif ($test->findvalues('./ADI/@Name[.="poster"]')){
undef $movie;
undef $photo;
$poster = 1;
}
}
除此之外我没有任何东西,因为它不起作用。我得到的错误是
Can't locate object method "findvalues" via package "XML::LibXML::Element"
作为此问题的奖励,如果我想完全删除包含照片和/或海报的<Metadata>
(和所有孩子),该怎么办?
答案 0 :(得分:3)
尝试初学者。
#!/usr/bin/perl
use strict;
use XML::LibXML;
my $xml2 = XML::LibXML->new();
my $data = $xml2->parse_file("adi.xml");
foreach my $test ($data->findnodes('//Metadata')) {
if ($test->findnodes('./ADI/@Name[.="movie"]')){
print "movie\n";
}
elsif ($test->findnodes('./ADI/@Name[.="photo"]')){
print "photo\n";
}
elsif ($test->findnodes('./ADI/@Name[.="poster"]')){
print "poster\n";
}
}
没有findvalues
方法。你想要做的是使用findnodes
,它会返回一个与XPath表达式匹配的节点列表。完成后,您可以遍历列表并提取所需的任何数据,就像您已经为Metadata
所做的那样。
另外,我假设你的XML文件有一个单一的根级元素。我使用下面的修改版本来测试上面的代码。
<root>
<Metadata>
<ADI Name="movie" />
<App_Data Name="Something I don't care about" value="who cares" />
<App_Data Name="Something I don't care about as well" value="who cares" />
<App_Data Name="ChangeMe" Value="" />
</Metadata>
<Metadata>
<ADI Name="photo" />
<App_Data Name="Something I don't care about" value="who cares" />
<App_Data Name="Something I don't care about as well" value="who cares" />
<App_Data Name="ChangeMe" Value="" />
</Metadata>
<Metadata>
<ADI Name="poster" />
<App_Data Name="Something I don't care about" value="who cares" />
<App_Data Name="Something I don't care about as well" value="who cares" />
<App_Data Name="ChangeMe" Value="" />
</Metadata>
</root>
我发现this cheatsheet对Perl的LibXML库很有用。
答案 1 :(得分:2)
您在哪里找到findvalues
?文档:
@nodes = $node->findnodes( $xpath_expression );
$result = $node->find( $xpath );
print $node->findvalue( $xpath );
为什么.
使用了这么多?
./ADI/@Name[.="movie"]
应该是
ADI[@Name="movie"]
您有多个元数据元素,但您只根据最后一个元素设置变量。
您不应该使用三个不同的变量来存储一条信息。
#!/usr/bin/perl
use strict;
use warnings;
use XML::LibXML qw( );
my $parser = XML::LibXML->new();
my $doc = $parser->parse_file("adi.xml");
for my $metadata ($doc->findnodes('//Metadata')) {
my ($adi_type) = $metadata->find('ADI/@Name')
or next;
my ($app_data) = $metadata->find('App_Data[@Name="ChangeMe"]');
if ($adi_type eq 'movie') {
...
}
elsif ($adi_type eq 'photo') {
...
}
elsif ($adi_type eq 'poster') {
...
}
}
或者您甚至可以使用:
my ($movie_adi) = $doc->findnodes('//Metadata[ADI/@Name="movie"]');
my ($movie_app_data) = $movie_adi->findnodes('App_Data[@Name="ChangeMe"]');
...
my ($photo_adi) = $doc->findnodes('//Metadata[ADI/@Name="photo"]');
my ($photo_app_data) = $photo_adi->findnodes('App_Data[@Name="ChangeMe"]');
...
my ($poster_adi) = $doc->findnodes('//Metadata[ADI/@Name="poster"]');
my ($poster_app_data) = $poster_adi->findnodes('App_Data[@Name="ChangeMe"]');
...
答案 2 :(得分:2)
可以在XPath表达式中完成很多工作,以找到您感兴趣的节点。
这个程序会按你的要求做。我在数据中添加了一个根元素<root>
,使其成为格式良好的XML文档。
use strict;
use warnings;
use XML::LibXML;
my $doc = XML::LibXML->load_xml(location => 'adi.xml', no_blanks => 1);
for my $metadata ($doc->findnodes('//Metadata')) {
if ( $metadata->findnodes('ADI[@Name = "movie" or @Name = "photo"]') ) {
$metadata->parentNode->removeChild($metadata);
}
}
print $doc->toString(1);
<强>输出强>
<?xml version="1.0"?>
<root>
<Metadata>
<ADI Name="poster"/>
<App_Data Name="Something I don't care about" value="who cares"/>
<App_Data Name="Something I don't care about as well" value="who cares"/>
<App_Data Name="ChangeMe" Value=""/>
</Metadata>
</root>