2015-06-12 53 views
4

隨着使用set_text方法XML::Twig set_text - 有一個警告:XML ::嫩枝 - 沒有重挫結構

set_text($字符串) 設置文本的元素:如果元素是PCDATA,只需設置其文本,否則剪切該元素的所有子元素併爲其創建一個包含文本的PCDATA子元素。

所以,如果我想要做簡單的東西,比如 - 說 - 在我的XML改變所有文本的情況下::文件:

#!/usr/bin/perl 

use strict; 
use warnings; 

use XML::Twig; 

my $twig = XML::Twig->new(
    'pretty_print' => 'indented_a', 
    'twig_handlers' => { 
     '_all_' => sub { 
      my $newtext = $_->text_only; 
      $newtext =~ tr/[a-z]/[A-Z]/; 
      $_->set_text($newtext); 
     } 
    } 
); 
$twig->parse(\*DATA); 
$twig->print; 

__DATA__ 
<root> 
    <some_content>fish 
     <a_subnode>morefish</a_subnode> 
    </some_content> 
    <some_more_content>cabbage</some_more_content> 
</root> 

這一點 - 因爲set_text代替孩子 - 被打一頓成:

<root></root> 

但如果我只專注於一個(底層)節點(例如a_subnode),那麼它工作正常。

有沒有一種優雅的方式來替換/轉換元素內的文本,而不會破壞它下面的數據結構?我的意思是,我可以測試孩子的存在或類似的東西,但是...似乎應該有一個更好的方法來做到這一點。 (一個不同的庫可能?)

(爲了清楚起見 - 這是我在文檔中音譯所有文本的示例,我的實際使用案例更加複雜,但仍在'關於'文本改造的探討)。我正在考慮可能是節點剪切/粘貼方法(剪切所有的孩子,替換文本,粘貼所有的孩子),但這似乎是一種低效率的方法。

+0

測試是否有孩子聽起來像一個好主意。 – simbabque

回答

4

而不必在_all_處理程序,儘量讓它只在文本元素:#TEXT,並改變text_onlytext。它應該工作。

更新:或者在創建小枝char_handler => sub { uc shift },而不是處理程序時使用char_handler選項。

+1

它非常接近(可能足夠滿足我的需求)。但是它不能提供所需的輸出,因爲它不會調整頂級'some_content'節點。 (大概是因爲有小孩的存在?) – Sobrique

+0

Drats!我錯過了這一點。它看起來像一個錯誤。當文本後面跟着一個打開的標籤時,處理程序不會被調用。我會檢查我們。 – mirod

+0

可能。我不確定,因爲'text'和'text_only'有一些奇怪的地方。它似乎也是以非指定縮進格式的方式重新格式化的。 (但我也可以接受)。 – Sobrique

2

我目前的做法是:

  • 迭代所有節點。
  • cut所有的孩子。
  • 修改文字。
  • paste所有的孩子。

這似乎效率不高,但它似乎工作:

#!/usr/bin/perl 

use strict; 
use warnings; 

use XML::Twig; 
use Data::Dumper; 

sub replace_text { 
    my ($twig, $element) = @_; 

    my $newtext = $element->text_only; 
    my @children; 
    foreach my $child ($element->children) { 
     if (not $child->tag eq "#PCDATA") { 
      push(@children, $child->cut); 
     } 
    } 
    $newtext =~ tr/[a-z]/[A-Z]/; 
    $element->set_text($newtext); 

    $_->paste('last_child', $element) for @children; 
} 

my $twig = 
    XML::Twig->new('twig_handlers' => { '_all_' => \&replace_text, }); 
$twig->parse(\*DATA); 

print "Result:\n"; 
$twig->print; 

__DATA__ 
<root> 
    <some_content>fish 
     <a_subnode>morefish</a_subnode> 
    </some_content> 
    <some_more_content>cabbage</some_more_content> 
</root> 

這令我輸出到:

<root><some_content>FISH 
     <a_subnode>MOREFISH</a_subnode></some_content><some_more_content>CABBAGE</some_more_content></root> 

因此,雖然它並transmogrify的節點,也出於某種原因,打破輸出格式。

重新分析它:

XML::Twig -> new ('pretty_print' => 'indented_a') -> parse ($twig -> sprint) -> print; 

似乎這樣的伎倆。 (雖然雙解析只是爲了重新格式化,看起來更不優雅)

<root> 
    <some_content>FISH 
     <a_subnode>MOREFISH</a_subnode></some_content> 
    <some_more_content>CABBAGE</some_more_content> 
</root>