我有下面的xml文件,在这里我想编写一个perl脚本,这样我就可以在第一本书名称和作者名称上进行grep,如果两者匹配,则更改字段" value"从虚假到真实。例如,如果书名是abc且作者姓名是john,则将值从false更改为true。
use warnings;
use strict;
use XML::LibXML;
my $parser = XML::LibXML->new();
my $xmldoc = $parser->parse_file('b.xml');
for my $book ($xmldoc->findnodes('/library/book')) {
my $name = $book->findvalue('/@name');
if($name eq "abc")
{
print "yes" ;
}
}
<library>
<book name="abc" id="3">
<key name="history">
<default label="base" value="1"/>
</key>
<author name="john">
<default label="base" value="false"/>
</author>
</book>
<book name="xyz" id="4">
<key name="science">
<default label="base" value="1"/>
</key>
<author name="nik">
<default label="base" value="false"/>
</author>
</book>
我是perl的新手,有人可以帮助我吗?我已经写了一些代码来达到第一点来检查作者名称,但这本身不起作用。
答案 0 :(得分:2)
for my $default_author_node ($xmldoc->findnodes(
'/library/book[@name="abc"]/author[@name="john"]/default'
)) {
$default_author_node->setAttribute('value', 'true');
}
但您可能希望名称可变。
解决方案1:动态构建上述XPath。
sub text_to_xpath {
my ($s) = @_;
return qq{"$s"} if $s !~ tr/"//;
return qq{'$s'} if $s !~ tr/'//;
$s = s/"/", '"', "/g;
return qq{concat("$s")};
}
my $target_book_xp = text_to_xpath($target_book);
my $target_author_xp = text_to_xpath($target_author);
for my $default_author_node ($xmldoc->findnodes(
"/library/book[\@name=$target_book_xp]/author[\@name=$target_author_xp]/default"
)) {
$default_author_node->setAttribute('value', 'true');
}
解决方案2:自己做检查。
这是您尝试的内容,但XPath /@name
在文档的根目录@
获取名为name
的子属性(/
),但是只有节点有根元素(library
)。就像在目录路径中一样,如果要相对于上下文进行搜索,请不要使用前导/
。
for my $book_node ($xmldoc->findnodes('/library/book')) {
my $name = $book_node->getAttribute('name');
next if !defined($name) || $name ne $target_book;
for my $author_node ($book_node->findnodes('author')) {
my $name = $book_node->getAttribute('name');
next if !defined($name) || $name ne $target_author;
for my $default_author_node ($author_node->findnodes('default')) {
$default_author_node->setAttribute('value', 'true');
}
}
}