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

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".

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>

xpath assertion in soapui not working

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

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);

Is it possible to rename th response namespace-prefix in a Spring WS webservice?

I've build a Spring WS webservice based on the example at http://spring.io/guides/gs/producing-web-service/. The response contains my namespace with the prefix "ns2".
xmlns:ns2="http://www.mycompany.com/somewhere"
Soap-Response
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header/>
<SOAP-ENV:Body>
<ns2:mitteilungResponse xmlns:ns2="http://www.mycompany.com/somewhere">
<ns2:responseContent>
<ns2:message>Hello World!</ns2:message>
</ns2:responseContent>
</ns2:mitteilungResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
Is it possible to rename that prefix to "myprefix"? How? Anybody?
OK, i found the solution. It's pretty easy... Simply add it to the #XmlSchema-Annotation in the package-info.java as follows:
#XmlSchema(
xmlns = {
#XmlNs(prefix = "myprefix", namespaceURI="http://www.mycompany.com/foobar")
},
namespace = "http://www.mycompany.com/somewhere",
elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED
)
package com.mycompany.project;

Having issue while using soap4r, unable to add namespace, encoding style to soap envelope

I am having problems with one of the soap service I'm using. I am using soap4r for consuming the soap service. But somehow they are expecting something else than what I am sending. This is what I'm sending:<?xml version="1.0" encoding="utf-8" ?>
<env:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:env="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<env:Header>
<authenticate env:mustUnderstand="0">
<username>USERNAME</username>
<apiKey>API_KEY</apiKey>
</authenticate>
<SoftLayer_Network_Media_Transcode_AccountInitParameters env:mustUnderstand="0">
<id>ID</id>
</SoftLayer_Network_Media_Transcode_AccountInitParameters>
<SoftLayer_Network_Media_Transcode_AccountObjectFilter env:mustUnderstand="0">
<transcodeJobs>
<transcodeStatus>
<name>
<operation>Complete</operation>
</name>
</transcodeStatus>
</transcodeJobs>
</SoftLayer_Network_Media_Transcode_AccountObjectFilter>
</env:Header>
<env:Body>
<n1:getTranscodeJobs xmlns:n1="http://api.service.softlayer.com/soap/v3/"
env:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
</n1:getTranscodeJobs>
</env:Body>
</env:Envelope> Which does not return the desired output. What they are expecting is:<?xml version="1.0" encoding="utf-8" ?>
<env:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:env="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:n1="http://api.service.softlayer.com/soap/v3/"
env:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<env:Header>
<authenticate env:mustUnderstand="0">
<username>USER_NAME</username>
<apiKey>API_KEY</apiKey>
</authenticate>
<SoftLayer_Network_Media_Transcode_AccountInitParameters env:mustUnderstand="0">
<id>id</id>
</SoftLayer_Network_Media_Transcode_AccountInitParameters>
<n1:SoftLayer_Network_Media_Transcode_AccountObjectFilter env:mustUnderstand="0">
<transcodeJobs>
<transcodeStatus>
<name>
<operation>Complete</operation>
</name>
</transcodeStatus>
</transcodeJobs>
</n1:SoftLayer_Network_Media_Transcode_AccountObjectFilter>
</env:Header>
<env:Body>
<n1:getTranscodeJobs >
</n1:getTranscodeJobs>
</env:Body>
</env:Envelope> namespace and encoding style in the root (as they are using it in the header ObjectFilter). soap4r is generating the previous request, and i am not able to change it to the later one which actually works.
Here is how I am using soap4r:class SLHeader < SOAP::Header::SimpleHandler
def initialize(tag, out)
#out = out
super(XSD::QName.new(nil, tag))
end
def on_simple_outbound
#out
end
end
SOAP_WSDL_ENDPOINT = "endpoint"
service = "service name"
initParams = {'id' => ID}
objectFilter = {'transcodeJobs' => {'transcodeStatus' => {'name' => {'operation' => STATUS}}}}
driver = SOAP::WSDLDriverFactory.new(SOAP_WSDL_ENDPOINT + service + "?wsdl").create_rpc_driver
driver.headerhandler << SLHeader.new('authenticate', {'username' => #auth_user, 'apiKey' => #auth_key})
driver.headerhandler << SLHeader.new(service + 'InitParameters', initParam)
driver.headerhandler << SLHeader.new(service + 'ObjectFilter', objectFilter)
I strongly recommend that you don't waste too much time with soap4r.
If it works, then it's great. But if your SOAP service has particular expectations or is broken in some way, then it is absolutely useless (and impossible to fix without a large amount of monkey patches). The internal state of the library is also pretty bad, and it doesn't work in Ruby 1.9.
For SOAP interfaces I have started using handsoap, which allows you to manually construct SOAP messages that are exactly how your service expects them to be. It's a little more work, but it has saved me a lot of headaches similar to yours. It also works in Ruby 1.9. I have not looked back.

Resources