2017-04-06 54 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方法分開了這一點,