7

I am setting up a SOAP webservice which takes XML input and has to return custom XML output. All this is defined in a WSDL. I apply soapServer for this (until someone says it has bugs preventing me from achieving my goal :-)).

I haven't been able yet to return custom XML: I get some result which seems to be based on teh WSDL, with a standard root element name equal to the input XML one plus "Response". Actually that surprises me too so as a side question I wonder why that is and whether it can be influenced. Of course it is a nice thing that the WSDL definitions are used somehow when responses are created, but as I said, I don't know how to get custom XML in the response.

I got as far as this:

WSDL

<?xml version="1.0" encoding="UTF-8"?>
<definitions
    xmlns="http://schemas.xmlsoap.org/wsdl/"
    xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
    xmlns:tns="http://pse/"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    name="PSE"
    targetNamespace="http://pse/">
    <types>
        <xs:schema>
            <xs:import namespace="http://pse/" schemaLocation="PSE.xsd"/>
        </xs:schema>
    </types>
    <message name="MI102Req">
        <part name="cdhead" type="tns:cdhead_T"/>
        <part name="instr" type="tns:instr_T"/>
    </message>
    <message name="Res">
        <part name="cdhead" type="tns:cdhead_T"/>
    </message>
    <portType name="MIPortType">
        <operation name="mi102">
            <input message="tns:MI102Req"/>
            <output message="tns:Res"/>
        </operation>
    </portType>
    <binding name="MIBinding" type="tns:MIPortType">
        <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
        <operation name="mi102">
            <soap:operation soapAction="http://www.testURL/test_soap.php#mi102"/>
            <input>
                <soap:body use="literal" namespace="http://pse/"/>
            </input>
            <output>
                <soap:body use="literal" namespace="http://pse/"/>
            </output>
        </operation>
    </binding>
    <service name="PSE">
        <port name="MIPortType" binding="tns:MIBinding">
            <soap:address location="http://www.testURL/test_soap.php"/>
        </port>
    </service>
</definitions>

Input XML

<Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/">
    <Body>
        <mi102 xmlns="http://pse">
            <cdhead version="13"/>
            <instr/>
        </mi102>
    </Body>
</Envelope>

current php

<?php
    class PSE {
        function mi102 ($stdClassInput) {
            $inp = file_get_contents ('php://input');
            $xml = simplexml_load_string ($inp); // Envelope
            $ch = $xml -> children ();
            $elt1 = $ch [0]; // Body
            $ch = $elt1 -> children ();
            $elt2 = $ch [0]; //mi102

            $xslt = new XSLTProcessor();
            $xslt -> registerPHPFunctions();
            $xslt -> importStylesheet ( DOMDocument::load ('test.xslt') );
            $dom = $xslt -> transformToDoc (DOMDocument::loadXML ($elt2 -> asXML()));

            $result = new SoapVar ($dom -> saveXML(), XSD_ANYXML);  
            return ($result);
        }
    }

    ini_set( "soap.wsdl_cache_enabled", "0");
    $server = new SoapServer ("test.wsdl");
    $server -> setClass ('PSE');
    $server -> setObject (new PSE());
    $server -> handle();
?>

XSLT used above is just one changing an attribute - and temp change the root name to the one returned by the server always (just in case :-))

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:pse="http://pse">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

    <xsl:template match="/">
        <xsl:apply-templates/>
    </xsl:template>

    <xsl:template match="pse:mi102">
        <mi102Response>
            <xsl:apply-templates/>
        </mi102Response>
    </xsl:template>

    <xsl:template match="pse:cdhead">
        <xsl:copy>
            <xsl:apply-templates select="@*"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="@*">
        <xsl:copy/>
    </xsl:template>

    <xsl:template match="@version">
        <xsl:attribute name="version">14</xsl:attribute>
    </xsl:template>

    <xsl:template match="*"/>

</xsl:stylesheet>

I expect the return XML to be something like

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://pse/">
    <SOAP-ENV:Body>
        <ns1:mi102Response>
            <cdhead version="14"/>
        </ns1:mi102Response>
    </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

But instead it is

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://pse/">
    <SOAP-ENV:Body>
        <ns1:mi102Response/>
    </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

Debugging $dom contents in above php shows exactly the XML I try to return (wrapped in SOAP Envelope/Body, of course, just like the input one):

<?xml version="1.0" encoding="UTF-8"?>
<mi102Response xmlns:pse="http://pse">
    <cdhead xmlns="http://pse" version="14"/>
</mi102Response>

Where do I go wrong? How get custom XML into the returned http response content?

1 Answer 1

7

Phew!

This took me several retries and googling until I discovered what is wrong.
I think it can be classified as a bug in SoapVar.

I discovered that while SoapVar is perfectly capable of parsing an XML string, it cannot do so if the string contains an XML declaration like <?xml version="1.0" encoding="UTF-8"?>. So when you have a DOMDocument or a SimpleXMLElement, you first have to strip off the declaration before parsing the string by SoapVar.

for a DOMDocument this can be done by applying saveXML with a parameter equal to a DOMNode variable constructed from the dom itself, choosing any node but usually this will be the root node of course.

In my server php, I added the following:

$nodes = $dom -> getElementsByTagName ('cdhead');
$node = $nodes -> item(0);

$result = new SoapVar ($dom -> saveXML($node), XSD_ANYXML);

And now my result is OK:

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://pse/">
<SOAP-ENV:Header/>
<SOAP-ENV:Body>
    <ns1:mi102Response>
        <cdhead version="14"/>
    </ns1:mi102Response>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>

As for the root name of the returned XML - I am sure I will find out a way to change that to whatever I want it to be (instead of the standard mi102Response generated by SoapVar)!!

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.