研究與 php(做為現在的主流開發語言) 5 捆綁在一起的 xml(標準化越來越近了)Reader 庫,它使 php(做為現在的主流開發語言) 頁面能夠以高效的流模式來處理 xml(標準化越來越近了) 文檔。
php(做為現在的主流開發語言) 5 引入了新的類 xml(標準化越來越近了)Reader,用於讀取可延伸標記語言 (XML)(Extensible Markup Language,xml(標準化越來越近了))。與 Simplexml(標準化越來越近了) 或文件物件模型(Document Object Model,DOM)不同,xml(標準化越來越近了)Reader 以流模式進行操作。即它從頭到尾讀取文檔。在文檔後面的內容編譯完成之前,可以先處理已編譯好的文檔前面的內容,從而實現非常快速、非常高效、非常節省地使用記憶體。需要處理的文檔越大,這個特點就越發重要。
libxml(標準化越來越近了)
這裡所說的 xml(標準化越來越近了)Reader API 位於 Gnome Project 中用於 C 和 C++ 的 libxml(標準化越來越近了) 庫之上。實際上 xml(標準化越來越近了)Reader 只是在 libxml(標準化越來越近了) 的 xml(標準化越來越近了)TextReader API 之上的很薄的 php(做為現在的主流開發語言) 層。xml(標準化越來越近了)TextReader 本身是模仿 .NET 的 xml(標準化越來越近了)TextReader 類和 xml(標準化越來越近了)Reader 類,儘管並不具有與這些類相似的代碼。
與 Simple API for xml(標準化越來越近了) (SAX) 不同,xml(標準化越來越近了)Reader 是推解析器,而不是拉解析器。這意味著程式是可以控制的。您將告訴解析器何時擷取下一個文檔片段,而不是在解析器看到文檔後告訴您所看到的內容。您將請求內容,而不是對內容進行反應。從另一個角度來考慮這個問題:xml(標準化越來越近了)Reader 是 Iterator 設計模式的實現,而不是 Observer 設計模式的實現。
樣本問題
先從簡單例子開始討論。假定正在編寫 php(做為現在的主流開發語言) 指令碼,用來接收 xml(標準化越來越近了)-RPC 請求並產生響應。更具體一些,假定請求如清單 1 所示。文檔的根項目是 methodCall,它包含 methodName 元素和 params 元素。方法的名稱是 sqrt.params 元素包含一個 param 元素,param 元素包含 double,double 的平方根是希望得到的值。沒有使用名稱空間。
清單 1. xml(標準化越來越近了)-RPC 請求
以下是引用片段: <?xml(標準化越來越近了) version="1.0"?> <methodCall> <methodName>sqrt</methodName> <params> <param> <value><double>36.0</double></value> </param> </params> </methodCall> |
下面是 php(做為現在的主流開發語言) 指令碼需要完成的工作:
1、檢查方法名,如果不是 sqrt(它是該指令碼懂得如何處理的惟一方法),則建置錯誤響應。
2、找到參數,如果參數不存在或參數類型錯誤,則建置錯誤響應。
3、另外,計算平方根。
4、在表單中返回結果,如清單 2 所示。
清單 2. xml(標準化越來越近了)-RPC 響應
以下是引用片段: <?xml(標準化越來越近了) version="1.0"?> <methodResponse> <params> <param> <value><double>6.0</double></value> </param> </params> </methodResponse> |
下面我們逐步展開說明。
初始化解析器並載入文檔
第一步是建立新的解析器對象。建立操作很簡單:
以下是引用片段: $reader = new xml(標準化越來越近了)Reader(); |
接著,需要為它提供一些用於解析的資料。對於 xml(標準化越來越近了)-RPC,這是超文字傳輸通訊協定 (HTTP)(Hypertext Transfer Protocol,HTTP)請求的原始主體。然後可以將該字串傳遞到讀取器的 xml(標準化越來越近了)() 函數:
填充原始發送資料
以下是引用片段: $request = $HTTP_RAW_POST_DATA; $reader->xml(標準化越來越近了)($request); |
如果發現 $HTTP_RAW_POST_DATA 是空的,則將以下程式碼添加到 php(做為現在的主流開發語言).ini 檔案:
以下是引用片段: always_populate_raw_post_data = On |
可以解析任何字串,無論它是從何處擷取的。例如,可以是程式中的一串文字或從本地檔案讀取。還可以使用 open() 函數從外部 URL 載入資料。例如,下面的語句準備解析其中一個 Atom 提要:
以下是引用片段: $reader->xml(標準化越來越近了)('http://www.cafeaulait.org/today.atom'); |
無論是從何處擷取未經處理資料,現在已建立了閱讀器並為解析做好準備。
讀取文檔
read() 函數使解析器前進到下一個標記。最簡單的方法是在 while 迴圈中遍曆整個文檔:
以下是引用片段: while ($reader->read()) { // processing code goes here... } |
完成遍曆後,關閉解析器以釋放它所持有的任何資源,並且重設解析器以便用於下一個文檔:
以下是引用片段: $reader->close(); |
在迴圈內部,將解析器放置在特殊節點上:元素的起點、元素的終點、文本節點、注釋等等。通過檢查以下屬性,可以發現解析器正在查看的內容:
localName 是本地的、未帶首碼的節點名。
name 是可能的節點首碼名。對於像注釋這種沒有名稱的節點,包括 #comment、#text、#document 等等,與 DOM 中的一樣。
namespaceURI 是節點名稱空間的統一資源識別項(Uniform Resource Identifier,URI)。
nodeType 是代表節點類型的整數 —— 例如,2 代表屬性節點,7 代表處理指示。
prefix 是節點的名稱空間首碼。
value 是節點的下一個常值內容。
如果節點有文本值,hasValue 值為 true;否則,值為 false.