2012-05-02 28 views
-1

我遇到一个问题访问使用Perl/XML :: Simple的XML响应中的一些嵌套的数据。印刷XML答复的摘录如下:XML ::简单和访问复杂的结构

<?xml version="1.0" encoding="UTF-8"?> 
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> 
<soapenv:Body> 
<ns1:SelectCmDeviceResponse soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:ns1="http://schemas.cisco.com/ast/soap/"> 
<SelectCmDeviceResult xsi:type="ns1:SelectCmDeviceResult"> 
<TotalDevicesFound xsi:type="xsd:unsignedInt">3</TotalDevicesFound> 
<CmNodes soapenc:arrayType="ns1:CmNode[3]" xsi:type="soapenc:Array" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"> 
<item xsi:type="ns1:CmNode"> 
<ReturnCode xsi:type="ns1:RisReturnCode">NotFound</ReturnCode> 
<Name xsi:type="xsd:string">10.186.78.4</Name> 
<NoChange xsi:type="xsd:boolean">false</NoChange> 
<CmDevices soapenc:arrayType="ns1:CmDevice[0]" xsi:type="soapenc:Array"/> 
</item> 
<item xsi:type="ns1:CmNode"> 
<ReturnCode xsi:type="ns1:RisReturnCode">Ok</ReturnCode> 
<Name xsi:type="xsd:string">10.186.78.68</Name> 
<NoChange xsi:type="xsd:boolean">false</NoChange> 
<CmDevices soapenc:arrayType="ns1:CmDevice[2]" xsi:type="soapenc:Array"> 
<item xsi:type="ns1:CmDevice"> 
<Name xsi:type="xsd:string">SEPD0574CF73FC0</Name> 
<IpAddress xsi:type="xsd:string">10.186.79.41</IpAddress> 
<DirNumber xsi:type="xsd:string">51251001-Registered,51251004-Registered,51251002-Registered</DirNumber> 
<Class xsi:type="ns1:DeviceClass">Phone</Class> 
<Model xsi:type="xsd:unsignedInt">404</Model> 
<Product xsi:type="xsd:unsignedInt">303</Product> 
<BoxProduct xsi:type="xsd:unsignedInt">0</BoxProduct> 

下面是代码,这应该解析响应并返回返回设备的Ip地址值:

#!/usr/bin/perl 
use strict; 
use warnings; 
use Data::Dumper; 
use XML::Simple; 
use LWP; 
use SOAP::Lite; 

my $cucmip = "10.1.10.1"; 
my $axl_port = "8443"; 
my $user = "admin"; 
my $password = "password"; 
my $axltoolkit = "http://schemas.cisco.com/ast/soap/action/#RisPort#SelectCmDevice"; 

sub getDevIp { 
    my $message = "<?xml POST message> 

    my $url="https://$cucmip:$axl_port/realtimeservice/services/RisPort?wsdl"; 
    my $ua = LWP::UserAgent->new; 
    my $header = new HTTP::Headers (
    'Content-Type' => 'application/xml; charset=utf-8', 
    'SOAPAction' => 'http://schemas.cisco.com/ast/soap/action/#RisPort#SelectCmDevice', 
    ); 
    my $req = HTTP::Request->new(POST => $url, $header, $message); 
    $req->authorization_basic($user,$password); 
    my $response = $ua->request($req); 
    my $xs = new XML::Simple(KeyAttr=>[]); 
    my $data = $xs->XMLin($response->content); 
    print $data->{'soapenv:Body'}->{'ns1:SelectCmDeviceResponse'}->{'SelectCmDeviceResult'}->{'CmNodes'}->{'item'}->[0]->{'CmDevices'}->{'item'}->[0]->{'IpAddress'}->{'content'}; 
} 

getDevIp(); 
+1

您是否认真地期望任何人横向来回滚动来理解这一点?如果你的数据结构太复杂,不要使用'XML :: Simple'。 –

+2

我做了一些滚动操作,并且在您的示例中识别出您尝试访问的数据不存在。访问(不存在)键时,Autovivification会创建一个“undef”值。你是否严格使用''和'使用警告;'? –

+0

@SinanÜnür - Messy,我同意,但我认为这会比错误地更改可能对想要帮助的人很重要的部分数据更好。 –

回答

3

这基本上就是你所拥有的。

$VAR1 = { 
    'soapenv:Body' => { 
     'ns1:SelectCmDeviceResponse' => { 
      'SelectCmDeviceResult' => { 
       'CmNodes' => { 
        'item' => [ 
         { 
          'xsi:type' => 'ns1:CmNode', 
          'CmDevices' => { 
           'soapenc:arrayType' => 'ns1:CmDevice[0]', 
           'xsi:type'   => 'soapenc:Array' 
          }, 
         }, 
        ], 
        # plus some more items with DIFFERENT structure 
       }, 
      }, 
     }, 
    }, 
}; 

您正试图

$data->{'soapenv:Body'} 
    ->{'ns1:SelectCmDeviceResponse'} 
     ->{'SelectCmDeviceResult'} 
      ->{'CmNodes'} 
       ->{'item'}->[0]    # you probably want ->[1] here! (wild guess) 
        ->{'CmDevices'} 
         ->{'item'}->[0]  # this data does not exist 
          ->{'IpAddress'} # and this does not exist 
           ->{'content'}; # and this 

没有通过第一次访问Perl的创建中存在的值来访问(这就是所谓的自动激活)和初始化undef

这就是您的警告的原因。

+0

我想这个问题是低估的,因为你似乎懒得看你的问题下面的评论,并考虑更多的10秒。 –

+0

@mugenenkenichi - Nah,你错了。它被立即拒绝投票,很可能是因为我发布了很难阅读的巨大Dumper响应,但我确实解释说,我认为包括更多细节比保留它们更好会更好(我也遵从发布您请求的XML)。关于懒惰,超级优雅。那时你很了解我。我很欣赏最新的答复,并提供了一些关于我可能会出错的细节。一旦我真正掌握了这一点,如果我能够贡献自己的力量,我一定会对其他那些懒惰的人更容易一些。 –

+0

提问时,通常会发布显示问题的工作代码示例(适用于任何人)。如有必要,完成(!)输入和预期输出。这让其他懒惰的人更容易回答你的问题。无论如何..我并不是故意粗鲁,但我会稍微侵入其他人的哈希值;) –

1

你可以试试SOAP::Deserializer。我无法尝试它,因为我无法访问正在解析的XML文档。它返回一个SOAP::SOM对象。

valueof(node)

$res = $som->valueof('[1]'); 

SOAP::SOM物体已经与匹配方法在内部相匹配的路径,该方法允许内的任何匹配的节点的数据的检索。数据作为本地Perl数据返回,而不是类实例(请参阅dataof)。在标量上下文中,此方法仅返回匹配节点集中的第一个元素。在数组列表上下文中,返回所有元素。假设之前的调用发生在较早的匹配调用之后,它会从$ som中包含的方法响应中检索结果实体,因为这是方法响应标签中的第一个子元素。