我的评论位于我正在处理的元素之前,并且希望用新评论替换它们。
我可以使用insert_new_elt(before ...)
添加新评论,但无法找到获取旧评论并替换旧评论的方法。
#!/usr/bin/perl
use common::sense;
use XML::Twig;
my $twig = XML::Twig->new(
twig_roots => { 'el' => sub { process_el(@_) } },
comments => "process",
pretty_print => "indented_c",
twig_print_outside_roots => 1,
);
$twig->parse(join('', <DATA>)) or die "Could not parse\n";
$twig->flush();
sub process_el {
my( $t, $e)= @_;
my $text = $e->text;
# replace old comment before this element ?
$e->insert_new_elt( before => '#COMMENT', "new comment on $text");
$e->flush();
}
__DATA__
<?xml version="1.0" encoding="utf-8"?>
<root>
<!-- old comment 1 -->
<el>element 1</el>
<el>element 2 without comment before</el>
<!-- old comment 3 -->
<el>element 3</el>
</root>
(我还需要检测实际上是否在元素之前发表评论。如果没有,我显然无法替换它)
我尝试prev_sibling
,但这给了我前面的元素,而不是中间的评论。
上面的代码用于插入新注释,但保留旧注释,这是我不想要的。
答案 0 :(得分:2)
问题来自于使用twig_roots
:注释不会被占用,因为它们不是根,因此XML :: Twig从未真正看到它们,只是打印出来的asis。
因此,您需要使用twig_handlers
代替twig_roots
,并删除twig_print_outside_roots
选项。然后,如果仍然使用flush
,则会遇到格式化问题,注释将打印在与前一个元素相同的行上。我不知道你获得所展示的具体格式有多重要。
为了获得您想要的内容,我删除了flush
并在解析后使用了一个简单的print
。根据您的约束(例如,大型XML文件),您可能希望使用flush
,如果需要在结果上使用xml_pp
以获得所需的格式(它可以正常工作)。
#!/usr/bin/perl
use common::sense;
use XML::Twig;
my $twig = XML::Twig->new(
twig_handlers => { 'el' => sub { process_el(@_) } },
comments => "process",
pretty_print => "indented",
);
$twig->parse(join('', <DATA>)) or die "Could not parse\n";
$twig->print();
sub process_el {
my( $t, $e)= @_;
my $text = $e->text;
if( $e->prev_sibling && $e->prev_sibling->is( '#COMMENT'))
{ $e->prev_sibling->cut; }
# replace old comment before this element ?
$e->insert_new_elt( before => '#COMMENT', "new comment on $text");
}
__DATA__
<?xml version="1.0" encoding="utf-8"?>
<root>
<!-- old comment 1 -->
<el>element 1</el>
<el>element 2 without comment before</el>
<!-- old comment 3 -->
<el>element 3</el>
</root>
答案 1 :(得分:1)
替代方法,使用XML::XSH2,XML::LibXML的包装:
open file.xml ;
for //el {
my $c = (preceding-sibling::* | preceding-sibling::comment() )[last()] ;
if $c/self::comment() delete $c ;
insert comment text() before . ;
}
save :b ;