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";

最后三个打印语句的输出是:

$VAR1 = undef;
$VAR1 = undef;
After

我无法提供整个 XML 或print Dumper($xst)它的输出,因为它太大并且动态生成,但我将提供它的示例。

导致问题的 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与将正确值设置为KeyAttr或相关ForceArray。我试图通过阅读找到它XML::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 没有数组之类的东西。它可能有重复的标签。但正因如此 - 'array' 和 '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 属性之一转换为散列中的“键”字段。

例如

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

如果您指定KeyAttras name,它将使用 和 的键进行firstelement散列secondelement

因为你dsg没有这个,那不是你想要的。

迭代dsg

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