Karate: Replace text at Envelope level [duplicate] - soap

I need to parse and print ns4:feature part. Karate prints it in json format. I tried referring to this answer. But, i get 'ERROR: 'Namespace for prefix 'xsi' has not been declared.' error, if used suggested xPath. i.e.,
* def list = $Test1/Envelope/Body/getPlan/planSummary/feature[1]
This is my XML: It contains lot many parts with different 'ns' values, but i have given here an extraxt.
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
<S:Header/>
<S:Body>
<ns9:getPlan xmlns:ns10="http://xmlschema.test.com/xsd_v8" xmlns:ns9="http://xmlschema.test.com/srv/SMO_v4" xmlns:ns8="http://xmlschema.test.com/xsd/Customer_v2" xmlns:ns7="http://xmlschema.test.com/xsd/Customer/Customer_v4" xmlns:ns6="http://schemas.test.com/eca/common_types_2_1" xmlns:ns5="http://xmlschema.test.com/xsd/Customer/BaseTypes_1_0" xmlns:ns4="http://xmlschema.test.com/xsd_v4" xmlns:ns3="http://xmlschema.test.com/xsd/Enterprise/BaseTypes/types/ping_v1" xmlns:ns2="http://xmlschema.test.com/xsd/common/exceptions/Exceptions_v1_0">
<ns9:planSummary xsi:type="ns4:Plan" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<ns5:code>XPBSMWAT</ns5:code>
<ns5:description>Test Plan</ns5:description>
<ns4:category xsi:nil="true"/>
<ns4:effectiveDate>2009-11-05</ns4:effectiveDate>
<ns4:sharingGroupList>
<ns4:sharingCode>CAD_DATA</ns4:sharingCode>
<ns4:contributingInd>true</ns4:contributingInd>
</ns4:sharingGroupList>
<ns4:feature>
<ns5:code>ABC</ns5:code>
<ns5:description>Service</ns5:description>
<ns5:descriptionFrench>Service</ns5:descriptionFrench>
<ns4:poolGroupId xsi:nil="true"/>
<ns4:switchCode/>
<ns4:type/>
<ns4:dtInd>false</ns4:dtInd>
<ns4:usageCharge>0.0</ns4:usageCharge>
<ns4:connectInd>false</ns4:connectInd>
</ns4:feature>
</ns9:planSummary>
</ns9:getPlan>
</S:Body>
</S:Envelope>
This is the xPath i used;
Note: I saved above xml in a separate file test1.xml. I am just reading it and parsing the value.
* def Test1 = read('classpath:PP1/data/test1.xml')
* def list = $Test1/Envelope/Body/*[local-name()='getPlan']/*[local-name()='planSummary']/*[local-name()='feature']/*
* print list
This is the response i am getting;
16:20:10.729 [ForkJoinPool-1-worker-1] INFO com.intuit.karate - [print] [
"ABC",
"Service",
"Service",
"",
"",
"",
"false",
"0.0",
"false"
]
How can i get the same in XML?

This is interesting, I haven't seen this before. The problem was you have an attribute with a namespace xsi:nil="true" which is causing problems when you take a sub-set of the XML but the namespace is not defined anymore. If you remove it first, things will work.
Try this:
* remove Test1 //poolGroupId/#nil
* def temp = $Test1/Envelope/Body/getPlan/planSummary/feature
Another approach you could have tried is to do a string replace to remove troublesome stuff in the XML before doing XPath.
EDIT: added info on how to do a string replace using Java. The below will strip out the entire xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ns4:Plan" part.
* string temp = Test1
* string temp = temp.replaceAll("xmlns:xsi[^>]*", "")
* print temp
So you get the idea. Just use regex.
Also see: https://stackoverflow.com/a/50372295/143475

Related

Querying XML data with a long, multi special character, path name

Just getting started with XQuery using BaseX.
The XML structure that I did not create and have no control over, looks like this:
2002test.xml:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<ns2:runSearchResponse xmlns:ns2="http://externalapi.business.footprints.numarasoftware.com/">
<return>
<_items>
<_containerDefinitionId>1234</_containerDefinitionId>
<_containerDefinitionName>Service Desk</_containerDefinitionName>
<_itemDefinitionId>2244</_itemDefinitionId>
<_itemDefinitionName>Service Request</_itemDefinitionName>
<_itemId>9989</_itemId>
<_itemFields>
<itemFields>
<fieldName>Icon Name</fieldName>
<fieldValue>
<value>default_ticket.png</value>
</fieldValue>
</itemFields>
<itemFields>
<fieldName>emailCustomerUpdate</fieldName>
<fieldValue>
<value>false</value>
</fieldValue>
</itemFields>
<itemFields>
<fieldName>bestContactNumber_Customer</fieldName>
<fieldValue>
<value/>
</fieldValue>
</itemFields>
</_itemFields>
</_items>
</return>
</ns2:runSearchResponse>
</soap:Body>
</soap:Envelope>
Doing a simple:
for $x in doc("2002test.xml")
return $x
returns my entire document as expected.
Any attempt to drill into it is not working for me however.
I've tried:
for $x in doc("2002test.xml")/soap:Envelope/soap:Body/ns2:runSearchResponse/return
return $x/_items/itemFields/fieldName
But the long path throws a "No namespace declared for 'soap:Envelope'."
So I tried declaring the path like this:
declare variable $m := "/soap:Envelope/soap:Body/ns2:runSearchResponse/return";
for $x in doc("2002test.xml")//$m
return $x
Which got me:
/soap:Envelope/soap:Body/ns2:runSearchResponse/return
/soap:Envelope/soap:Body/ns2:runSearchResponse/return
/soap:Envelope/soap:Body/ns2:runSearchResponse/return
...
I tried:
for $x in doc("2002test.xml")/*[local-name()='soap:Envelope'][local-name()='soap:Body'][local-name()='ns2:runSearchResponse'][local-name()='return']
return $x
Which did nothing.
Very simply I'd like to be able to do something like this:
for $x in doc("2002test.xml")
where $x/return/_items/_itemFields/itemFields/fieldValue/value="default_ticket.png"
return $x/return/_items/_itemFields/itemFields/fieldName/text()
resulting in:
Icon Name
Any advice?
Use basic XPath expressions with a predicate e.g.
doc("2002test.xml")//itemFields[fieldValue/value = "default_ticket.png"]/fieldName/text()
If you think you need a FLOWR expression then use e.g.
for $field in doc("2002test.xml")//itemFields
where $field/fieldValue/value = "default_ticket.png"
return $field/fieldName/text()

Printing SOAP response in Karate DSL

I have this feature file and i get a response correctly. I want to print obtained value from response but somehow I am not able to do that. Tried to research some stuff but I couldnt help myself.
Can anyone help please? Thanks in advance
Feature:
test of soap
Background:
* url 'http://www.dataaccess.com/webservicesserver/numberconversion.wso'
Scenario: soap 1.1
Given request
"""
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:web="http://www.dataaccess.com/webservicesserver/">
<soapenv:Header/>
<soapenv:Body>
<web:NumberToDollars>
<web:dNum>10</web:dNum>
</web:NumberToDollars>
</soapenv:Body>
</soapenv:Envelope>
"""
When soap action 'Conversion'
Then status 200
* print '\n', response
#working
* match response /Envelope/Body/NumberToDollarsResponse/NumberToDollarsResult == 'ten dollars'
#not working
* print response.Envelope.Body.NumberToDollarsResponse.NumberToDollarsResult
#not working
* print response /Envelope/Body/NumberToDollarsResponse/NumberToDollarsResult
#not working
* def x = response /Envelope/Body/NumberToDollarsResponse/NumberToDollarsResult
* print x
If you read the docs, print only handles JS on the right-hand-side, not XPath.
For what you want, please do in 2 steps:
* def temp = /Envelope/Body/NumberToDollarsResponse/NumberToDollarsResult
* print temp

Parsing XML and ignoring sections with powershell

I want to parse out the key fields and Data table information from here with PowerShell.
I only want the datatable name if there is a keyfield so in the example below I do not want CC:Attribute.
I also want to output things to a text file.
I want to have a text file that is created that holds the Data table name & Access as well as all the key fields and what they are.
This is the code I have so far:
[xml]$global:xmldata = get-content "C:\hackathon\Mfg.xml"
$xmldata2 = $xmldata.SchemaPackage.Tables
$SField = $xmldata2.DataTable.KeyFields | %{$_.StringField}
$Reffield = $xmldata2.DataTable.KeyFields | %{$_.ReferenceField}
$table = $xmldata2 | %{$_.DataTable}
Xml File:
<?xml version="1.0" encoding="utf-8"?>
<SchemaPackage Namespace="Mfg" xmlns="" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<DataTable Name="CC::Attribute">
<DataFields>
</DataFields>
</DataTable>
<DataTable Name="PlannerCode" Access="WW">
<Licenses>Manufacturing, DemandManagement</Licenses>
<Flags>
</Flags>
<KeyFields>
<StringField Name="Value"/>
<ReferenceField Name="Site" Target="Core::Site" SetField="PlannerCodes"/>
</KeyFields>
<DataFields>
<StringField Name="Description"/>
</DataFields>
</DataTable>
</SchemaPackage>
Despite the edit you made, I can only get your XML to validate if I modify it slightly (cleaning the opening XML tag and removing the SchemaPackage namespace). Regardless,
if you're experiencing no issues with your XML import then it's fine.
Here I'm just constructing the XML object from a herestring because I haven't got it in a file on disk.
[xml]$xmldata = #"
<xml>
<DataTable Name="CC::Attribute">
<DataFields>
</DataFields>
</DataTable>
<DataTable Name="PlannerCode">
<Licenses>Manufacturing, DemandManagement</Licenses>
<Flags>
</Flags>
<KeyFields>
<StringField Name="Value"/>
<ReferenceField Name="Site" Target="Core::Site" SetField="PlannerCodes"/>
</KeyFields>
<DataFields>
<StringField Name="Description"/>
</DataFields>
</DataTable>
</xml>
"#
# Filter DataTable nodes for those with a KeyFields child node.
$DataTablesWithKeyFields = $xmldata.xml.DataTable | Where-Object { $_.KeyFields }
$DataTableName = $DataTablesWithKeyFields.Name
$StringFieldData = $DataTablesWithKeyFields.KeyFields.ReferenceField
$ReferenceFieldData = $DataTablesWithKeyFields.KeyFields.ReferenceField
I'm not sure if that's what you're after. $DataTablesWithKeyFields could be an array depending on your XML file so you may need to loop it to extract the information you require.
Since we're working with XML, one of the querying options is XPath!
You can select only DataTable nodes that have a KeyFields child with the following XPath expression:
/SchemaPackage/DataTable[KeyFields]
You can use Select-Xml:
Select-Xml -Path C:\hackathon\Mfg.xml -XPath /SchemaPackage/DataTable[KeyFields] |Select-Object -Expand Node
or pass the expression as an argument to the SelectSingleNodes() method:
[xml]$xmldata = Get-Content C:\hackathon\Mfg.xml
$xmldata.SelectNodes('/SchemaPackage/DataTable[KeyFields]')

XML parsing, illegal character in the end of the string

I'm getting very strange error when I trying to convert a string to XML in MS SQL Server:
Msg 9420, Level 16, State 1, Line 5
XML parsing: line 1, character 8071, illegal xml character
If I check the string in some text editor, I can see that its length is 8070. Why is it complaining about character 8071 if it does not exist?
This is how I'm converting string to XML:
CAST(REPLACE(SUBSTRING(
REPLACE(REPLACE(REPLACE(ResponseData,'ä','a'),'ö','o'),'å','a'),
PATINDEX('%<?xml%',ResponseData), PATINDEX('%sonType>', ResponseData)+6),
'<?xml version="1.0" encoding="utf-16"?>',
'<?xml version="1.0" encoding="utf-8"?>')as XML) as ResponseData
Are any of replaces causing the problem?
UPD: The problem also is that in ResponseData column the XML string is stored together with some other data. Example:
Error from service: <Some error description>. Sent request: <?xml version="1.0" encoding="utf-16"?><Contents of the XML>
So I need to get that XML string from the column and then convert it to XML.
You could try to change original encoding from UTF-16 to ISO-8859-1, or a more precise encoding for your characters:
DECLARE #data varchar(max) = '<?xml version="1.0" encoding="utf-16"?><...>'
SELECT CAST(REPLACE(#data,
'<?xml version="1.0" encoding="utf-16"?>',
'<?xml version="1.0" encoding="iso-8859-1"?>') AS XML) ResponseData

xpath soap namespace grabbing items

I am feeling like i am doing something really not correct.
When doing a soap they return me with an xml which may or may not contain an error.
I would like to check if the error exists if not read the values.
somehow, I can't grab it directly :(
Below is a sample return of something with results and one which gives an error (name not found)
<?xml version="1.0" encoding="utf-8"?>
<soapEnvelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<envHeader xmlns:env="http://www.w3.org/2003/05/soap-envelope">
<wsaAction>http://www.rechtspraak.nl/namespaces/ccr01/searchPersonResponse</wsaAction>
<wsaMessageID>urn:uuid:b75d2932-5687-4871-9d07-3b74b084978a</wsaMessageID>
<wsaRelatesTo>urn:uuid:9112d870-248d-4d07-acd0-d88e4a48d547</wsaRelatesTo>
<wsaTo>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</wsaTo>
<wsseSecurity>
<wsuTimestamp wsu:Id="Timestamp-061df7b5-32a2-4021-852d-2df98953e076">
<wsuCreated>2011-05-27T12:11:45Z</wsuCreated>
<wsuExpires>2011-05-27T12:16:45Z</wsuExpires>
</wsuTimestamp>
</envHeader>
<soapBody>
<searchPersonResponse xmlns="http://www.rechtspraak.nl/namespaces/ccr01">
<searchPersonResult>
<CCR_WS xmlns="http://www.rechtspraak.nl/namespaces/ccr">
<curandus>
<ccn>1</ccn>
<cur_voornamen>Jan</cur_voornamen>
<cur_voorvoegsels>van</cur_voorvoegsels>
<cur_achternaam>Beek</cur_achternaam>
<geboorte_datum>1980-01-02</geboorte_datum>
<geboorte_plaats>Werkendam</geboorte_plaats>
</curandus>
</CCR_WS>
</searchPersonResult>
</searchPersonResponse>
</soapBody>
</soapEnvelope>
and the one without results
<?xml version="1.0" encoding="utf-8"?>
<soapEnvelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<envHeader xmlns:env="http://www.w3.org/2003/05/soap-envelope">
<wsaAction>http://www.rechtspraak.nl/namespaces/ccr01/searchPersonResponse</wsaAction>
<wsaMessageID>urn:uuid:b75d2932-5687-4871-9d07-3b74b084978a</wsaMessageID>
<wsaRelatesTo>urn:uuid:9112d870-248d-4d07-acd0-d88e4a48d547</wsaRelatesTo>
<wsaTo>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</wsaTo>
<wsseSecurity>
<wsuTimestamp wsu:Id="Timestamp-061df7b5-32a2-4021-852d-2df98953e076">
<wsuCreated>2011-05-27T12:11:45Z</wsuCreated>
<wsuExpires>2011-05-27T12:16:45Z</wsuExpires>
</wsuTimestamp>
</envHeader>
<soapBody>
<searchPersonResponse xmlns="http://www.rechtspraak.nl/namespaces/ccr01">
<searchPersonResult>
<CCR_WS xmlns="http://www.rechtspraak.nl/namespaces/ccr">
<exceptie errorcode="1">No Results found.</exceptie>
</CCR_WS>
</searchPersonResult>
</searchPersonResponse>
</soapBody>
</soapEnvelope>
Here is my code to select the namespace, then check
$results = simplexml_load_string($response);
$results->registerXPathNamespace('ccr','http://www.rechtspraak.nl/namespaces/ccr');
$lijst = $results->xpath('//ccr:CCR_WS');
$errorcode = $lijst[0]->exceptie->attributes()->errorcode;
$error = $lijst[0]->exceptie;
if (isset($errorcode) AND $errorcode != "") {
// do things with the error code
} else {
$lijst = $results->xpath('//ccr01:searchPersonResult');
$cur = $lijst[0]->CCR_WS->curandus;
echo $cur->ccn."<BR>";
echo $cur->cur_voornamen."<BR>";
echo $cur->cur_voorvoegsels."<BR>";
echo $cur->cur_achternaam."<BR>";
echo $cur->geboorte_datum."<BR>";
echo $cur->geboorte_plaats."<BR>";
}
surely there is a better way of grabbing
$lijst[0]->exceptie->attributes()->errorcode
for example...
...Don't know if this is a "better way" to everyone, but here is a direct XPath expression to select the errorcode. You can make it shorter and less efficient by dropping steps and using // (in the beginning or in the middle). Attributes are selected with # (or with attribute:: axis if you prefer the longer syntax). If attribute (or the exceptie element) doesn't exist, nothing is returned.
/*/*/ccr01:searchPersonResponse/ccr01:searchPersonResult/ccr:CCR_WS/ccr:exceptie/#errorcode
Remember to register all the namespace prefixes that yo use in your XPath expression.