如何将子标签移动到子级

时间:2013-03-21 11:39:27

标签: perl

我是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>

我是怎么做到的?

2 个答案:

答案 0 :(得分:1)

XML::Twig对于使用twig_handlers逐个处理非常大的XML文档非常有用,但是 没有像这样使用它。它将构建一个完整的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>

答案 1 :(得分:0)

您的XML和Perl脚本中都存在一些拼写错误。 NB。我修改了&amp;整理了您的XML示例(请参阅 notes 标记)。

您的主要问题是$tagg->move正在转移到$tagg(即本身!),因此无效:(

下面是我的简化版本,可以满足您的需求(即,当它看到book/sec标记带有第一个孩子notes时,它会将此sec移到上一个{{1}的末尾}}并演示sec的工作原理。

->move