有没有用XML::simple提取深度嵌套值的简单方法?
我正在使用Perl解析深度嵌套的XML,并希望从下面4个级别提取一小部分元素:有没有用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
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}就可以了。