Как вернуть пользовательский XML-ответ в ответе soapServer?

Я устанавливаю веб-сервис SOAP, который принимает XML-ввод и должен возвращать пользовательский XML-вывод. Все это определено в WSDL. Я применяю soapServer для этого (пока кто-то не скажет, что у него есть ошибки, мешающие мне достичь моей цели:-)).

Я еще не смог вернуть пользовательский XML: я получил некоторый результат, который, кажется, основан на WSDL, со стандартным именем корневого элемента, равным входному XML, плюс плюс "Response". На самом деле это меня тоже удивляет, так что, как побочный вопрос, мне интересно, почему это так и можно ли на это повлиять. Конечно, хорошо, что определения WSDL используются как-то при создании ответов, но, как я уже сказал, я не знаю, как получить пользовательский XML в ответе.

Я дошел до этого:

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>

Входной XML

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

текущий 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, использованный выше, это всего лишь одно изменение атрибута - и временное изменение корневого имени на имя, возвращаемое сервером всегда (на всякий случай:-))

<?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>

Я ожидаю, что возвращаемый XML будет что-то вроде

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

Но вместо этого

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

Отладка содержимого $dom в приведенном выше php показывает именно тот XML, который я пытаюсь вернуть (обернутый в SOAP Envelope/Body, конечно, точно так же, как и входной):

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

Где я могу пойти не так? Как получить пользовательский XML в возвращенный контент ответа HTTP?

1 ответ

Решение

Уф!

Это заняло у меня несколько попыток и поиск в Google, пока я не обнаружил, что не так.
Я думаю, что это может быть классифицировано как ошибка в SoapVar,

Я обнаружил, что, хотя SoapVar вполне способен анализировать строку XML, он не может этого сделать, если строка содержит объявление XML, например <?xml version="1.0" encoding="UTF-8"?>, Итак, когда у вас есть DOMDocument или SimpleXMLElementВы должны сначала удалить объявление перед синтаксическим анализом строки с помощью SoapVar.

для DOMDocument это можно сделать, применив saveXML с параметром, равным DOMNode переменная, созданная из самого домена, выбирающая любой узел, но обычно это будет корневой узел.

На моем сервере php я добавил следующее:

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

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

И теперь мой результат в порядке:

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

Что касается корневого имени возвращаемого XML - я уверен, что я найду способ изменить его на то, что я хочу (вместо стандартного mi102Response, сгенерированного SoapVar)!!

Другие вопросы по тегам