XML :: Twig取代以前的评论

时间:2013-08-15 10:17:36

标签: xml perl xml-twig

我的评论位于我正在处理的元素之前,并且希望用新评论替换它们。

我可以使用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,但这给了我前面的元素,而不是中间的评论。

上面的代码用于插入新注释,但保留旧注释,这是我不想要的。

2 个答案:

答案 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::XSH2XML::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 ;