2017-04-06 15 views
0

我正在循环一个树枝的后代,并且在这个循环中我想创建一个新的树枝以后输出这些新的树枝基本上是当前环状物品的包装版本。了解XML :: Twig的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> 

换句话说,该属性被添加到最初的“根”,并且没有包装发生。但我想要实现的是:

<treebank id="someid" c="d"> 
    <trees> 
    <tree> 
     <node begin="0"> 
     <node a="b"></node> 
     </node> 
    </tree> 
    </trees> 
</treebank> 

有趣的是,当我打电话$_->root我能看到原始根($twig的根),所以我想根被隐式继承的对象的一部分。我认为这就是我的大部分困惑所在:特殊$_root实际上是$twig的根,而不是子树本身的根。

什么是正确的方式来采取输入树枝后裔,把它变成一个具有包装结构的树枝?

+0

(不是我的DV)。我能否提出一些完整的示例XML输入将有助于大量了解您的代码目前的功能? – Sobrique

+0

你迫切需要阅读[*我如何问一个好问题?*](http://stackoverflow.com/questions/how-to-ask) 和[*如何创建一个最小,完整和可验证的例子*](http://stackoverflow.com/help/mcve)。我记不得任何提供足够信息的许多问题,甚至无法正确理解您的情况,也不会介意MCVE能够简单复制代码和数据并运行它的理想。 – Borodin

+0

你是否意识到'descendants_or_self'只是返回对象元素及其所有后代?你通过所有这些元素的循环,并为他们每个人,包裹整个文档的根节点的'tree'元素,产生像' ...'。我相信那不是你想要的。 – Borodin

回答

1

正常情况下,当试图创建这样的子文档时,我只是创建一个新文档,并插入一个复制节点。

事情是这样的:

#!/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文档根。这是一个特殊情况的XML元素,并且root指向顶层,因为它是节点上下文的一部分。

wrap_in是用于修改节点一个特例,但它不会有一个根节点工作,因为他们是一个特殊情况。所以,你可以(用我上面的例子):

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::Twigcutpaste方法分开了这一点,