xpath assertion in soapui not working - xpath

I am reach up to this using xpath- //ns1:GetAtomicWeightResponse/ns1:GetAtomicWeightResult[1] but how to reach upto AtomicWeight.
<NewDataSet>
<Table>
<AtomicWeight>12.0115</AtomicWeight>
</Table>
</NewDataSet>
Here , I am not able to get value of AutomicWeight from table XML.
EDIT: Based on the comments from OP, adding the xml in the question.
<soap:Envelope
xmlns:soap="schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="w3.org/2001/XMLSchema-instance"
xmlns:xsd="w3.org/2001/XMLSchema">
<soap:Body>
<GetAtomicWeightResponse
xmlns="webserviceX.NET">
<GetAtomicWeightResult>
<![CDATA[<NewDataSet><Table><AtomicWeight>12.0115</AtomicWeight></Table></NewDataSet>]]>
</GetAtomicWeightResult>
</GetAtomicWeightResponse>
</soap:Body>
</soap:Envelope>

Consider Following response in your soap XML
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body>
<ConversionRateResponse xmlns="http://www.webserviceX.NET/">
<ConversionRateResult>1505.7</ConversionRateResult>
</ConversionRateResponse>
</soap:Body>
</soap:Envelope>
Xpath would be
declare namespace ns1='http://www.webserviceX.NET/';
//ns1:ConversionRateResponse[1]/ns1:ConversionRateResult[1]

Please use below xpath
//NewDataSet/Table/AtomicWeight
EDIT: Based on OP's data
Since, the data originally mentioned by you is in cdata that is why you were not able to get that value.
You can use below Groovy Script:
def xml = """<soap:Envelope xmlns:soap="schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="w3.org/2001/XMLSchema-instance" xmlns:xsd="w3.org/2001/XMLSchema">
<soap:Body>
<GetAtomicWeightResponse xmlns="webserviceX.NET">
<GetAtomicWeightResult><![CDATA[<NewDataSet><Table><AtomicWeight>12.0115</AtomicWeight></Table></NewDataSet>]]></GetAtomicWeightResult>
</GetAtomicWeightResponse>
</soap:Body>
</soap:Envelope>"""
def getData = { data, element -> new XmlSlurper().parseText(data).'**'.find{it.name() == element} }
def atomicWeight = getData((getData(xml, 'GetAtomicWeightResult') as String).trim(), 'AtomicWeight').text()
log.info atomicWeight
Or you can quickly try online Demo
If you are using it in SoapUI's test case, you do not have to add an additional Groovy Test step to get that value. Instead add the Script Assertion to the same request step (where you get that response) with below code(processing is same, but you do not have to use fixed xml, instead a dynamic response can be used).
Script Assertion
assert context.response, 'Response is empty or null'
def getData = { data, element -> new XmlSlurper().parseText(data).'**'.find{it.name() == element} }
def atomicWeight = getData((getData(context.response, 'GetAtomicWeightResult') as String).trim(), 'AtomicWeight').text()
log.info atomicWeight

Related

Apache Camel CXF Component issue

I have exposed a webservice bu using CXFEndpoint. However, there is an error that I guess, MessageContentsList problem can not be converted . May be I made a mistake. Could you help me?
public CxfEndpoint insurerService() {
CxfEndpoint serviceEndpoint = new CxfEndpoint();
serviceEndpoint.setServiceClass(XXXX.class);
serviceEndpoint.setAddress("/XXXX");
serviceEndpoint.setDataFormat(DataFormat.POJO);
serviceEndpoint.setServiceName(new QName("http://tempuri.org/","XXXX"));
serviceEndpoint.setPortName("XXXXX");
serviceEndpoint.setBus(bus);
return serviceEndpoint;
}
from(getUrl())
.id("xxxxx-service")
.unmarshal().json(JsonLibrary.Jackson, xxxx.class)
.to("bean-validator")
.dynamicRouter(method(xxx, "route").getExpression())
.marshal().json(JsonLibrary.Jackson, true);
Response will return ;
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<soap:Fault>
<faultcode>soap:Server</faultcode>
<faultstring>java.lang.String cannot be cast to java.util.List</faultstring>
</soap:Fault>
</soap:Body>
</soap:Envelope>

Access Purchase Orders via web service

We are busy developing an interface between Acumatica and our application via the web services. We are developing it in Ruby using the Savon gem.
We've got some of the exports working for the information we need, like this one for Vendor data:
We post the following SOAP call (after logging in):
<?xml version="1.0"?>
<env:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tns="http://www.acumatica.com/typed/" xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
<env:Body>
<tns:Export>
<tns:commands>
<tns:Command>
<tns:FieldName>AcctCD</tns:FieldName>
<tns:ObjectName>BAccount</tns:ObjectName>
<tns:Value>Account code</tns:Value>
</tns:Command>
<tns:Command>
<tns:FieldName>AcctName</tns:FieldName>
<tns:ObjectName>BAccount</tns:ObjectName>
<tns:Value>Account name</tns:Value>
</tns:Command>
</tns:commands>
<tns:filters/>
<tns:startRow>0</tns:startRow>
<tns:topCount>0</tns:topCount>
<tns:includeHeaders>false</tns:includeHeaders>
<tns:breakOnError>false</tns:breakOnError>
</tns:Export>
</env:Body>
</env:Envelope>
to the testing endpoint:
http://p3.tryacumatica.com/(W(10003))/Soap/AP303000.asmx?WSDL
We are also able to do the same kind of thing for Inventory and Sites. However we're struggling to get it working for Purchase Orders.
We post the following:
<?xml version="1.0"?>
<env:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tns="http://www.acumatica.com/typed/" xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
<env:Body>
<tns:Export>
<tns:commands>
<tns:Command>
<tns:FieldName>Type</tns:FieldName>
<tns:ObjectName>POOrder</tns:ObjectName>
<tns:Value>Type</tns:Value>
</tns:Command>
<tns:Command>
<tns:FieldName>OrderNbr</tns:FieldName>
<tns:ObjectName>POOrder</tns:ObjectName>
<tns:Value>Order number</tns:Value>
</tns:Command>
</tns:commands>
<tns:filters/>
<tns:startRow>0</tns:startRow>
<tns:topCount>0</tns:topCount>
<tns:includeHeaders>false</tns:includeHeaders>
<tns:breakOnError>false</tns:breakOnError>
</tns:Export>
</env:Body>
</env:Envelope>
to the testing endpoint:
http://p3.tryacumatica.com/(W(3))/Soap/PO301000.asmx?WSDL
We always just get an empty respone. Any ideas?
Check to see if PO module is turned on. Also check to see if the user has rights to query the PO objects. Does the database receive a query? One option is debug from the database side. See if the database picks up an queries submitted from the web service input.
I know these are simple ideas, but it's worth a look.
Well, my first question is why do you need a FULL list PO ? it could be a huge data.
PO has a composite key - Type, OrderNbr and basically using Export command you have to specify value like EveryOrderNbr
see link below
link
+
old c# example for SO
Content SO301000 = context.GetSchema();
context.Clear();
string[][] data = context.Export(new Command[]
{
SO301000.OrderSummary.ServiceCommands.EveryOrderType,
SO301000.OrderSummary.ServiceCommands.EveryOrderNbr,
SO301000.OrderSummary.OrderType,
SO301000.OrderSummary.OrderNbr,
SO301000.OrderSummary.Description,
SO301000.OrderSummary.Hold,
}, null,
new Filter[]
{
new Filter { Field = SO301000.OrderSummary.OrderType, Condition = FilterCondition.Equals, Value = "IN", Operator = FilterOperator.And },
new Filter { Field = SO301000.OrderSummary.OrderNbr, Condition = FilterCondition.Equals, Value = "23630843", Operator = FilterOperator.And }
},
0, false, true);

How can find the hidden white space, or new line within the "Net::HTTP.post_form" for XML?

I'm using the ruby gem Net::HTTP.post_form to post XML to a ConnectWise server, using the CompanyAPI. I'm getting this error:
System.Xml.XmlException: Data at the root level is invalid. Line 1, position 1.
From everything I can find I likely have a whitespace or newline character before the <?xml version="1.0" encoding="utf-8"?>
Here is the code:
require 'net/http'
require 'uri'
require 'builder'
#f = File.new('cw.get_company.xml', 'w')
#cwhostname = 'cw_fqdn'
companyapi_url = 'https://' + #cwhostname + '/v4_6_release/apis/2.0/CompanyApi.asmx'
uri = URI(companyapi_url)
def cw_company_api_get_company
companyid = 'company_name'
integratorloginid = 'inegrator_login_id'
integratorpassword = 'inegrator_passwd'
companyidint = 0
xml = Builder::XmlMarkup.new(:indent=>2)
xml.instruct!
xml.tag!('soap:Envelope'){
xml.tag!('soap:Body'){
xml.tag!('GetCompany xmlns="https://'+#cwhostname+'"'){
xml.tag!('credentials'){
xml.CompanyId(companyid)
xml.IntegratorLoginId(integratorloginid)
xml.IntegratorPassword(integratorpassword)
}
}
xml.id(companyidint)
}
}
end
response = Net::HTTP.post_form(uri,[cw_company_api_get_company])
#puts cw_company_api_get_company
puts response.body
Here is the full output with error:
<?xml version="1.0" encoding="utf-8"?><soap:Envelope 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"><soap:Body><soap:Fault><soap:Code><soap:Value>soap:Receiver</soap:Value></soap:Code><soap:Reason><soap:Text xml:lang="en">System.Web.Services.Protocols.SoapException: Server was unable to process request. ---> System.Xml.XmlException: Data at the root level is invalid. Line 1, position 1.
at System.Xml.XmlTextReaderImpl.Throw(String res, String arg)
at System.Xml.XmlTextReaderImpl.ParseRootLevelWhitespace()
at System.Xml.XmlTextReaderImpl.ParseDocumentContent()
at System.Web.Services.Protocols.SoapServerProtocol.SoapEnvelopeReader.Read()
at System.Xml.XmlReader.MoveToContent()
at System.Web.Services.Protocols.SoapServerProtocol.SoapEnvelopeReader.MoveToContent()
at System.Web.Services.Protocols.SoapServerProtocolHelper.GetRequestElement()
at System.Web.Services.Protocols.Soap12ServerProtocolHelper.RouteRequest()
at System.Web.Services.Protocols.SoapServerProtocol.Initialize()
at System.Web.Services.Protocols.ServerProtocolFactory.Create(Type type, HttpContext context, HttpRequest request, HttpResponse response, Boolean& abortProcessing)
--- End of inner exception stack trace ---</soap:Text></soap:Reason><soap:Detail /></soap:Fault></soap:Body></soap:Envelope>
If I just print to a file it appears to be fine, how can I find the white space or newline (or whatever else could be at line 1) and remove it?
Here is a sample XML provided in the ConnectWise API documentation:
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<GetCompany xmlns="http://connectwise.com">
<credentials>
<CompanyId>string</CompanyId>
<IntegratorLoginId>string</IntegratorLoginId>
<IntegratorPassword>string</IntegratorPassword>
</credentials>
<id>int</id>
</GetCompany>
</soap:Body>
</soap:Envelope>
It has nothing to do with whitespace. Your XML is simply incorrect. The problem is in the string:
xml.tag!('GetCompany xmlns="https://'+#cwhostname+'"')
it apparently treats the whole string as a tag, producing closing tag as:
</GetCompany xmlns="https://connectwise.com">
You might easily see this by puts cw_company_api_get_company anywhere in your code. Attributes are to be passed to builder tags as:
xml.tag!('GetCompany', :xmlns => "https://#{#cwhostname}")
Another glitch is that you need to put id inside GetCompany tag. The summing up:
def cw_company_api_get_company
companyid = 'company_name'
integratorloginid = 'inegrator_login_id'
integratorpassword = 'inegrator_passwd'
companyidint = 0
xml = Builder::XmlMarkup.new(:indent=>2)
xml.instruct!
xml.tag!('soap:Envelope'){
xml.tag!('soap:Body'){
xml.tag!('GetCompany', :xmlns => "https://#{#cwhostname}"){
xml.tag!('credentials'){
xml.CompanyId(companyid)
xml.IntegratorLoginId(integratorloginid)
xml.IntegratorPassword(integratorpassword)
}
xml.id(companyidint)
}
}
}
end
Hope this helps.

Ruby/Savon: Having trouble with namespace for a soap request

I'm having trouble changing the namespace for the SOAP xml I'm building. I'm not sure how to change "xmlns:env=" to "xmlns:soapenv=" and "xmlns:tns=" to "xmlns:web="
What I'm trying to build:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:web="http://www.webserviceX.NET/">
<soapenv:Header/>
<soapenv:Body>
<web:ConvertTemp>
<web:Temperature>100</web:Temperature>
<web:FromUnit>degreeCelsius</web:FromUnit>
<web:ToUnit>degreeFahrenheit</web:ToUnit>
</web:ConvertTemp>
</soapenv:Body>
</soapenv:Envelope>
What I'm currently getting
<?xml version="1.0" encoding="UTF-8"?>
<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:tns="http://www.webserviceX.NET/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<env:Body>
<tns:ConvertTemp>
<tns:temperature>100</tns:temperature>
<tns:fromUnit>degreeCelsius</tns:fromUnit>
<tns:toUnit>degreeFahrenheit</tns:toUnit>
</tns:ConvertTemp>
</env:Body>
</env:Envelope>
My code:
client = Savon.client(wsdl: "http://www.webservicex.net/ConvertTemperature.asmx?WSDL")
message = { temperature: '100',FromUnit: 'degreeCelsius' , ToUnit: 'degreeFahrenheit'}
response = client.call(:convert_temp, message: message)
Thanks for the help.
I was able to figure out how to change those. If anybody is interested the way to change those is:
client = Savon.client(env_namespace: :soapenv,namespace_identifier: :web)
That wasn't actually causing my problem though. Turns out that my fields were getting camelcased without me noticing. "FromUnit" became "fromUnit".

Camel Apache: xpath to extract some value out of received XML

during my Camel routes, I query a server (a HTTP GET) and as a result, I receive a 200 OK with a XML body looking similar like this:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<userProfiles xmlns="http://www.mycompany.com/AEContext/xmldata">
<userProfile name="guest">
<userProfileAttributes>
<userProfileAttribute name="parameter1" value="data1" nameVisibility="ALL"/>
<userProfileAttribute name="parameter2" value="data2" nameVisibility="ALL"/>
<userProfileAttribute name="parameter3" value="data3" nameVisibility="ALL"/>
</userProfileAttributes>
</userProfile>
</userProfiles>
Any idea how I would be able to get the value of "parameter2" in the XML part (in my example 'data2') and store that value in an exchange property ? I guess by using an xpath expression ? Or ...
Thanks for your help.
An easy way to retrieve the value would be to use the XPath Language. It will allow you to extract the data you want and set it somewhere (header, body , ...). Here is how to set a parameter2 header with the value:
<setHeader headerName="parameter2">
<xpath resultType="java.lang.String">
/userProfiles/userProfile/userProfileAttributes/userProfileAttribute[2]/#value
</xpath>
</setHeader>
Using Java DSL
An example using the Java DSL and setting the message body:
final Namespaces ns = new Namespaces("c", "http://www.mycompany.com/AEContext/xmldata");
// existing code
from(...)
.setBody(
ns.xpath(
"/c:userProfiles/userProfile/userProfileAttributes/userProfileAttribute[2]/#value",
String.class)
)
.to(...);

Resources