Monday, January 25, 2016

SOAP/WSDL on Perl, Ruby, PHP or Python (anything but .NET/Java)

SOAP was designed to provide cross platform RPC but the reality is that the only usable implementations of the spec are on .NET and Java.  Yes there are several available for other programming languages but they are incomplete or broken (they may or may not work).  Want to know what ALWAYS works?  Read on.

My recommendation is to avoid them completely and download SoapUI (which is written in Java).  This desktop software will allow you to create a new project using the WSDL (file or URL) and view and manually create requests against a service.  You can see the raw data exchange (HINT: There can be additional required HTTP headers you need to pass.  SOAPAction is one that is almost ALWAYS used) and then using whatever language you want create a web client that POSTs the XML (templated so you can change various parameters) and then parse the resulting XML response to get the data you want.  Every programming language has a decent XML parser so that shouldn't be a problem (although sometimes you have "massage" the resulting XML).

Here is a simple example of a client in PHP:

        $soap_url = "https://blahblah.com:1234/Service";
        $soap_act = '"/SomeCall"'; // Use SoapUI raw view of request to find this
        $soap_xml = <<<ENDOFFILE
        <soapenv .......... </soapenv ...............
        ENDOFFILE;

        $resp = \Httpful\Request::post($soap_url)
            ->body($soap_xml)
            ->sends('text/xml')
            ->addHeader('SOAPAction', $soap_act)
            ->timeoutIn(10)
            ->send();

        // There are ways to make the PHP XML parser handle namespaces but usually
        // we don't need them so make them simple XML elements instead
        // (eg. s_Envelope)

        $xml_str = str_replace('<?xml version="1.0" encoding="UTF-8"?>', '',
                               $resp->body);
        $xml_str = preg_replace("/(<\/?)(\w+):([^>]*>)/", "$1$2_$3", $xml_str);
        $xml_str = preg_replace("/ \w+(:\w+)?=\"[^\"]*\"/", "", $xml_str);

        $xml = new \SimpleXMLElement($xml_str);
        $body = $xml->xpath('//s_Envelope'); // Can use this to narrow it down

        $array = json_decode(json_encode((array)$body), TRUE);

        // Now you can access the data using $array['key_name'][1] etc.. etc..

        print_r($array);

Good luck and hopefully this will save you some time! :)