我有一个XML(示例)文件:test.xml
<root>
<tag1>AAA</tag1>
<tag2>BBB</tag2>
<tag3>
<tag4>DDD</tag4>
</tag3>
</root>
我想要实现的结果是,设置两个变量(来自输入):即:
my $xpath = '/root/tag3/tag4'; # or '/root/tag2/tag5' or '/root/tag6'
my $xvalue = 'CCC'; # or 'EEE'
该脚本将检查$ xpath变量,如果它存在于XML文件中,则它会更改它的文本。如果它不存在于XML文件中,那么它将使用$ xpath和$ xvalue创建元素。
我使用下面的脚本来设置$ xpath的文本,但是如何修改它以便它可以根据$ xpath存在做正确的事情?非常感谢,
open( my $output, '>', "$ofile") or die "cannot create $ofile: $!";
XML::Twig->new( twig_roots => { "$xpath" =>
sub { my $text= $_->text();
$_->set_text($xvalue);
$_->flush;
},
},
twig_print_outside_roots => $output,
pretty_print => 'indented',
)
->parsefile( "test.xml" );
答案 0 :(得分:4)
使用递归子程序
这是一项相当简单的任务在下面的程序中,每次调用add_xpath
都会提升$node
的值,并从$path
参数中的XPath表达式中删除一步
如果路径以斜杠和标记名称开头,则检查标记名称以确保它与根元素的名称匹配。然后将当前节点设置为根元素,子例程将递归
如果路径立即以标记名称开头,则调用has_child
以查看该名称的子项是否已存在。如果没有,则insert_new_elt
为我们添加一个。当前节点设置为新的或预先存在的子节点,子例程递归
否则路径应为空,并检查以确保路径。然后调用set_text
来设置currenty节点的文本内容,并且递归终止
输出显示在您在问题中显示的三个操作中的每一个之后生成的XML结构
use strict;
use warnings;
use XML::Twig;
use Carp;
my $twig = XML::Twig->new;
$twig->parsefile('test.xml');
$twig->set_pretty_print('indented');
print $twig->sprint, "\n";
add_xpath($twig->root, '/root/tag3/tag4', 'CCC');
print $twig->sprint, "\n";
add_xpath($twig->root, '/root/tag2/tag5', 'EEE');
print $twig->sprint, "\n";
add_xpath($twig->root, '/root/tag6', 'GGG');
print $twig->sprint, "\n";
sub add_xpath {
my ($node, $path, $value) = @_;
if ( $path =~ s|^/(\w+)/?|| ) {
my $tag = $1;
$node = $node->root;
carp "Root element has wrong tag name" unless $node->tag eq $tag;
}
elsif ( $path =~ s|^(\w+)/?|| ) {
my $tag = $1;
if ( my $child = $node->has_child($tag) ) {
$node = $child;
}
else {
$node = $node->insert_new_elt('last_child', $tag);
}
}
else {
carp qq{Invalid path at "$path"} if $path =~ /\S/;
$node->set_text($value);
return 1;
}
add_xpath($node, $path, $value);
}
<root>
<tag1>AAA</tag1>
<tag2>BBB</tag2>
<tag3>
<tag4>DDD</tag4>
</tag3>
</root>
<root>
<tag1>AAA</tag1>
<tag2>BBB</tag2>
<tag3>
<tag4>CCC</tag4>
</tag3>
</root>
<root>
<tag1>AAA</tag1>
<tag2>BBB<tag5>EEE</tag5></tag2>
<tag3>
<tag4>CCC</tag4>
</tag3>
</root>
<root>
<tag1>AAA</tag1>
<tag2>BBB<tag5>EEE</tag5></tag2>
<tag3>
<tag4>CCC</tag4>
</tag3>
<tag6>GGG</tag6>
</root>