Perl不解释ticks中的值,称其为未定义的值

时间:2014-06-16 22:54:56

标签: xml perl xml-simple

我正在编写一个子程序,它使用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

2 个答案:

答案 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::TwigXML::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,所以你已经在你的系统上拥有它了。它的输出不需要咀嚼。