XML 是編程中最常用的資料格式之一,對於非同步應用程式中的伺服器響應能夠帶來切實的好處。在Ajax中也不例外。
Ajax 應用程式就表現在其核心對象所選的名稱 —— XMLHttpRequest
,這個名稱不是很好,因為它並沒有反映技術上的實際情況。換句話說,多數人之所以認為 XML 是 Ajax 的核心組成部分,僅僅是因為他們想當然地以為 XMLHttpRequest
對象在任何時候都使用 XML。但實情並非如此,本文第一部分給出了原因。實際上,您將看到在多數 Ajax 應用程式中 XML 很少出現。 XML 確實有應用在 Ajax 中,而且 XMLHttpRequest
也支援這種用法。也確實沒有什麼能阻擋您向伺服器發送 XML。
XML在Ajax中的使用
在非同步應用程式中 XML 有兩種基本的用法:
1.以 XML 格式從網頁向伺服器發送請求
2.以 XML 格式在網頁中從伺服器接收請求
其中第一種用法,即用 XML 發送請求,需要將請求的格式設定為 XML,可以使用 API 來完成,也可以與文本連成字串,然後將結果發送到伺服器。按照這種思路,主要的任務就是通過既符合 XML 規則又能被伺服器理解的方式構造請求。因此這裡的關鍵實際上是 XML 格式,得到需要發送的資料之後,只需要用 XML 文法將其封裝起來。本文後面討論 XML 在 Ajax 應用程式中的這種用法。
第二種用法,即用 XML 接收請求,需要從伺服器上接收響應,然後從 XML 提取資料(同樣,可以用 API 或者採用蠻力方法)。這種情況下,關鍵在於來自伺服器的資料,而您恰好需要從 XML 中提取這些資料以便使用。
客戶機到伺服器的 XML
在您編寫的 90% Web 應用程式中,最終都會使用名/值對發送到伺服器。比方說,如果使用者在網頁表單中輸入姓名和地址,可能希望資料採用下列形式:
firstName=Larry lastName=Gullahorn street=9018 Heatherhorn Drive city=Rowlett state=Texas zipCode=75080 |
清單 1. 使用普通文本發送名/值對
function callServer() { // Get the city and state from the Web form var firstName = document.getElementById("firstName").value; var lastName = document.getElementById("lastName").value; var street = document.getElementById("street").value; var city = document.getElementById("city").value; var state = document.getElementById("state").value; var zipCode = document.getElementById("zipCode").value; // Build the URL to connect to var url = "/scripts/saveAddress.php?firstName=" + escape(firstName) + "&lastName=" + escape(lastName) + "&street=" + escape(street) + "&city=" + escape(city) + "&state=" + escape(state) + "&zipCode=" + escape(zipCode); // Open a connection to the server xmlHttp.open("GET", url, true); // Set up a function for the server to run when it's done xmlHttp.onreadystatechange = confirmUpdate; // Send the request xmlHttp.send(null); } |
將名/值對轉化成 XML
如果希望這樣使用 XML 作為資料格式,首先要做的是找到一種基本 XML 格式來儲存資料。顯然,名/值對可以全部轉化成 XML 元素,以其中的名稱作為元素名,值作為元素的內容:
<firstName>Larry</firstName> <lastName>Gullahorn</lastName> <street>9018 Heatherhorn Drive</street> <city>Rowlett</city> <state>Texas</state> <zipCode>75080</zipCode> |
當然,XML 要求有一個根項目;如果使用文檔片段(XML 文檔的一部分)的話則需要一個封閉元素。因此可能需要將上述 XML 轉化成下面的形式:
<address> <firstName>Larry</firstName> <lastName>Gullahorn</lastName> <street>9018 Heatherhorn Drive</street> <city>Rowlett</city> <state>Texas</state> <zipCode>75080</zipCode> </address> |
現在基本上可以準備在 Web 客戶機上建立這種結構並發送到伺服器了。
通訊:
在網路上傳輸 XML 之前,需要保證伺服器以及發送資料的指令碼能夠接受 XML。現在對很多人來說這麼強調似乎有點多餘,認為這是理所當然的,但是很多新手往往認為只要通過網路發送 XML,就能夠被正確地接收和解釋。實際上,需要兩個步驟來保證發送的 XML 的資料能夠被正確地接收:
1.保證向其發送 XML 的指令碼能夠接受 XML 資料格式。
2.保證指令碼認可發送資料所採用的特定 XML 格式和結構。
這兩方面都可能要求您進行人際溝通,必須明確地告知對方!嚴格地說,如果確實需要發送 XML 資料,多數指令碼作者都會協助您,因此尋找能夠接受 XML 的指令碼應該不難。但是,仍然需要保證格式是指令碼所希望的格式。比方說,假設伺服器接受下列格式的資料:
<profile> <firstName>Larry</firstName> <lastName>Gullahorn</lastName> <street>9018 Heatherhorn Drive</street> <city>Rowlett</city> <state>Texas</state> <zip-code>75080</zip-code> </profile> |
看起來和上面的 XML 類似,只有兩點不同:
- 來自客戶機的 XML 封裝在
address
元素,但是伺服器要求資料封裝在 profile
元素中。
- 來自客戶機的 XML 使用了
zipCode
元素,而伺服器希望郵遞區號放在 zip-code
元素中。
從大的層面上來說,這些小問題僅僅是伺服器接收和處理資料的區別,但是伺服器會徹底失敗,在網頁上(可能向其使用者)顯示意義含糊的錯誤訊息。因此必須明確伺服器的期望的格式,並把要發送的資料塞進那種格式。然後,只有在這時才會涉及到從客戶機向伺服器發送 XML 資料的真正的技術問題。
向伺服器發送 XML
當向伺服器發送 XML 的時候,更多的代碼用於擷取資料和封裝成 XML,而不是真正的傳輸資料。實際上,只要準備好發送到伺服器的 XML 字串,發送工作就和普通文本一樣。用 XML 發送名/值對:
function callServer() { // Get the city and state from the Web form var firstName = document.getElementById("firstName").value; var lastName = document.getElementById("lastName").value; var street = document.getElementById("street").value; var city = document.getElementById("city").value; var state = document.getElementById("state").value; var zipCode = document.getElementById("zipCode").value; var xmlString = "<profile>" + " <firstName>" + escape(firstName) + "</firstName>" + " <lastName>" + escape(lastName) + "</lastName>" + " <street>" + escape(street) + "</street>" + " <city>" + escape(city) + "</city>" + " <state>" + escape(state) + "</state>" + " <zip-code>" + escape(zipCode) + "</zip-code>" + "</profile>"; // Build the URL to connect to var url = "/scripts/saveAddress.aspx"; // Open a connection to the server xmlHttp.open("POST", url, true); // Tell the server you're sending it XML xmlHttp.setRequestHeader("Content-Type", "text/xml"); // Set up a function for the server to run when it's done xmlHttp.onreadystatechange = confirmUpdate; // Send the request xmlHttp.send(xmlString); } |
大部分代碼都很簡單,只有少數地方值得提一下。首先,請求中的資料必須手工格式化為 XML。閱讀了三篇關於使用文檔物件類型的文章之後,再來討論它是不是很簡單了?雖然不禁止在 JavaScript 中使用 DOM 建立 XML 文檔,但是在通過 GET 或 POST 請求發送到網路上之前必須將 DOM 對象轉化成文本。因此使用常規字串操作來格式化資料更簡單一些。當然,這樣很容易出現錯誤和誤輸入,因此在編寫處理 XML 的代碼時必須非常小心。
建立 XML 之後,按照和發送文本基本相同的方式開啟串連。對於 XML 最好使用 POST 請求,因為有些瀏覽器限制了 GET 請求字串的長度,而 XML 可能很長,可以看到程式碼片段中把 GET 改成了 POST 方法。此外,XML 通過 send()
方法發送,而不是附加在請求 URL 最後的參數。這些都是非常細微的區別,很容易修改。
但是必須編寫一行新的代碼:
xmlHttp.setRequestHeader("Content-Type", "text/xml"); |
看起來很難理解,它只不過是告訴伺服器要發送的是 XML 而不是一般的名/值對。無論哪種情況,發送的資料都是文本,但這裡使用 text/xml
或者 XML 作為普通文本發送。如果使用名/值對,對應的行應該是:
xmlHttp.setRequestHeader("Content-Type", "text/plain"); |
如果忘記告訴伺服器發送的是 XML,就會出現問題,因此不要忘掉這一步驟。
完成這些之後,剩下的就是調用 send()
並傳入 XML 字串了。伺服器將收到您的 XML 請求,並(假設已經做好了準備工作)接受 XML,解釋它,然後返迴響應。實際上要做的只有這麼多 —— XML 請求只需要稍微修改代碼。
伺服器端接受到XML做出什麼樣的相應,在下篇文章中將介紹。