删除 perl 中除一个节点外的所有节点 XML::Twig
removing all but one node in perl XML::Twig
我有一个包含许多 level3 元素的 xml 文件。我想删除除一个这样的元素之外的所有元素。我的 xml 文件:
<?xml version="1.0" encoding="UTF-8"?>
<level1 id="level1_id">
<level2 id="level2_id">
<level3 id="level3_id1">
<attributes>
<attribute>1</attribute>
<attribute>2</attribute>
</attributes>
</level3>
<level3 id="level3_id2">
<attributes>
<attribute>1</attribute>
<attribute>2</attribute>
</attributes>
</level3>
<level3 id="level3_id3">
<attributes>
<attribute>1</attribute>
<attribute>2</attribute>
</attributes>
</level3>
</level2>
</level1>
我的 perl 脚本:
my $filename = 'test3.xml';
my $outfile = $filename."_after";
open my $output, '>', $outfile or die "Couldn't open output file\n";
my $twig = new XML::Twig (twig_handlers => { 'level2' => \&edit });
$twig->parsefile($filename);
#$twig->flush;
$twig->print($output);
sub edit {
my ($twig, $element) = @_;
my @elements= $element->children('level3');
print $#elements."\n";
my @elements= @elements[1..$#elements];
print $#elements."\n";
my $count = 0;
foreach (@elements){
$count++;
$_->delete;
}
print $count;
$twig->purge;
}
然而,这只留下了 level1 元素:
<?xml version="1.0" encoding="UTF-8"?>
<level1 id="level1_id"></level1>
另一方面,当顶层是 level2 时,我的脚本工作得很好。示例xml文件和处理后的结果:
<?xml version="1.0" encoding="UTF-8"?>
<level2 id="level2_id">
<level3 id="level3_id1">
<attributes>
<attribute>1</attribute>
<attribute>2</attribute>
</attributes>
</level3>
<level3 id="level3_id2">
<attributes>
<attribute>1</attribute>
<attribute>2</attribute>
</attributes>
</level3>
<level3 id="level3_id3">
<attributes>
<attribute>1</attribute>
<attribute>2</attribute>
</attributes>
</level3>
</level2>
结果:
<?xml version="1.0" encoding="UTF-8"?>
<level2 id="level2_id">
<level3 id="level3_id1">
<attributes>
<attribute>1</attribute>
<attribute>2</attribute>
</attributes>
</level3>
</level2>
这正是我想要的,即只剩下一个 level3 元素。我究竟做错了什么?这与我如何定义树枝处理程序有关吗?
我不想硬编码 xml 结构,例如我的 $twig = new XML::Twig (twig_handlers => { 'level1/level2' => \&edit });
我不知道 level2 在实际 xml 文件中有多深,实际文件的结构可能不相同,所以这部分应该是动态的
不需要$twig->purge
行或类似的东西,我不明白你为什么要写它
它将丢弃任何已解析但未打印到输出的内容,即您刚刚编辑的整个 level2
元素
我也推荐你写
my $twig = XML::Twig->new(
twig_handlers => { level2 => \&edit },
pretty_print => 'indented',
);
因为您使用的 间接对象 语法不明确且容易出错。 pretty_print
选项还将使输出 XML 更具可读性。
我建议除非您特别想对大文件进行增量解析,否则 twig_handers
会不必要地复杂化。如果您想将 XML 视为流和其中的 modify/discard 部分,这是一个强大的工具,但实际上通常只是加载整个 XML,并且使用它更简单、更清晰。
您想要做的似乎是删除第一个之后的所有 'level3' 个元素。
所以:
#!/usr/bin/perl
use strict;
use warnings;
use XML::Twig;
my $twig = XML::Twig->new->parsefile('your_xml_file.xml');
my $count;
foreach my $level3 ( $twig->get_xpath('.//level3') ) {
#delete after the first one.
$level3->delete if $count++;
}
#set formatting
$twig -> set_pretty_print('indented_a');
#print to stdout
$twig->print;
我有一个包含许多 level3 元素的 xml 文件。我想删除除一个这样的元素之外的所有元素。我的 xml 文件:
<?xml version="1.0" encoding="UTF-8"?>
<level1 id="level1_id">
<level2 id="level2_id">
<level3 id="level3_id1">
<attributes>
<attribute>1</attribute>
<attribute>2</attribute>
</attributes>
</level3>
<level3 id="level3_id2">
<attributes>
<attribute>1</attribute>
<attribute>2</attribute>
</attributes>
</level3>
<level3 id="level3_id3">
<attributes>
<attribute>1</attribute>
<attribute>2</attribute>
</attributes>
</level3>
</level2>
</level1>
我的 perl 脚本:
my $filename = 'test3.xml';
my $outfile = $filename."_after";
open my $output, '>', $outfile or die "Couldn't open output file\n";
my $twig = new XML::Twig (twig_handlers => { 'level2' => \&edit });
$twig->parsefile($filename);
#$twig->flush;
$twig->print($output);
sub edit {
my ($twig, $element) = @_;
my @elements= $element->children('level3');
print $#elements."\n";
my @elements= @elements[1..$#elements];
print $#elements."\n";
my $count = 0;
foreach (@elements){
$count++;
$_->delete;
}
print $count;
$twig->purge;
}
然而,这只留下了 level1 元素:
<?xml version="1.0" encoding="UTF-8"?>
<level1 id="level1_id"></level1>
另一方面,当顶层是 level2 时,我的脚本工作得很好。示例xml文件和处理后的结果:
<?xml version="1.0" encoding="UTF-8"?>
<level2 id="level2_id">
<level3 id="level3_id1">
<attributes>
<attribute>1</attribute>
<attribute>2</attribute>
</attributes>
</level3>
<level3 id="level3_id2">
<attributes>
<attribute>1</attribute>
<attribute>2</attribute>
</attributes>
</level3>
<level3 id="level3_id3">
<attributes>
<attribute>1</attribute>
<attribute>2</attribute>
</attributes>
</level3>
</level2>
结果:
<?xml version="1.0" encoding="UTF-8"?>
<level2 id="level2_id">
<level3 id="level3_id1">
<attributes>
<attribute>1</attribute>
<attribute>2</attribute>
</attributes>
</level3>
</level2>
这正是我想要的,即只剩下一个 level3 元素。我究竟做错了什么?这与我如何定义树枝处理程序有关吗? 我不想硬编码 xml 结构,例如我的 $twig = new XML::Twig (twig_handlers => { 'level1/level2' => \&edit }); 我不知道 level2 在实际 xml 文件中有多深,实际文件的结构可能不相同,所以这部分应该是动态的
不需要$twig->purge
行或类似的东西,我不明白你为什么要写它
它将丢弃任何已解析但未打印到输出的内容,即您刚刚编辑的整个 level2
元素
我也推荐你写
my $twig = XML::Twig->new(
twig_handlers => { level2 => \&edit },
pretty_print => 'indented',
);
因为您使用的 间接对象 语法不明确且容易出错。 pretty_print
选项还将使输出 XML 更具可读性。
我建议除非您特别想对大文件进行增量解析,否则 twig_handers
会不必要地复杂化。如果您想将 XML 视为流和其中的 modify/discard 部分,这是一个强大的工具,但实际上通常只是加载整个 XML,并且使用它更简单、更清晰。
您想要做的似乎是删除第一个之后的所有 'level3' 个元素。
所以:
#!/usr/bin/perl
use strict;
use warnings;
use XML::Twig;
my $twig = XML::Twig->new->parsefile('your_xml_file.xml');
my $count;
foreach my $level3 ( $twig->get_xpath('.//level3') ) {
#delete after the first one.
$level3->delete if $count++;
}
#set formatting
$twig -> set_pretty_print('indented_a');
#print to stdout
$twig->print;