XML::Twig 根据节点存在更改标签或创建元素
XML::Twig change tag or create element based on node existence
我有一个 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" );
这是一个使用递归子程序的相当简单的任务
在下面的程序中,每次调用 add_xpath
都会增加 $node
的值并从 $path
参数
中的 XPath 表达式中删除一个步骤
如果路径以斜杠和标签名称开头,则会检查标签名称以确保它与根元素的名称相匹配。然后将当前节点设置为根元素,子程序递归
如果路径立即以标记名称开始,则调用 has_child
以查看该名称的子项是否已存在。如果不是,则 insert_new_elt
为我们添加一个。当前节点设置为新的或预先存在的子节点并且子例程递归
否则路径应该为空,检查确定。然后调用set_text
设置当前节点的文本内容,递归终止
输出显示了您在问题中显示的三个操作中的每一个之后的结果 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 = ;
$node = $node->root;
carp "Root element has wrong tag name" unless $node->tag eq $tag;
}
elsif ( $path =~ s|^(\w+)/?|| ) {
my $tag = ;
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>
我有一个 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" );
这是一个使用递归子程序的相当简单的任务
在下面的程序中,每次调用 add_xpath
都会增加 $node
的值并从 $path
参数
如果路径以斜杠和标签名称开头,则会检查标签名称以确保它与根元素的名称相匹配。然后将当前节点设置为根元素,子程序递归
如果路径立即以标记名称开始,则调用
has_child
以查看该名称的子项是否已存在。如果不是,则insert_new_elt
为我们添加一个。当前节点设置为新的或预先存在的子节点并且子例程递归否则路径应该为空,检查确定。然后调用
set_text
设置当前节点的文本内容,递归终止
输出显示了您在问题中显示的三个操作中的每一个之后的结果 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 = ;
$node = $node->root;
carp "Root element has wrong tag name" unless $node->tag eq $tag;
}
elsif ( $path =~ s|^(\w+)/?|| ) {
my $tag = ;
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>