我正在编写一个子程序,它使用XML::Simple
模块从配置文件中提取信息。
XML文件具有以下结构
<main>
<server hostname="blahblah" ... more_attributes="more"/>
<server etc./>
<server etc./>
</main>
代码工作正常。它将XML数据按预期放入嵌套哈希中。但是,当我想使用当前系统hostname
将一台服务器与其余服务器隔离时,我会遇到问题。
我想这一行
my %systemHash = %{$xmlObject->{SERVER}->{`hostname`}};
应将当前计算机的主机名插入最后一组括号中。但是当执行代码时我得到了
Can't use an undefined value as a HASH reference
答案 0 :(得分:5)
首先,请不要使用XML::Simple
。它自己的文档说明了这个
不鼓励在新代码中使用此模块。其他模块可用,提供更直接和一致的接口。特别强烈建议使用XML :: LibXML。
此模块的主要问题是大量选项以及这些选项交互的任意方式 - 通常会产生意外结果。
您还应该使用Data::Dump
检查任何子例程调用或shell命令的结果。它看起来像这样
perl -MData::Dump -E'dd `hostname`'
在我的系统上显示
"Samurai-U\n"
希望你现在看到问题了吗?反引号返回的字符串有一个尾随的换行符,并且$xmlObject
哈希中有一个元素就是这样的键。您可以使用
chomp(my $host = `hostname`)
之后你可以写
my %systemHash = %{ $xmlObject->{SERVER}{$host} }
最后,像这里一样复制哈希的所有第一级是浪费的
my %systemHash = %{$xmlObject->{SERVER}->{`hostname`}}
您不会继续显示您想要使用此信息的内容,但一般来说,使用
提取哈希引用要好得多chomp( my $hostname = `hostname` );
my $systemHash = $xmlObject->{SERVER}{$hostname};
<强>更新强>
使用正确的XML解析模块会好得多。
以下是使用XML::LibXML
use strict;
use warnings;
use 5.010; # For 'say'
use XML::LibXML;
my ($xml_file) = @ARGV;
my $xml = XML::LibXML->load_xml(location => $xml_file);
my @servers = $xml->findnodes('/main/server');
my @server_names = map $_->findvalue('@hostname'), @servers;
say "- $_" for @server_names;
输入文件
<main>
<server hostname="server1" more_attributes="more"/>
<server hostname="server2" more_attributes="more"/>
<server hostname="server3" more_attributes="more"/>
</main>
<强>输出强>
- server1
- server2
- server3
答案 1 :(得分:3)
您应该使用Data::Dumper转储XML::Simple 的输出,如下所示:
use Data::Dumper;
# Retrieve your data structure via XML::Simple. Then...
print Dumper $xmlObject;
您会看到它没有创建您期望的结构,这就是您获取Can't use an undefined value as a HASH reference
消息的原因。该消息表示$xmlObject
未定义,或$xmlObject->{SERVER}
未定义。 perldiag将错误描述为:
用作硬引用或符号引用的值必须 是一个定义的值。这有助于消除一些潜在的错误。
您将未定义的值视为哈希引用。如上所述,原因可能是XML :: Simple结构与您的期望不同。
XML ::简单并不像其名称所暗示的那样简单,也不像人们希望的那样简单。目前它自己的文档不鼓励使用它。有一些配置选项有助于规范化它所产生的结构,但是没有看到更多的XML,以及你用来阅读它的代码,这就像我能给出的详细解释一样。关于如何解析XML的最佳建议是使用更可靠的模块。两个非常常见且备受推崇的替代方案是XML::Twig和XML::LibXML。
您的代码中还有一个错误,接下来会遇到:您的系统调用返回的主机名为&#39; hostname
&#39;最后有一个换行符,所以你要求一个名为:
"somehost\n"
......当你真的想要&#34; somehost
&#34;。我怀疑你并不指望这一点。最低限度,你需要这样的东西:
chomp( my $h = `hostname` );
my %systemHash = %{$xmlObject->{SERVER}->{$h}};
或者这个:
use Sys::Hostname;
my %systemHash = %{$xmlObject->{SERVER}->{hostname()};
我更喜欢后者,因为它更便携,而模块Sys::Hostname comes with Perl,所以你已经在你的系统上拥有它了。它的输出不需要咀嚼。