2011-01-26 131 views
4

有一个tonofexistingquestions关于PHP的SimpleXML和使用命名空间的处理XML。所有的我看了都取得了基本假设的问题:提前命名空间会是什么代码知道要包含在传入的SOAP请求。就我而言,我在SOAP请求中看到了不一致的名称空间。PHP的SimpleXML:在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()选择ELE发言:,但假设你知道如何寻找的命名空间中,没有任何一致性的命名空间,我有一个很难搞清楚如何正确,程序选择处理节点的内容。

命名空间在这个应用程序中是完全不相关的 - 我可以通过正则表达式运行原始XML以便首先从<whatever:mytag>中删除whatever:

回答

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); 
+0

是的!我将前缀理解为命名空间的快捷方式。具有讽刺意味的是,我实际上是在尝试过自己的解决方案之前,无法让xpath识别我定义的备用前缀。我一定是做错了事。我显然还没有完全理解Xpath。原谅新手跟进问题(在这一点上应该不会令人惊讶),但是如果我不一定知道紧接着身体的下一个标记是什么,我仍然可以通过通配符选择它,或者一个使用'/ soap:Envelope/child :: soap:Body'的轴? – beporter 2011-01-27 14:44:29

1

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

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

我是一个新用户,所以我不能发布PHP的文档中的链接到其他的方法。

+0

我*想*我明白你的意思,但肯定会有助于看到一个例子。假设我想要一个$ var包含一个用于验证的SimpleXMLElement,并带有两个子项:strUserName和strPassword。我的目标是能够将通用化(意味着元素名称中没有名称空间)对象传递给仅知道寻找$ var-> children() - > strUserName的处理程序。 – beporter 2011-01-26 17:33:19