I have a XML (example) file: test.xml
我有一个XML(示例)文件:test.xml。
<root>
<tag1>AAA</tag1>
<tag2>BBB</tag2>
<tag3>
<tag4>DDD</tag4>
</tag3>
</root>
The result I want to achieve is, set two variables (from input): i.e.:
我想要达到的结果是,设置两个变量(来自输入):即:
my $xpath = '/root/tag3/tag4'; # or '/root/tag2/tag5' or '/root/tag6'
my $xvalue = 'CCC'; # or 'EEE'
The script would check the $xpath variable, if it exists in the XML file, then it changes the text of it. If it doesn't exist in the XML file, then it creates the element with $xpath and $xvalue.
脚本将检查$xpath变量,如果它存在于XML文件中,那么它将更改它的文本。如果它不存在于XML文件中,则使用$xpath和$xvalue创建元素。
I use below script to set the text for $xpath, but how to modify it so that it would do proper things based on the $xpath existence? Thanks a lot,
我使用下面的脚本设置$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" );
1 个解决方案
#1
4
It's a fairly simple task using a recursive subroutine
这是一个使用递归子例程的相当简单的任务
In the program below, each call to add_xpath
advances the value of $node
and removes one step from the XPath expression in the $path
parameter
在下面的程序中,每个对add_xpath的调用都会提高$node的值,并从$path参数中的XPath表达式中移除一步。
-
If the path begins with a slash and a tag name then the tag name is checked to make sure it matches the name of the root element. Then the current node is set to the root element and the subroutine recurses
如果路径以斜线和标记名开头,则检查标记名,以确保它与根元素的名称匹配。然后将当前节点设置为根元素,然后将子例程递归
-
If the path starts immediately with a tag name, then
has_child
is called to see if a child of that name already exists. If not theninsert_new_elt
adds one for us. The current node is set to the new or pre-existing child node and the subroutine recurses如果路径立即以标记名开始,则调用has_child来查看该名称的子节点是否已经存在。如果没有,那么insert_new_elt为我们添加一个。当前节点被设置为新的或已存在的子节点,子例程递归
-
Otherwise the path should be empty, and it is checked to make sure. Then
set_text
is called to set the text contents of the currenty node and the recursion terminates否则路径应该为空,并检查它以确保。然后调用set_text来设置currenty节点的文本内容,递归结束
The output show the resulting XML structure after each of the three operations that you show in your question
输出显示了问题中显示的三个操作中的每个操作之后的结果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);
}
output
<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>
#1
4
It's a fairly simple task using a recursive subroutine
这是一个使用递归子例程的相当简单的任务
In the program below, each call to add_xpath
advances the value of $node
and removes one step from the XPath expression in the $path
parameter
在下面的程序中,每个对add_xpath的调用都会提高$node的值,并从$path参数中的XPath表达式中移除一步。
-
If the path begins with a slash and a tag name then the tag name is checked to make sure it matches the name of the root element. Then the current node is set to the root element and the subroutine recurses
如果路径以斜线和标记名开头,则检查标记名,以确保它与根元素的名称匹配。然后将当前节点设置为根元素,然后将子例程递归
-
If the path starts immediately with a tag name, then
has_child
is called to see if a child of that name already exists. If not theninsert_new_elt
adds one for us. The current node is set to the new or pre-existing child node and the subroutine recurses如果路径立即以标记名开始,则调用has_child来查看该名称的子节点是否已经存在。如果没有,那么insert_new_elt为我们添加一个。当前节点被设置为新的或已存在的子节点,子例程递归
-
Otherwise the path should be empty, and it is checked to make sure. Then
set_text
is called to set the text contents of the currenty node and the recursion terminates否则路径应该为空,并检查它以确保。然后调用set_text来设置currenty节点的文本内容,递归结束
The output show the resulting XML structure after each of the three operations that you show in your question
输出显示了问题中显示的三个操作中的每个操作之后的结果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);
}
output
<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>