如何使用SOAP :: Lite解析子数组?

时间:2015-07-24 09:44:42

标签: xml perl soap

我正在编写一个perl脚本来调用第三方的Web服务并解析响应XML,以便将数据写入数据库。我被建议使用SOAP :: Lite(目前在草莓Perl 5.22.0.1中使用1.14 for Windows 64-bit)。

响应可能如下所示:

<soap:Envelope>
  <soap:Body>
    <getEventsResponse>
      <GetEventsResponse>
        <events>
          <Event>
            <EventAttr1>valueofattr1</EventAttr1>
            <EventAttr2>valueofattr2</EventAttr2>
            <EventAttr3>valueofattr3</EventAttr3>
          </Event>
          <Event>
            <EventAttr1>valueofattr1</EventAttr1>
            <EventAttr2>valueofattr2</EventAttr2>
            <EventAttr3>valueofattr3</EventAttr3>
          </Event>
          <Event>
            <EventAttr1>valueofattr1</EventAttr1>
            <EventAttr2>valueofattr2</EventAttr2>
            <EventAttr3>valueofattr3</EventAttr3>
          </Event>
          <Event>
            <EventAttr1>valueofattr1</EventAttr1>
            <EventAttr2>valueofattr2</EventAttr2>
            <EventAttr3>valueofattr3</EventAttr3>
          </Event>
          .
          .
          .
       </events>
      </GetEventsResponse>
    </getEventsResponse>
  </soap:Body>
</soap:Envelope>

其中valueofattr1可以是该Event对象的唯一标识符,并且Events的数量是可变的。每个活动都有相同的吸引力。

要检索和评估事件,请使用以下软件包和代码:

package EventServices;
use SOAP::Lite;
sub new {
    my ($class)            = shift;
    my ($url)              = shift;
    my ($soapuser)         = shift;
    my ($soappasswordhash) = shift;
    my $self = {
        "url"              => $url,
        "soapuser"         => $soapuser,
        "soappasswordhash" => $soappasswordhash,
        "client"           => undef
};
bless $self, 'EventServices';
return $self;
}
sub connect {
    my $self = shift;
    $self->{client} =
        SOAP::Lite->uri('http://3rdparty.co.uk')
        ->proxy( $self->{url} . '/hosted/services/EventServicesWS' );

    $self->{client}->autotype(0); 
    # This stops SOAP::DATA automatically adding type definitions within every
    # XML element, which is often wrong and fails the XSD validation.
}   
sub getBatch {
my $self            = shift;
my $startDate       = shift;
my $endDate         = shift;

my $result =
$self->{client}->getEvents(
    SOAP::Data->prefix('ns2')->uri('http://3rdparty.co.uk')->name("userContext" =>
                            \SOAP::Data->value(
                            SOAP::Data->prefix('ns1')
                            .
                            .
                            .
              )
        )
    );
    return $result;
}
1;
my $fs = new EventServices( "https://3rdparty.co.uk", "<username>", "<hashedpassed>" );
$fs->connect();
$result = $fs->getBatch($startDate, $endDate);
for my $event ( $result->valueof('//getEventsResponse/GetEventsResponse/events/Event'))
{
  my $e_eventAttr1 = $event->{e_eventAttr1};
  my $e_eventAttr2 = $event->{e_eventAttr2};
  my $e_eventAttr3 = $event->{e_eventAttr3};
  .
  .
  .
}

这一切都运行正常,代码愉快地遍历每个事件。我一如既往地相信有不止一种方法可以实现这一目标,但这很简单。

循环遍历一系列事件,我现在需要探索如何遍历每个事件中的子数组。 XML现在看起来像这样:

<soap:Envelope>
  <soap:Body>
    <getEventsResponse>
      <GetEventsResponse>
        <events>
          <Event>
            <EventAttr1>valueofattr1</EventAttr1>
            <EventAttr2>valueofattr2</EventAttr2>
            <EventMessages>
              <EventMessageDetail>
                <MessageType>type1</MessageType>
                <MessageText>textOfTheMessageForType1</MessageText>
              <\EventMessageDetail>
              <EventMessageDetail>
                <MessageType>type2</MessageType>
                <MessageText>textOfTheMessageForType2</MessageText>
              <\EventMessageDetail>
              <EventMessageDetail>
                <MessageType>type3</MessageType>
                <MessageText>textOfTheMessageForType3</MessageText>
              <\EventMessageDetail>
              .
              .
              .
            </EventMessages>
            <EventAttr3>valueofattr3</EventAttr3>
          </Event>
          <Event>
            <EventAttr1>valueofattr1</EventAttr1>
            <EventAttr2>valueofattr2</EventAttr2>
            <EventMessages>
              <EventMessageDetail>
                <MessageType>type1</MessageType>
                <MessageText>textOfTheMessageForType1</MessageText>
              <\EventMessageDetail>
              <EventMessageDetail>
                <MessageType>type2</MessageType>
                <MessageText>textOfTheMessageForType2</MessageText>
              <\EventMessageDetail>
              <EventMessageDetail>
                <MessageType>type3</MessageType>
                <MessageText>textOfTheMessageForType3</MessageText>
              <\EventMessageDetail>
              .
              .
              .
            </EventMessages>
            <EventAttr3>valueofattr3</EventAttr3>
          </Event>
          <Event>
            <EventAttr1>valueofattr1</EventAttr1>
            <EventAttr2>valueofattr2</EventAttr2>
            <EventMessages>
              <EventMessageDetail>
                <MessageType>type1</MessageType>
                <MessageText>textOfTheMessageForType1</MessageText>
              <\EventMessageDetail>
              <EventMessageDetail>
                <MessageType>type2</MessageType>
                <MessageText>textOfTheMessageForType2</MessageText>
              <\EventMessageDetail>
              <EventMessageDetail>
                <MessageType>type3</MessageType>
                <MessageText>textOfTheMessageForType3</MessageText>
              <\EventMessageDetail>
              .
              .
              .
            </EventMessages>
            <EventAttr3>valueofattr3</EventAttr3>
          </Event>
          <Event>
            <EventAttr1>valueofattr1</EventAttr1>
            <EventAttr2>valueofattr2</EventAttr2>
            <EventMessages>
              <EventMessageDetail>
                <MessageType>type1</MessageType>
                <MessageText>textOfTheMessageForType1</MessageText>
              <\EventMessageDetail>
              <EventMessageDetail>
                <MessageType>type2</MessageType>
                <MessageText>textOfTheMessageForType2</MessageText>
              <\EventMessageDetail>
              <EventMessageDetail>
                <MessageType>type3</MessageType>
                <MessageText>textOfTheMessageForType3</MessageText>
              <\EventMessageDetail>
              .
              .
              .
            </EventMessages>
            <EventAttr3>valueofattr3</EventAttr3>
          </Event>
          .
          .
          .
        </events>
      </GetEventsResponse>
    </getEventsResponse>
  </soap:Body>
</soap:Envelope>

我应该严格地假设事件具有相同数量的EventMessages,如果 任何

我希望在事件的外部for循环中有一个for循环,但我发现如果我尝试$result->valueof('//getEventsResponse/GetEventsResponse/events/Event/EventMessages/EventMessageDetail'),那么内部for循环就会通过对于所有事件,所有EventMessageDetails,而不仅仅是外部for循环捕获的Event的EventMessageDetails。

我尝试使用[n]从for中的外部$result->match( )循环引用当前事件,但无法确定它应该如何工作。

有谁能告诉我如何解决这个问题?

一个解决方案:

在看了一下DATA :: Dumper的提示后,我终于发现在主for循环中添加以下代码是一种享受。

use Data::Dumper
my $a = Dumper($Event->{'EventMessages'}->{'EventMessageDetail'});
eval $a;
for my $MessageDetail (@{$VAR1}) {
  print "MessageType: $MessageDetail->{MessageType}; \n";
  print "MessageText = $MessageDetail->{MessageText}; \n";
}

解答:

这是一个更简洁,更快速的执行编码方法,根本不需要Data :: Dumper模块:

for my $MessageDetail ( @{ $Event->{'EventMessages'}->{'EventMessageDetail'} } ) { 
  print "MessageType: $MessageDetail->{MessageType}; \n";
  print "MessageText = $MessageDetail->{MessageText}; \n";
}

1 个答案:

答案 0 :(得分:0)

所以简单的答案是for my $MessageDetail ( @{ $Event->{'EventMessages'}->{'EventMessageDetail'} } ) {...}

谢谢simbabque