2015-04-24 51 views
3

我有一些XML,看起來像這樣:使用XML :: Twig,有沒有找到具有特定屬性的'first_child'的方法?

<?xml version="1.0" encoding="UTF-8"?> 
<DataSet> 
<Category> 
    <Name mode="source">somename</Name> 
    <Name mode="destination">someothername</Name> 
    <Content>Some text here</Content> 
</Category> 
</DataSet> 

我試圖做的是過程中的「類別」,並提取基於上下文不同的名稱。

我試着children迭代它 - 這個工程:

use strict; 
use warnings; 
use XML::Twig; 

sub process_category { 
    my ($twig, $category) = @_; 
    my $cat_name; 
    foreach my $name ($category->children('Name')) { 
     if ($name->att('mode') eq 'source') { 
      $cat_name = $name->text; 
     } 
    } 

    print "$cat_name ", $category->first_child_text('Content'), "\n"; 
} 

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


__DATA__ 
<?xml version="1.0" encoding="UTF-8"?> 
<DataSet> 
<Category> 
    <Name mode="source">somename</Name> 
    <Name mode="destination">someothername</Name> 
    <Content>Some Text</Content> 
</Category> 
</DataSet> 

但是我想知道 - 有超過迭代的元素更好的辦法?我無法弄清楚first_child是否支持屬性搜索,或者是否有另一種方法。

回答

4

使用XML :: Twig的get_xpath方法來搜索屬性中的匹配值。例如:

my $cat_name = $category->get_xpath('./Name[@mode="source"]', 0)->text; 

默認情況下,get_xpath返回一個數組。通過傳遞「0」,只傳遞數組的第一個元素(這是你需要的,可能只有一個匹配)。然後,文本被提出->text。使用它,你可以刪除你的for循環。

+0

可愛,這聽起來甚至比我在看的代碼ref解決方案更好。 – Sobrique

0

您可以將code_ref傳遞給first_child。這個子元素依次交給每個元素,如果它返回'真',那麼first_child方法匹配。 (然後不會繼續尋找)。

所以這應該做的伎倆:

use strict; 
use warnings; 
use XML::Twig; 

sub is_name_source { 
    my ($element) = @_; 

    print $element ->tag, "\n"; 
    if ( $element->tag eq 'Name' 
     and $element->att('mode') eq 'source') 
    { 
     return 1; 
    } 
} 

sub process_category { 
    my ($twig, $category) = @_; 
    my $cat_name = $category->first_child(\&is_name_source)->text; 
    print "$cat_name ", $category->first_child_text('Content'), "\n"; 
} 

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


__DATA__ 
<?xml version="1.0" encoding="UTF-8"?> 
<DataSet> 
<Category> 
    <Name mode="source">somename</Name> 
    <Name mode="destination">someothername</Name> 
    <Content>Some Text</Content> 
</Category> 
</DataSet> 

你當然可以,內嵌is_name_source與匿名子。這是一個品味問題。

相關問題