PHP SoapClient为相同的元素创建XML引用,这使得服务无法接受


PHP SoapClient creating XML references for identical elements, makes it unacceptable for service

我正在用PHP开发一个SOAP客户端,调用一直进行到服务fine,但存在彼此相同元素的调用除外。当这种情况发生时,似乎不是创建两个单独但相同的元素,比如:

<ns1:someelement>
  <ns1:name>name1</ns1:name>
  <ns1:value>value1</ns1:value>
</ns1:someelement>
<ns1:someelement>
  <ns1:name>name1</ns1:name>
  <ns1:value>value1</ns1:value>
</ns1:someelement>

它坚持只复制元素的一个副本,并为其分配一个ID,并对该元素的任何后续实例使用href(如下所示),这是我使用的Web服务不支持的(我不知道为什么,但这并不重要,因为我无法更改它)

<ns1:someelement id="#ref1">
  <ns1:name>name1</ns1:name>
  <ns1:value>value1</ns1:value>
</ns1:someelement>
<ns1:someelement href="#ref1" />

因此,我的问题是如何强制XML完整地包含重复元素,而不是使用hrefs/ids。我在PHP SoapClient的文档中查看了一个选项或类似的东西,但找不到任何东西。如有任何帮助或建议,我们将不胜感激。谢谢

SoapClient只有在多个XML节点上使用同一对象时才会进行引用。如果不需要参照,请为每个位置创建一个新对象。

在您的PHP代码中创建一个具有唯一索引的属性,这样得到的XML将看起来像:

<ns1:someelement>
  <ns1:name>name1</ns1:name>
  <ns1:value>value1</ns1:value>
  <ns1:index>0</ns1:value>
</ns1:someelement>
<ns1:someelement>
  <ns1:name>name1</ns1:name>
  <ns1:value>value1</ns1:value>
  <ns1:index>1</ns1:value>
</ns1:someelement>

然后PHP SoapClient将不会对相同的数据副本进行href引用,在我的情况下,web服务成功地忽略了这些唯一字段。不,我不会在PHP代码中传递与引用相同的someelement字段。它们是被克隆的,但不幸的是,PHP SoapClient足够聪明,可以将它们的多次出现压缩为引用。

  • 确保不使用引用
  • 尝试使用SoapParam手动添加参数
  • 尝试使用SoapVar手动添加参数

$soapClient->__soapCall('Method', array(
    new SoapParam($someelement1, 'someelement'),
    // or
    new SoapVar('<ns1:someelement><ns1:name>name1</ns1:name><ns1:value>value1</ns1:value></ns1:someelement>', XSD_ANYXML)
));

你好,你可以尝试这个修复程序:

您需要扩展SoapClient并修复生成的请求:

你需要在这里添加导致问题的标签

$tags = ['Tag1', 'Tag2', 'Tag3'];

然后使用MySoapClient而不是SoapClient

class MySoapClient extends SoapClient {
public function __construct($a, $b){
    parent::__construct($a, $b);
}
public function __doRequest($request, $location, $action, $version, $one_way = 0) {
    $tags = ['Tag1', 'Tag2', 'Tag3'];
    foreach($tags as $tag){
        if (preg_match("~<ns1:{$tag} id='"ref(.+)'">(.+)</ns1:{$tag}>~ismU", $request, $matches)) {
            $ref = $matches[1];
            $request = str_replace([' id="ref'.$ref.'"'], '', $request);
            $tagValue = "<ns1:{$tag}>{$matches[2]}</ns1:{$tag}>";
            $request = str_replace("<ns1:{$tag} href='"#ref{$ref}'"/>", $tagValue, $request);
        }
    }
    return parent::__doRequest($request, $location, $action, $version);
}

}