Perl哈希有一些问题。 我有一个XML:
<?xml version="1.0" encoding="utf-8"?>
<SvnRequestUsers>
<AccessCode>$TR0ngP@ssvv0rd!</AccessCode>
<SvnUsers>
<SvnUser>
<Username>svn.testname</Username>
<Password>jA=B*+q%</Password>
<Create>true</Create>
</SvnUser>
<SvnUser>
<Username>svn.testname2</Username>
<Password>jA=B*+q%</Password>
<Create>true</Create>
</SvnUser>
</SvnUsers>
</SvnRequestUsers>
我想循环通过SvnUser节点。当我使用
我的$ usersList = $ ref-&gt; {&#39; SvnUsers&#39;};
foreach my $key ( @{$usersList->{'SvnUser'}} )
{ ..... }
当有多个节点但不适用于一个节点时,这是有效的。
使用时
我的@usersList = $ ref-&gt; {&#39; SvnUsers&#39;} - &gt; {&#39; SvnUser&#39;};
foreach my $key ( @usersList )
{ ..... }
仅在恰好有一个节点时才有效。 诀窍在哪里???
答案 0 :(得分:2)
如果您使用的是XML :: Simple,您可能想要全局启用ForceArray(这可能需要您在代码中添加更多数组解引用)或者可能具有一个或多个节点的特定元素;见https://metacpan.org/module/XML::Simple#ForceArray-names-in---important。
答案 1 :(得分:1)
这看起来像是远离简单XML::Simple
的工作。我相信它通过成为第一个声称它的命名空间而赢得了它的知名度,而IMO它有很多缺点。
如果我的猜测是正确的,那么你可以通过enabling the ForceArray
option克服一些尴尬。模块的POD说
检查ForceArray,因为你几乎肯定想要打开它
在您的情况下,这将确保$ref->{SvnUsers}{SvnUser}
总是一个数组引用,即使XML中的那个点上只有一个<SvnUser>
元素。因此$ref->{SvnUsers}{SvnUser}[0]
将始终访问第一个或唯一的用户元素。
我的建议是升级到更一致的XML模块。 XML::Smart
允许以与XML::Simple
结构非常相似的方式访问数据,但它广泛使用tie
来提供更好的DWIM接口。例如,在XML::Smart
下,可以使用SvnUser
或SvnUsers
访问第一个$ref->{SvnUsers}{SvnUser}
元素的第一个$ref->{SvnUsers}[0]{SvnUser}[0]
。
只需切换到XML::Smart
即可解决您的问题。例如,下面的代码将列出所有用户的用户名,无论是否有一个或多个用户名(或者实际上没有用户名,因为在这种情况下对象将返回一个空列表)。
我自己的偏好是一个“适当的”XML模块,如XML::LibXML
或
XML::Twig
,但当然选择是你的。
use strict;
use warnings;
use XML::Smart;
my $ref = XML::Smart->new(\*DATA);
my $users_list= $ref->{SvnRequestUsers}{SvnUsers};
foreach my $key ( @{ $users_list->{SvnUser} } ) {
print $key->{Username}, "\n";
}
__DATA__
<?xml version="1.0" encoding="utf-8"?>
<SvnRequestUsers>
<AccessCode>$TR0ngP@ssvv0rd!</AccessCode>
<SvnUsers>
<SvnUser>
<Username>svn.testname</Username>
<Password>jA=B*+q%</Password>
<Create>true</Create>
</SvnUser>
<SvnUser>
<Username>svn.testname2</Username>
<Password>jA=B*+q%</Password>
<Create>true</Create>
</SvnUser>
</SvnUsers>
</SvnRequestUsers>
<强>输出强>
svn.testname
svn.testname2
答案 2 :(得分:0)
你用什么模块来读取ahref中的XML?如果有更多用户,我猜你需要像这样访问你的数据:
my @usersList = $ref->{'SvnUsers'}->[0]->{'SvnUser'};
这会给你第一个用户,因为在'SvnUsers'键下会有一个arrayref作为值
迭代可能如下所示:
my $maxusers = scalar(@{$ref->{'SvnUsers'}}); # get the number of elements in your ref
for my $i(0 .. $maxusers){
my $svnuser = $ref->{'SvnUsers'}->[$i]->{'SvnUser'}; # get current
....... # do your stuff
}
答案 3 :(得分:0)
尝试这样做:
#!/usr/bin/perl
use strict;
use warnings;
use XML::XPath;
use XML::XPath::XMLParser;
my $xp = XML::XPath->new(filename => 'file.xml');
my $nodeset = $xp->find('/SvnRequestUsers/SvnUsers/SvnUser'); # find svn users
foreach my $node ($nodeset->get_nodelist) {
print "FOUND\n\n",
XML::XPath::XMLParser::as_string($node),
"\n\n";
}
结果:
FOUND
<SvnUser>
<Username>svn.testname</Username>
<Password>jA=B*+q%</Password>
<Create>true</Create>
</SvnUser>
FOUND
<SvnUser>
<Username>svn.testname2</Username>
<Password>jA=B*+q%</Password>
<Create>true</Create>
</SvnUser>
答案 4 :(得分:0)
像往常一样,我会推荐Mojo::DOM套件的Mojolicious。使用选择器和转换/迭代器方法,问题变得非常简单:
#!/usr/bin/env perl
use strict;
use warnings;
use Mojo::DOM;
my $dom = Mojo::DOM->new(<<'END');
<?xml version="1.0" encoding="utf-8"?>
<SvnRequestUsers>
<AccessCode>$TR0ngP@ssvv0rd!</AccessCode>
<SvnUsers>
<SvnUser>
<Username>svn.testname</Username>
<Password>jA=B*+q%</Password>
<Create>true</Create>
</SvnUser>
<SvnUser>
<Username>svn.testname2</Username>
<Password>jA=B*+q%</Password>
<Create>true</Create>
</SvnUser>
</SvnUsers>
</SvnRequestUsers>
END
# get an array
my @users = $dom->find('SvnUser')
->pluck('Username')
->pluck('text')
->each;
# or do something with each element
$dom->find('SvnUser')
->pluck('Username')
->pluck('text')
->each(sub{ print "$_\n" });
当然,如果您实际上只是想要用户名,那么您可能只使用更加量身定制的选择器find('SvnUser Username')
,上面的示例就是显示方法。