我正在设置一个 SOAP Web 服务,它应该返回一个复合消息。
此消息的有效实例如下:
<dl190Response xmlns="http://pse/">
    <cdhead cisprik="5563167"/>
    <mvts>
        <mvts_S att="a1">
            <x>x1</x>
            <w>w1</w>
        </mvts_S>
        <mvts_S>
            <x>x2</x>
            <w>w2</w>
        </mvts_S>
    </mvts>
</dl190Response>
所有这些都在 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 xmlns="http://pse/" targetNamespace="http://pse/">
            <xs:complexType name="cdhead_T">
                <xs:attribute name="cisprik" type="xs:long"/>
            </xs:complexType>
            <xs:complexType name="mvts_T">
                <xs:sequence>
                    <xs:element name="mvts_S" type="mvts_S_T" minOccurs="0" maxOccurs="unbounded"/>
                </xs:sequence>
            </xs:complexType>
            <xs:complexType name="mvts_S_T">
                <xs:sequence>
                    <xs:element name="x" type="xs:string"/>
                    <xs:element name="w" type="xs:string"/>
                </xs:sequence>
                <xs:attribute name="att" type="xs:string" use="optional"/>
            </xs:complexType>
        </xs:schema>
    </types>
    <message name="DL190Req">
        <part name="cdhead" type="tns:cdhead_T"/>
    </message>
    <message name="DL190Res">
        <part name="cdhead" type="tns:cdhead_T"/>
        <part name="mvts" type="tns:mvts_T"/>
    </message>
    <portType name="DLPortType">
        <operation name="dl190">
            <input message="tns:DL190Req"/>
            <output message="tns:DL190Res"/>
        </operation>
    </portType>
    <binding name="DLBinding" type="tns:DLPortType">
        <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
        <operation name="dl190">
            <soap:operation soapAction="http://www.testServer.com/test_soap.php#dl190"/>
            <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="DLPortType" binding="tns:DLBinding">
            <soap:address location="http://www.testServer.com/test_soap.php"/>
        </port>
    </service>
</definitions>
我一直在服务器端 test_soap.php 无休止地工作以使其正确,但我没有成功。在返回 XML 之前正常工作的部分内容如下:
<?php
    class PSE {
        function dl190 ($arg) {
            //I don't need to extract the input data just now
            mysql_connect('127.0.0.1:3306', 'user', 'password');
            mysql_select_db('myDatabase');
            $xml = new SimpleXMLElement('<dl190Res/>');
            $xml -> addChild('cdhead');
            $mvts = $xml -> addChild('mvts');
            $rows = mysql_query('select * from trx');
            while($data = mysql_fetch_assoc($rows)) {
                $mvts_S = $mvts -> addChild('mvts_S'); 
                foreach($data as $key => $value) {
                    if ($key == 'att') { $mvts_S -> addAttribute($key, $value);}
                    else    {$mvts_S -> addChild($key, $value);}
                }
            };
            $dom = dom_import_simplexml ($xml) -> ownerDocument;
            // now respond to the request and return the XML
        }
    };
    ini_set( "soap.wsdl_cache_enabled", "0");
    $server = new SoapServer ("test.wsdl");
    $server -> setClass ('PSE');
    $server -> setObject (new PSE());
    $server -> handle();    
?>
我几乎尝试了我能想到的所有方法来得到正确的响应,但我没有成功。我能够对之前仅包含一个部分的消息执行相同的操作(请参阅我最近的问题+答案)。
但是在这里,有两个消息部分,我没有成功。
$xml 内容的调试表明它正是我希望看到的返回,当然,在让肥皂服务器将其包装到 Envelope+Body 之后。
实际上,这种情况与只有一个消息部分的情况不同:只要我先剥离 XML 声明,然后返回它,我就可以从一个部分创建一个新的 SoapVar。在这里我不能这样做,因为返回值由两部分组成。
所以我想知道我现在应该做什么:
- 为响应消息声明一个类并填充并返回它
 - 使用 SoapVar 和/或 SoapParam 执行一些魔术(请注意,我已经尝试了很多)
 - 使用数组和 SoapVar 执行一些魔术(已经尝试了很多)
 - 不知何故(如何?)向wsdl寻求帮助
 - 完全不同的东西
 - 用 SoapServer 退出整个噩梦,从头开始创建我自己的 http 响应
 
我感谢所有的帮助,所以所有的肥皂专家,不要犹豫,试着回答这个问题!
添加
作为临时解决方法,我编辑了 WSDL,将响应消息更改为只有一个部分。这允许我将预期的消息作为预期的两个部分的串联传递(或任何其他消息,因为 SoapVar 没有对返回的值进行消息定义的结构 WSDL 检查):
$xml1 = new SimpleXMLElement('<cdhead/>');
$xml1 -> addAttribute ('xmlns', 'http://pse/');
$xml1 -> addAttribute ('cisprik', $newCisprik);
$xml2 = new SimpleXMLElement('<mvts/>');
$rows = mysql_query('select * from trx');
while($data = mysql_fetch_assoc($rows)) {
    $mvts_S = $xml2 -> addChild('mvts_S'); 
    foreach($data as $key => $value) {
        if ($key == 'att') { $mvts_S -> addAttribute($key, $value);}
        else    {$mvts_S -> addChild($key, $value);}
    }
};
$dom1 = dom_import_simplexml ($xml1) -> ownerDocument;
$dom2 = dom_import_simplexml ($xml2) -> ownerDocument;
$part1 = $dom1 -> saveXML($dom1 -> documentElement);
$part2 = $dom2 -> saveXML($dom2 -> documentElement);
$result = new SoapVar ($part1 . $part2, XSD_ANYXML);
对此的特殊之处在于,连接当然不是有效的 XML,缺少周围的根元素,但 SoapVar 无论如何都能解析它。
就是这样:任何对 SoapVar 和 SoapParam / SoapServer 有详细了解的人都可以解释是否有可能返回两个消息部分?
并解释如何做到这一点?
或者,提供有关如何在其他 SOAP 设置中执行此操作的详细信息?