【问题标题】:With XML::Twig, is there a way of find a 'first_child' with a particular attribute?使用 XML::Twig,有没有办法找到具有特定属性的“first_child”?
【发布时间】:2015-04-24 20:41:46
【问题描述】:

我有一些看起来像这样的 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>

我要做的是处理“类别”,并根据上下文提取不同的名称。

我尝试使用 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 是否支持属性搜索,或者是否有另一种方法可以做到这一点。

【问题讨论】:

    标签: xml perl xml-twig


    【解决方案1】:

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

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

    默认情况下,get_xpath 返回一个数组。通过传递“0”,仅传递数组的第一个元素(这是您需要的,并且很可能无论如何只会有一个匹配项)。然后,使用-&gt;text 提取文本。使用它,你可以删除你的 for 循环。

    【讨论】:

    • 可爱,这听起来比我正在查看的代码参考解决方案更好。
    【解决方案2】:

    您可以将 code_ref 传递给first_child。这个 sub 依次传递给每个元素,如果它返回“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 与匿名子内联。那是口味问题。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-08-23
      • 1970-01-01
      • 1970-01-01
      • 2022-01-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-04-29
      相关资源
      最近更新 更多