DIV CSS 佈局教程網

 DIV+CSS佈局教程網 >> 網頁腳本 >> XML學習教程 >> XML詳解 >> GWT 與 PHP 之間的橋梁
GWT 與 PHP 之間的橋梁
編輯:XML詳解     

通過 GWT 可以方便地訪問用 Java 語言編寫的服務器端 servlet,並且客戶機和服務器之間的數據傳遞是透明的。但是,當使用 GWT 時,不僅可以與那些 servlet 通信,還可以隨意地與所有類型的 Web 服務交換數據。在很多情況下(對於簡單的服務),可以用純文本格式傳輸數據,但是每當遇到結構化的數據或較復雜的數據(例如 RSS)時,數據很可能是用 XML 表示的。

  本文研究一個簡單的 GWT 應用程序和兩個 PHP Web 服務,展示生成和使用 XML 文檔的幾種不同的方法。本文無意成為詳盡的教程或手冊,而是提供一些忠告,使您能更快地開始使用 XML 作為連接 GWT 與 PHP 的橋梁。

  測試應用程序

  為了展示如何使用 XML 作為 PHP 與 GWT 之間的橋梁,我提供一個簡單的應用程序,這個應用程序基於國家/地區/城市數據。查看 清單 1 中的數據庫創建代碼,可以看到:

  國家(country)有惟一的代碼(例如 UY 表示烏拉圭)和名稱。

  國家 被劃分為多個地區(region),地區有(國家內惟一的)代碼和名稱。

  地區 內有多個城市(city),城市有(純 ASCII)名稱、別名(可能包括外來字符)、人口(如果未知則為 0)、緯度和經度。城市名可出現在同一個國家的不同地區。

  清單 1. 數據庫創建代碼

   
CREATE DATABASE world 
  DEFAULT CHARACTER SET latin1 
  COLLATE latin1_general_ci; 
 
USE world; 
 
CREATE TABLE countrIEs ( 
  countryCode char(2) NOT NULL, 
  countryName varchar(50) NOT NULL, 
  PRIMARY KEY (countryCode) 
  KEY countryName (countryName) 
  ); 
 
CREATE TABLE regions ( 
  countryCode char(2) NOT NULL, 
  regionCode char(2) NOT NULL, 
  regionName varchar(50) NOT NULL, 
  PRIMARY KEY (countryCode,regionCode), 
  KEY regionName (regionName) 
  ); 
 
CREATE TABLE citIEs ( 
  countryCode char(2) NOT NULL, 
  cityName varchar(50) NOT NULL, 
  cityAccentedName varchar(50) NOT NULL, 
  regionCode char(2) NOT NULL, 
  population bigint(20) NOT NULL, 
  latitude float(10,7) NOT NULL, 
  longitude float(10,7) NOT NULL, 
  KEY `INDEX` (countryCode,regionCode,cityName), 
  KEY cityName (cityName), 
  KEY cityAccentedName (cityAccentedName) 
  ); 

  我創建了一個簡單的 GWT 項目,它只有一個表單和兩個 PHP Web 服務。(下載 小節提供了完整的源代碼)。啟動該應用程序時,可以看到 圖 1 中的窗口。

  圖 1. 空的表單

XML:GWT 與 PHP 之間的橋梁

  圖片看不清楚?請點擊這裡查看原圖(大圖)。

  GWT 表單允許輸入一個城市名的一部分,然後調用一個 PHP 服務獲得與輸入的內容匹配的所有城市。這些城市顯示在一個網格中,可以編輯人口(population)、緯度(latitude)和經度(longitude)字段。然後,可以將編輯的數據發回到另一個 PHP Web 服務,後者將更新數據庫。所有數據傳輸都是通過 XML 進行的。2009 年是查爾斯達爾文 200 誕辰和他的著作物種起源 誕生 150 周年,您可以查看城市名中包含 DARWIN 的城市;圖 2 顯示了結果。

  圖 2. 搜索城市名中包含 “Darwin” 的城市

XML:GWT 與 PHP 之間的橋梁

  圖片看不清楚?請點擊這裡查看原圖(大圖)。

  一些額外的配置

  下面是我使用的軟件,僅供參考:

  GWT version 1.5.3

  PHP version 5.2.8

  MySQL® database server version 5.0.67

  apache version 2.2.10 under OpenSUSE® version 11.1

  我安裝的所有軟件都是開箱即用的,但是 GWT 要求一個額外的配置步驟,這樣才能測試 GWT-PHP 連接;請參閱側邊欄 SOP 問題,看看是什麼原因。為了禁用內部 GWT 浏覽器的同源策略(same-origin policy,SOP)檢查,可以編輯 GWT 目錄中的 ./mozilla-1.7.12/greprefs/all.JS 文件,在文件的最後添加 清單 2 中的代碼行:

  清單 2. 修改內部 GWT 浏覽器的配置

   
pref("capability.policy.default.XMLHttpRequest.abort", "allAccess"); 
pref("capability.policy.default.XMLHttpRequest.getAllResponseHeaders","allAccess"); 
pref("capability.policy.default.XMLHttpRequest.getResponseHeader","allAccess"); 
pref("capability.policy.default.XMLHttpRequest.open", "allAccess"); 
pref("capability.policy.default.XMLHttpRequest.send", "allAccess"); 
pref("capability.policy.default.XMLHttpRequest.setRequestHeader","allAccess"); 
pref("capability.policy.default.XMLHttpRequest.onreadystatechange","allAccess"); 
pref("capability.policy.default.XMLHttpRequest.readyState", "allAccess"); 
pref("capability.policy.default.XMLHttpRequest.responseText","allAccess"); 
pref("capability.policy.default.XMLHttpRequest.responseXML","allAccess"); 
pref("capability.policy.default.XMLHttpRequest.status", "allAccess"); 
pref("capability.policy.default.XMLHttpRequest.statusText", "allAccess"); 

  每當更新 GWT 時,需要再次作出這樣的更改。而且,請注意,如果不這樣做,編寫的代碼在 Hosted 模式下會失敗,但是在 compiled 模式下卻可以正確運行。作出以上更改後,您的代碼可能在 Hosted 模式下可以運行,但是在 Compiled 模式下卻會失敗,所以要小心!

  用 PHP 發送 XML

  這個應用程序只定義一個簡單的表單,其中有一些標簽、一個文本框、兩個命令按鈕和一個用於顯示結果的網格。每當單擊 Get citIEs 時,該應用程序調用一個 PHP 服務,以便獲得一個 XML 文檔,其中包含與文本框中輸入的內容匹配的所有城市。清單 3 顯示從 PHP 服務發送到 GWT 應用程序的一個示例 XML(有所簡化)。生成的 XML 代碼要用於演示一些 XML 功能,所以比用於真正的應用程序的 XML 要長得多。 通常,設計良好的 XML 服務使用更少的標記和更多的屬性,避免縮進,並且更短一些。

  清單 3. 搜索 “tokyo” 時生成的 XML 文檔

   
<?XML version="1.0" encoding="UTF-8"?> 
 <citIEs> 
 <city name="tokyo"> 
  <country code="JP" name="Japan"/> 
  <region code="40" name="Tokyo"/> 
  <coords> 
  <lat>35.6850014</lat> 
  <lon>139.7513885</lon> 
  </coords> 
  <pop>31480498</pop> 
 </city> 
 <city name="tokyo"> 
  <country code="PG" name="Papua New Guinea"/> 
  <region code="01" name="Central"/> 
  <coords> 
  <lat>-8.3999996</lat> 
  <lon>147.1499939</lon> 
  </coords> 
 </city> 
 <city name="tokyojitori"> 
  <country code="KR" name="Korea, Republic of"/> 
  <region code="16" name="Cholla-namdo"/> 
  <coords> 
  <lat>34.2380562</lat> 
  <lon>125.9394455</lon> 
  </coords> 
 </city> 
</citIEs> 

  這個 PHP 服務本身有兩個版本 — getcities1.php 和 getcitIEs2.PHP —,每個版本展示生成 XML 的不同方法。

  到目前為止,生成 XML 的最簡單的方法是連續輸出適當的文本,或者構建一個字符串,然後使用 echo 發出它。這裡應該將 content type 設為 text/xml,使之能夠被正確地識別,並且還要記得包括一個適當的 description 行,以指定 XML 版本和數據編碼方式。另外還必須轉義字符串,使字符串中不包括小於(<)、大於(>)或和(&)字符。最簡單的方法是使用 Htmlspecialchars() PHP 函數。代碼很容易編寫,如 清單 4 所示。注意,縮進和換行實際上是不需要的,不過這樣做可以讓代碼更易於閱讀。

  清單 4. 從 PHP 服務生成 XML 的最簡單的方法

   
... 
header("Content-type: text/XML"); 
... 
echo '<?XML version="1.0" encoding="UTF-8"?>'."\n"; 
echo '<citIEs>'."\n"; 
... 
while ($row= MySQL_fetch_assoc($result)) { 
 echo ' <city name="'.Htmlspecialchars($row['cityName']).'">'."\n"; 
 echo ' <country code="'.$row['countryCode'].'" '; 
 echo 'name="'.HtmlentitIEs($row['countryName']).'"/>'."\n"; 
 echo ' <region code="'.$row['regionCode'].'" '; 
 echo 'name="'.HtmlentitIEs($row['regionName']).'"/>'."\n"; 
 
 echo ' <coords>'."\n"; 
 echo '  <lat>'.$row['latitude'].'</lat>'."\n"; 
 echo '  <lon>'.$row['longitude'].'</lon>'."\n"; 
 echo ' </coords>'."\n"; 
 
 if ($row['population']>0) { 
  echo ' <pop>'.$row['population'].'</pop>'."\n"; 
 } 
 
 echo ' </city>'."\n"; 
} 
echo '</citIEs>'."\n"; 

  生成 XML 代碼的另一種方法(也不是很長)是使用 XMLWriter。(與之成對的另一個類 XMLReader 可用於 XML 處理)。現在可以不用關心字符的轉義,因為這是自動完成的。雖然這種方法看起來比前面的 echo() 方法冗長一點,但是這種方法編寫的代碼更易於理解。特別注意,這裡使用了 PHP://output 協議,以便用 echo 命令發出文本。(如 清單 5 所示)。

  清單 5. XMLWriter 提供逐個元素地構建 XML 文檔的簡單方法

   
... 
$writer= new XMLWriter(); 
$writer->openURI('PHP://output') 
$writer->startDocument('1.0', 'UTF-8'); 
$writer->startElement("citIEs"); 
 
while ($row= MySQL_fetch_assoc($result)) { 
 $writer->startElement("city"); 
 $writer->writeAttribute("name", $row['cityName']); 
 
 $writer->startElement("country"); 
 $writer->writeAttribute("code", $row['countryCode']); 
 $writer->writeAttribute("name", $row['countryName']); 
 $writer->endElement(); 
 
 $writer->startElement("region"); 
 $writer->writeAttribute("code", $row['regionCode']); 
 $writer->writeAttribute("name", $row['regionName']); 
 $writer->endElement(); 
 
 $writer->startElement("coords"); 
 $writer->writeElement("lat", $row['latitude']); 
 $writer->writeElement("lon", $row['longitude']); 
 $writer->endElement(); 
 
 if ($row['population']>0) { 
  $writer->writeElement("pop", $row['population']); 
 } 
 
 $writer->endElement(); // city 
} 
$writer->endElement(); // citIEs 
... 

  如果想體驗更多生成 XML 的方法,PHP 當然提供了很多的選擇。例如,可以使用 SimpleXML;以後您將使用它讀取 XML,但是它還提供 XML 文檔創建功能。另外,還可以看一下 PEAR 框架,它包括一些可用於輕松生成 XML 的類。(請參閱 參考資料,獲得更多信息的鏈接)。

  用 GWT 處理 XML

  GWT 只提供 XMLParser(在 com.google.gwt.xml.clIEnt 包中)用於讀、寫 XML。可以使用 parse() 方法創建一個 Document,然後使用 getDocumentElement() 獲得它的根元素;然後,便可以開始處理 XML。

  注意,應該使用 removeWhitespace() 方法去掉文檔中的空白。浏覽器解析器有時候會創建與制表符或換行符對應的空文本節點,如果不去掉它們,處理過程中會遇到不相關的、意外的元素,這樣會破壞邏輯(見 清單 6)。另外還有一點要注意:如果預期有 CDATA 區段,那麼需要檢查浏覽器是否接受 supportsCDATASection() 方法;如果不接受,那些區段將產生文本節點。請參閱 GWT 文檔(見 參考資料),獲得更多這方面的信息。

  清單 6. GWT 中提供了 XMLParser 用於讀取和創建 XML

   
protected void loadCitIEs(final String XMLCitIEs) { 
 ... 
 final Document xmlDoc= XMLParser.parse(XMLCitIEs); 
 final Element root= XMLDoc.getDocumentElement(); 
 XMLParser.removeWhitespace(XMLDoc); 
 
 final NodeList citIEs= root.getElementsByTagName("city"); 
 for (int i= 0; i < citIEs.getLength(); i++) { 
  final Element city= (Element)citIEs.item(i); 
  // show city.getAttributeNode("name").getValue() 
 
  final Element country= (Element)city.getElementsByTagName("country").item(0); 
  // show country.getAttributeNode("code").getValue() 
  // show country.getAttributeNode("name").getValue() 
  ... 
  final Element population= (Element)city.getElementsByTagName("pop").item(0); 
  if (population != null) { 
   // show population.getFirstChild().getNodeValue() 
  } 
 
  final Element coords= (Element)city.getElementsByTagName("coords").item(0); 
  final Element lat= (Element)coords.getElementsByTagName("lat").item(0); 
  // show lat.getFirstChild().getNodeValue() 
  ... 
 } 
... 

  要獲得重復的元素(例如這個例子中的 city),可以使用 getElementsByTagName() 方法,並迭代生成的數組。另一種方法是使用 getFirstChild() 方法,然後使用 getNextSibling() 遍歷同一級別上的其他元素。要獲得屬性,首先需要使用 getAttributeNode() 方法,然後使用 getValue() 方法。還有一些用於處理 CDATA 區段、注釋和所有可能的 XML 組件的方法。

  用 GWT 發送 XML

  GWT 應用程序讓用戶編輯人口、緯度和經度字段,然後將城市數據發回到服務器,以更新數據庫。有兩種算法:一種是簡單的算法,這種算法逐塊構建 XML 字符串,還有一種基於 XMLParser 的算法,該算法使用特定的方法創建所需的結構。

  getCitIEs1() 方法中顯示了較簡單的算法。可以使用 String 或 StringBuffer 對象構建 XML。我使用了前者,因為它使代碼更加清晰;但是如果考慮性能,後者很可能更好一些。這裡也存在和 PHP 版本中一樣的字符串轉義問題,所以使用 Html.Htmlspecialchars() 方法修改該問題。(見 清單 7,為了看起來更清晰,稍微作了修改)。

  清單 7. 使用字符串逐塊構建 XML 很簡單

   
protected String getCitIEs1() { 
 String result= ""; 
 
 result+= "<?XML version=\"1.0\" encoding=\"UTF-8\"?>\n"; 
 result+= "<citIEs>\n"; 
 
 for (all rows in the grid) { 
  // get cityName, countryCode, regionCode, pop, lat, and lon, from the grid 
 
  result+= " <city name=\"" + Html.Htmlspecialchars(cityName) + "\">\n"; 
  result+= " <country code=\"" + countryCode + "\"/>\n"; 
  result+= " <region code=\"" + regionCode + "\"/>\n"; 
  if (!pop.equals("0") && !pop.isEmpty()) { 
   result+= " <pop>" + pop + "</pop>\n"; 
  } 
 
  result+= " <coords>\n"; 
  result+= "  <lat>" + lat + "</lat>\n"; 
  result+= "  <lon>" + lon + "</lon>\n"; 
  result+= " </coords>\n"; 
  result+= "</city>\n"; 
 } 
 result+= "</citIEs>\n"; 
 return result; 
} 

  另一種創建 XML 的簡單算法是 XMLParser 類的 createDocument() 方法。這種算法的風格很容易讓人想起 PHP 中的 SimpleXML 函數,首先創建一個空文檔,然後向其中添加元素。可以創建所有類型的節點,並設置屬性值。最後,標准的 Java toString() 方法生成對象的一個表示。您只需添加初始版本和編碼行,就可以得到需要的字符串。(見 清單 8,為了看起來更清晰,代碼有所修改和刪減)。

  清單 8. 創建 XML 的 XMLParser 方法類似於 PHP 中的 SimpleXML 方法

   
protected String getCitIEs2() { 
 Document xml= XMLParser.createDocument(); 
 Element citIEs= XML.createElement("citIEs"); 
 XML.appendChild(citIEs); 
 
 for (all rows in the grid) { 
  // get cityName, countryCode, regionCode, pop, lat, and lon, from the grid 
 
  Element city= XML.createElement("city"); 
  city.setAttribute("name", cityName); 
 
  Element country= XML.createElement("country"); 
  country.setAttribute("code", countryCode); 
  city.appendChild(country); 
  ... 
  if (!pop.equals("0") && !pop.isEmpty()) { 
   Element popEl= XML.createElement("pop"); 
   Text popText= XML.createTextNode(pop); 
   popEl.appendChild(popText); 
   city.appendChild(popEl); 
  } 
 
  Element coords= XML.createElement("coords"); 
  Element lat= XML.createElement("lat"); 
  Text latText= XML.createTextNode(lat); 
  lat.appendChild(latText); 
  coords.appendChild(lat); 
  ... 
  city.appendChild(coords); 
  citIEs.appendChild(city); 
 } 
 return "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + XML.toString(); 
} 

  在 PHP 中讀取 XML

  在 PHP 中處理 XML 是一個老問題,有很多的解決方案。但是,我認為,從清晰和簡潔的角度看,沒有哪種方案能比得上 SimpleXML 。基本上,首先通過將 XML 文檔提供給 simpleXML_load_string() 方法創建一個 PHP 對象,然後使用標准的 PHP 操作符遍歷結果。屬性變成數組中的元素(例如,清單 9 展示了如何讀取國家代碼),而元素則可以作為一個數組(通過使用 children() 方法)或作為對象的屬性來訪問。

  清單 9. SimpleXML 是目前在 PHP 中進行 XML 處理的最容易的方法

   
$xml_str= $_POST["XMLdata"]; 
$xml_obj= simplexml_load_string($XML_str); 
... 
foreach($XML_obj->children() as $city) { 
 $name= addslashes($city['name']); 
 $country= $city->country['code']; 
 $region= $city->region['code']; 
 $pop= $city->pop; 
 $lat= $city->coords->lat; 
 $lon= $city->coords->lon; 
 
 MySQL_query("REPLACE INTO citIEs ". 
  "(cityName, countryCode, regionCode, population, latitude, longitude) VALUES (". 
  "'{$name}', '{$country}', '{$region}', '{$pop}', '{$lat}', '{$lon}')"); 
} 

  在 PHP 中處理 XML 還有許多種方法,可以從 參考資料 小節找到相關的鏈接。

  結束語

  有很多方法可以使用 XML 作為 GWT 與 PHP 之間的橋梁,我只是略作探討,不過,本文給出的方法應該足以讓您邁出第一步。需要記住的要點是,GWT 不止局限於它自己的 RPC 方法,還可以與 XML 友好共存,輕松生成和使用 XML 文檔。

  下載

描述 名字 大小 下載方法 本文的 Java 源代碼 Java_source_code.zip 4KB HTTP 本文的 PHP 源代碼 PHP_source_code.zip 4KB HTTP


XML學習教程| jQuery入門知識| AJAX入門| Dreamweaver教程| Fireworks入門知識| SEO技巧| SEO優化集錦|
Copyright © DIV+CSS佈局教程網 All Rights Reserved