如何在 Perl 中遍历 SOAP::Lite 响应的子数组?

How to loop through subarrays of a SOAP::Lite response in Perl?

我有一个 Perl 脚本可以成功地从我的 ShoreTel Phone 服务器获得响应。服务器提供有关输入的分机当前连接的呼叫的信息。但是,当有多个项目时,我在遍历子数组以获得多个响应时遇到问题。在这种情况下,我想获取当前连接的每个来电显示。

我的 SOAP:LITE 请求使用以下代码从服务器成功提取数据:

use strict;
use warnings;
use SOAP::Lite;
use CGI;
use Data::Dumper;

my $myWebService = SOAP::Lite
  -> uri('http://www.ShoreTel.com/ProServices/SDK/Web')
  -> proxy('http://10.1.##.##:8070/ShoreTelWebSDK/WebService')
  -> on_action(sub {sprintf '%s/ShoreTelWebService/%s', $_[0], $_[1]});

my $query = new CGI;
my $ip = $query->remote_host;                    # IP address of remote party...use later as unique identifier
my $myClientID = $query->param('MyClientID');    # Possible client ID from previous script passed into us.
my $extnNr = $query->param('MyExtn');            # Has to be at least an extension number so we know who to status.
my $url = CGI::url(-path_info=>1);               # What is my URL?

# There should be an extension number given, else what would we status.

if (defined($refreshNr) &&  defined($extnNr) && ($extnNr ne '') && ($refreshNr ne ''))
{
    # If there is a client ID defined, use it...otherwise registering and getting a client ID
    # is the first thing we need to do when using our web service.

  unless (defined($myClientID))
  {
    # To use our service, we need to register ourselves as a client...use remote IP address
    # as a unique name for association to this session.

    my $regClientResult = $myWebService->RegisterClient(SOAP::Data->name('clientName' => $ip));
    if ($regClientResult->fault)
    {
      print '<p>FAULT', $myClientID->faultcode, ', ', $myClientID->faultstring;
    }
    else
    {
      # Retrieve client ID which we will be using for subsequent communication.

      $myClientID = $regClientResult->valueof('//RegisterClientResponse/RegisterClientResult/');
    }
  }

   if (defined($myClientID))
  {
    # Use our web service to open the line.  This is necessary to get a line ID.

    # print '<br>Client ID ', $myClientID, ' has been registered.<br>';

    my $openResult = $myWebService->OpenLine(SOAP::Data->name('clientHandle' => $myClientID), SOAP::Data->name('lineAddress' => $extnNr));
    my $lineID = $openResult->valueof('//OpenLineResponse/OpenLineResult/lineID/');
    my $lineType = $openResult->valueof('//OpenLineResponse/OpenLineResult/lineType/');
    my $lineName = $openResult->valueof('//OpenLineResponse/OpenLineResult/lineName/');
    my $lineState = $openResult->valueof('//OpenLineResponse/OpenLineResult/lineState/');

# Call GetActiveCalls to see if anything is going on with this line.

    my $result = $myWebService->GetActiveCalls(SOAP::Data->name('clientHandle' => $myClientID), SOAP::Data->name('lineID' => $lineID));

    my $callID = $result->valueof('//GetActiveCallsResponse/GetActiveCallsResult/ShoreTelCallStateInfo/callInfo/callID/');

if ($callID ne '')
    {
      # print '<br>Call ID is ', $callID;

      my $isExternal = $result->valueof('//GetActiveCallsResponse/GetActiveCallsResult/ShoreTelCallStateInfo/callInfo/isExternal/');
      my $isInbound = $result->valueof('//GetActiveCallsResponse/GetActiveCallsResult/ShoreTelCallStateInfo/callInfo/isInbound/');
      my $callReason = $result->valueof('//GetActiveCallsResponse/GetActiveCallsResult/ShoreTelCallStateInfo/callInfo/callReason/');
      my $connectedID = $result->valueof('//GetActiveCallsResponse/GetActiveCallsResult/ShoreTelCallStateInfo/callInfo/connectedID/');
      my $connectedIDName = $result->valueof('//GetActiveCallsResponse/GetActiveCallsResult/ShoreTelCallStateInfo/callInfo/connectedIDName/');
      my $callerID = $result->valueof('//GetActiveCallsResponse/GetActiveCallsResult/ShoreTelCallStateInfo/callInfo/callerID/');
      my $callerIDName = $result->valueof('//GetActiveCallsResponse/GetActiveCallsResult/ShoreTelCallStateInfo/callInfo/callerIDName/');
      my $calledID = $result->valueof('//GetActiveCallsResponse/GetActiveCallsResult/ShoreTelCallStateInfo/callInfo/calledID/');
      my $calledIDName = $result->valueof('//GetActiveCallsResponse/GetActiveCallsResult/ShoreTelCallStateInfo/callInfo/calledIDName/');

      my $callState = $result->valueof('//GetActiveCallsResponse/GetActiveCallsResult/ShoreTelCallStateInfo/callState/');
      my $callStateDetail = $result->valueof('//GetActiveCallsResponse/GetActiveCallsResult/ShoreTelCallStateInfo/callStateDetail/');

      # Print call information.

      print <<EndOfCallInfo;
      HTML CODE
EndOfCallInfo

    }
    else
    {
         print <<EndOfCallInfo2;
         HTML CODE

EndOfCallInfo2
    }
  }

}

但我只能访问多维数组中的第一个结果。
我尝试使用

遍历结果
for my $t ($result->result({ShoreTelCallStateInfo}{callInfo}')) {
    print $t->{callerID} . "\n";}

但我完全没有得到任何结果。看来连循环都没有进入。

我的以下代码工作正常,但只提取第一个来电显示,在本例中为 1955。

my $callerID = $result->valueof('//GetActiveCallsResponse/GetActiveCallsResult/ShoreTelCallStateInfo/callInfo/callerID/');

我该怎么做才能使我的循环工作?

为了让您看到我从服务器接收到的内容,我使用 DUMP 包含了来自 SOAP 服务器的响应:

$VAR1 = { 'ShoreTelCallStateInfo' => [ 
            { 'callStateDetail' => 'Active', 
              'callState' => 'OnHold', 
              'callInfo' => 
                { 'callerIDName' => 'Joel LASTNAME', 
                  'callID' => '69105', 'lineID' => '3947', 
                  'connectedIDName' => 'VM-Forward', 
                  'calledID' => '2105', 
                  'callerID' => '1955', 
                  'isInbound' => 'false', 
                  'calledIDName' => 'VM-Forward', 
                  'callReason' => 'None', 
                  'callUniqueID' => '1369702515', 
                  'connectedID' => '2105', 
                  'isExternal' => 'false', 
                  'callGUID' => '{00030000-66C2-537E-3FD8-0010492377D9}' 
                 } 
            }, 
            { 'callStateDetail' => 'Active', 
              'callState' => 'Connected', 
              'callInfo' => 
                { 'callerIDName' => 'LASTNAME Joel ', 
                  'callID' => '71649', 
                  'lineID' => '3947', 
                  'connectedIDName' => 'LASTNAME Joel ', 
                  'calledID' => '1955', 
                  'callerID' => '+1385#######', 
                  'isInbound' => 'true', 
                  'calledIDName' => 'Joel LASTNAME', 
                  'callReason' => 'None', 
                  'callUniqueID' => '1117287558', 
                  'connectedID' => '+1385#######', 
                  'isExternal' => 'true', 
                  'callGUID' => '{00030000-66C5-537E-3FD8-0010492377D9}' 
                } 
            } 
        ] 
        }; 

只是猜测...

The following code I have works fine, but only pulls the first caller ID, in this case 1955.

my $callerID = $result->valueof('//GetActiveCallsResponse/GetActiveCallsResult/ShoreTelCallStateInfo/callInfo/callerID/');

What can I do to make my loop work?

SOAP::Lite docs 说:

valueof()

Returns the value of a (previously) matched node. It accepts a node path. In this case, it returns the value of matched node, but does not change the current node. Suitable when you want to match a node and then navigate through node children:

  $som->match('/Envelope/Body/[1]'); # match method
  $som->valueof('[1]');              # result
  $som->valueof('[2]');              # first out parameter (if present)

The returned value depends on the context. In a scalar context it will return the first element from matched nodeset. In an array context it will return all matched elements.

这是否会产生您期望的行为?它将列表上下文强加于 valueof 方法。

for my $callerID ($result->valueof('//GetActiveCallsResponse/GetActiveCallsResult/ShoreTelCallStateInfo/callInfo/callerID/')) {
      ...
      # do something with each callerID
}

my @callerIDs = $result->valueof('//GetActiveCallsResponse/GetActiveCallsResult/ShoreTelCallStateInfo/callInfo/callerID/');