PHP simpleXML: handling unknown namespaces in SOAP requests

There are tons of questions about PHP simpleXML and XML processing with namespaces. All the questions I looked at made a fundamental assumption: the code knows in advance which namespaces will be included in the incoming SOAP request. In my case, I saw inconsistent namespaces in SOAP requests.

In particular, I was working on implementing a web service to talk to the Quickbooks Web Connector (pdf) and some example of the requests I saw look like this:

<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> 

... and some look like this:

 <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> 

... or that:

 <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> 

I understand the use of xpath () to select elements, but it is assumed that you know what namespace to look for. Without any consistency in the namespace, it’s difficult for me to determine how to correctly and programmatically select node contents for processing.

The namespace is completely irrelevant to this application - could I just run the raw XML through a regular expression to remove whatever: from <whatever:mytag> ?

+4
source share
2 answers

First of all, if you plan to use SOAP a lot, you can take a look at the PHP SOAP extension if you haven't already. I have never used it.

Back to your question, you said: "In my case, I saw inconsistent namespaces in SOAP requests." Get ready because I'm going to blow your mind: no, you didn’t. :)

In these three examples, the two namespaces are the same: there http://schemas.xmlsoap.org/soap/envelope/ and there http://developer.intuit.com/ - which distinguishes the prefix here . The good news is the prefix, which doesn't really matter. See This as a namespace alias. The prefixes used in the document are automatically registered for use in XPath, but you can also register your own.

Here is an example of using the prefixes that were defined in the document (well, if you already know what it is) or register your own prefixes and use them.

 $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); 
+5
source

There are some useful simplexml element methods that can help you identify and use the correct namespaces when querying using the xpath method. The first two are getNamespaces and getDocNamespaces. getNamespaces will return all namespaces used in the document (specify a recursive parameter), and getDocNamespaces will return all namespaces declared by the document.

When you have an array of available namespaces, you can use registerXPathNamespace to register each namespace with simplexml_element in which you intend to use the xpath method.

I am a new user, so I cannot post links to other methods in php documentation.

+1
source

Source: https://habr.com/ru/post/1337166/


All Articles