Invoke-WebReqeust - XML String needs to be stored in a form field called REQUEST and should be sent to our servers via HTTP POST method - powershell

Stuck following some poor documentation. Attempting to connect to a vendors API to pull orders into my own DB. The vendor has only one line and example (not even a proper url that I am still attempting to get).
Documentation =
XML String needs to be stored in a form field called REQUEST and should be sent to our servers via HTTP POST method. All of the methods described in this document must follow this standard.
Example =
GET ORDERS method XML format:
<?xml version="1.0" encoding="utf-8"?>
<OrderXML>
<Method>GET ORDERS</Method>
<Authentication>
<Username>Your Username</Username>
<Password>Your Password</Password>
</Authentication>
</OrderXML>
Tried in Postman and PowerShell just cannot figure out how to get "Request" form.
My code returns bad request and I am not sure if due to URL or not getting the "Request" form coded correctly.
$URI = "https://orders.website.com/webservice/default.cfm"
[xml]$requestXML = #'
REQUEST=
<OrderXML>
<Method>GET ORDERS</Method>
<TestMode>YES</TestMode>
<Authentication>
<Username>USERNAME</Username>
<Password>PASSWORD</Password>
</Authentication>
</OrderXML>
'#
Invoke-WebRequest -Uri $URI -Method Post -Body $requestXML
Thank you

So finally figured it out in Postman.
Used the form control instead of Raw XML.
With Key being the required "REQUEST" and the Value being the XML.

Related

Microsoft Ads 'AccountPerformanceReportRequest' data contract. The deserializer has no knowledge of any type that maps to this contract

I'm trying to use the Microsoft Bing Ads' Reporting API to gather ad performance data such as clicks, spend, etc. programmatically. Below, I describe the steps taken.
There are two issues -
1 - I have to request for user consent again and again as access token
is short lived and refreshed token also giving unauthenticated token
error.
2 - After following the steps I don't get the expected SOAP
Response. Instead I get below response.
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<s:Fault>
<faultcode xmlns:a="http://schemas.microsoft.com/net/2005/12/windowscommunicationfoundation/dispatcher">a:DeserializationFailed</faultcode>
<faultstring>The formatter threw an exception while trying to deserialize the message: There was an error while trying to deserialize parameter https://bingads.microsoft.com/Reporting/v13:ReportRequest. The InnerException message was 'Error in line 13 position 71. Element 'https://bingads.microsoft.com/Reporting/v13:ReportRequest' contains data of the ':AccountPerformanceReportRequest' data contract. The deserializer has no knowledge of any type that maps to this contract. Add the type corresponding to 'AccountPerformanceReportRequest' to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding it to the list of known types passed to DataContractSerializer.'. Please see InnerException for more details.</faultstring>
</s:Fault>
</s:Body>
</s:Envelope>
I'm using Postman to test the service and my end goal is to use http to do the same in Mulesoft later. This is the URL I am using
https://reporting.api.bingads.microsoft.com/Api/Advertiser/Reporting/V13/ReportingService.svc
Authentication
I have followed their OAuth 2.0 Authentication Flow in that, I have:
Registered my Application (using the Developer Account)
Requested user consent (through the Ad account)
Generated the Access Token and Refresh Token Every time I hit the API.
**
I generate a new Access Token by requesting user consent again and again as refreshing
token is also not working.
**
Making the Request
The documentation describes a Reporting Service Operation which follows an asynchronous approach. First we need to use SubmitGenerateReport to make a request to the Reporting Service. This returns a ResponseRequestId which we can then use to repeatedly poll the service using PollGenerateReport till we get the requested report in response.
SubmitGenerateReport
SubmitGenerateReport has to be in SOAP XML Format as stated here. Following is the document I generated for my use case looking at the provided example in the documentation. Action I am passing as header attribute - SOAPAction:SubmitGenerateReport
<x:Envelope
xmlns:x="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:v="https://bingads.microsoft.com/Reporting/v13"
xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<x:Header>
<v:AuthenticationToken>****</v:AuthenticationToken>
<v:CustomerAccountId>****</v:CustomerAccountId>
<v:CustomerId>****</v:CustomerId>
<v:DeveloperToken>****</v:DeveloperToken>
</x:Header>
<x:Body>
<v:SubmitGenerateReportRequest>
<v:ReportRequest i:type="AccountPerformanceReportRequest">
<v:Format>Csv</v:Format>
<v:ReportName>AccountPerformanceReportRequest</v:ReportName>
<v:Aggregation>Summary</v:Aggregation>
</v:ReportRequest>
</v:SubmitGenerateReportRequest>
</x:Body>
</x:Envelope>
I even tried passing all the input variables, scope, time etc but getting some error again. I understand error clearly tells me where the error is but the report types I am using are given in Microsoft documentations.
Any help and suggestion would be really helpful.
1. I have to request for user consent again and again as access token is short lived and refreshed token also giving unauthenticated token error.
I would like to point you to these tutorial, as reference for my code below.
https://learn.microsoft.com/en-us/advertising/guides/get-started?view=bingads-13
https://learn.microsoft.com/en-us/advertising/guides/authentication-oauth-quick-start?view=bingads-13
In the first step, you fetch code, for this you need browser verification.
$clientId = '...'
Start-Process "https://login.microsoftonline.com/common/oauth2/v2.0/authorize?client_id=$clientId&scope=openid%20profile%20https://ads.microsoft.com/msads.manage%20offline_access&response_type=code&redirect_uri=https://login.microsoftonline.com/common/oauth2/nativeclient&state=ClientStateGoesHere&prompt=login"
$code = 'https://login.microsoftonline.com/common/oauth2/nativeclient?code=<code>&state=ClientStateGoesHere'
$code = $code -match 'code=(.*)\&'
$code = $Matches[1]
Now, using this code, you get accessToken/refreshToken.
$response = Invoke-WebRequest https://login.microsoftonline.com/common/oauth2/v2.0/token -ContentType application/x-www-form-urlencoded -Method POST -Body "client_id=$clientId&scope=https://ads.microsoft.com/msads.manage%20offline_access&code=$code&grant_type=authorization_code&redirect_uri=https%3A%2F%2Flogin.microsoftonline.com%2Fcommon%2Foauth2%2Fnativeclient"
$oauthTokens = ($response.Content | ConvertFrom-Json)
Since, this access token $oauthTokens.access_token will expire after one hour, use the refresh token to get new access and refresh tokens. This process you need to do periodically, say on 1/2 hourly basis.
Process to refresh is the following. This does not require you to login.
$response = Invoke-WebRequest https://login.microsoftonline.com/common/oauth2/v2.0/token -ContentType application/x-www-form-urlencoded -Method POST -Body "client_id=$clientId&scope=https://ads.microsoft.com/msads.manage%20offline_access&code=$code&grant_type=refresh_token&refresh_token=$($oauthTokens.refresh_token)"
$oauthTokens = ($response.Content | ConvertFrom-Json)
PS, I'm unclear if we could refresh infinitely or whether it is bound to a day. I verified that an expired accessToken could be renewed via refreshToken via this method after 1.5 hours - no need of generating code again via relogin.
2. After following the steps I don't get the expected SOAP Response. Instead I get below response
Thank you for providing the detailed soap xmls. I tried the same on my test account and able to repro exact same error message.
Here's the udpated SOAP xml request I used to get it to work.
<s:Envelope xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Header xmlns="https://bingads.microsoft.com/Reporting/v13">
<AuthenticationToken i:nil="false">here goes token</AuthenticationToken>
<CustomerAccountId i:nil="false">176045209</CustomerAccountId>
<CustomerId i:nil="false">169549046</CustomerId>
<DeveloperToken i:nil="false">here goes dev Token</DeveloperToken>
</s:Header>
<s:Body>
<SubmitGenerateReportRequest xmlns="https://bingads.microsoft.com/Reporting/v13">
<ReportRequest i:nil="false" i:type="AccountPerformanceReportRequest">
<Format i:nil="false">Csv</Format>
<ReportName i:nil="false">reportName1</ReportName>
<!--These fields are applicable if the derived type attribute is set to AccountPerformanceReportRequest-->
<Aggregation>Summary</Aggregation>
<Columns i:nil="false">
<AccountPerformanceReportColumn>Impressions</AccountPerformanceReportColumn>
<AccountPerformanceReportColumn>Revenue</AccountPerformanceReportColumn>
<AccountPerformanceReportColumn>AccountName</AccountPerformanceReportColumn>
</Columns>
<Scope i:nil="false">
<AccountIds i:nil="false" xmlns:a1="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
<a1:long>176045209</a1:long>
</AccountIds>
</Scope>
<Time i:nil="false">
<CustomDateRangeEnd i:nil="false">
<Day>22</Day>
<Month>07</Month>
<Year>2022</Year>
</CustomDateRangeEnd>
<CustomDateRangeStart i:nil="false">
<Day>01</Day>
<Month>07</Month>
<Year>2022</Year>
</CustomDateRangeStart>
</Time>
</ReportRequest>
</SubmitGenerateReportRequest>
</s:Body>
</s:Envelope>
Here's the postman result.
PS, I received error, when some fields were missing. I did not use xml namespaces.
Hope this helps.

Problem with validation of SOAP request with Zeep (python)

I have problems to get SOAP request through Zeep, I get a (client) validation error... I have also tested with SoapUI and that does NOT give me the same validation error...
The specification below is from the server... Based on that specification, the OrderStatus and SynchStatus are needed to perform the request.
<soapenv:Envelope xmlns:soapenv=http://schemas.xmlsoap.org/soap/envelope/ xmlns:web="WebServiceProvider">
<soapenv:Header/>
<soapenv:Body>
<web:Order_Get>
<!--Optional:-->
<web:orderOptions>
<web:FromDate>?</web:FromDate>
<web:ToDate>?</web:ToDate>
<web:OrderStatus>?</web:OrderStatus>
<web:SynchStatus>?</web:SynchStatus>
<!--Optional:-->
<web:OrderNumber>?</web:OrderNumber>
<web:FromOrderNumberToLastRecieved>?</web:FromOrderNumberToLastRecieved>
<web:PaymentStatus>?</web:PaymentStatus>
</web:orderOptions>
</web:Order_Get>
</soapenv:Body>
</soapenv:Envelope>
However, executing this from the SoapUI without OrderStatus and SynchStatus will give me a list of all the orders for the specified dates:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:web="WebServiceProvider">
<soapenv:Header/>
<soapenv:Body>
<web:Order_Get>
<web:orderOptions>
<web:FromDate>2021-03-30</web:FromDate>
<web:ToDate>2021-03-31</web:ToDate>
</web:orderOptions>
</web:Order_Get>
</soapenv:Body>
</soapenv:Envelope>
I want to do the same with Zeep (https://github.com/mvantellingen/python-zeep) but the client validation fails...
I initiate the request with the following code:
api_url = 'https://abc.se/Webservice20/v3.0/webservice.asmx?WSDL'
session.auth = HTTPDigestAuth(username, password)
api = Client(api_url, transport=Transport(session=session))
And then I try to execute the following request:
order_options = {
'FromDate': '2021-03-30',
'ToDate': '2021-03-31',
}
orders = api.service.Order_Get(orderOptions=order_options)
This will result in the following error:
zeep.exceptions.ValidationError: Missing element OrderStatus (Order_Get.orderOptions.OrderStatus)
If I add OrderStatus to the request, I will get a validation error saying that SynchStatus is missing. When that has been added as well, the request is sent to the server.
I.e. it seems like the zeep client is more strict with regards to validating the data in the request than what the server is... Is there a way to force the client to skip this validation?
Many thanks in advance!
Searched a bit more and found a workaround in this post: Getting zeep.exceptions.ValidationError: Missing element for method that worked with suds
So the solution in my case looks like this:
from zeep import xsd
...
order_options = {
'FromDate': '2021-03-30',
'ToDate': '2021-03-31',
'OrderStatus': xsd.SkipValue,
'SynchStatus': xsd.SkipValue,
}
response = api.service.Order_Get(orderOptions=order_options)
This will block zeep from doing client side validation of the parameters OrderStatus and SynchStatus.
it seems like the zeep client is more strict with regards to validating the data in the request than what the server is...
Looks like it.
Looking at the request SoapUI generates based on the WSDL, the two fields you mention are mandatory:
<web:orderOptions>
<web:FromDate>?</web:FromDate>
<web:ToDate>?</web:ToDate>
<web:OrderStatus>?</web:OrderStatus>
<web:SynchStatus>?</web:SynchStatus>
<!--Optional:-->
<web:OrderNumber>?</web:OrderNumber>
<web:FromOrderNumberToLastRecieved>?</web:FromOrderNumberToLastRecieved>
<web:PaymentStatus>?</web:PaymentStatus>
</web:orderOptions>
So the error that the zeep client displays is correct. Zeep inspects the WSDL and generates the corresponding code to use the types in the contract. Your WSDL contract says that OrderStatus and SynchStatus are mandatory. The fact that the server doesn't validate them shows a problem: the web service isn't respecting it's own documented contract
The WSDL and the behavior of the web service should be the same. I suggest you contact the web service owners and ask about this behavior. It might be a validation missing on the server and what you get is just some side effect of that, or the behavior is intentional but someone forgot to update the WSDL to say that you can also make the call without those parameters.
Meanwhile, the workaround is very simple. Download the WSDL, change it to make the two fields optional, then feed this changed WSDL to zeep for it to generate the code, instead of using the original WSDL. You should however clarify this with the web service provider. If it's indeed a neglect of someone, this might be spotted at some point and fixed, making your workaround call fail a server validation because of the missing fields.

PowerShell: How to make email message body to be html fomatted but to contain raw soap response

Using a PowerShell script I invoke a web request and save the response in a variable
$SOAP_RESP=(Invoke-WebRequest $WEB_SRV_URL -Method Post -ContentType "text/xml" -InFile $SOAP_REQ_FILE_PATH).Content
I have email body HTML formatted and I append the earlier obtained SOAP response to it.
$MESSAGE_BODDY="$($HTML_FORMATTED_MESSAGE)<br><br>$($SOAP_RESP)"
Next I want to send an email containing email body from the previous step -BodyAsHtml
Send-MailMessage -From $SMTP_FROM -To $SMTP_TO -Subject $MESSAGE_SUBJECT -Body $MESSAGE_BODDY -BodyAsHtml -Priority high
Obviously, it formats the SOAP response and the email which is delivered is a mess.
Does anyone know how can I deal with this situation? I need SOAP request to be in the email.
[EDIT]
The soap response is
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xmm="http://namespace.mynamespace/mapping" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<SOAP-ENV:Body>
<m:service_name xmlns:m="urn:com-s-s-rpc:SYSTEM">
<_INPUT_PARAM>
<UNIT_ID>0dbghfgd</UNIT_ID>
<MSG>test</MSG>
</_INPUT_PARAM>
<_OUTPUT_PARAM>
<RETURN_ERROR_MSG>Invalid Format</RETURN_ERROR_MSG>
</_OUTPUT_PARAM>
</m:service_name>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
What I get in email is only below string (not entire response)
<_INPUT_PARAM>0dbghfgdtest<_OUTPUT_PARAM>Invalid Format
Per the comment from TessellatingHeckler, the <pre> and <code> HTML tags both force the contents of those tags to be presented raw and any HTML tags within are not interpreted. Pre stands for Preformatted Text. Code means "This is computer code".
You can use both together for a belt and braces approach:
$MESSAGE_BODDY="$($HTML_FORMATTED_MESSAGE)<br><br><pre><code>$($SOAP_RESP)</pre></code>"

Why is Invoke-WebRequest and Invoke-RestMethod failing and succeeding at the same time?

I wrote a small PowerShell script to send a request to a server and get a simple XML result back.
PowerShell Script
$xml = "<?xml version='1.0' encoding='utf-8'?><Search><ID>278A87E1-1BC2-4E19-82E9-8BBE31D67D20</ID></Search>"
$response = Invoke-RestMethod -Method Post -Uri "http://localhost/search" -ContentType "application/xml" -Body $xml
That's it, really simple and there's no reason that I can see for it to be failing. I have also tried the script with Invoke-WebRequest and both fail. The error returned is Invoke-RestMethod : Value cannot be null. Parameter name: name. The strange thing is that when I monitor this with Wireshark, I see the connection, I see the POST and I see the result from the server and all looks perfectly good but the cmdlet is saying it failed (and yes, the return code is 200).
If I run the Invoke-WebRequest/Invoke-RestMethod with the -OutFile parameter, it runs fine with no errors and saves the result to the specified file; -OutVariable fails just in case you're wondering.
The result is an xml file, the headers specify that it is xml and the xml is properly formatted.
Result when successful
<?xml version="1.0" encoding="UTF-8" ?>
<Result version="1.0" xmlns="urn:xmlns-org">
<searchID>{278a87e1-1bc2-4e19-82e9-8bbe31d67d20}</searchID>
<responseStatus>true</responseStatus>
<responseStatusStrg>MORE</responseStatusStrg>
<numOfMatches>40</numOfMatches>
</Result>
Does anyone know why the Invoke-XXX cmdlets are returning an error and what I can do to fix it? Again, it works perfectly fine when I use the -OutFile parameter and even when it fails I can see a proper conversation between the script and the server in Wireshark.
Also, if I use -Verbose it tells me the following:
VERBOSE: POST http://localhost/search with -1-byte payload
VERBOSE: received X-byte response of content type application/xml; charset="UTF-8"
Where X-byte is the actual size of the response but it obviously differs with each response depending on the data sent to the server. I just find it odd that the cmdlet fails but says it received a response with data and that it sent a -1-byte payload.
I went ahead and looked into the Invoke-WebRequest cmdlet code and found out why it's failing with this particular error.
It's failing on a call to System.Globalization.EncodingTable.GetCodePageFromName. The encoding is passed to that function as a parameter and the encoding is retrieved from the the cmdlet through the Content-Type header. In the case of this server the Content-Type was sent back in the response as Content-Type: application/xml; charset="UTF-8".
The problem with this is that quotes aren't standard for wrapping the value in charset so the cmdlet parses it out as "UTF-8" instead of the valid UTF-8. The cmdlet passes "UTF-8" to the function and the function throws an exception stating that the provided encoding is invalid. This is fine and would make so much more sense if that is what was reported in the final exception but it's not.
The Invalid encoding exception is caught by the Microsoft.PowerShell.Commands.ContentHelper.GetEncodingOrDefault function and in the exception handler it calls GetEncoding again but with a null parameter which results in the final ArgumentNullException for parameter name.
Microsoft.PowerShell.Commands.ContentHelper.GetEncodingOrDefault
internal static Encoding GetEncodingOrDefault(string characterSet)
{
string name = string.IsNullOrEmpty(characterSet) ? "ISO-8859-1" : characterSet;
try
{
return Encoding.GetEncoding(name);
}
catch (ArgumentException ex)
{
return Encoding.GetEncoding((string) null);
}
}
The call to GetEncoding inside the catch statement triggers the following code inside GetCodePageFromName which is itself called from GetEncoding
if (name==null) {
throw new ArgumentNullException("name");
}
PowerShell is handling this properly since technically it is an invalid value but you'd think they would call Trim("\"") just to be safe.
Although this thread is years-old, I came across it in 2022 when I encountered the same error 'Invoke-RestMethod : Value cannot be null. Parameter name: name' accessing an API to create a user. In my case Content-Type was application/json (rather than application/xml in Vane's question above). The API POST required Basic Auth.
I UTF8 encoded the credentials prior to converting to Base64, and et voilà the error disappeared. Given that the Content-Type investigation by Vane above tracked a return of charset="UTF-8", this UTF8 encoding and the disappearance of the error may be related, although this is just surmise on my part.
$username = "your_username"
$password = "your_password"
$credential = "${username}:${password}"
$credentialBytes = [System.Text.Encoding]::UTF8.GetBytes($credential)
$encodedCredential = [System.Convert]::ToBase64String($credentialBytes)
$headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$headers.Add("Authorization", "Basic $encodedCredential")
$headers.Add("Content-Type", "application/json")

SoapUI Pro, validating response using groovy script

I am using SoapUI Pro to test web services used for creating postal despatch shipments.
I am using a groovy script to validate my web service requests. If I am expecting the request to succeed I look for a value of ‘Allocated’ in the ‘status’ field. If I am expecting the request to fail I look for the correct error code and errorDescription in the integration footer.
Sometimes a valid request will have a warning message (e.g. to inform user that field data is too long and has been truncated). I also want to validate these warning messages as well.
I specify the element path that I want to validate in my data source file and then pass it to my groovy script that does the validation.
The groovy script retrieves the value in the element path and assigns it to a variable actualReturn1 using ..
actualReturn1 = holder.getNodeValue(testElementOne);
where testElementOne could be either
//NS1:completedShipmentInfo/NS1:status/status/statusCode/code
OR
//NS1:createShipmentResponse/NS1:integrationFooter/errors/error/errorCode
The first path is valid and correctly assigns the value of this status field to actualReturn1.
But the second path does not appear to be valid and assigns null to actualReturn1.
Below are part of my 2 response files the elements I’m trying to extract data from.
Response with status element that is extracted successfully..
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<NS1:createShipmentResponse xmlns:NS1="http://www.royalmailgroup.com/api/ship/V1">
<NS1:integrationHeader>
<dateTime xmlns="http://www.royalmailgroup.com/integration/core/V1">2013-12-02T17:06:11</dateTime>
<version xmlns="http://www.royalmailgroup.com/integration/core/V1">1</version>
<identification xmlns="http://www.royalmailgroup.com/integration/core/V1">
<applicationId>111111113</applicationId>
<transactionId>420642961</transactionId>
</identification>
</NS1:integrationHeader>
<NS1:completedShipmentInfo>
<NS1:status>
<status>
<statusCode>
<code>Allocated</code>
</statusCode>
</status>
Response with errorCode that can not be extracted…
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<NS1:createShipmentResponse xmlns:NS1="http://www.royalmailgroup.com/api/ship/V1">
<NS1:integrationHeader>
<dateTime xmlns="http://www.royalmailgroup.com/integration/core/V1">2013-12-02T17:06:13</dateTime>
<version xmlns="http://www.royalmailgroup.com/integration/core/V1">1</version>
<identification xmlns="http://www.royalmailgroup.com/integration/core/V1">
<applicationId>111111113</applicationId>
<transactionId>420642961</transactionId>
</identification>
</NS1:integrationHeader>
<NS1:integrationFooter>
<errors xmlns="http://www.royalmailgroup.com/integration/core/V1">
<error>
<errorCode>E1101</errorCode>
<errorDescription>Name is a required field</errorDescription>
</error>
</errors>
Could someone tell me why this isn't working for the second response? If I have warning messages in a valid response then I'm also not able to extract the value. Is it because this is in the integrationFooter?
Happened to see this now, so adding the answer.
In the 2nd case, it was not working for you because of the namespace issue.
The element, errors is using default namespace and is different from its parent element integrationFooter. And in your xpath, no namespace was referred to element errors and its child elements.
Here is the script that works for 2nd case:
def xml = '''
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<NS1:createShipmentResponse xmlns:NS1="http://www.royalmailgroup.com/api/ship/V1">
<NS1:integrationHeader>
<dateTime xmlns="http://www.royalmailgroup.com/integration/core/V1">2013-12-02T17:06:13</dateTime>
<version xmlns="http://www.royalmailgroup.com/integration/core/V1">1</version>
<identification xmlns="http://www.royalmailgroup.com/integration/core/V1">
<applicationId>111111113</applicationId>
<transactionId>420642961</transactionId>
</identification>
</NS1:integrationHeader>
<NS1:integrationFooter>
<errors xmlns="http://www.royalmailgroup.com/integration/core/V1">
<error>
<errorCode>E1101</errorCode>
<errorDescription>Name is a required field</errorDescription>
</error>
</errors>
</NS1:integrationFooter>
</NS1:createShipmentResponse>
</soapenv:Body>
</soapenv:Envelope>'''
def holder = new com.eviware.soapui.support.XmlHolder( xml )
holder.declareNamespace('a','http://www.royalmailgroup.com/api/ship/V1')
holder.declareNamespace('b','http://www.royalmailgroup.com/integration/core/V1' )
def errorCode = holder.getNodeValue( "//a:integrationFooter/b:errors/b:error/b:errorCode" )
assert errorCode == 'E1101'