有没有用XML::simple提取深度嵌套值的简单方法?

有没有用XML::simple提取深度嵌套值的简单方法?,xml,perl,Xml,Perl,我正在使用Perl解析深度嵌套的XML,并希望从下面4个级别提取一小部分元素: A B C D1 D2 D3 理想情况下,如果可能的话,我希望在输入步骤中这样做。像这样: my @list = XMLin($xml, { SomeAttribute => 'ButWhat?' }); 结果和我做的一样: @list = ('D1', 'D2', 'D3') 有可能吗?或者不是那么简单?假设内存中的数据如下所示: my $parsed

我正在使用Perl解析深度嵌套的XML,并希望从下面4个级别提取一小部分元素:

A
  B
    C 
      D1
      D2
      D3
理想情况下,如果可能的话,我希望在输入步骤中这样做。像这样:

my @list = XMLin($xml, { SomeAttribute => 'ButWhat?' });
结果和我做的一样:

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

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

假设内存中的数据如下所示:

my $parsed = {
    A => {
        B => {
            C => [ qw/here is your list/ ],
        },
    },
};
然后您可以使用
my@list=@{$parsed->{A}{B}{C}
获取您的列表

这就是你想做的吗

编辑:考虑到一些评论,也许你想要 . 然后可以提取所有数组,如:

my @arrays;
my $v = Data::Visitor::Callback->new(
    array => sub { push @arrays, $_ },
);
$v->visit( $parsed_xml );
运行之后,\@数组将是对的引用列表 任意深度嵌套数组

最后,如果您只有一个属性名,并且想要搜索 匹配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"]');
不管怎样,TMTOWTI。如果您正在使用XML,并且希望 复杂的是,XML::Simple很少是正确的答案。我用 LibXML,因为它几乎总是更简单

还有一件事,你可能想要 . 它让
您可以“XPath”一个内存中的perl数据结构:

使用XML::Simple这一事实与此无关;您正在尝试搜索has REF和array REF的结构。你知道你在找什么吗?它总是在同一个地方吗?如果是这样的话,那么像jrockway所写的东西将很容易做到这一点。如果没有,那么你需要走走每一块建筑,直到你找到你要找的东西

我经常做的一件事是转储XML::Simple使用返回的结构,以查看它的外观(如果它总是“看起来”相同;如果不是,则可以通过测试某物是否为ref以及它是什么类型的ref来动态确定如何遍历它)。真正的问题是:你在寻找什么?

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

在此基础上,以下是我需要做这类事情时使用的基本代码。如果我需要更喜欢的东西,如果允许的话,我通常会去拿一个模块

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; } 使用鲤鱼qw(croak); 我的$parsed={ A=>{ B=>{ C=>[qw/这是您的列表/], D=>{ E=>[qw/这是一个更深层次的列表/], }, }, }, }; my@keys=qw(A、B、C、D); 我的@values=eval{get_values($parsed,@keys)}或死亡; $" = " ][ "; 打印“值为[@Values]\n”; sub-get_值 { 我的($hash,@keys)=@; my$v=$hash;#开始引用 foreach my$key(@keys) { croak“值不是散列ref[at$key!]\n”,除非ref$v eq ref{}; croak“Key$Key不存在!\n”除非存在$v->{$Key}; $v=$v->{$key};#替换为向下一级的ref } croak“Value不是数组ref!”除非ref$v eq ref[]; @$v; }
谢谢你的建议

最后,我通过使用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";
}

谢谢你的回答。是的,我知道我可以做到这一点-但我希望不必测试哈希中是否存在所有级别来访问列表。诀窍是,在开始之前,你必须知道你要深入多少级别。我认为你不需要那么多->'s-$xml_tree->{A}{B}{C}就可以了。