WIKI使用導(dǎo)航
站長百科導(dǎo)航
站長專題
- 網(wǎng)站推廣
- 網(wǎng)站程序
- 網(wǎng)站賺錢
- 虛擬主機
- cPanel
- 網(wǎng)址導(dǎo)航專題
- 云計算
- 微博營銷
- 虛擬主機管理系統(tǒng)
- 開放平臺
- WIKI程序與應(yīng)用
- 美國十大主機
Ajax- 與服務(wù)器通信1
導(dǎo)航: 上一頁 | ASP | PHP | JSP | HTML | CSS | XHTML | aJAX | Ruby | JAVA | XML | Python | ColdFusion
XMLHttpRequest對象提供了兩個可以用來訪問服務(wù)器響應(yīng)的屬性。第一個屬性respo-
nseText將響應(yīng)提供為一個串,第二個屬性responseXML將響應(yīng)提供為一個XML對象。一些簡單的用例就很適合按簡單文本來獲取響應(yīng),如將響應(yīng)顯示在警告框中,或者響應(yīng)只是指示成功還是失敗的詞。
第2章中的例子就使用了responseText屬性來訪問服務(wù)器響應(yīng),并將響應(yīng)顯示在警告框中。
使用innerHTML屬性創(chuàng)建動態(tài)內(nèi)容[ ]
如果將服務(wù)器響應(yīng)作為簡單文本來訪問,則靈活性欠佳。簡單文本沒有結(jié)構(gòu),很難用JavaScript進行邏輯性的表述,而且要想動態(tài)地生成頁面內(nèi)容也很困難。
如果結(jié)合使用HTML元素的innerHTML屬性,responseText屬性就會變得非常有用。innerHTML屬性是一個非標準的屬性,最早在IE中實現(xiàn),后來也為其他許多流行的瀏覽器所采用。這是一個簡單的串,表示一組開始標記和結(jié)束標記之間的內(nèi)容。
通過結(jié)合使用responseText和inner-
HTML,服務(wù)器就能“生產(chǎn)”或生成HTML內(nèi)容,由瀏覽器使用innerHTML屬性來“消費”或處理。下面的例子展示了一個搜索功能,這是使用XMLHttpRequest對象、其responseText屬性和HTML元素的innerHTML屬性實現(xiàn)的。點擊search(搜索)按鈕將在服務(wù)器上啟動“搜索”,服務(wù)器將生成一個結(jié)果表作為響應(yīng)。瀏覽器處理響應(yīng)時將div元素的innerHTML屬性設(shè)置為XMLHttpRequest對象的response-
Text屬性值。圖3-1顯示了點擊search按鈕而且在窗口內(nèi)容中增加了結(jié)果表之后的瀏覽器窗口。
第2章的例子只是將服務(wù)器響應(yīng)顯示在警告框中,這個例子的代碼與它很相似。具體步驟如下:
1. 點擊search按鈕,調(diào)用startRequest函數(shù),它先調(diào)用createXMLHttpRequest函數(shù)來初始化XMLHttpRequest對象的一個新實例;
2. startRequest函數(shù)將回調(diào)函數(shù)設(shè)置為handleStateChange函數(shù);
3. startRequest函數(shù)使用open()方法來設(shè)置請求方法(GET)及請求目標,并且設(shè)置為異步地完成請求;
4. 使用XMLHttpRequest對象的send()方法發(fā)送請求;
5. XMLHttpRequest對象的內(nèi)部狀態(tài)每次有變化時,都會調(diào)用handleStateChange函數(shù)。一旦接收到響應(yīng)(如果readyState屬性的值為4),div元素的innerHTML屬性就將使用XMLHttpRequest對象的responseText屬性設(shè)置。
代碼清單3-1顯示了innerHTML.html。代碼清單3-2顯示了innerHTML.xml,表示搜索生成的內(nèi)容。
代碼清單3-1 innerHTML.html
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
" <html xmlns=" <head>
<title>Using responseText with innerHTML</title>
<script type="text/javascript">
var xmlHttp;
function createXMLHttpRequest() {
if (window.ActiveXObject) {
xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
}
else if (window.XMLHttpRequest) {
xmlHttp = new XMLHttpRequest();
}
}
function startRequest() {
createXMLHttpRequest();
xmlHttp.onreadystatechange = handleStateChange;
xmlHttp.open("GET", "innerHTML.xml", true);
xmlHttp.send(null);
}
function handleStateChange() {
if(xmlHttp.readyState == 4) {
if(xmlHttp.status == 200) {
document.getElementById("results").innerHTML = xmlHttp.responseText;
}
}
}
</script>
</head>
<body>
<form action="#">
<input type="button" value="Search for Today's Activities"
onclick="startRequest();"/>
</form>
</body>
</html>
代碼清單3-2 innerHTML.xml
<tbody>
<tr>
<th>Activity Name</th>
<th>Location</th>
<th>Time</th>
</tr>
<tr>
<td>Waterskiing</td>
<td>Dock #1</td>
<td>9:00 AM</td>
</tr>
<tr>
<td>Volleyball</td>
<td>East Court</td>
<td>2:00 PM</td>
</tr>
<tr>
<td>Hiking</td><br> <td>Trail 3</td>
<td>3:30 PM</td>
</tr>
</tbody>
</table>
使用responseText和innerHTML可以大大簡化向頁面增加動態(tài)內(nèi)容的工作。遺憾的是,這種方法存在一些缺陷。前面已經(jīng)提到,innerHTML屬性不是HTML元素的標準屬性,所以與標準兼容的瀏覽器不一定提供這個屬性的實現(xiàn)。不過,當前大多數(shù)瀏覽器都支持innerHTML屬性??尚Φ氖牵琁E是率先使用innerHTML的瀏覽器,但它的innerHTML實現(xiàn)反而最受限制。如今許多瀏覽器都將innerHTML屬性作為所有HTML元素的讀/寫屬性。與此不同,IE則有所限制,在表和表行之類的HTML元素上innerHTML屬性僅僅是只讀屬性,從一定程度上講,這就限制了它的用途。
將響應(yīng)解析為XML[ ]
你已經(jīng)了解到,服務(wù)器不一定按XML格式發(fā)送響應(yīng)。只要Content-Type響應(yīng)首部正確地設(shè)置為text/plain(如果是XML,Content-Type響應(yīng)首部則是text/xml),將響應(yīng)作為簡單文本發(fā)送是完全可以的。復(fù)雜的數(shù)據(jù)結(jié)構(gòu)就很適合以XML格式發(fā)送。對于導(dǎo)航XML文檔以及修改XML文檔的結(jié)構(gòu)和內(nèi)容,當前瀏覽器已經(jīng)提供了很好的支持。
瀏覽器到底怎么處理服務(wù)器返回的XML呢?當前瀏覽器把XML看作是遵循W3C DOM的XML文檔。W3C DOM指定了一組很豐富的API,可用于搜索和處理XML文檔。DOM兼容的瀏覽器必須實現(xiàn)這些API,而且不允許有自定義的行為,這樣就能盡可能地改善腳本在不同瀏覽器之間的可移植性。
W3C DOM
W3C DOM到底是什么?W3C主頁提供了清晰的定義:
文檔對象模型(DOM)是與平臺和語言無關(guān)的接口,允許程序和腳本動態(tài)地訪問和更新文檔的內(nèi)容、結(jié)構(gòu)和樣式。文檔可以進一步處理,處理的結(jié)果可以放回到所提供的頁面中。
不僅如此,W3C還解釋了為什么要定義標準的DOM。W3C從其成員處收到了大量請求,這些請求都是關(guān)于將XML和HTML文檔的對象模型提供給腳本所要采用的方法。提案并沒有提出任何新的標記或樣式表技術(shù),而只是力圖確保這些可互操作而且與腳本語言無關(guān)的解決方案能得到共識,并為開發(fā)社區(qū)所采納。簡單地說,W3C DOM標準的目的是盡量避免20世紀90年代末的腳本惡夢,那時相互競爭的瀏覽器都有自己專用的對象模型,而且通常都是不兼容的,這就使得實現(xiàn)跨平臺的腳本極其困難。
W3C DOM和JavaScript
W3C DOM和JavaScript很容易混淆不清。DOM是面向HTML和XML文檔的API,為文檔提供了結(jié)構(gòu)化表示,并定義了如何通過腳本來訪問文檔結(jié)構(gòu)。JavaScript則是用于訪問和處理DOM的語言。如果沒有DOM,JavaScript根本沒有Web頁面和構(gòu)成頁面元素的概念。文檔中的每個元素都是DOM的一部分,這就使得JavaScript可以訪問元素的屬性和方法。
DOM獨立于具體的編程語言,通常通過JavaScript訪問DOM,不過并不嚴格要求這樣??梢允褂萌魏文_本語言來訪問DOM,這要歸功于其一致的API。表3-1列出了DOM元素的一些有用的屬性,表3-2列出了一些有用的方法。
表3-1 用于處理XML文檔的DOM元素屬性
childNodes
返回當前元素所有子元素的數(shù)組
firstChild
返回當前元素的第一個下級子元素
lastChild
返回當前元素的最后一個子元素
nextSibling
返回緊跟在當前元素后面的元素
nodeValue
指定表示元素值的讀/寫屬性
parentNode
返回元素的父節(jié)點
previousSibling
返回緊鄰當前元素之前的元素
表3-2 用于遍歷XML文檔的DOM元素方法
getElementById(id) (document)
獲取有指定惟一ID屬性值文檔中的元素
getElementsByTagName(name)
返回當前元素中有指定標記名的子元素的數(shù)組
hasChildNodes()
返回一個布爾值,指示元素是否有子元素
getAttribute(name)
返回元素的屬性值,屬性由name指定
有了W3C DOM,就能編寫簡單的跨瀏覽器腳本,從而充分利用XML的強大功能和靈活性,將XML作為瀏覽器和服務(wù)器之間的通信介質(zhì)。
從下面的例子可以看到,使用遵循W3C DOM的JavaScript來讀取XML文檔是何等簡單。代碼清單3-3顯示了服務(wù)器向瀏覽器返回的XML文檔的內(nèi)容。這是一個簡單的美國州名列表,各個州按地區(qū)劃分。
代碼清單3-3 服務(wù)器返回的美國州名列表
<?xml version="1.0" encoding="UTF-8"?>
<states>
<north>
<state>Minnesota</state>
<state>Iowa</state>
<state>North Dakota</state>
</north>
<south>
<state>Texas</state>
<state>Oklahoma</state>
<state>Louisiana</state>
</south>
<east>
<state>New York</state>
<state>North Carolina</state>
<state>Massachusetts</state>
</east>
<west>
<state>California</state>
<state>Oregon</state>
<state>Nevada</state>
</west>
</states>
在瀏覽器上會生成具有兩個按鈕的HTML頁面。點擊第一個按鈕,將從服務(wù)器加載XML文檔,然后在警告框中顯示列于文檔中的所有州。點擊第二個按鈕也會從服務(wù)器加載XML文檔,不過只在警告框中顯示北部地區(qū)的各個州(見圖3-2)。
圖3-2 點擊頁面上的任何一個按鈕都會從服務(wù)器加載XML文檔,并在警告框中顯示適當?shù)慕Y(jié)果
代碼清單3-4顯示了parseXML.html。
代碼清單3-4 parseXML.html
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
" <html xmlns=" <head>
<title>Parsing XML Responses with the W3C DOM</title>
<script type="text/javascript">
var xmlHttp;
var requestType = "";
function createXMLHttpRequest() {
if (window.ActiveXObject) {
xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
}
else if (window.XMLHttpRequest) {
xmlHttp = new XMLHttpRequest();
}
}
function startRequest(requestedList) {
requestType = requestedList;
createXMLHttpRequest();
xmlHttp.onreadystatechange = handleStateChange;
xmlHttp.open("GET", "parseXML.xml", true);
xmlHttp.send(null);
}
function handleStateChange() {
if(xmlHttp.readyState == 4) {
if(xmlHttp.status == 200) {
if(requestType == "north") {
listNorthStates();
}
else if(requestType == "all") {
listAllStates();
}
}
}
}
function listNorthStates() {
var xmlDoc = xmlHttp.responseXML;
var northNode = xmlDoc.getElementsByTagName("north")[0];
var out = "Northern States";
var northStates = northNode.getElementsByTagName("state");
outputList("Northern States", northStates);
}
function listAllStates() {
var xmlDoc = xmlHttp.responseXML;
var allStates = xmlDoc.getElementsByTagName("state");
outputList("All States in Document", allStates);
}
function outputList(title, states) {
var out = title;
var currentState = null;
for(var i = 0; i < states.length; i++) {
currentState = states[i];
out = out + "\n- " + currentState.childNodes[0].nodeValue;
}
alert(out);
}
</script>
</head>
<body>
<h1>Process XML Document of U.S. States</h1>
<br/><br/>
<form action="#">
<input type="button" value="View All Listed States"
onclick="startRequest('all');"/>
<br/><br/>
<input type="button" value="View All Listed Northern States"
onclick="startRequest('north');"/>
</form>
</body>
</html>
以上腳本從服務(wù)器獲取XML文檔并加以處理,它與前面看到的例子很相似,不過前面的例子只是將響應(yīng)處理為簡單文本。關(guān)鍵區(qū)別就在于listNorthStates和listAllStates函數(shù)。前面的例子從XMLHttpRequest對象獲取服務(wù)器響應(yīng),并使用XMLHttpRequest對象的responseText屬性將響應(yīng)獲取為文本。listNorthStates和listAllStates函數(shù)則不同,它們使用了XMLHttpRequest對象的responseXML屬性,將結(jié)果獲取為XML文檔,這樣一來,你就可以使用W3C DOM方法來遍歷XML文檔了。
仔細研究一下listAllStates函數(shù)。它首先創(chuàng)建了一個局部變量,名為xmlDoc,并將這個變量初始化設(shè)置為服務(wù)器返回的XML文檔,這個XML文檔是使用XMLHttpRequest對象的responseXML屬性得到的。利用XML文檔的getElementsByTagName方法可以獲取文檔中所有標記名為state的元素。getElementsByTagName方法返回了包含所有state元素的數(shù)組,這個數(shù)組將賦給名為allStates的局部變量。
從XML文檔獲取了所有state元素之后,listAllStates函數(shù)調(diào)用outputList函數(shù),并在警告框中顯示這些state元素。listAllStates方法將迭代處理state元素的數(shù)組,將各元素的相應(yīng)州名逐個追加到一個串中,這個串最后將顯示在警告框中。
有一點要特別注意,即如何從state元素獲取州名。你可能認為,state元素會簡單地提供屬性或方法來得到這個元素的文本,但并非如此。
表示州名的文本實際上是state元素的子元素。在XML文檔中,文本本身被認為是一個節(jié)點,而且必須是另外某個元素的子元素。由于表示州名的文本實際上是state元素的子元素,所以必須先從state元素獲取文本元素,再從這個文本元素得到其文本內(nèi)容。
outputList函數(shù)的工作就是如此。它迭代處理數(shù)組中的所有元素,將當前元素賦給currentState變量。因為表示州名的文本元素總是state元素的第一個子元素,所以可以使用childNodes屬性來得到文本元素。一旦有了具體的文本元素,就可以使用nodeValue屬性返回表示州名的文本內(nèi)容。
listNorthStates函數(shù)與listAllStates是類似的,只不過增加了一個小技巧。你只想得到北部地區(qū)的州,而不是所有州。為此,首先使用getElementsByTagName方法獲取north標記,從而獲得XML文檔中的north元素。因為文檔只包含一個north元素,而且getElementsByTagName方法總是返回一個數(shù)組,所以要用[0]記法來抽出north元素。這是因為,在getElementsByTagName方法返回的數(shù)組中,north元素處在第一個位置上(也是惟一的位置)。既然有了north元素,接下來調(diào)用north元素的getElementsByTagName方法,就可以得到north元素的state子元素。有了north元素所有state子元素的數(shù)組后,再使用outputList方法在警告框中顯示這些州名。
使用W3C DOM動態(tài)編輯頁面[ ]
Web最初只是作為媒介向各處分發(fā)靜態(tài)的文本文檔,如今它本身已經(jīng)發(fā)展為一個應(yīng)用開發(fā)平臺。遺留的企業(yè)系統(tǒng)通常通過純文本的終端部署,或者作為客戶—服務(wù)器應(yīng)用部署,這些遺留系統(tǒng)正在被完全通過Web瀏覽器部署的系統(tǒng)所取代。
隨著最終用戶越來越習(xí)慣于使用基于Web的應(yīng)用,他們開始有了新的要求,需要一種更豐富的用戶體驗。用戶不再滿足于完全頁面刷新,即每次在頁面上編輯一些數(shù)據(jù)時頁面都會完全刷新。他們想立即看到結(jié)果,而不是坐等與服務(wù)器完成完整的往返通信。
你已經(jīng)了解了解析服務(wù)器發(fā)送的XML消息是多么容易。W3C DOM提供了一些屬性和方法,使你能輕松地遍歷XML結(jié)構(gòu),并抽取所需的數(shù)據(jù)。
前面的例子對于服務(wù)器發(fā)送的XML響應(yīng)并沒有做多少有用的事情。在警告框中顯示XML文檔的值沒有太大的實際意義。你真正想做到的是讓用戶享有豐富的客戶體驗,不再遭遇一般Web應(yīng)用中常見的連續(xù)頁面刷新問題。頁面連續(xù)刷新不僅使用戶不滿意,還會浪費服務(wù)器上寶貴的處理器時間,因為頁面刷新需要重新構(gòu)建整個頁面的內(nèi)容,而且會不必要地使用網(wǎng)絡(luò)帶寬來傳送刷新的頁面。
當然,最好的解決辦法是根據(jù)需要修改頁面上已有的內(nèi)容。如果頁面上大多數(shù)數(shù)據(jù)沒有改變,則不應(yīng)刷新整個頁面,只需要修改頁面中信息有變化的部分。
以往,在Web瀏覽器的限制之下,這一點很難做到。瀏覽器只是一個工具,它解釋特殊的標記(HTML),并根據(jù)一組預(yù)定的規(guī)則顯示這些標記。Web以及Web瀏覽器原來只是為了顯示靜態(tài)的信息,如果不以新頁面的形式從服務(wù)器請求新的數(shù)據(jù),這些信息不會改變。
除了一些例外情況,當前的瀏覽器都使用W3C DOM來表示W(wǎng)eb頁面的內(nèi)容。這樣做可以確保在不同的瀏覽器上Web頁面會以同樣的方式呈現(xiàn),同時在不同的瀏覽器上,用于修改頁面內(nèi)容的腳本也會有相同的表現(xiàn)。Web瀏覽器的W3C DOM和JavaScript實現(xiàn)越來越成熟,這大大簡化了在瀏覽器上動態(tài)創(chuàng)建內(nèi)容的任務(wù)。原來總是要苦心積慮地解決瀏覽器間的不兼容性,如今這已經(jīng)不太需要。表3-3列出了用于動態(tài)創(chuàng)建內(nèi)容的DOM屬性和方法。
表3-3 動態(tài)創(chuàng)建內(nèi)容時所用的W3C DOM屬性和方法
document.createElement(tagName)
文檔對象上的createElement方法可以創(chuàng)建由tagName指定的元素。如果以串div作為方法參數(shù),就會生成一個div元素
document.createTextNode(text)
文檔對象的createTextNode方法會創(chuàng)建一個包含靜態(tài)文本的節(jié)點
<element>.appendChild(childNode)
appendChild方法將指定的節(jié)點增加到當前元素的子節(jié)點列表(作為一個新的子節(jié)點)。例如,可以增加一個option元素,作為select元素的子節(jié)點
<element>.getAttribute(name)
<element>.setAttribute(name, value)
這些方法分別獲得和設(shè)置元素中name屬性的值
<element>.insertBefore(newNode, targetNode)
這個方法將節(jié)點newNode作為當前元素的子節(jié)點插到targetNode元素前面
<element>.removeAttribute(name)
這個方法從元素中刪除屬性name
<element>.removeChild(childNode)
這個方法從元素中刪除子元素childNode
<element>.replaceChild(newNode, oldNode)
這個方法將節(jié)點oldNode替換為節(jié)點newNode
<element>.hasChildnodes()
這個方法返回一個布爾值,指示元素是否有子元素
關(guān)于瀏覽器的不兼容性
盡管當前Web瀏覽器中W3C DOM和JavaScript的實現(xiàn)在不斷改進,但還是存在一些特異性和不兼容性,這使得應(yīng)用DOM和JavaScript進行開發(fā)時很是頭疼。
IE的W3C DOM和JavaScript實現(xiàn)最受限制。2000年初,一些統(tǒng)計稱IE占據(jù)了整個瀏覽器市場95%的份額,由于沒有競爭壓力,Microsoft決定不完全實現(xiàn)各個Web標準。
關(guān)于setAttribute方法,IE也有麻煩。IE不能使用setAttribute正確地設(shè)置class屬性。對此有一個跨瀏覽器的解決方法,即同時使用setAttribute("class", "new- ClassName") 和setAttribute("className","newClassName")。另外,在IE中不能使用setAttribute設(shè)置style屬性。最能保證瀏覽器兼容的技術(shù)不是<element>.setA- ttribute("style, "font-weight:bold;"),而是<element>.style.cssText = "font - weight:bold;"。
本書中的例子會盡可能地遵循W3C DOM和JavaScript標準,不過如果必須確保大多數(shù)當前瀏覽器的兼容性,可能也會稍稍偏離標準。
下面的例子展示了如何使用W3C DOM和JavaScript來動態(tài)創(chuàng)建內(nèi)容。這個例子是假想的房地產(chǎn)清單搜索引擎,點擊表單上的Search(搜索)按鈕,會使用XMLHttpRequest對象以XML格式獲取結(jié)果。使用JavaScript處理響應(yīng)XML,從而生成一個表,其中列出搜索到的結(jié)果(見圖3-3)。

服務(wù)器返回的XML很簡單(見代碼清單3-5)。根節(jié)點properties包含了得到的所有property元素。每個property元素包含3個子元素:address、price和comments。
代碼清單3-5 dynamicContent.xml
<?xml version="1.0" encoding="UTF-8"?>
<properties>
<property>
<address>812 Gwyn Ave</address>
<price>$100,000</price>
<comments>Quiet, serene neighborhood</comments>
</property>
<property>
<address>3308 James Ave S</address>
<price>$110,000</price>
<comments>Close to schools, shopping, entertainment</comments>
</property>
<property>
<address>98320 County Rd 113</address>
<price>$115,000</price>
<comments>Small acreage outside of town</comments>
</property>
</properties>
具體向服務(wù)器發(fā)送請求并對服務(wù)器響應(yīng)做出回應(yīng)的JavaScript與前面的例子是一樣的。不過,從handleReadyStateChange函數(shù)開始有所不同。假設(shè)請求成功地完成,接下來第一件事就是調(diào)用clearPreviousResults函數(shù),將以前搜索所創(chuàng)建的內(nèi)容刪除。
clearPreviousResults函數(shù)完成兩個任務(wù):刪除出現(xiàn)在最上面的“Results”標題文本,并從結(jié)果表中清除所有行。首先使用hasChildNodes方法查看可能包括標題文本的span元素是否有子元素。應(yīng)該知道,只有hasChildNodes方法返回true時才存在標題文本。如果確實返回true,則刪除span元素的第一個(也是惟一的)子節(jié)點,因為這個子節(jié)點表示的就是標題文本。
clearPreviousResults的下一個任務(wù)是在顯示搜索結(jié)果的表中刪除所有行。所有結(jié)果行都是tbody節(jié)點的子節(jié)點,所以先使用document.getElementById方法得到該tbody節(jié)點的引用。一旦有了tbody節(jié)點,只要這個tbody節(jié)點還有子節(jié)點(tr元素)就進行迭代處理。每次迭代時都會從表體中刪除childNodes集合中的第一個子節(jié)點。當表體中再沒有更多的表行時,迭代結(jié)束。
搜索結(jié)果表在parseResults函數(shù)中建立。這個函數(shù)首先創(chuàng)建一個名為results的局部變量,這是使用XMLHttpRequest對象的responseXML屬性得到的XML文檔。
使用getElementsByTagName方法來獲得XML文檔中包含所有property元素的數(shù)組,然后將這個數(shù)組賦給局部變量properties。一旦有了property元素的數(shù)組,可以迭代處理數(shù)組中的各個元素,并獲得property的address、price和comments。
var properties = results.getElementsByTagName("property"); for(var i = 0; i < properties.length; i++) { property = properties[i]; address = property.getElementsByTagName("address")[0].firstChild.nodeValue; price = property.getElementsByTagName("price")[0].firstChild.nodeValue; comments = property.getElementsByTagName("comments")[0].firstChild.nodeValue; addTableRow(address, price, comments); } 下面來仔細分析這個循環(huán),因為這正是parseResults函數(shù)的核心。在for循環(huán)中,首先得到數(shù)組中的下一個元素,并把它賦給局部變量property。接下來,對于你感興趣的各個子元素(address、price和comments),分別獲得它們的節(jié)點值。
請考慮address元素,這是property元素的一個子元素。首先在property元素上調(diào)用getElementsByTagName方法來得到單個address元素。getElementsByTagName方法返回一個數(shù)組,不過因為你知道有且僅有一個address元素,所以可以使用[0]記法來引用這個元素。
沿著XML結(jié)構(gòu)繼續(xù)向下,現(xiàn)在有了address標記的引用,你需要得到它的文本內(nèi)容。記住,文本實際上是父元素的一個子節(jié)點,所以可以使用firstChild屬性來訪問address元素的文本節(jié)點。有了文本節(jié)點后,可以引用文本節(jié)點的nodeValue屬性來得到文本。
采用同樣的辦法來得到price和comments元素的值,并把各個值分別賦給局部變量price和comments。再將address、price和comments傳遞給名為addTableRow的輔助函數(shù),它會用這些結(jié)果數(shù)據(jù)具體建立一個表行。
addTableRow函數(shù)使用W3C DOM方法和JavaScript建立一個表行。使用document.cre- ateElement方法創(chuàng)建一個row對象,之后,再使用名為createCellWithText的輔助函數(shù)分別為address、price和comments值創(chuàng)建一個cell對象。createCellWithText函數(shù)會創(chuàng)建并返回一個以指定的文本作為單元格內(nèi)容的cell對象。
createCellWithText函數(shù)首先使用document.createElement方法創(chuàng)建一個td元素,然后使用document.createTextNode方法創(chuàng)建一個包含所需文本的文本節(jié)點,所得到的文本節(jié)點追加到td元素。這個函數(shù)再把新創(chuàng)建的td元素返回給調(diào)用函數(shù)(addTableRow)。
addTableRow函數(shù)對address、price和comments值重復(fù)調(diào)用createCellWithText函數(shù),每一次向tr元素追加一個新創(chuàng)建的td元素。一旦向row(行)增加了所有cell(單元格),這個row就將被增加到表的tbody元素中。
就這么多!你已經(jīng)成功地讀取了服務(wù)器返回的XML文檔,而且動態(tài)創(chuàng)建了一個結(jié)果表。代碼清單3-6顯示了這個例子完整的JavaScript和可擴展HTML代碼。
代碼清單3-6 dynamicContent.html
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
" <html xmlns=" <head>
<title>Dynamically Editing Page Content</title>
<script type="text/javascript">
var xmlHttp;
function createXMLHttpRequest() {
if (window.ActiveXObject) {
xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
}
else if (window.XMLHttpRequest) {
xmlHttp = new XMLHttpRequest();
}
}
function doSearch() {
createXMLHttpRequest();
xmlHttp.onreadystatechange = handleStateChange;
xmlHttp.open("GET", "dynamicContent.xml", true);
xmlHttp.send(null);
}
function handleStateChange() {
if(xmlHttp.readyState == 4) {
if(xmlHttp.status == 200) {
clearPreviousResults();
parseResults();
}
}
}
function clearPreviousResults() {
var header = document.getElementById("header");
if(header.hasChildNodes()) {
header.removeChild(header.childNodes[0]);
}
var tableBody = document.getElementById("resultsBody");
while(tableBody.childNodes.length > 0) {
tableBody.removeChild(tableBody.childNodes[0]);
}
}
function parseResults() {
var results = xmlHttp.responseXML;
var property = null;
var address = "";
var price = "";
var comments = "";
var properties = results.getElementsByTagName("property");
for(var i = 0; i < properties.length; i++) {
property = properties[i];
address = property.getElementsByTagName("address")[0].firstChild.nodeValue;
price = property.getElementsByTagName("price")[0].firstChild.nodeValue;
comments = property.getElementsByTagName("comments")[0]
.firstChild.nodeValue;
addTableRow(address, price, comments);
}
var header = document.createElement("h2");
var headerText = document.createTextNode("Results:");
header.appendChild(headerText);
document.getElementById("header").appendChild(header);
document.getElementById("resultsTable").setAttribute("border", "1");
}
function addTableRow(address, price, comments) {
var row = document.createElement("tr");
var cell = createCellWithText(address);
row.appendChild(cell);
cell = createCellWithText(price);
row.appendChild(cell);
cell = createCellWithText(comments);
row.appendChild(cell);
document.getElementById("resultsBody").appendChild(row);
}
function createCellWithText(text) {
var cell = document.createElement("td");
var textNode = document.createTextNode(text);
cell.appendChild(textNode);
return cell;
}
</script>
</head>
<body>
<h1>Search Real Estate Listings</h1>
<form action="#">
Show listings from
<select>
<option value="50000">$50,000</option>
<option value="100000">$100,000</option>
<option value="150000">$150,000</option>
</select>
to
<select>
<option value="100000">$100,000</option>
<option value="150000">$150,000</option>
<option value="200000">$200,000</option>
</select>
<input type="button" value="Search" onclick="doSearch();"/>
</form>
<span id="header">
</span>
<table id="resultsTable" width="75%" border="0">
<tbody id="resultsBody">
</tbody>
</table>
</body>
</html>