Parsing SOAP response using libxml in Ruby - ruby

I am trying to parse following SOAP response coming from Savon SOAP api
<?xml version='1.0' encoding='UTF-8'?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<ns:getConnectionResponse xmlns:ns="http://webservice.jchem.chemaxon">
<ns:return>
<ConnectionHandlerId>connectionHandlerID-283854719</ConnectionHandlerId>
</ns:return>
</ns:getConnectionResponse>
</soapenv:Body>
</soapenv:Envelope>
I am trying to use libxml-ruby without any success. Basically I want to extract anything inside tag and the connectionHandlerID value.

As you are using Savon you can convert the response to a hash. The conversion method response.to_hash does some other useful things for you as well.
You would then be able to get the value you want using code similar to the following
hres = soap_response.to_hash
conn_handler_id = hres[:get_connection_response][:return][:connection_handler_id]
Check out the documentation

I'd recommend nokogiri.
Assuming your XML response is in an object named response.
require 'nokogiri'
doc = Nokogiri::XML::parse response
doc.at_xpath("//ConnectionHandlerId").text

Related

SOAP UI Property transfer from JDBC request into SOAP Request

I have successfully created a JDBC request which is obtaining data from a db in the following XML:
<Results>
<ResultSet fetchSize="64">
<Row rowNumber="1">
<POLICY>9999</POLICY>
<CUSTOMER>00001</CUSTOMER>
</Row>
</ResultSet>
</Results>
I have a SOAP Request and I am trying to pass in both policy and customer values into specific locations on my request. I have set up a Property Transfer step to facilitate this.
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:v1="http://www.xxxxxxxxx.com/services" xmlns:v11="http://www.xxxxxxxxx.com/types" xmlns:v12="http://www.xxxxxxxxx.com/common">
<soapenv:Header/>
<soapenv:Body>
<v1:ReqMessage>
<v11:ServiceHeader>
<v11:CommonHeader>
<v11:ServiceName>Treatment</v11:ServiceName>
<v11:DateTimestamp>2017-02-10T10:51:00.000</v11:DateTimestamp>
</v11:CommonHeader>
<v11:ClientHeader>
<v11:SourceSystem>System</v11:SourceSystem>
</v11:ClientHeader>
<v11:SecurityHeader>
<v11:Username>9A</v11:Username>
</v11:SecurityHeader>
</v11:ServiceHeader>
<v1:ServiceBody>
<v12:TreatmentRequest>
<v12:PolicyNumber></v12:PolicyNumber>
<v12:MemberNumber></v12:MemberNumber>
</v12:GetTreatmentTypesRequest>
</v1:ServiceBody>
</v1:GetProdAndTreatTypesReqMessage>
</soapenv:Body>
</soapenv:Envelope>
I'm struggling to know the Xpath for both source and target to insert into the Property Transfer step.
I am not using SOAP UI Pro.

Xpath not working in camel route

I'm sending soap xml through exchange object.When i try to route the request using xpath in apache camel,i'm not able to execute it properly.Please suggest
My Exchange body xml is
<Envelope><Header>
</Header>
<Body>
<Choice>
<Selector>1</selector>
</Choice>
</Body>
</Envelope>
My Camel Route
from(direct:XX)
.to(when(xpath("body()/Choice/Selector/.",String.class)=='1')
.to("direct:X")
.otherwise()
.to("direct:Y")
your Envelope cannot look like that. it must be something like:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Header/>
<soapenv:Body>
...
body()/Choice/Selector/. is not an Xpath. there is no such thing like body() in XPath.
Assuming that you have a SOAP Body content in the Exchange.body processed by some JAX-WS endpoint XPath will be
/Choice/Selector or /Choice/Selector/text() if it is an element with mixed content
BTW: if your Envelope is real example you try to test do not forget to fix your XML - you have wrong <Selector>1</selector> Tag names are case sensitive. It must be <Selector>1</Selector>

Formatting the response XML of a WebService when using Savon

I'm working using an external Webservice which I consume using the Savon gem.
I want to process the response of the WebService, before Savon, in order to clean the XML and get the correct Hash to work with. Currently, the Savon call method, answers with the Hash:
{:envelope => {
:body => {
:get_method_result => {
:result=>"OK",
:dataset_xml => "
<NewDataSet>
<xs:schema id=\"NewDataSet\" xmlns=\"\"........
Wich, as you can see, after dataset_xml has an XML string. So I have to take this and process it in order to have a full Hash.
All of this is happening because my response has thing like: <NewDataSet>\r\n <xs:schema id=\"NewDataSet\" xmlns=\ inside it's XML, which if I could be able to fix, then I wouldn't need to do all the after-process to turn it into a Hash.
You could simply try to parse the xml your self with nokogiri gem. Have you tried that already?
I would simply try
Nokogiri::XML(response[:body])
A friend solved it, he added a module named mod_substitute to Apache. I used it to parse the incoming XML, extracting the CDATA characters. With tha being done, the Savon gem received a clean XML which was parsed perfectly, in one step, to a Hash.
<Location />
AddOutputFilterByType SUBSTITUTE text/html
Substitute "s|CDATAREGEX|' '|i"
</Location>

Validate XML against 2 XSD

I'm trying to parse and validate a SOAP request with SAX. Two XSD are necessary, one for SOAP envelope (http://schemas.xmlsoap.org/soap/envelope/) and the one I defined. I cannot find a way to properly validate the request against these two XSD.
Here's the code I use to parse the request and validate it against soapenv.xsd. It works fine. If I specify my XSD instead, the validation fails with "Cannot find the declaration of element 'soapenv:Envelope'".
SAXParserFactory factory = SAXParserFactory.newInstance();
factory.setNamespaceAware(true);
factory.setValidating(true);
SAXParser saxParser = factory.newSAXParser();
saxParser.setProperty("http://java.sun.com/xml/jaxp/properties/schemaLanguage", "http://www.w3.org/2001/XMLSchema");
saxParser.setProperty("http://java.sun.com/xml/jaxp/properties/schemaSource", MyClass.class.getResourceAsStream("/xml/soapenv.xsd"));
InputSource is = new InputSource(MyClass.class.getResourceAsStream("/xml/request.xml"));
XMLReader reader = saxParser.getXMLReader();
reader.setContentHandler(new MyHandler());
reader.setErrorHandler(new MyErrorHandler());
reader.parse(is);
How can I specify a second XSD?
Is there a better way to parse and validate SOAP requests?
EDIT
As proposed, I created thirdpty.xsd that imports my two XSDs.
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema targetNamespace="thirdparty:general"
xmlns="thirdparty:general"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:import schemaLocation="D:\ucfed\ValidateWSDL\src\xml\soapenv.xsd"
namespace="http://schemas.xmlsoap.org/soap/envelope/"/>
<xs:import schemaLocation="D:\ucfed\ValidateWSDL\src\xml\Presence.xsd"
namespace="thirdparty:presence"/>
</xs:schema>
I specify this new XSD for the validation:
saxParser.setProperty("http://java.sun.com/xml/jaxp/properties/schemaSource", MyClass.class.getResourceAsStream("/xml/thidpty.xsd"));
But still, only the SOAP envelope XSD is used for validation. If a modify one element from my other XSD, the validation does not detect it.
Here is the xml I am trying to validate
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="thirdparty:presence">
<soapenv:Header/>
<soapenv:Body>
<urn:getPresenceQuery>
<urn:origAccount uri="test#origin.com"/>
<urn:destAccount uri="test#destination.com"/>
</urn:getPresenceQuery>
</soapenv:Body>
</soapenv:Envelope>
Other ideas ?
Write a driver schema document which imports the other two; validate against the driver.

How do I process multipart http responses in Ruby Net:HTTP?

There is so much information out there on how to generate multipart responses or do multipart file uploads. I can't seem to find any information on how to process a multipart http response. Here is some IRB output from a multipart http response I am working with.
>> response.http.content_type
=> "multipart/related"
>> response.http.body[0..2048]
=> "\r\n------=_Part_3_806633756.1271797659309\r\nContent-Type: text/xml; charset=UTF-8\r\nContent-Transfer-Encoding: binary\r\nContent-Id: <A0FCC4333C6D0FCA346B97FAB6B61818>\r\n\r\n<?xml version="1.0" encoding="UTF-8"?><soapenv:Envelope xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><soapenv:Body><ns1:runReportResponse soapenv:encodingStyle="http://www.w3.org/2003/05/soap-encoding" xmlns:ns1="http://192.168.1.200:8080/jasperserver/services/repository"><ns2:result xmlns:ns2="http://www.w3.org/2003/05/soap-rpc">runReportReturn</ns2:result><runReportReturn xsi:type="xsd:string"><?xml version="1.0" encoding="UTF-8"?>\n<operationResult version="2.0.1">\n\t<returnCode><![CDATA[0]]></returnCode>\n</operationResult>\n</runReportReturn></ns1:runReportResponse></soapenv:Body></soapenv:Envelope>\r\n------=_Part_3_806633756.1271797659309\r\nContent-Type: application/pdf\r\nContent-Transfer-Encoding: binary\r\nContent-Id: <report>\r\n\r\n%PDF-1.4\n%\342\343\317\323\n3 0 obj
You can use Rack to do that for you, here's the utility function that does it: Rack::Utils::parse_multipart. Obviously you'll have to make your response object look like a request object Rack would accept (the env object).

Resources