Perl module XML::Compile::WSDL11: Body isn't added to request - perl

I'm trying to build a WSDL client using XML::Compile::WSDL11 and this WSDL. The Operation in question is GetBGList3.
The problem is: The created request doesn't contain the body.
The example code is:
use XML::Compile::SOAP11;
use XML::Compile::WSDL11;
use XML::Compile::Transport::SOAPHTTP;
use Log::Report mode => 'VERBOSE'; # or 'VERBOSE' 'DEBUG'
my $wsdl_file="OpenScape-Voice.wsdl";
my $url="http://127.0.0.1:80/test";
my $ope="GetBGList3";
my $wsdl = XML::Compile::WSDL11->new;
$wsdl->addWSDL($wsdl_file);
$wsdl->compileCall($ope,address => $url);
my $hiqHEADER =
# Describing complex tns:hiqHEADER
# {urn:openscape-voice}hiqHEADER
# xmlns:tns urn:openscape-voice
# is a tns:hiqGLOBALHEADER
{ # sequence of InterfaceWSDL, OperatorId, ClientId
# is a xs:string
# is nillable, hence value or NIL
# is optional
InterfaceWSDL => "NIL",
# is a xs:string
# is nillable, hence value or NIL
# is optional
OperatorId => "myid",
# is a xs:string
# is nillable, hence value or NIL
# is optional
ClientId => "NIL", }
;
# Body part 'Body' is content for element tns:GetBGList3
my $Body =
# Describing complex tns:GetBGList3
# {urn:openscape-voice}GetBGList3
# xmlns:tns urn:openscape-voice
# xmlns:xs http://www.w3.org/2001/XMLSchema
# is an unnamed complex
{ # sequence of GetBGListRequest
# is a tns:GetBGListRequest
GetBGListRequest =>
{ # sequence of OperatorId, NumberPlanName, BGName,
# DNReserveEnabled, Paging, GetBGListDataOptionList,
# GetBGListSortList
# is a xs:string
# is nillable, hence value or NIL
# is optional
OperatorId => "myid",
# is a xs:string
# is nillable, hence value or NIL
# is optional
NumberPlanName => "NIL",
# is a xs:string
# is nillable, hence value or NIL
# is optional
BGName => "NIL",
# is a xs:boolean
# is nillable, hence value or NIL
# is optional
DNReserveEnabled => "true",
# is a tns:Paging
# is nillable, as: Paging => NIL
# is optional
Paging =>
{ # sequence of PageSize, PageNumber
# is a xs:int
PageSize => 42,
# is a xs:int
PageNumber => 42,
},
# is a tns:GetBGListDataOptionList
# is nillable, as: GetBGListDataOptionList => NIL
# is optional
GetBGListDataOptionList =>
{ # sequence of GetBGListDataOptionItem
# is a tns:GetBGListDataOptionItem
# occurs any number of times
GetBGListDataOptionItem =>
[ { # sequence of GetBGListDataOption
# is a xs:string
# is nillable, hence value or NIL
# is optional
# Enum: BgListDataInclBGDisplayNum
GetBGListDataOption => "BgListDataInclBGDisplayNum",
},
],
},
# is a tns:GetBGListSortList
# is nillable, as: GetBGListSortList => NIL
# is optional
GetBGListSortList =>
{ # sequence of GetBGListSortElement
# is a tns:GetBGListSortElement
# occurs any number of times
GetBGListSortElement =>
[ { # sequence of GetBGListSortType, SortOrder
# is a xs:string
# is nillable, hence value or NIL
# is optional
# Enum: BGListSortBGName
GetBGListSortType => "BGListSortBGName",
# is a xs:string
# is nillable, hence value or NIL
# is optional
# Enum: SortOrderAscending SortOrderDescending
SortOrder => "SortOrderAscending",
},
],
},
},
}
;
# Call with the combination of parts.
my #params = (
hiqHEADER => $hiqHEADER,
Body => $Body,
);
my ($answer, $trace) = $wsdl->call($ope,#params);
Running the script creates the warning
warning: unused values GetBGListRequest
Not providing the $Body creates this error:
error: required value for element `GetBGListRequest' missing at tns:GetBGList3
This means: the Body seems to be requested / needed to build the request - but finally it isn't added to the request.
The question now is: How can I achieve it to get the body added to the request, too?

Related

incorporating local variables in a global hash in perl

I need to incorporate a generic hash (macro) in multiple user hashes. In actuality these are all specifications written as HoH/HoL in perl.
I would like the 'user' specs to adopt the macro specs with their own modifications. In example below, the variable '$v_Y' needs to have different values in user1 and user2.
What I have below is not exactly code, but an attempt to illustrate the problem. I am unable to have multiple values of $v_Y since macro_spec is already created.
## this is in a package
my $MACRO_SPEC = {
mkeyX => "value_X",
mkeyY => $v_Y,
};
#this is USER1 package,
$v_Y = "U1_VALUE_X";
# use MACRO_SPEC
my $USER1 = (
u1key1 => "u1value1", u1macrokey => $MACRO_SPEC, # need macro to interpolate 'local' $v_Y
);
#this is USER2 package,
$v_Y = "U2_VALUE_X";
# use MACRO_SPEC
my $USER2 = (
u2key1 => "u2value1",
u2macrokey => $MACRO_SPEC, # need macro to interpolate 'local' $v_Y
);
#this is how USER1 should look after the interpolation
my $USER1 = (
u1key1 => "u1value1",
u1macrokey => {
mkeyX => "value_X",
mkeyY => "U1_VALUE_X"
},
);
#this is how USER2 should look after the interpolation
my $USER2 = (
u2key1 => "u2value1",
u1macrokey => {
mkeyX => "value_X",
mkeyY => "U2_VALUE_X"
},
);
Like melpomene suggested, you want $MACRO_SPEC to be a function that can generate something different each time it is called.
package One;
our $v_Y;
my $MACRO_SPEC = sub { +{ mkeyX => "value_X", mkeyY => $v_Y } };
...
package USER1;
$One::v_Y = "U1_VALUE_X";
my $user1 = { # { }, not ( ), to define a hash reference
u1key1 => "u1value1",
u1macrokey => $MACRO_SPEC->(), # $f->() to exec code defined in $f
...
};

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

I have a Perl script that is successfully getting a response from my ShoreTel Phone server. The server provides information on what calls are currently connected for the extension entered. However I am having issues looping through the sub arrays to get more than one response when there are multiple items. In this case I want to get each of the caller IDs that is currently connected.
My SOAP:LITE request is successfully pulling data from the server using the following code:
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
}
}
}
But I am only able to access the first result in the multidimensional array.
I have tried looping through the results using
for my $t ($result->result({ShoreTelCallStateInfo}{callInfo}')) {
print $t->{callerID} . "\n";}
But I am getting absolutely no results. It appears that the the loop is not even entered.
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?
So that you can see what I am receiving from the server I have included the response from the SOAP Server using DUMP :
$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}'
}
}
]
};
Just a guess...
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 say:
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.
Does this give the behavior you expect? It imposes list context on the valueof method.
for my $callerID ($result->valueof('//GetActiveCallsResponse/GetActiveCallsResult/ShoreTelCallStateInfo/callInfo/callerID/')) {
...
# do something with each callerID
}
or
my #callerIDs = $result->valueof('//GetActiveCallsResponse/GetActiveCallsResult/ShoreTelCallStateInfo/callInfo/callerID/');

Query Jenkins for job list using a perl script

I am not sure if this question is a duplicate or not but I cannot find any example of how one would do this. Is there any way we can query jenkins for the list of jobs. I have tried using the Jenkins::API that cpan provides but $jenkins->current_status()->jobs() returns a list of hash values. I am not sure if i am supposed to somehow translate these to readable jobs in english. Any tips??
Have a look at http://metacpan.org/pod/Jenkins::API.
$jenkins->current_status() does indeed return hash values. Each job hash contains keys 'color','name', and 'url'. But they are nested in a list at several levels. I found Data::Dumper helpful in seeing the full structure.
current_status
Returns the current status of the server as returned by the API. This is a hash containing a fairly comprehensive list of what's going on.
$jenkins->current_status();
# {
# 'assignedLabels' => [
# {}
# ],
# 'description' => undef,
# 'jobs' => [
# {
# 'color' => 'blue',
# 'name' => 'Jenkins-API',
# 'url' => 'http://jenkins:8080/job/Jenkins-API/'
# },
# ...
# ]
Example:
use Jenkins::API;
$jenkins = Jenkins::API->new({ base_url => 'http://localhost:8080' });
#statuses = $jenkins->current_status();
for ($i = 0;$i <= $#{$statuses[0]{'jobs'}};$i++) {
print $statuses[0]{'jobs'}[$i]{'name'},"\n";
}

How do I access Sinatra params using a symbol?

In Sinatra, I use params to get the key/value passed through the URL query string. I noticed I can use either a string or a symbol as the key to get the value. So if the URL is:
http://localhost:4567/x?a=1&b=2
Then:
params[:a] # => "1"
params["a"] # => "1"
params.to_s # => '{"name"=>"x", "a"=>"1", "b"=>"2"}'
params.class # => Hash
I can tell params is a Hash. But this doesn't seem to be a common behavior of a Hash.
h = {"a" => "1", "b" => "2"}
h["a"] # => "1"
h[:a] # => nil
Can someone please explain how this is achieved through Sinatra?
Always a good idea to have a read of the source. Specifically, the indifferent_params method.
# Enable string or symbol key access to the nested params hash.
def indifferent_params(params)
params = indifferent_hash.merge(params)
params.each do |key, value|
next unless value.is_a?(Hash)
params[key] = indifferent_params(value)
end
end
As the comment states, it's this method (invoked on line 704 of the same file) that allows string and symbol access to the params hash.

check field formmail

i am trying to change this:
foreach $require (#Required) {
# If the required field is the email field, the syntax of the email #
# address if checked to make sure it passes a valid syntax. #
if ($require eq 'email' && !&check_email($Config{$require})) {
push(#error,$require);
}
//////////////////////////////////////////////////////////////////////////////////
sub check_email {
# Initialize local email variable with input to subroutine. #
$email = $_[0];
# If the e-mail address contains: #
if ($email =~ /(#.*#)|(\.\.)|(#\.)|(\.#)|(^\.)/ ||
# the e-mail address contains an invalid syntax. Or, if the #
# syntax does not match the following regular expression pattern #
# it fails basic syntax verification. #
$email !~ /^.+\#(\[?)[a-zA-Z0-9\-\.]+\.([a-zA-Z0-9]+)(\]?)$/) {
# Basic syntax requires: one or more characters before the # sign, #
# followed by an optional '[', then any number of letters, numbers, #
# dashes or periods (valid domain/IP characters) ending in a period #
# and then 2 or 3 letters (for domain suffixes) or 1 to 3 numbers #
# (for IP addresses). An ending bracket is also allowed as it is #
# valid syntax to have an email address like: user#[255.255.255.0] #
# Return a false value, since the e-mail address did not pass valid #
# syntax. #
return 0;
}
else {
# Return a true value, e-mail verification passed. #
return 1;
}
}
into this:
foreach $require (#Required) {
if ($require eq 'fieldb' && !&check_fieldb($Config{$require})) {
push(#error,$require);
}
///////////////////////////////////////////////////////////////////////////////
sub check_fieldb {
# If field b is under 20% of field a: #
if ($fieldb <=($fielda/100)*20 ) {
# Return a false value, since field b is less than 20% of field a
return 0;
}
else {
# Return a true value, fieldb verification passed. #
return 1;
}
}
but it does not work, always returns as 0.
how would i fix this?
It's impossible to be sure what's wrong without knowing the values of $fielda and $fieldb. My diagnosis is that $fieldb is less than or equal to ($fielda/100)*20
You pass a value to check_fieldb, but you never use it. Why do you pass it? As a commenter noted you should be passing to the function the values you want to check. Are $fielda and $fieldb guaranteed to be correctly initialized before check_fieldb is called?
Do you meant to be saying
foreach my $require (#Required){
if($require eq 'fieldb' && !check_fieldb($value_of_fielda, $value_of_fieldb)){
push(#error, $require);
}
}
# ... later ...
sub check_fieldb($$){
my $fielda = shift;
my $fieldb = shift;
return !($fieldb <=($fielda/100)*20);
}
perhaps?