1

を使用してスクリプトを作成する途中ですXML::Simple。私はそれがそれほど「単純」ではないことを読みました。独自のドキュメントでさえ、新しいコードでの使用を思いとどまらせていますが、このスクリプトは既存のコードの拡張になるため、他に選択肢はありません。

私がしているのはこれです

  1. URL から読み取って XML を取得する
  2. を使用して解析しますXML::Simple
  3. データから必要な要素を読み取る
  4. これらの必須要素に対してさまざまなチェックを実行します

いくつかの要素を解析していくつかのチェックを行うことができましたが、配列内の要素を読み取っているときにundef.

これは私のコードです:

#!/usr/bin/perl

use strict;
use warnings;

use LWP::UserAgent;
use LWP::Simple;
use XML::Simple;
use DBI;

use Data::Dumper;

my $str = "<Actual_URL>";

my $ua = LWP::UserAgent->new;
$ua->timeout( 180 );
$ua->agent( "$0/0.1 " . $ua->agent );

my $req = HTTP::Request->new( GET => $str );

my $buffer;
$req->content_type( 'text/xml' );
$req->content( $buffer );

my $response = $ua->request( $req );

my $xml = $response->content();
print "Value of \$xml is:\n";
print $xml;

my $filename = 'record.txt';
open( my $fh, '>', $filename ) or die "Could not open file '$filename' $!";
print $fh $xml;
close $fh;

my $number_of_lines = `wc -l record.txt | cut -d' ' -f1`;
print "Number of lines in $filename are: $number_of_lines\n";
if ( $number_of_lines >= 50 ) {
    print "TEST_1 SUCCESS\n";
}

my $mysql_dbh;
my $test_id;

my $xst;
my %cmts_Pre_EQ_tags;

if ( ( not defined $xml ) or ( $xml =~ m/read\stimeout/i ) ) {
    &printXMLErr( 'DRUM request timed out' );
}
else {
    my $xs = XML::Simple->new();
    $xst = eval { $xs->XMLin( $xml, KeyAttr => 1 ) };
    &printXMLErr( $@ ) if ( $@ );
    print "Value of \$xst inside is:\n";
    print Dumper( $xst );
}

$cmts_Pre_EQ_tags{'$cmts_Pre_EQ_groupDelayMag'} =
    $xst->{cmts}->{Pre_EQ}->{groupDelayMag}->{content};

#More elements like this are checked here
$cmts_Pre_EQ_tags{'$cmts_Pre_EQ_ICFR'} =
    $xst->{cmts}->{Pre_EQ}->{ICFR}->{content};

my $decision1 = 1;
print "\%cmts_Pre_EQ_tags:\n";
foreach ( sort keys %cmts_Pre_EQ_tags ) {
    print "$_ : $cmts_Pre_EQ_tags{$_}\n";
    if ( $cmts_Pre_EQ_tags{$_} eq '' ) {
        print "$_ is empty!\n";
        $decision1 = 0;
    }
}
print "\n";

if ( $decision1 == 0 ) {
    print "TEST_2_1 FAIL\n";
}
else {
    print "TEST_2_1 SUCCESS\n";
}

my $cpeIP4 = $xst->{cmts}->{cpeIP4}->{content};
print "The cpe IP is: $cpeIP4\n";

if ( $cpeIP4 ne '' ) {
    print "TEST_2_2 SUCCESS\n";
}
else {
    print "TEST_2_2 FAIL\n";
}

# Working fine until here, but following 2 print are showing undef
print Dumper ( $xst->{cmts}{STBDSG}{dsg}[0]{dsgIfStdTunnelFilterTunnelId} );
print Dumper ( $xst->{cmts}{STBDSG}{dsg}[0]{dsgIfStdTunnelFilterClientIdType} );
print "After\n";

最後の 3 つの print ステートメントの出力は次のとおりです。

$VAR1 = undef;
$VAR1 = undef;
After

print Dumper($xst)XML は大きすぎて動的に生成されるため、XML 全体または出力を提供することはできませんが、サンプルを提供します。

問題を引き起こしている XML の部分は

<cmts>
  <STBDSG>
    <dsg>
      <dsgIfStdTunnelFilterTunnelId>1</dsgIfStdTunnelFilterTunnelId>
      <dsgIfStdTunnelFilterClientIdType>caSystemId</dsgIfStdTunnelFilterClientIdType>
    </dsg>
    <dsg>
      <dsgIfStdTunnelFilterTunnelId>2</dsgIfStdTunnelFilterTunnelId>
      <dsgIfStdTunnelFilterClientIdType>gaSystemId</dsgIfStdTunnelFilterClientIdType>
    </dsg>
  </STBDSG>
</cmts>

この部分が解析されると、対応する出力は次のようになり$xstます。

$VAR1 = {
    'cmts' => {
            'STBDSG' => {
                'dsg' => [
                         {
                           'dsgIfStdTunnelFilterTunnelId' => '1',
                           'dsgIfStdTunnelFilterClientIdType' => 'caSystemId',
                         },
                         {
                           'dsgIfStdTunnelFilterTunnelId' => '2',
                           'dsgIfStdTunnelFilterClientIdType' => 'gaSystemId',
                         }
                         ]
                     },
    },
};

値を解析した後に正常に取得される XML 部分は次のようになります。

<cmts>
    <name field_name="Name">cts01nsocmo</name>
    <object field_name="Nemos Object">888</object>
    <vendor field_name="Vendor">xyz</vendor>
</cmts>

これは次のように変換されました:

    $VAR1 = {
      'cmts' => {
        'name' => {
                    'content' => 'cts01nsocmo',
                    'field_name' => 'Name'
                  },
        'object' => {
                      'content' => '888',
                      'field_name' => 'Nemos Object'
                    },
        'vendor' => {
                      'content' => 'xyz',
                      'field_name' => 'Vendor'
                    }
         },
};

基本的に、解析されたコンテンツに配列がない場合、値は変数に正しくフェッチされています。

どうやらこの理由は

print Dumper ( $xst->{cmts}{STBDSG}{dsg}[0]{dsgIfStdTunnelFilterTunnelId} );
print Dumper ( $xst->{cmts}{STBDSG}{dsg}[0]{dsgIfStdTunnelFilterClientIdType} );

は、またはundefに正しい値を設定することに関連しています。を読んで見つけようとしていますが、ここに欠けている明確なものがあるかどうかを確認したかったのです。KeyAttrForceArrayXML::Simple

4

2 に答える 2

4

XML::Twigプロジェクトの残りの部分が何をするかに関係なく、の使用を検討する価値があります

特に、XML::Twig::Eltオブジェクト (XML 要素のモジュールの実装) にはsimplifyメソッドがあり、そのドキュメントには次のように書かれています

XML::Simple のものに疑わしいほど似たデータ構造を返します。オプションは XMLin オプションと同じです

したがってXML::Twig、その精度と利便性のために使用でき、データ構造simplifyのように見えるデータを渡す必要がある場合はメソッドを適用できますXML::Simple

于 2015-07-07T20:15:03.730 に答える
1

あなたが見つけたように -XML::Simpleではありません。ドキュメントでさえ、次のことを示唆しています:

新しいコードでこのモジュールを使用することはお勧めできません。より直接的で一貫したインターフェースを提供する他のモジュールが利用可能です。

問題の一部は、XML には配列のようなものがないことです。タグが重複している可能性があります。しかし、「配列」と「XML」の間に直線的なマッピングがないため、常にプログラミングが不快になります。

dsg要素が配列であると想定し、それらを自動的にキャストしています。

とにかく、XML::Twig代わりに使用することをお勧めします-そして、「印刷」ステートメントは次のようになります。

#!/usr/bin/env perl
use strict;
use warnings;
use XML::Twig;

my $twig = XML::Twig->new->parse( \*DATA );

foreach my $element ( $twig->get_xpath( "cmts/STBDSG/dsg", 0 ) ) {
    print $element ->first_child_text("dsgIfStdTunnelFilterTunnelId"), "\n";
    print $element ->first_child_text("dsgIfStdTunnelFilterClientIdType"),
        "\n";
}

とにかく、使用を余儀なくされた場合、XML::Simpleそれを捨てて最初からやり直すことはできません。(真剣に、私はそれを検討します!)。

XML::Simple が「一致する」要素に対して行うことは、配列であるかのように見せかけることです。

一致する要素がない場合は、それらをハッシュとして扱います。それはおそらくあなたを捕まえているものです。問題は-perlでは、ハッシュは重複するキーを持つことができないため、あなたの例ではdsg-複製するのではなく、配列化します。

オンにすると、すべてForceArrayが配列に入れられますが、配列の一部は単一の要素である可能性があります。ただし、一貫性が必要な場合は便利です。

KeyAttrおそらく役に立ちません-これは主に、さまざまなサブ要素を持ち、それらを「マップ」したい場合に適しています。これにより、XML 属性の 1 つをハッシュの「キー」フィールドに変換できます。

例えば

<element name="firstelement">content</element>
<element name="secondelement">morecontent</element>

KeyAttrasを指定すると、とnameのキーを持つハッシュが作成されます。firstelementsecondelement

あなたにdsgはこれがないので、それはあなたが望むものではありません。

を繰り返すにはdsg:

foreach my $element ( @{ $xst->{cmts}{STBDSG}{dsg} } ) {
    print $element ->{dsgIfStdTunnelFilterTunnelId},     "\n";
    print $element ->{dsgIfStdTunnelFilterClientIdType}, "\n";
}
于 2015-07-07T19:51:12.397 に答える