2011-01-26 135 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