0

我是新手XML::Twig

我需要将子标签移动到子标签。

我怎样才能做到这一点?

当我notes将父标签与子标签匹配到之前的部分时。

我的 XML 如下所示:

<book>
  <sec>
    <p>The indicated something</p>
    <p>The something</p>
  </sec>
  <sec>
    <notes>note</notes>
    <p>text</p>
  </sec>

  <sec>
    <p>The indicated</p>
    <p>The something</p>
  </sec>
  <sec>
    <notes>note</notes>
    <p>text1</p>
  </sec>

</book>

我试过:

use XML::Twig;

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

my $story_file = XML::Twig->new(
    keep_encoding => 1,
    twig_handlers => { 'book' => \&book, },
    pretty_print  => 'indented',
);
$story_file->parse("sample.xml");
$story_file->print($output);
$story_file->purge;

sub book {
    my ($stroy_file, $book) = @_;
    my @sub_elmt = $book->children;
    Get_children(\@sub_elmt) if ($#sub_elmt >= 0);
}

sub Get_children {
    my ($ref) = @_;
    foreach my $tagg (@$ref) {
        my @children = $tagg->children;
        my $tagName  = $tagg->name;
        if ($tagName =~ /^sec$/) {
            my $f = $tagg->first_child;
            if ($f->name =~ /^notes$/) {
                $tagg->move('last_child', $tagg);
            }
        }
        Get_children(\@children) if ($#children >= 0);
    }
}

它不能工作,我该怎么做?

我需要这样的输出:

<book>
  <sec>
    <p>The indicated something</p>
    <p>The something</p>
    <sec>
      <notes>note</notes>
      <p>text</p>
    </sec>
  </sec>
  <sec>
    <p>The indicated</p>
    <p>The something</p>
    <sec>
      <notes>note</notes>
      <p>text1</p>
    </sec>
  </sec>
</book>

我该怎么做?

4

2 回答 2

1

XML::Twig使用 逐个处理非常大的 XML 文档可能非常有用twig_handlers,但您不必那样使用它。它将构建一个完整的 XML 文档树,并让您像大多数其他 XML 模块一样操作该树并将其打印出来。

该程序从 读取整个文档sample.xml,然后搜索notes元素内的所有sec元素。使用 找到包含sec元素,使用 找到parent前一个sec元素(要插入的元素)prev_sibling。然后move用于将sec元素重新定位为前一个的最后一个子元素sec

use strict;
use warnings;

use XML::Twig;

my $twig = XML::Twig->new;
$twig->parsefile('sample.xml');

for my $notes ( $twig->findnodes('//sec/notes') ) {
  my $sec = $notes->parent;
  my $prev_sec = $sec->prev_sibling('sec');
  $sec->move(last_child => $prev_sec);
}

$twig->print_to_file('output.xml', pretty_print => 'indented');

输出

<book>
  <sec>
    <p>The indicated something</p>
    <p>The something</p>
    <sec>
      <notes>note</notes>
      <p>text</p>
    </sec>
  </sec>
  <sec>
    <p>The indicated</p>
    <p>The something</p>
    <sec>
      <notes>note</notes>
      <p>text1</p>
    </sec>
  </sec>
</book>
于 2013-03-21T22:01:38.983 回答
0

您的 XML 和 Perl 脚本中都有一些拼写错误。注意。我已经修改并整理了您的 XML 示例(请参阅注释标签)。

你的主要问题是$tagg->move移动到$tagg(即它本身!)所以这不起作用:(

下面是我的简化版本,它可以满足您的要求(即,当它看到book/sec带有第一个孩子的标签时,notes它会将其移动sec到 previous 的末尾sec)并演示如何->move工作。

use strict;
use warnings;
use XML::Twig; 

my $book_sec = do {
    my $last_sec;
    sub {
        my ($twig, $sec) = @_;

        # if <sec> has first child <notes> then this needs
        # to be moved to end of previous <sec>

        $sec->move( 'last_child', $last_sec ) 
            if $sec->first_child('notes') && $last_sec;

        $last_sec = $sec;   # cache that last <sec>
    };
};

XML::Twig->new(
    twig_handlers => { 'book/sec' => $book_sec },
    pretty_print  => 'indented',
)->parsefile( 'sample.xml' )->print_to_file( 'output.xml' );
于 2013-03-21T15:26:26.693 回答