1

我在我正在处理的元素之前有评论,并想用新评论替换它们。

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

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

4

2 回答 2

2

问题来自于使用twig_roots:注释没有被处理,因为它们不是根,所以 XML::Twig 从来没有真正看到它们,只是按原样打印。

因此,您需要使用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>
于 2013-08-15T10:35:19.017 回答
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 ;
于 2013-08-15T10:46:12.963 回答