了解 XML::Twig"s wrap_in
Understanding XML::Twig"s wrap_in
我正在遍历树枝的后代,在这个循环中我想创建新的树枝以供稍后输出。那些新的树枝基本上是当前循环项目的包装版本。像这样:
# $twig already exists.
my @descendants = $twig->root->first_child->descendants_or_self;
foreach (@descendants) {
$_->root->wrap_in('tree');
my $treetop = XML::Twig->new()->set_root($_);
$treetop->root->wrap_in('trees', treebank => {
id => 'someid'
});
if (exists $hash{'somekey'}) {
$treetop->root->set_att(c => 'd');
}
}
循环中$_->sprint
的例子:
<node begin="0">
<node a="b"></node>
</node>
但是,这个(在最后一个 if 子句之后)的结果是 ($treetop->sprint
):
<node begin="0" c="d">
<node a="b"></node>
</node>
换句话说,属性被添加到初始 'root',并且没有发生换行。但我想要实现的是:
<treebank id="someid" c="d">
<trees>
<tree>
<node begin="0">
<node a="b"></node>
</node>
</tree>
</trees>
</treebank>
有趣的是,当我调用 $_->root
时,我看到了原始根($twig
的根),所以我猜根是作为对象的一部分隐式继承的。我认为这就是我最困惑的地方:特殊 $_
的 root
实际上是 $twig
的根,而不是子树本身的根。
将输入的 twig 后代变成具有包装结构的 twig 的正确方法是什么?
通常在尝试创建这样的子文档时,我只是创建一个新的,然后插入一个复制的节点。
像这样:
#!/usr/bin/env perl
use strict;
use warnings;
use XML::Twig;
my $twig = XML::Twig->new->parse( \*DATA );
foreach my $node ( $twig->get_xpath('./node') ) {
my $new_root =
XML::Twig::Elt->new( 'treebank', { id => "someid", c => "d" } );
my $new_doc = XML::Twig->new->set_root($new_root);
$new_doc->set_xml_version('1.0');
my $tree = $new_doc->root->insert_new_elt('trees')->insert_new_elt('tree');
$node->cut;
$node->paste( 'last_child', $tree );
$new_doc->set_pretty_print('indented');
$new_doc->print;
}
__DATA__
<xml>
<node begin="0" c="d">
<node a="b"></node>
</node>
</xml>
但是为了解决您的具体问题 - 是的,root
确实提供了 document 根目录。这是一个特例 XML 元素,root
将您指向顶层,因为它是节点上下文的一部分。
wrap_in
是修改 node 的特例,但它不适用于根节点,因为它们是特例。所以你可以(使用我上面的例子):
foreach my $node ( $twig->get_xpath('./node') ) {
my $new_doc = XML::Twig->new;
$new_doc->set_xml_version('1.0');
$node->cut;
$new_doc->set_root ($node);
$node->wrap_in( 'trees', treebank => { id => 'someid' } );
$new_doc->set_pretty_print('indented');
$new_doc->print;
}
您可以使用 XML::Twig
、
的 cut
和 paste
方法将其分开
我正在遍历树枝的后代,在这个循环中我想创建新的树枝以供稍后输出。那些新的树枝基本上是当前循环项目的包装版本。像这样:
# $twig already exists.
my @descendants = $twig->root->first_child->descendants_or_self;
foreach (@descendants) {
$_->root->wrap_in('tree');
my $treetop = XML::Twig->new()->set_root($_);
$treetop->root->wrap_in('trees', treebank => {
id => 'someid'
});
if (exists $hash{'somekey'}) {
$treetop->root->set_att(c => 'd');
}
}
循环中$_->sprint
的例子:
<node begin="0">
<node a="b"></node>
</node>
但是,这个(在最后一个 if 子句之后)的结果是 ($treetop->sprint
):
<node begin="0" c="d">
<node a="b"></node>
</node>
换句话说,属性被添加到初始 'root',并且没有发生换行。但我想要实现的是:
<treebank id="someid" c="d">
<trees>
<tree>
<node begin="0">
<node a="b"></node>
</node>
</tree>
</trees>
</treebank>
有趣的是,当我调用 $_->root
时,我看到了原始根($twig
的根),所以我猜根是作为对象的一部分隐式继承的。我认为这就是我最困惑的地方:特殊 $_
的 root
实际上是 $twig
的根,而不是子树本身的根。
将输入的 twig 后代变成具有包装结构的 twig 的正确方法是什么?
通常在尝试创建这样的子文档时,我只是创建一个新的,然后插入一个复制的节点。
像这样:
#!/usr/bin/env perl
use strict;
use warnings;
use XML::Twig;
my $twig = XML::Twig->new->parse( \*DATA );
foreach my $node ( $twig->get_xpath('./node') ) {
my $new_root =
XML::Twig::Elt->new( 'treebank', { id => "someid", c => "d" } );
my $new_doc = XML::Twig->new->set_root($new_root);
$new_doc->set_xml_version('1.0');
my $tree = $new_doc->root->insert_new_elt('trees')->insert_new_elt('tree');
$node->cut;
$node->paste( 'last_child', $tree );
$new_doc->set_pretty_print('indented');
$new_doc->print;
}
__DATA__
<xml>
<node begin="0" c="d">
<node a="b"></node>
</node>
</xml>
但是为了解决您的具体问题 - 是的,root
确实提供了 document 根目录。这是一个特例 XML 元素,root
将您指向顶层,因为它是节点上下文的一部分。
wrap_in
是修改 node 的特例,但它不适用于根节点,因为它们是特例。所以你可以(使用我上面的例子):
foreach my $node ( $twig->get_xpath('./node') ) {
my $new_doc = XML::Twig->new;
$new_doc->set_xml_version('1.0');
$node->cut;
$new_doc->set_root ($node);
$node->wrap_in( 'trees', treebank => { id => 'someid' } );
$new_doc->set_pretty_print('indented');
$new_doc->print;
}
您可以使用 XML::Twig
、
cut
和 paste
方法将其分开