是否有* simple *方法使用XML :: Simple提取深层嵌套值?

时间:2009-02-12 11:23:46

标签: xml perl

我正在使用Perl的XML::Simple来解析深层嵌套的XML,并希望提取一个关于4个级别的元素的小列表:

A
  B
    C 
      D1
      D2
      D3

理想情况下,如果可能,我想在输入步骤中执行此操作。像这样:

my @list = XMLin($xml, { SomeAttribute => 'ButWhat?' });

以与我相同的方式结束:

@list = ('D1', 'D2', 'D3')

有可能吗?或者只是不那么“简单”?

5 个答案:

答案 0 :(得分:3)

假设您的内存数据如下:

my $parsed = {
    A => {
        B => {
            C => [ qw/here is your list/ ],
        },
    },
};

然后,您可以使用my @list = @{ $parsed->{A}{B}{C} }获取列表。

这是你想要做的吗?

编辑:考虑到一些评论,也许你想要的 Data::Visitor::Callback。 然后,您可以提取所有数组,如:

my @arrays;
my $v = Data::Visitor::Callback->new(
    array => sub { push @arrays, $_ },
);
$v->visit( $parsed_xml );

运行之后,\ @arrays将是一个引用列表 任意深度嵌套的数组。

最后,如果您只有一个属性名称并想要搜索 匹配XML节点,你真的想要XPath:

use XML::LibXML;
my $parser = XML::LibXML->new;
my $doc = $parser->parse_string( $xml_string );

# yeah, I am naming the variable data.  so there.
my @data = map { $_->textContent } $doc->findnodes('//p[@id="foo"]');

无论如何,TMTOWTDI。如果您正在使用XML,并且想要这样做 复杂的东西,XML :: Simple很少是正确的答案。我用 XML :: LibXML适用于所有内容,因为它几乎总是更容易。

还有一件事,你可能想要 Data::DPath。它让 你“XPath”是一个内存中的perl数据结构:

答案 1 :(得分:1)

Jon's answer上构建,这是我在需要做这类事情时使用的基本代码。如果我需要更高级的东西,如果我被允许这样做,我通常会找到一个模块。

get_values中的技巧从顶级引用开始,获得下一个较低级别,并将其放在同一个变量中。它一直持续到我到达我想去的地方。大多数代码只是断言,以确保事情正常运行。在大多数情况下,我发现它是混乱的数据,而不是遍历(但我做了大量的数据清理工作)。根据您的情况调整错误检查。

use Carp qw(croak);

my $parsed = {
  A => {
    B => {
      C => [ qw/here is your list/ ],
      D => {
        E =>  [ qw/this is a deeper list/ ],
        },
    },
  },
};

my @keys = qw( A B C D );

my @values = eval { get_values( $parsed, @keys ) } or die;

$" = " ][ ";
print "Values are [ @values ]\n";

sub get_values
    {
    my( $hash, @keys ) = @_;

    my $v = $hash; # starting reference

    foreach my $key ( @keys )
        {
        croak "Value is not a hash ref [at $key!]\n" unless ref $v eq ref {};
        croak "Key $key does not exist!\n" unless exists $v->{$key};
        $v = $v->{$key}; # replace with ref down one level
        }

    croak "Value is not an array ref!" unless ref $v eq ref [];
    @$v;
    }

答案 2 :(得分:0)

您使用XML :: Simple这一事实无关紧要;你正试图搜索有refs和数组引用的结构。你知道你在寻找什么吗?它会永远在同一个地方吗?如果是这样的话,那么jrockway写的东西很容易就能解决问题。如果没有,那么你需要走完每个结构,直到找到你想要的东西。

我经常做的一件事是转储XML :: Simple使用Data::Dumper返回的结构,看看它看起来像什么(如果它总是“看起来”相同;如果没有,你可以动态地确定如何通过测试走它是一个参考,它是什么样的参考)。真正的问题是:你在寻找什么?

答案 3 :(得分:0)

Data::Diver为挖掘深层结构提供了一个很好的界面。

答案 4 :(得分:0)

感谢所有建议。

最后,我通过使用eval块避免了遍历数据结构的问题。

my $xml_tree;
my @list;

eval {

   # just go for it
   my @list = @{ $xml_tree->{A}->{B}->{C} };

};

if ($@) {
   say "oops - xml is not in expected format - and that happens sometimes";
}