使用XML :: Twig,有没有办法找到' first_child'具有特定属性?

时间:2015-04-24 20:41:47

标签: xml perl xml-twig

我有一些看起来像这样的XML:

<?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>

我尝试做的是处理&#39;类别&#39;,并根据上下文提取不同的名称。

我已尝试使用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是否支持属性搜索,或者是否有另一种方法可以执行相同操作。

2 个答案:

答案 0 :(得分:5)

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

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

默认情况下,get_xpath返回一个数组。通过传递&#34; 0&#34;,只传递数组的第一个元素(这是你需要的,并且可能只有一个匹配)。然后,使用->text拉出文本。使用它,您可以删除for循环。

答案 1 :(得分:0)

您可以将code_ref传递给first_child。该子元素依次传递给每个元素,如果它返回“true”,则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。这是一个品味问题。