如何最好地通过此 perl 数据结构重申所需的输出?不重建现有的是否可能?
How to best reiterate through this perl data structure for desired output ? Is it possible without rebuilding existing one?
这里是 Perl 初学者,我有一个脚本可以进行 api 调用,以 xml 格式收集反馈,然后使用 XML::Simple,将数据按摩到下面的数据结构中,我正在尝试拍摄以下输出:
filename1.req, UserFaulted,123
filename2.req,用户故障,321
数据结构:
$VAR1 = {
'xmlns:i' => 'http://www.w3.org/2001/XMLSchema-instance',
'xmlns' => 'http://example.com',
'UserRequest' => {
'i1' => {
'Id' => 'e012',
'Dependencies' => [
{}
],
'xmlns:z' => 'http://schemas.microsoft.com/2003/10/Serialization/',
'IdentityUserNumber' => '123',
'Stage' => 'UserFaulted',
'StartTimestamp' => '2016-04-29T00:05:11',
'HomeFileName' => 'filename1.req',
'UseBypass' => 'false'
},
'i2' => {
'Id' => 'e013',
'Dependencies' => [
{}
],
'xmlns:z' => 'http://schemas.microsoft.com/2003/10/Serialization/',
'IdentityUserNumber' => '321',
'Stage' => 'UserFaulted',
'StartTimestamp' => '2016-04-19T19:50:18',
'HomeFileName' => 'filename2.req',
'UseBypass' => 'false'
}
}
};
这是我目前所知道的,在这一点上我开始认为我搬起石头砸自己的脚,但是任何反馈或建议将不胜感激
#!/usr/bin/perl
use strict;
use warnings;
use XML::Simple qw(:strict);
use Data::Dumper;
my $time = "2016-04-19";
my $api_faultedreqs = `curl -x 111.222.333.444:8080 -U user:pass -H "Accept: application/xml" -H "Content-Type: application/xml" "https://example.com" 2>/dev/null`;
my $xml_fault_reqs = XMLin($api_faultedreqs, KeyAttr => { UserRequest => 'Id' }, ForceArray => [ 'UserRequest', 'Dependencies' ]);
my %xml_fault_reqs = %$xml_fault_reqs;
my %clean_out = ();
print Dumper($xml_fault_reqs);
#print $xml_fault_reqs->{UserRequest}->{i1}->{HomeFileName};
for my $outer_key (keys %xml_fault_reqs){
next if $outer_key =~/xmlns/;
for my $req_ids2 (keys %{ $xml_fault_reqs{$outer_key} }){
for my $req_data (keys %{ $xml_fault_reqs{$outer_key}{$req_ids2} }){
next if $req_data =~/xmlns/ or $req_data =~/Dependencies/ or $req_data =~/UseBypass/ or $req_data =~/EndTimestamp/;
#print "$req_data, $xml_fault_reqs{$outer_key}{$req_ids2}{$req_data}\n";
print "$xml_fault_reqs{$outer_key}{$req_ids2}{HomeFileName}, $xml_fault_reqs{$outer_key}{$req_ids2}{Stage}\n";
}
}
}
XML 按要求输出:
<ArrayOfUserRequest xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://example.com">
<UserRequest xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/" z:Id="i1">
<Dependencies/>
<HomeFileName>filename1.req</HomeFileName>
<IdentityUserNumber>123</IdentityUserNumber>
<Stage>UserFaulted</Stage>
<StartTimestamp>2016-04-29T00:05:11</StartTimestamp>
<UseBypass>false</UseBypass>
</UserRequest>
<UserRequest xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/" z:Id="i2">
<Dependencies/>
<HomeFileName>filename2.req</HomeFileName>
<IdentityUserNumber>321</IdentityUserNumber>
<Stage>UserFaulted</Stage>
<StartTimestamp>2016-04-20T15:44:51</StartTimestamp>
<UseBypass>false</UseBypass>
</UserRequest>
作为 , XML::Simple
is generally frowned upon for a number of reasons. You may want to read the Stack Overflow question 更好地理解为什么会这样
但是您眼前的问题是如何导航一个相当普通的 Perl 嵌套数据结构,您将在 perldoc perlreftut
中找到一个有用的教程
这是解决您的问题的简单方法。感兴趣的项目是具有 UserRequest
的二级散列的值,因此该程序迭代这些值并从每个项目中打印所需的字段
printf
使用散列 切片 一次访问所有三个字段,键为 HomeFileName
、Stage
和 IdentityUserNumber
。 printf
格式以您要求的格式在一行中显示所有三个
use strict;
use warnings 'all';
use XML::Simple;
# my $data = XMLin(...);
my $data = {
'xmlns:i' => 'http://www.w3.org/2001/XMLSchema-instance',
'xmlns' => 'http://example.com',
'UserRequest' => {
'i1' => {
'Id' => 'e012',
'Dependencies' => [ {} ],
'xmlns:z' => 'http://schemas.microsoft.com/2003/10/Serialization/',
'IdentityUserNumber' => '123',
'Stage' => 'UserFaulted',
'StartTimestamp' => '2016-04-29T00:05:11',
'HomeFileName' => 'filename1.req',
'UseBypass' => 'false'
},
'i2' => {
'Id' => 'e013',
'Dependencies' => [ {} ],
'xmlns:z' => 'http://schemas.microsoft.com/2003/10/Serialization/',
'IdentityUserNumber' => '321',
'Stage' => 'UserFaulted',
'StartTimestamp' => '2016-04-19T19:50:18',
'HomeFileName' => 'filename2.req',
'UseBypass' => 'false'
}
}
};
for my $request ( values %{ $data->{UserRequest} } ) {
printf "%s, %s,%s\n", @{$request}{qw/ HomeFileName Stage IdentityUserNumber /};
}
产出
filename1.req, UserFaulted,123
filename2.req, UserFaulted,321
感谢您展示 XML 数据。很有帮助
这是一个使用 XML::LibXML
module to parse the data. It's a little more complicated than it could be because your data uses the default namespace with xmlns="http://example.com"
. That namespace must be defined and used explicitly in an XPath expression, which means you also need to create an XPath context object using the XML::LibXML::XPathContext
模块的解决方案。这允许您注册名称空间并在 XPath 表达式中使用它们。即使是默认命名空间也必须有一个名称,所以我将其命名为 nul
,并在每个节点名称前加上前缀 nul:
代码很简单。它使用 findnodes
定位所有 UserRequest
节点,并从每个节点中提取 HomeFileName
、Stage
和 IdentityUserNumber
子节点的值,打印结果printf
通话
use strict;
use warnings 'all';
use feature 'say';
use XML::LibXML;
my $dom = XML::LibXML->load_xml(IO => \*DATA);
my $xpc = XML::LibXML::XPathContext->new($dom);
$xpc->registerNs(nul => 'http://example.com');
for my $request ( $xpc->findnodes('/nul:ArrayOfUserRequest/nul:UserRequest') ) {
printf "%s, %s,%s\n",
$xpc->findvalue('nul:HomeFileName', $request),
$xpc->findvalue('nul:Stage', $request),
$xpc->findvalue('nul:IdentityUserNumber', $request);
}
__DATA__
<ArrayOfUserRequest xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://example.com">
<UserRequest xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/" z:Id="i1">
<Dependencies/>
<HomeFileName>filename1.req</HomeFileName>
<IdentityUserNumber>123</IdentityUserNumber>
<Stage>UserFaulted</Stage>
<StartTimestamp>2016-04-29T00:05:11</StartTimestamp>
<UseBypass>false</UseBypass>
</UserRequest>
<UserRequest xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/" z:Id="i2">
<Dependencies/>
<HomeFileName>filename2.req</HomeFileName>
<IdentityUserNumber>321</IdentityUserNumber>
<Stage>UserFaulted</Stage>
<StartTimestamp>2016-04-20T15:44:51</StartTimestamp>
<UseBypass>false</UseBypass>
</UserRequest>
</ArrayOfUserRequest>
产出
filename1.req, UserFaulted,123
filename2.req, UserFaulted,321
您似乎只是想打印元素 HomeFileName
和 Stage
。
既然如此,使用 XML::Twig 之类的东西可以让您:
use XML::Twig;
my @things = qw ( HomeFileName Stage IdentityUserNumber );
my $twig = XML::Twig->parse($api_faultedreqs);
foreach my $user_request ( $twig->get_xpath('//UserRequest') ) {
print join ",", (map { $user_request -> first_child_text($_) } @things), "\n";
}
这里是 Perl 初学者,我有一个脚本可以进行 api 调用,以 xml 格式收集反馈,然后使用 XML::Simple,将数据按摩到下面的数据结构中,我正在尝试拍摄以下输出:
filename1.req, UserFaulted,123
filename2.req,用户故障,321
数据结构:
$VAR1 = {
'xmlns:i' => 'http://www.w3.org/2001/XMLSchema-instance',
'xmlns' => 'http://example.com',
'UserRequest' => {
'i1' => {
'Id' => 'e012',
'Dependencies' => [
{}
],
'xmlns:z' => 'http://schemas.microsoft.com/2003/10/Serialization/',
'IdentityUserNumber' => '123',
'Stage' => 'UserFaulted',
'StartTimestamp' => '2016-04-29T00:05:11',
'HomeFileName' => 'filename1.req',
'UseBypass' => 'false'
},
'i2' => {
'Id' => 'e013',
'Dependencies' => [
{}
],
'xmlns:z' => 'http://schemas.microsoft.com/2003/10/Serialization/',
'IdentityUserNumber' => '321',
'Stage' => 'UserFaulted',
'StartTimestamp' => '2016-04-19T19:50:18',
'HomeFileName' => 'filename2.req',
'UseBypass' => 'false'
}
}
};
这是我目前所知道的,在这一点上我开始认为我搬起石头砸自己的脚,但是任何反馈或建议将不胜感激
#!/usr/bin/perl
use strict;
use warnings;
use XML::Simple qw(:strict);
use Data::Dumper;
my $time = "2016-04-19";
my $api_faultedreqs = `curl -x 111.222.333.444:8080 -U user:pass -H "Accept: application/xml" -H "Content-Type: application/xml" "https://example.com" 2>/dev/null`;
my $xml_fault_reqs = XMLin($api_faultedreqs, KeyAttr => { UserRequest => 'Id' }, ForceArray => [ 'UserRequest', 'Dependencies' ]);
my %xml_fault_reqs = %$xml_fault_reqs;
my %clean_out = ();
print Dumper($xml_fault_reqs);
#print $xml_fault_reqs->{UserRequest}->{i1}->{HomeFileName};
for my $outer_key (keys %xml_fault_reqs){
next if $outer_key =~/xmlns/;
for my $req_ids2 (keys %{ $xml_fault_reqs{$outer_key} }){
for my $req_data (keys %{ $xml_fault_reqs{$outer_key}{$req_ids2} }){
next if $req_data =~/xmlns/ or $req_data =~/Dependencies/ or $req_data =~/UseBypass/ or $req_data =~/EndTimestamp/;
#print "$req_data, $xml_fault_reqs{$outer_key}{$req_ids2}{$req_data}\n";
print "$xml_fault_reqs{$outer_key}{$req_ids2}{HomeFileName}, $xml_fault_reqs{$outer_key}{$req_ids2}{Stage}\n";
}
}
}
XML 按要求输出:
<ArrayOfUserRequest xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://example.com">
<UserRequest xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/" z:Id="i1">
<Dependencies/>
<HomeFileName>filename1.req</HomeFileName>
<IdentityUserNumber>123</IdentityUserNumber>
<Stage>UserFaulted</Stage>
<StartTimestamp>2016-04-29T00:05:11</StartTimestamp>
<UseBypass>false</UseBypass>
</UserRequest>
<UserRequest xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/" z:Id="i2">
<Dependencies/>
<HomeFileName>filename2.req</HomeFileName>
<IdentityUserNumber>321</IdentityUserNumber>
<Stage>UserFaulted</Stage>
<StartTimestamp>2016-04-20T15:44:51</StartTimestamp>
<UseBypass>false</UseBypass>
</UserRequest>
作为 XML::Simple
is generally frowned upon for a number of reasons. You may want to read the Stack Overflow question
但是您眼前的问题是如何导航一个相当普通的 Perl 嵌套数据结构,您将在 perldoc perlreftut
这是解决您的问题的简单方法。感兴趣的项目是具有 UserRequest
的二级散列的值,因此该程序迭代这些值并从每个项目中打印所需的字段
printf
使用散列 切片 一次访问所有三个字段,键为 HomeFileName
、Stage
和 IdentityUserNumber
。 printf
格式以您要求的格式在一行中显示所有三个
use strict;
use warnings 'all';
use XML::Simple;
# my $data = XMLin(...);
my $data = {
'xmlns:i' => 'http://www.w3.org/2001/XMLSchema-instance',
'xmlns' => 'http://example.com',
'UserRequest' => {
'i1' => {
'Id' => 'e012',
'Dependencies' => [ {} ],
'xmlns:z' => 'http://schemas.microsoft.com/2003/10/Serialization/',
'IdentityUserNumber' => '123',
'Stage' => 'UserFaulted',
'StartTimestamp' => '2016-04-29T00:05:11',
'HomeFileName' => 'filename1.req',
'UseBypass' => 'false'
},
'i2' => {
'Id' => 'e013',
'Dependencies' => [ {} ],
'xmlns:z' => 'http://schemas.microsoft.com/2003/10/Serialization/',
'IdentityUserNumber' => '321',
'Stage' => 'UserFaulted',
'StartTimestamp' => '2016-04-19T19:50:18',
'HomeFileName' => 'filename2.req',
'UseBypass' => 'false'
}
}
};
for my $request ( values %{ $data->{UserRequest} } ) {
printf "%s, %s,%s\n", @{$request}{qw/ HomeFileName Stage IdentityUserNumber /};
}
产出
filename1.req, UserFaulted,123
filename2.req, UserFaulted,321
感谢您展示 XML 数据。很有帮助
这是一个使用 XML::LibXML
module to parse the data. It's a little more complicated than it could be because your data uses the default namespace with xmlns="http://example.com"
. That namespace must be defined and used explicitly in an XPath expression, which means you also need to create an XPath context object using the XML::LibXML::XPathContext
模块的解决方案。这允许您注册名称空间并在 XPath 表达式中使用它们。即使是默认命名空间也必须有一个名称,所以我将其命名为 nul
,并在每个节点名称前加上前缀 nul:
代码很简单。它使用 findnodes
定位所有 UserRequest
节点,并从每个节点中提取 HomeFileName
、Stage
和 IdentityUserNumber
子节点的值,打印结果printf
通话
use strict;
use warnings 'all';
use feature 'say';
use XML::LibXML;
my $dom = XML::LibXML->load_xml(IO => \*DATA);
my $xpc = XML::LibXML::XPathContext->new($dom);
$xpc->registerNs(nul => 'http://example.com');
for my $request ( $xpc->findnodes('/nul:ArrayOfUserRequest/nul:UserRequest') ) {
printf "%s, %s,%s\n",
$xpc->findvalue('nul:HomeFileName', $request),
$xpc->findvalue('nul:Stage', $request),
$xpc->findvalue('nul:IdentityUserNumber', $request);
}
__DATA__
<ArrayOfUserRequest xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://example.com">
<UserRequest xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/" z:Id="i1">
<Dependencies/>
<HomeFileName>filename1.req</HomeFileName>
<IdentityUserNumber>123</IdentityUserNumber>
<Stage>UserFaulted</Stage>
<StartTimestamp>2016-04-29T00:05:11</StartTimestamp>
<UseBypass>false</UseBypass>
</UserRequest>
<UserRequest xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/" z:Id="i2">
<Dependencies/>
<HomeFileName>filename2.req</HomeFileName>
<IdentityUserNumber>321</IdentityUserNumber>
<Stage>UserFaulted</Stage>
<StartTimestamp>2016-04-20T15:44:51</StartTimestamp>
<UseBypass>false</UseBypass>
</UserRequest>
</ArrayOfUserRequest>
产出
filename1.req, UserFaulted,123
filename2.req, UserFaulted,321
您似乎只是想打印元素 HomeFileName
和 Stage
。
既然如此,使用 XML::Twig 之类的东西可以让您:
use XML::Twig;
my @things = qw ( HomeFileName Stage IdentityUserNumber );
my $twig = XML::Twig->parse($api_faultedreqs);
foreach my $user_request ( $twig->get_xpath('//UserRequest') ) {
print join ",", (map { $user_request -> first_child_text($_) } @things), "\n";
}