PHP simpleXML:处理SOAP请求中的未知命名空间

时间:2011-01-26 16:30:50

标签: php soap namespaces simplexml

有关于PHP的simpleXML和使用命名空间处理XML的ton of existing questions。我所看到的所有问题都提出了一个基本假设:代码事先知道将在传入的SOAP请求中包含哪些命名空间。就我而言,我在SOAP请求中看到了不一致的命名空间。

具体来说,我一直在努力实现一个Web服务来与Quickbooks Web Connector(pdf)交谈,我看到的一些示例请求看起来像这样:

<soapenv:Envelope 
 xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" 
 xmlns:dev="http://developer.intuit.com/">
   <soapenv:Header/>
   <soapenv:Body>
      <dev:authenticate>
         <dev:strUserName>username</dev:strUserName>
         <dev:strPassword>password</dev:strPassword>
      </dev:authenticate>
   </soapenv:Body>
</soapenv:Envelope>

......有些看起来像这样:

<s11:Envelope 
 xmlns:s11='http://schemas.xmlsoap.org/soap/envelope/' 
 xmlns:ns1='http://developer.intuit.com/'>
  <s11:Header/>
  <s11:Body>
    <ns1:authenticate>
      <ns1:strUserName>username</ns1:strUserName>
      <ns1:strPassword>password</ns1:strPassword>
    </ns1:authenticate>
  </s11:Body>
</s11:Envelope>

......或者这个:

<SOAP-ENV:Envelope 
 xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" 
 xmlns:ns1="http://developer.intuit.com/">
   <SOAP-ENV:Header/>
   <SOAP-ENV:Body>
      <ns1:authenticate>
         <ns1:strUserName>username</ns1:strUserName>
         <ns1:strPassword>password</ns1:strPassword>
      </ns1:authenticate>
   </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

我理解使用xpath()来选择元素,但是假设你知道要查找的命名空间。在命名空间没有任何一致性的情况下,我很难弄清楚如何正确和以编程方式选择内容要处理的节点。

命名空间在此应用程序中完全无关紧要 - 我是否可以通过正则表达式运行原始XML以首先从whatever:删除<whatever:mytag>

2 个答案:

答案 0 :(得分:5)

首先,如果您计划大量使用SOAP,如果您还没有,可能需要查看PHP's SOAP extension。但我从未使用它。

回到你的问题,你说“在我的情况下,我在SOAP请求中看到了不一致的命名空间。”准备好因为我要打扰你的想法:不,你没有。 :)

在这三个示例中,两个名称空间是相同的:http://schemas.xmlsoap.org/soap/envelope/http://developer.intuit.com/ - 这里有什么不同的是 前缀 。好消息是前缀并不重要。将其视为命名空间的别名。文档中使用的前缀会自动注册以在XPath中使用,但您也可以注册自己的前缀。

以下是如何使用文档中定义的前缀的示例(如果您已经知道它们是什么,那就很好)或者注册您自己的前缀并使用它们。

$xml = '<soapenv:Envelope 
 xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" 
 xmlns:dev="http://developer.intuit.com/">
   <soapenv:Header/>
   <soapenv:Body>
      <dev:authenticate>
         <dev:strUserName>username</dev:strUserName>
         <dev:strPassword>password</dev:strPassword>
      </dev:authenticate>
   </soapenv:Body>
</soapenv:Envelope>';

$Envelope = simplexml_load_string($xml);

// you can register and use your own prefixes
$Envelope->registerXPathNamespace('soap', 'http://schemas.xmlsoap.org/soap/envelope/');
$Envelope->registerXPathNamespace('auth', 'http://developer.intuit.com/');

$nodes = $Envelope->xpath('/soap:Envelope/soap:Body/auth:authenticate/auth:strUserName');
$username = (string) $nodes[0];

// or you can use the prefixes that are already defined in the document
$nodes = $Envelope->xpath('/soapenv:Envelope/soapenv:Body/dev:authenticate/dev:strPassword');
$password = (string) $nodes[0];

var_dump($username, $password);

答案 1 :(得分:1)

有一些有用的simplexml元素方法可以帮助您在使用xpath方法查询时确定并使用正确的命名空间。前两个是getNamespaces和getDocNamespaces。 getNamespaces将返回文档中使用的所有命名空间(指定递归参数),而getDocNamespaces将返回文档声明的所有命名空间。

一旦有了可用的命名空间数组,就可以使用registerXPathNamespace将每个命名空间注册到要使用xpath方法的simplexml_element。

我是新用户,因此无法将链接发布到php文档中的其他方法。