Perl - 解析包含多个文档和访问对象的YAML

时间:2017-10-15 14:21:14

标签: perl yaml

我正在尝试从我的perl脚本的YAML文件中获取数据。

以下是类似的示例场景:

让我们考虑员工数据的YAML文件。

---
emp_name: John
emp_age: 27
DOB: 1/1/1990
others:
  - key1: value1
  - key2: value2
---
emp_name: Doe
emp_age: 25
DOB: 1/1/1992
others:
  - key1: value1
  - key2: value2
---
emp_name: foo
emp_age: 22
DOB: 1/1/1995
others:
  - key1: value1
  - key2: value2
---
emp_name: Bar
emp_age: 21
DOB: 1/1/1996
others:
  - key1: value1
  - key2: value2
...

我有以上四组值。我试图将所有员工姓名保存在一个数组中。但我无法得到它。

使用dumper,我只能将第一部分(John's)文件作为JSON打印,我无法获得单个值(例如,获取数组中的所有员工姓名)。 / p>

use strict;
use warnings;
use YAML::XS 'LoadFile';
use Data::Dumper;
my $config = LoadFile('input2.yml');
print Dumper($config), '\n';
print "Expected output:\n";
print "John \nDoe \nfoo \nBar\n";
print "--- Actual Output --";
my $empName;
for(my $i=0; $i<4; $i++)
{
$empName = $config->[$i]->{emp_name};
}

任何帮助?

以上是代码。我想获取员工姓名列表,但收到错误:Not an ARRAY reference at yamlParser.pl line 15

3 个答案:

答案 0 :(得分:2)

与JSON不同,YAML可能包含多个文档。它们中的每一个都以数据流中的---开头,最后一个文档的末尾由...

表示

您使用的YAML数据包含四个此类文档,这些文档由LoadFile作为引用列表返回。如果将该列表分配给标量变量,那么它将获取最后一个元素,因此您需要将结果放入数组(或标量变量列表)

此代码将按您的要求执行。它将YAML数据检索到数组@config,然后使用map提取每个哈希的emp_name元素

use strict;
use warnings 'all';
use feature 'say';

use YAML::XS 'LoadFile';

my @config = LoadFile 'input2.yml';

my @names = map { $_->{emp_name} } @config;

say for @names;

输出

John
Doe
foo
Bar

答案 1 :(得分:1)

提供的yaml提供4个文档,而不是4个项目的数组,因此您只需要取消引用它们。阅读文档: perldoc YAML::XS

变化:

my $config = LoadFile('input2.yml');

致:

my @conf = LoadFile('input2.yml');
my $config = \@conf;

答案 2 :(得分:-1)

让我们首先考虑一些关于YAML的基本知识,而不是文件本身。

包含 YAML流的文件可以包含多个完整不同数据结构的无关 YAML文档,由---分隔。

您的文件似乎包含相同结构的记录,您可能只需要一个文档,其中包含记录的 YAML序列 记录为 YAML映射

以下是你应该拥有的:

- emp_name: John
  emp_age: 27
  DOB: 1/1/1990
  others:
    key1: value1
    key2: value2
- emp_name: Doe
  emp_age: 25
  DOB: 1/1/1992
  others:
    key1: value1
    key2: value2
- emp_name: foo
  emp_age: 22
  DOB: 1/1/1995
  others:
    key1: value1
    key2: value2
- emp_name: Bar
  emp_age: 21
  DOB: 1/1/1996
  others:
    key1: value1
    key2: value2

注意区别; 1份文件;每条记录都以包含-的行开头; others现在是一个真正的映射,而不是单个映射的序列- key: value,已移除-

现在,以下代码将文件的内容读入单个变量,该变量将ArrayRef保存到单个YAML文档的整个数据结构

use strict;
use warnings;

use YAML;

my $data = YAML::LoadFile('input2_correct.yml');

use Data::Dumper;
print Dumper $data;

仅供参考:在列表上下文中使用YAML::LoadFile会读取所有单独的文档。

请修复您的YAML文件!

从现在开始,如果需要,可以轻松地使用map来操作散列中的Perl数据结构,或者打印名称:

print "$_->{emp_name}\n" foreach @$data;

或者,如果你想打印所有'Doe'记录的年龄......

my $name = 'Doe';

foreach my $emp_record ( @$data ) {
    next unless $emp_record->{emp_name} eq $name;
    # do what you like to do with the record
    print "$emp_record->{emp_age}\n";
}

如果只有1个记录'Doe',下面的代码将打印第一个'Doe'的年龄:

my ($found) = grep { $_->{emp_name} eq $name } @$data;
print "$found->{emp_age}\n";

grep会将列表缩减为仅在给定表达式中评估为true的列表。 my (found)导致grep的列表上下文,并将被分配缩小列表的第一个