Zend SOAP:将默认数组元素名称“item”更改为 WSDL 中复杂类型的类名称

Posted

技术标签:

【中文标题】Zend SOAP:将默认数组元素名称“item”更改为 WSDL 中复杂类型的类名称【英文标题】:Zend SOAP: Change the default array element name "item" to class name of complex type in WSDL 【发布时间】:2015-07-08 14:40:15 【问题描述】:

这个问题可能会被问到,但它很难搜索,我找不到任何关于它的信息。而且问起来也不容易。

我正在使用 Zend SOAP 的自动发现功能重新创建我们的旧 SOAP 接口(因为切换到微服务并重新处理所有内容)。

到目前为止,它就像一个魅力。但是在使用列表/数组时,我在重新创建某些服务的 SOAP 响应时遇到了一个问题。

SOAP 请求的旧响应 XML 如下所示。它在<SMSEntries> 列表中包含两个<SMSEntry>

<SOAP-ENV:Envelope>
   <SOAP-ENV:Body>
      <ns1:getSMSByTimeSpanResult>
         <AmountOfEntries>2</AmountOfEntries>
         <SMSEntries>
            <SMSEntry></SMSEntry>
            <SMSEntry></SMSEntry>
         </SMSEntries>
      </ns1:getSMSByTimeSpanResult>
   </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

但是重新创建的响应看起来像这样。它在&lt;SMSentries&gt; 列表中包含两个&lt;item&gt;s 类型为SMSEntry

<SOAP-ENV:Envelope>
   <SOAP-ENV:Body>
      <ns1:getSMSByTimeSpanResponse>
         <return xsi:type="ns1:getSMSByTimeSpanResponse">
            <AmountOfEntries xsi:type="xsd:int">2</AmountOfEntries>
            <SMSEntries SOAP-ENC:arrayType="ns1:SMSEntry[2]" xsi:type="ns1:ArrayOfSMSEntry">
               <item xsi:type="ns1:SMSEntry"></item>
               <item xsi:type="ns1:SMSEntry"></item>
            </SMSEntries>
            <DataEx xsi:nil="true"/>
         </return>
      </ns1:getSMSByTimeSpanResponse>
   </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

我无法控制客户。他们可能会通过比较字符串来检查SMSEntry。我想使用类名 SMSEntry 作为 XML 标记名。

其次,我想省略额外的,包装所有内容,&lt;return&gt; 标签。

我正在使用这样的自动发现:

use Zend\Soap\AutoDiscover;
use Zend\Soap\Wsdl\ComplexTypeStrategy\ArrayOfTypeComplex;

$autoDiscover = new AutoDiscover(new ArrayOfTypeComplex());
$autoDiscover->setClass(new Standard($sm));

getSMSByTimeSpanResponse 的定义如下:

标准.php

/**
 * Class getSMSByTimeSpanResponse
 *
 * @package LgxServiceManager\Service
 */
class getSMSByTimeSpanResponse

    /**
     * @var int
     */
    public $AmountOfEntries;

    /**
     * @var \LgxServiceManager\Service\SMSEntry[]
     */
    public $SMSEntries;


/**
 * Class SMSEntry
 *
 * @package LgxServiceManager\Service
 */
class SMSEntry


有人知道怎么做吗?

我在library\Zend\Soap\Wsdl\ComplexTypeStrategy\ArrayOfTypeSequence.php:122 中找到了一些代码 _addSequenceType() 方法设置硬编码属性的地方:

$element->setAttribute('name', 'item');

但这是“序列”类型,而不是我正在使用的“复杂”类型......

提前谢谢你, 菲利普


\编辑

哦,伙计...我刚刚发现了另一个我不知道如何使用 Zend SOAP 的自动发现创建的结构...

 <mainMember1>SERIALNUMBER</mainMember1>
 <mainMember2>NAMEOFPRODUCT</mainMember2>
 <mainMember3>000000-000-0</mainMember3>
 <Rules>
    <RuleEntry>
       <singleValue>allow</singleValue>
       <ResourceList>
          <Name>generic</Name>
          <ResourceEntry>[...]</ResourceEntry>
          <ResourceEntry>[...]</ResourceEntry>
          <ResourceEntry>[...]</ResourceEntry>
       </ResourceList>
       <ResourceList>
          <Name>default</Name>
          <ResourceEntry>[...]</ResourceEntry>
          <ResourceEntry>[...]</ResourceEntry>
          <ResourceEntry>[...]</ResourceEntry>
       </ResourceList>
    </RuleEntry>
 </Rules>

如您所见,&lt;RuleEntry&gt; 内部有一个&lt;singleValue&gt;,但有多个&lt;ResourceList&gt;s。资源列表内部使用相同的结构:一个&lt;Name&gt;和多个&lt;ResourceEntry&gt;...

这甚至可以通过自动发现来处理吗?

【问题讨论】:

也许这会给你一些提示:***.com/questions/17307571/… 谢谢。我自己弄清楚了,并按照我的问题代码中的描述使用了它。我的 WSDL 看起来很好。但是响应 XML 比那些“项目”元素... 无论答案如何,我都能感受到你的痛苦。任何时候有人暗示将来要使用 SOAP,你必须非常快地喊出“使用 REST!”。在他们身上。 【参考方案1】:

我知道这是一个旧线程,但我正在努力帮助那些遇到与我相同问题的追随者。

现在我们使用 Laminas,但原理是一样的。

解决原始问题的另一种方法是对 供应商\Laminas\Laminas-Soap\src\Wsdl\ComplexTypeStrategy\ArrayOfTypeSequence.php:124 用这样的代码:

        // Paulo
        // $element->setAttribute('name', 'item');   // Original Code
           $element->setAttribute('name', substr($childType, 4));
        // Paulo End

希望对大家有帮助

【讨论】:

【参考方案2】:

对于仍有上述问题的任何人: stdClass() 的默认响应如下:

$array = ['lets', 'test', 'it'];
$response = new stdClass();
$response->results = $array;

会是这样的:

 <return xsi:type="SOAP-ENC:Struct">
    <results SOAP-ENC:arrayType="xsd:string[3]" xsi:type="SOAP-ENC:Array">
       <item xsi:type="xsd:string">lets</item>
       <item xsi:type="xsd:string">test</item>
       <item xsi:type="xsd:string">it</item>
    </results>
 </return>

我们能做什么——我们可以将数组更改为ArrayObject()

    $array = ['lets', 'test', 'it'];

    $response = new stdClass();
    $response->results = new ArrayObject();
    foreach($array as $item) 
      $response->results->append($item);
    

返回:

         <return xsi:type="SOAP-ENC:Struct">
            <results xsi:type="SOAP-ENC:Struct">
               <BOGUS xsi:type="xsd:string">lets</BOGUS>
               <BOGUS xsi:type="xsd:string">test</BOGUS>
               <BOGUS xsi:type="xsd:string">it</BOGUS>
            </results>
         </return>

最后是锦上添花:

$array = ['lets', 'test', 'it'];

$response = new stdClass();
$response->results = new ArrayObject();
foreach($array as $item) 
    $soapVar = new SoapVar($item,XSD_STRING,NULL,NULL,'result');
    $response->results->append($soapVar);

它会返回:

 <return xsi:type="SOAP-ENC:Struct">
    <results xsi:type="SOAP-ENC:Struct">
       <result xsi:type="xsd:string">lets</result>
       <result xsi:type="xsd:string">test</result>
       <result xsi:type="xsd:string">it</result>
    </results>
 </return>

如您所见,第五个参数告诉了 xml 元素的键是什么。您还需要注意第二个参数,因为它告诉变量的类型。你可以在这里找到更多: https://secure.php.net/manual/en/class.soapvar.php

【讨论】:

以上是关于Zend SOAP:将默认数组元素名称“item”更改为 WSDL 中复杂类型的类名称的主要内容,如果未能解决你的问题,请参考以下文章

具有两个元素的 SOAP 主体

如何将 Zend_Dojo 表单元素动态添加到 zend_form?

动作脚本 3. 如何检查数组的当前元素是不是有准确的名称?

如何删除Zend_Soap中的命名空间?

Zend 表单/子表单部分渲染

div中的Zend Form元素