如何使用ajax開發web應用程式(二)

來源:互聯網
上載者:User

作者: Jonathan Fenocchi
時間:2005.10.26
譯者:Sheneyan
英文原文:
http://www.webreference.com/programming/javascript/jf/column13/

在上一篇文章中,我們討論了如何通過javascript從一個遠程XML檔案中取得資料。在這篇文章中,我們將學會怎樣對資料作更複雜的處理。作為一個樣本,我們會準備一組XML資料,將資料分割成獨立的片斷並以不同的方式展示這些片斷(取決於它們是如何被標識的)。

這篇文章是建立在上一篇文章中構造的範例程式碼的基礎之上,所以如果你不能理解我們現在的代碼,你可以回過頭去讀第一篇文章(sheneyan註:就在上面)。

開始~

讓我們開始我們的第一步:構造XML。我們準備寫一個XML文檔,它組織了一系列準備讓javascript處理的資料,所以我們將一起組織一些節點和子節點(或者,元素和子項目)。在這個例子裡,我們將使用一些家庭寵物的名字:

<?xml version="1.0" encoding="UTF-8"?>
<data>
  <pets>
   <pet>貓</pet>
   <pet>狗</pet>
   <pet>魚</pet>
  </pets>
</data>

在上面,我們有這個XML聲明(標明這個文檔是一個XML 1.0 文檔,使用UTF-8編碼),一個根項目(<data>)將下面所有的元素組合在一起,一個<pets>元素組織了所有的寵物,然後一個<pet>節點對應一隻寵物。為了指定每一隻寵物是什麼類型的動物,我們在<pet>元素中設定了文本節點:貓,狗,魚。

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"
  "http://www.w3.org/TR/html4/strict.dtd">
<html lang="zh" dir="ltr">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=gb2312">
    <title>使用Ajax開發Web應用程式 - 樣本</title>
    <script type="text/javascript"><!--
    function ajaxRead(file){
      var xmlObj = null;
      if(window.XMLHttpRequest){
          xmlObj = new XMLHttpRequest();
      } else if(window.ActiveXObject){
          xmlObj = new ActiveXObject("Microsoft.XMLHTTP");
      } else {
          return;
      }
      xmlObj.onreadystatechange = function(){
        if(xmlObj.readyState == 4){
          processXML(xmlObj.responseXML);
        }
      }
      xmlObj.open ('GET', file, true);
      xmlObj.send ('');
    }
    function processXML(obj){
      var dataArray = obj.getElementsByTagName('pet');
      var dataArrayLen = dataArray.length;
      var insertData = '<table style="width:150px; border: solid 1px #000"><tr><th>'
        + 'Pets</th></tr>';
      for (var i=0; i<dataArrayLen; i++){
          insertData += '<tr><td>' + dataArray[i].firstChild.data + '</td></tr>';
      }
      insertData += '</table>';
      document.getElementById ('dataArea').innerHTML = insertData;
    }
    //--></script>
  </head>
  <body>
    <h1>使用Ajax開發web應用程式</h1>
    <p>這個頁面示範了AJAX技術如何通過動態讀取一個遠程檔案來更新一個網頁的內容--不需要任何網頁的重新載入。注意:這個例子對于禁止js的使用者來說沒有效果。</p>
    <p>這個頁面將示範如從取回並處理成組的XML資料。被取回的資料將會以表格形式輸出到底下。
<a href="#" onclick="ajaxRead('data_2.xml'); return false">查看示範</a>.</p>
    <div id="dataArea"></div>
  </body>
</html>

(Sheneyan註:完整程式碼範例見 example_2.html ,XML檔案見:data_2.xml)

你會注意到我們和上次一樣以同樣的方式(通過一個超連結)調用了這個函數,而且我們將資料放入一個DIV(這次這個東東叫做“dataArea”)。這個ajaxRead()函數和上次很接近,除了一點不同:onreadystatechange函數。讓我們先看一下這個函數:

xmlObj.onreadystatechange = function(){
      if(xmlObj.readyState == 4){
          processXML(xmlObj.responseXML);
     }
}

我們取消了updateObj函數並用一個叫做processXML()的新函數來代替它。這個函數將得到XML文檔本身(也就是被ajaxRead函數取回的)並處理它。(這“XML文檔本身”我指的是參數“xmlObj.responseXML”)

現在讓我們分析一下這個函數processXML。下面是它的代碼:

      function processXML(obj){
      var dataArray = obj.getElementsByTagName('pet');
      var dataArrayLen = dataArray.length;
      var insertData = '<table style="width:150px; border: solid 1px #000"><tr><th>'
      + 'Pets</th></tr>';
      for (var i=0; i<dataArrayLen; i++){
          insertData += '<tr><td>' + dataArray[i].firstChild.data + '</td></tr>';
     }
     insertData += '</table>';
     document.getElementById ('dataArea').innerHTML = insertData;
   } 

首先,我們定義了一些變數。“dataArray”作為所有<pet>節點的數組(不是節點資料,只是節點)。“dataArrayLen”是這個數組的長度,用於我們的迴圈。“insertData”則是一個表格的開頭的HTML。

我們的第二步則是遍曆所有的<pet>元素(通過變數“dataArray”)並將資料添加到變數insertData中。這裡我們會建立一個表格行,插入一個表格式資料節點(td)進去,再將每一個<pet>元素的文本包含進這個表格式資料節點,並將這些都添加進變數“insertData”。因此,每迴圈一次,變數insertData將添加一行包含三個寵物中之一名稱的新資料。

新資料行添加完後,我們插入一個“</table>”結束標籤到變數“insertData”。這完成了這個表格,然後我只剩這最後一步來達成我們的目標:我們需要將這個表格放到頁面上。幸運的是,我們得感謝innerHTML 屬性,這很簡單。我們通過函數document.getElementById()取得DIV“dataArea”並將變數“insertData”中的HTML插進去。嗯,這個表格冒出來了!

我們繼續之前……

我得指出兩點:

首先,你會注意到我們並沒有使用節點<pets>。這事因為我們只有一個資料群組(<pets>)以及後來所有的元素(每一個<pet>元素);這些子節點包含了不同的資料但它們有相同的名字。在這個例子中,這個節點能夠被忽略。然而,將所有的元素<pet>放進<pets>元素還是比較好,而不是讓這些<pet>元素自己散放(但仍然在data元素裡面)。

另外一種方式是給每一個寵物放一個指定的標籤,比如:

 <?xml version="1.0" encoding="UTF-8"?>
<data>
  <pets>
    <貓 />
    <狗 />
    <魚 />
  </pets>
</data> 

然後我們能夠遍曆元素<pets>裡的節點。這個processXML函數看起來就像這樣:

    function processXML(obj){
      var dataArray = obj.getElementsByTagName('pets')[0].childNodes;
      var dataArrayLen = dataArray.length;
      var insertData = '<table style="width:150px; border: solid 1px #000"><tr><th>'
     + 'Pets</th></tr>';
    for (var i=0; i<dataArrayLen; i++){
       if(dataArray[i].tagName){
          insertData += '<tr><td>' + dataArray[i].tagName + '</td></tr>';
       }
    }
    insertData += '</table>';
    document.getElementById ('dataArea').innerHTML = insertData;
  }

(Sheneyan註:修改後的樣本見:example_2_1.html ,XML檔案見:data_2_1.xml)

這裡所作的修改就是我們指向了<pets>組元素(這個“[0]”意味這是第一個,即使它就是唯一的那一個)以及它的子節點(元素<貓 />,<狗 />,<魚 />)。因為文本元素分割了這幾個元素(空格被認為是一個節點),我們需要確定只有那些有標籤名的節點(嗯,也就是只有標籤)通過。然後我們輸出每一個標籤的名字。因為每一個標籤名是一個寵物,我們不需要取得每一個節點的資料-節點名本身已經足夠。去看一下它是怎麼工作的吧。

還有另外一種方式來完成我們上面的工作,就是給每一個<pet>節點設定一個屬性值。你的XML文檔看起來就像這樣:

<?xml version="1.0" encoding="UTF-8"?>
<data>
  <pets>
    <pet type="貓" />
    <pet type="狗" />
    <pet type="魚" />
  </pets>
</data> 

你只需要稍微修改一下你的processXML函數,它變成這樣子了:

    function processXML(obj){
      var dataArray = obj.getElementsByTagName('pet');
      var dataArrayLen = dataArray.length;
      var insertData = '<table style="width:150px; border: solid 1px #000"><tr><th>'
      + 'Pets</th></tr>';
    for (var i=0; i<dataArrayLen; i++){
          insertData += '<tr><td>' + dataArray[i].getAttribute('type') + '</td></tr>';
      }
      insertData += '</table>';
      document.getElementById ('dataArea').innerHTML = insertData;
   }

(Sheneyan註:修改後的樣本見:example_2_2.html  ,XML檔案見:data_2_2.xml)

關鍵的不同在於我們通過dataArray[i].getAttribute('type')取得值,它返回了當前<pet>節點的“type”屬性的值。

繼續...

現在我們已經知道了一些從一個單獨的XML資料群組中取回資料的有效方法,讓我們看看如何從多個組中取回資料。和只是列出一個pets所擁有的內容不同,我們假設我們有一個針對我們寵物的日課表。因為它們都有不同的需要,每一隻寵物都得仔細的照顧。面對這種情況,動物的看管員需要一個每日依據。現在來讓我們將這些放入一個良好格式的XML:

<?xml version="1.0" encoding="UTF-8"?>
<data>
  <pets>
    <pet>Cat
      <task>Feed</task>
      <task>Water</task>
      <task>Comb out fleas</task>
    </pet>
    <pet>Dog
      <task>Feed</task>
      <task>Water</task>
      <task>Put outside</task>
    </pet>
    <pet>Fish
      <task>Feed</task>
      <task>Check oxygen, water purity, etc.</task>
    </pet>
  </pets>
</data>

也許這個看起來很奇怪,但這就是我們正在建立的子組(sub-group)。每一個<pet>元素都是一個組<pets>的子組,而每一個<task>則是每一個<pet>組的子項目。

在我繼續之前,你也許希望將你的表格用一些css美化一下,比如:

  <style type="text/css"><!--
  table, tr, th, td {
    border: solid 1px #000;
    border-collapse: collapse;
    padding: 5px;
 }
--></style>

這讓這個表格更容易讀取。現在讓我們去研究函數processXML:

  function processXML(obj){
    var dataArray = obj.getElementsByTagName('pet');
    var dataArrayLen = dataArray.length;
    var subAry, subAryLen;
    var insertData = '<table><tr><th>'
      + 'Pets</th><th>Tasks</th></tr>';
    for (var i=0; i<dataArrayLen; i++){
          insertData += '<tr><td>' + dataArray[i].firstChild.data + '</td>';
          subAry = dataArray[i].getElementsByTagName('task');
          subAryLen = subAry.length;
          insertData += '<td>';
            for(var j=0; j<subAryLen; j++){
              insertData += subAry[j].firstChild.data;
              if( subAryLen != j+1 ) { insertData += ', '; }
            }
        insertData += '</td></tr>';
  }
  insertData += '</table>';
  document.getElementById ('dataArea').innerHTML = insertData;
}

(Sheneyan註:修改後的樣本見:example_2_3.html ,XML檔案見:data_2_3.xml)

新增加的內容,首先是兩個新變數的聲明:“subAry”和“subAryLen”。它們和之前的變數“dataArray”和“dataArrayLen”類似,除了它們指向不同的數組(特別是它們將指向那些“task”元素-當“dataArray”和“dataArrayLen”指向“pet”元素的時候)。

我們也改變了變數“insertData”的初始值-我們增加了一個表格頭(<th>)給我們的“tasks”欄位。

下一步改變在於迴圈:我們把值賦給subAry和subAryLen變數。變數subAry成為當前<pet>的<task>元素的數組。變數subAryLen成為這個數組的長度,直到這個數組發生變化(當外部迴圈走到下一個<pet>時)。

我們建立了一個內嵌的迴圈來處理所有的<task>元素,一次一個。大概來說,我們建立一個新的資料格,放進一個用逗號分隔的工作清單,然後關閉資料表格以及當前行。尤其,這些<task>元素節點資料(任務本身,比如,“餵食”)放置入變數“insertData”裡的資料格。

接下來,我們檢驗當前<pet>是否有其它更多的task。如果還有,我們增加一個逗號(,)到變數insertData來讓每一個任務使用一個逗號分隔(“a, b, c”,而不是“a, b, c,”-注意,最後一個逗號在第二個任務那裡,所以我們不需要)。這個工作在我們取得subAry數組長度的時候(給迴圈的“j”變數加1)就完成了。因為這個迴圈會在下一個迴圈的時候把變數“j”遞增1,“j”會比它這次檢驗時還多1。因此,如果“j+1”(或者,“當迴圈再次開始的時候j的值”)等於subAryLen(當前<pet>節點的<task>節點數目),這個迴圈將停止。如果迴圈不再運行,我們就不再添加新的逗號來分隔任務。所以如果“j+1”不等於subAryLen,我們直到我們可以安全的加入逗號到“insertData”,為下一個<task>作準備。

一旦內迴圈結束,我們關閉task資料格以及pet行。外部迴圈會重新開始建立一個新行以及移動到下一個<pet>。這個處理一直進行到所有的<pet>元素(以及每一個pet的所有<task>元素)都被處理完。

有其他方法嗎?

你也許會想:“那javascript變得相當複雜了,但它只會隨著XML越來越複雜而跟著變複雜,也許我們能夠簡化XML,然後,簡化javascript”。如果你這麼想,很棒,因為你完全正確。我之前展示的不同方法之一,我詳細說明的那個也許能夠成為最合適的。我們怎麼使用屬性來對應每一隻寵物以及相應任務?XML看起來會變成怎樣?

<?xml version="1.0" encoding="UTF-8"?>
<data>
  <pets>
    <pet type="Cat" tasks="Feed, Water, Comb out fleas" />
    <pet type="Dog" tasks="Feed, Water, Put outside" />
    <pet type="Fish" tasks="Feed, Check oxygen, water purity, etc." />
  </pets>
</data> 

哇哦!看起來簡單多了。讓我們看看我們的processXML函數如何修改:

  function processXML(obj){
    var dataArray = obj.getElementsByTagName('pet');
    var dataArrayLen = dataArray.length;
    var insertData = '<table><tr><th>'
     + 'Pets</th><th>Tasks</th></tr>';
    for (var i=0; i<dataArrayLen; i++){
        insertData += '<tr><td>' + dataArray[i].getAttribute('type')             + '</td>'
+ '<td>' + dataArray[i].getAttribute('tasks') + '</td></tr>';
    }
    insertData += '</table>';
    document.getElementById ('dataArea').innerHTML = insertData;
}

(Sheneyan註:修改後的樣本見:example_2_4.html,XML檔案見:data_2_4.xml)

就像你猜的一樣,函數簡單多了。因為代碼變得簡單,它也會變得更有效率。和我們比較老的函數的唯一的不同在於這個變數insertData現在插入更多的HTML,尤其是兩個新變數“type”和“tasks”。就如我們較早之前所學的,那些屬性是我們從XML文檔的<pet>元素中取得的,而且每個pet的屬性都有不同的值。對於你自己修改這個XML檔案以適應你的進度的變動來說也許是最簡單的方法。例如,如果你最終把你的貓身上的跳蚤抓光了,你只要簡單從你的貓的每日任務表中把“減少跳蚤數量”刪除,然而在之前我們使用的XML中,實現起來也許會覺得糊裡糊塗。

最後的XML格式化的方法是將兩部分混合。現在,我們將使用屬性和不同的標籤。讓我們看一下樣本XML:

<?xml version="1.0" encoding="UTF-8"?>
<data>
  <pets>
    <貓 tasks="餵食, 飲水, 減少跳蚤數量" />
    <狗 tasks="餵食, 飲水, 帶出去遛遛" />
    <魚 tasks="餵食, 檢查氧氣,水的純度,其它" />
  </pets>
</data> 

這也許是最便於理解的XML。讓我們分析一下我們為了讓processXML函數運作起來所作的變更:

function processXML(obj){
    var dataArray = obj.getElementsByTagName('pets')[0].childNodes;
    var dataArrayLen = dataArray.length;
    var insertData = '<table><tr><th>'
     + 'Pets</th><th>Tasks</th></tr>';
    for (var i=0; i<dataArrayLen; i++){
      if(dataArray[i].tagName){
        insertData += '<tr><td>' + dataArray[i].tagName + '</td>'
            + '<td>' + dataArray[i].getAttribute('tasks') + '</td></tr>';
      }
  }
  insertData += '</table>';
  document.getElementById ('dataArea').innerHTML = insertData;
}

(Sheneyan註:修改後的樣本見:example_2_5.html,XML檔案見:data_2_5.xml)

“dataArray”現在指向了<pets>的子節點,將它們作為一個數組對待(換句話說,dataArray現在是在<pets>節點內所有節點的數組)。這事因為每一個標籤都不同(<貓 />,<狗 />,<魚 />),所以我們不能使用這些元素的名稱來搜尋它們(而之前我們可以使用<pet>,因為所有的元素都是<pet>)。

還是一樣,每個節點之間的有空格,所以在我們的處理過程中得排除掉文本節點。我們能夠檢驗標籤名是否存在-文本節點是節點但沒有標籤,而<貓 />,<狗 />,<魚 />節點都是標籤。所以如果一個標籤有名字,那我們能夠將資料插入變數insertData。我們插入的資料是一個表格並有兩個表格式資料格。這第一個儲存格是標籤名,也就是寵物的類型(貓,狗或魚),而第二個儲存格則是指定動物的“tasks”屬性值(比如“餵食或飲水”)。

結束語

在這篇文章裡,我示範了這個例子的很多變化,你可以隨意實驗它們來檢驗哪個更適合你。只要記住一點,XML是“可擴充的”,所以沒有“錯誤的”方法來組合你的資料,雖然經常有一個“最好的”方法。而且,要注意讓你的XML保持格式良好。記住很多問題來自於忘記結束一個標籤(比如<狗 />而不是<狗>;除非這個節點中有資料,比如下面的<狗>這裡有資料哦</狗>)。

我意圖使XML和javascript的應用不糊塗而變得明朗。一步步的學習處理更多的資料,你能夠將ajax運用於更大的用途。我希望看到ajax更多的應用於企業網站,及其它。所以如果你將這些知識應用於實踐,我很高興瞭解到你學到了什麼(mail:jona#slightlyremarkable.com #換成@)。

關於作者

Jonathan Fenocchi(mail:jona#slightlyremarkable.com #換成@)是一個網路開發人員,主攻web設計,用戶端指令碼,php指令碼。
他的網站位於http://www.slightlyremarkable.com

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.