【问题标题】:change soap prefixes in php在php中更改soap前缀
【发布时间】:2011-12-28 00:09:09
【问题描述】:

我正在将soap web 服务从.net 重写为php。默认情况下,php 给我的标签看起来像这样:

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://tempuri.org/"><SOAP-ENV:Header><ns1:FindAllCategories/></SOAP-ENV:Header><SOAP-ENV:Body><ns1:FindAllCategoriesResponse><ns1:FindAllCategoriesResult><ns1:ArtistCategoryDto>

等等……

但我需要这个:

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Body><FindAllCategoriesResponse xmlns="http://tempuri.org/"><FindAllCategoriesResult><ArtistCategoryDto>

这类似于这里的问题:PHP AND SOAP. Change envelope 但是我不想像他那样破解它。此外,我正在创建一个将由现有的 iphone 应用程序使用的肥皂服务,而不是使用 PHP 来使用 SoapClient 使用肥皂服务。 iphone 应用程序只解析原始 xml,我现在无法更改 iphone 应用程序。

【问题讨论】:

  • 您能具体说说您不喜欢其他解决方案的哪些方面吗?你觉得哪里有缺点? “我只需要这个工作”也很难做到,因为 Iphone App 显然有一个缺点。也许它不是唯一的,所以如果不只是猜测,有人怎么能回答你的问题呢?
  • 当然。所以有几个问题。首先,我正在构建一个soap 服务,示例是使用soap 客户端。我根本没有使用 php soap 客户端——应用程序就是客户端。其次,我不喜欢使用 RegEx 破解 xml。我宁愿使用一些本机 api,或者如果绝对必要,使用 xml 解析器来解析命名空间,但我不知道如何获取解析 XML 的响应。该应用程序肯定有一个缺点,因为它没有按照预期的方式使用肥皂。但它的构建方式是因为当时没有好的肥皂解析器。

标签: php soap


【解决方案1】:

在重新阅读您想要的内容并在此处搜索 php 文档后,这是我的解决方案以及我所做的一些假设

假设

  • 如果我是正确的,您知道 SOAP 前缀本身不是问题(您可以使用任何前缀,只要它是一致的)。
  • 我们需要为这个特定的 Iphone 应用程序创建一个解决方法,该应用程序使用您当前无法修改/升级的 (xml) 解析器

你想要什么?

  1. 您想使用本机 API 来更改 SOAP 前缀
  2. 您希望捕获 SoapServer 响应,以便在返回 SOAP 前缀之前更改它

解决方案

  1. 目前没有本地 SoapServer API 方法来更改 SOAP 前缀
  2. 您可以捕获 SoapServer 响应并通过正则表达式或 xml 解析器处理响应,请参见下面的示例
<?php

// Create you parse function - Regex
function SoapServerRegexParser($input)
{
    // $input contains your XML Response
    // Do str_replace or preg_replace   
    $request = preg_replace({do replace});

    //return modified output to client
    return $request;
}

// OR create you parse function - Regex XML Parser
function SoapServerXMLParser($input)
{
    // $input contains your XML Response
    // Use any xml parser that you would like   
    $xml = new DOMDocument();
    $xml->formatOutput = true;
    $xml->preserveWhiteSpace = false;
    $xml->loadXML($input);
    //Do replacement have a looke at: DOMNode::replaceChild

    //return modified output to client
    return $xml->saveXML();
}

// Make php buffer all output
// Send all output to a callBack function

// Replace 'SoapServerRegexParser' with the callback function name of choice
ob_start('SoapServerRegexParser'); //buffer output and set callback function

// Create SoapServer
$server = new SoapServer('wsdlfile.wsdl');
$server->handle(); //Handle incoming request
ob_end_flush(); //Release buffer, but send through callback function first

?>

这应该可以解决问题,我还没有创建正则表达式部分或实际的 xlm 节点替换,但我认为你可以自己做

【讨论】:

  • 实际上,我确实需要命名空间前缀非常具体。 iphone 应用程序正在寻找它们。但是,如果我可以像您在这里所做的那样更改缓冲区中的输出,我想我很好。所以代替: ob_start('SoapServerRegexParser');我会使用:SoapServerXMLParser'); ...如果我想使用 xml 解析它?
  • 是的,这是正确的。查看nl2.php.net/manual/en/domnode.replacechild.php 了解如何替换子节点。如果您正在搜索的字符串,并且您想替换它们,我认为使用 str_replace 会更容易
  • 非常酷——正是我快速编写灵活的soap服务器所需要的。
【解决方案2】:

如果您不想使用正则表达式,我已经完成了这个快速类实现,它使用 DomXPath 和 DomDocument 来清理 XML 并在节点级别附加命名空间属性。

<?php

public BetterSoapClient extends SoapClient {

    public function __construct($wsdl, $options = null) {
        parent::__construct($wsdl, $options);
    }

    public function __doRequest($request, $location, $action, $version) {

        $dom = new DOMDocument('1.0');

        // loads the SOAP request to the Document
        $dom->loadXML($request);

        // Create a XPath object
        $path = new DOMXPath($dom);

        // Search the nodes to fix
        $nodesToFix = $path->query('//SOAP-ENV:Envelope/SOAP-ENV:Body/*', null, true);

        // Remove unwanted namespaces
        $this->fixNamespace($nodesToFix, 'ns1', 'http://tempuri.org/');

        // Save the modified SOAP request
        $request = $dom->saveXML();

        return parent::__doRequest($request, $location, $action, $version);
    }

    public function fixNamespace(DOMNodeList $nodes, $namespace, $value) {
        // Remove namespace from envelope
        $nodes->item(0)
                ->ownerDocument
                ->firstChild
                ->removeAttributeNS($value, $namespace);

        //iterate through the node list and remove namespace

        foreach ($nodes as $node) {

            $nodeName = str_replace($namespace . ':', '', $node->nodeName);
            $newNode = $node->ownerDocument->createElement($nodeName);

            // Append namespace at the node level
            $newNode->setAttribute('xmlns', $value);

            // And replace former node
            $node->parentNode->replaceChild($newNode, $node);
        }
    }
}

【讨论】:

  • 这对我没有帮助。我正在使用 SoapServer 构建一个肥皂 Web 服务,而不是使用 SoapClient 使用另一个服务。我已经修改了原始帖子以使其更清楚,尽管我最初确实提到过它并且也在 cmets 中。
猜你喜欢
  • 2019-04-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-12-16
相关资源
最近更新 更多