1

我是 xml-twig 的新手,如何拆分父标签?

文件:

<xml>
   <p class="indent">text text incluce <div>text</div> ateas</p>
   <p class="text">text text incluce <div>text</div> ateas</p>
</xml>

我需要输出为:

<xml>
   <p class="indent">text text incluce</p>
   <div>text</div>
   <p class="indent">ateas</p>
   <p class="text">text text incluce</p>
    <div>text</div>
   <p class="text">ateas</p>
</xml>

如何拆分标签?

use strict;
use XML::Twig;

open(my $output , '>', "split.xml") || die "can't open the Output $!\n";

my $xml_twig_content = XML::Twig->new(
        'p' => \&split, )

$xml_twig_content->parsefile("sample.xml");
$xml_twig_content->print($output);

sub split{
        my ($xml_twig_content, $p) = @_;

}

如何拆分标签?...

4

2 回答 2

1

可能有几种方法可以做到这一点。以下代码使用wrap_in,它在所有文本节点周围添加一个新<p>的,然后erase删除原来的<p>. atts用于将原始属性复制<p>到新属性。

#!/usr/bin/perl
use warnings;
use strict;

use XML::Twig;

open(my $output , '>', "split.xml") || die "can't open the Output $!\n";

my $xml = XML::Twig->new( twig_handlers => { p => \&split_tag } );

$xml->parsefile("1.xml");
$xml->print($output);

sub split_tag {
    my ($twig, $p) = @_;
    $_->wrap_in('p', $p->atts) for $p->children('#TEXT');
    $p->erase;
}

顺便说一句,请发布可运行的代码。您的示例代码遗漏了重要部分(tgtwig_handlers或分号)。

对于您的附加约束,您可以按如下方式弯曲脚本:

sub split_tag {
    my ($twig, $p) = @_;
  CHILD:
    for my $ch ($p->children(sub {'div' ne shift->name})) {
        my $wrap = $ch->wrap_in('p', $p->atts);
        my $prev = $wrap->prev_sibling or next CHILD;
        $prev->merge($wrap) if 'p' eq $prev->name;
    }
    $p->erase;
}
于 2013-01-04T13:45:33.307 回答
0

很大程度上取决于完整 XML 数据的性质。例如,如果您期望嵌套<p>元素,则解决方案要复杂得多,并且需要更好地定义行为。

但是,该程序似乎可以满足您的需要,并且可以处理您的示例数据。与在您自己的代码中一样,split子例程处理遇到的每个<p>元素。如果元素只包含文本,则元素保持不变,否则子元素将被分离并用于在 array 中创建替换节点列表@split。此列表中的文本节点通过创建父<p>元素的克隆并将文本粘贴为其内容进行转换。一旦所有文本节点都被修改,调用将replace_with用新的元素列表替换原始<p>元素。

请注意,该print_to_file方法避免了单独打开输出文件的需要。

use strict;
use warnings;

use XML::Twig;

my $twig = XML::Twig->new(
  twig_handlers => { p => \&split },
);

$twig ->parsefile('sample.xml');
$twig->print_to_file('split.xml', pretty_print => 'indented');

sub split{
  my ($twig, $p) = @_;
  return if $p->contains_only_text;

  my @split = $p->cut_children;
  for my $child (grep $_->is_pcdata, @split) {
    my $text = $child;
    $child = $p->copy;
    $text->paste(last_child => $child);
  }

  $p->replace_with(@split);
}

输出

<xml>
  <p class="indent">text text incluce </p>
  <div>text</div>
  <p class="indent"> ateas</p>
  <p class="text">text text incluce </p>
  <div>text</div>
  <p class="text"> ateas</p>
</xml>
于 2013-01-05T15:30:59.537 回答