1

XML::Simpleモジュールを使用して構成ファイルから情報を引き出すサブルーチンを作成しています。

XML ファイルの構造は次のとおりです。

<main>
  <server hostname="blahblah" ... more_attributes="more"/>
  <server etc./>
  <server etc./>
</main>

コードは正常に動作します。予想どおり、XML データをネストされたハッシュに入れます。しかし、現在のシステムを使用して 1 つのサーバーを残りのサーバーから分離したい場合、hostname問題が発生します。

このラインだと思います

my %systemHash = %{$xmlObject->{SERVER}->{`hostname`}};

現在のマシンのホスト名を括弧の最後のセットに挿入する必要があります。しかし、私が得るコードを実行すると

Can't use an undefined value as a HASH reference
4

2 に答える 2

5

まず、使わないでくださいXML::Simple。それ自身のドキュメントはこれを言います

新しいコードでこのモジュールを使用することはお勧めできません。より単純で一貫したインターフェースを提供する他のモジュールが利用可能です。特に、XML::LibXML を強くお勧めします。

このモジュールの主な問題は、多数のオプションと、これらのオプションが相互作用する恣意的な方法であり、しばしば予期しない結果をもたらします。

を使用して、サブルーチン呼び出しまたはシェル コマンドの結果も確認する必要がありますData::Dump。このようになります

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
于 2014-06-16T23:25:54.153 に答える
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::Simple は、その名前が示すほど単純でもなく、期待するほど単純でもありません。そして現在、独自のドキュメントはその使用を思いとどまらせています。それが生成する構造を正規化するのに役立つ構成オプションがありますが、XML とそれを読み取るために使用しているコードをさらに見ることなく、それは私が与えることができるのと同じくらい詳細な説明です。XML の解析方法に関する最良のアドバイスは、より信頼性の高いモジュールを使用することです。XML::TwigXML::LibXMLの 2 つの非常に一般的で評価の高い代替手段があります。

あなたのコードには、次に遭遇する追加のバグがあります: ' ' へのシステム コールによって返されるホスト名にhostnameは、末尾に改行があるため、次の名前のハッシュ キーを要求しています:

"somehost\n"

...本当に " somehost" だけが欲しいとき。あなたはそれを当てにしていないのではないかと思います。最低限、次のようなものが必要です。

chomp( my $h = `hostname` );
my %systemHash = %{$xmlObject->{SERVER}->{$h}};

またはこれ:

use Sys::Hostname;
my %systemHash = %{$xmlObject->{SERVER}->{hostname()};

後者の方が移植性が高く、モジュールSys::Hostname が Perlに付属しているため、後者をお勧めします。そのため、既にシステムにインストールされています。その出力はチョッピングを必要としません。

于 2014-06-16T23:02:14.410 に答える