2015年4月23日 星期四

AJAX 入門:第五個範例


AJAX 入門:第五個範例

The following examples had been tested on Mozilla's Firefox and Microsoft's IE. The document is provided as is. You are welcomed to use it for non-commercial purpose.
Written by: 國立中興大學資管系呂瑞麟

請勿轉貼
看其他教材

這個範例跟第四個範例非常類似,主要不同的地方在於這次我們增加了一個使用 XMLHttpRequest 的地方,也就是選擇了 XML 檔案後,AJAX 會要求 server 將解析 之後的結果回傳;最後,AJAX 網頁將回傳的內容放置於如網頁中綠色的方塊中 (這效果是採用 CSS 的結果)。請參考 demo 網站

請選擇: 自行輸入網址 選擇現有的 XML 檔

範例說明:
  • 在這個範例中,我們在"範例說明:"之後,加了一段 div 區塊,其內容如下, 這個區塊也就是右邊綠色的方塊,該方塊的 id 為 rssBox:
    <div id="rssBox" class="on">
    </div>
    
    而 rssBox 的 CSS 設定內容下:(可以參考 CSS 簡介
    #rssBox {
      width:350px;
      margin:5px;
      float:right;
      height:220px;
      border:1px dotted #317082;
      padding:3px;
      font-size:0.8em;
      background-color:#99FF99;
      overflow-x: scroll;
      overflow-y: scroll;
    }
    
  • HTML 元件的部份有一個地方跟第四個範例不同的地方我們需要特別說明一下, 先列示其原始碼如下:
    <form name="myform">
    請選擇:
    <input type="radio" name="xml" value="url"
           onClick="callServer();">自行輸入網址</input>
    <input type="radio" name="xml" value="xml"
           onClick="callServer();">選擇現有的 XML 檔</input>
    <br/>
    <div id="label" class="on">
    </div>
    </form>
    
    請特別注意綠色的部份:第四個範例中,在 form 標籤中,我們有 method 和 action 屬性,這些屬性會迫使以同步的方式進行伺服器程式的呼叫。 為了能夠進行非同步式的呼叫,我們必須把這兩個屬性刪除掉,然後利用 onClick 的方式來進行非同步式的呼叫。也因此,不論是 display() 或者 callServer(),我們不再使用
    <input type="submit" value="確定">
    
    而改用
    <input type="button" value="確定" onClick="dispXML();">
    
    來進行。
  • 大部分 dispXML() 程式碼跟之前的 AJAX 程式大同小異,我們只針對需要說明的 地方描述。如以下程式碼所示,首先是定義事件處理函數為 showXML(),這是因為在 這個網頁的其他 AJAX 呼叫已經使用了 alertContents()(也就是說,本範例定義了 兩個事件處理函數;能定義兩個事件處理函數,自然可以定義更多的事件處理函數), 而其內容與這次的處理方式不同,所以我們必須定義另一個事件處理函數。
    01    // 定義事件處理函數為 showXML()
    02    http_request.onreadystatechange = function() {
    03                                      showXML(http_request); };
    
    04    // 由於 radio button 有一個以上,所以一般都是以陣列的方式處理
    05    // 只是這個範例只有兩個,所以就簡單的用 if 來解決
    06    var option;
    07    if(document.myform.xml[0].checked)
    08      option = document.myform.xml[0].value;
    09    else
    10      option = document.myform.xml[1].value;
    11    var url = "/jlu/servlet/DOMBox?xml=" + option +
    12              "&file=" + document.myform.file.value;
    13    http_request.open('GET', url, true);
    14    http_request.send(null);
    
    在第 11 行,我們利用 DOMBox.java 這個 servlet 來 開啟 XML 檔案,但是由於一個要開啟伺服器內的檔案(利用 java.io.*),另一個 要開啟 URL 所指定的檔案(利用 java.net.URL),所以我們必須傳遞適當的參數 給 DOMBox.java,而傳遞的方式就是設定適當的 url 值。為了能夠傳遞正確的 url 值,我們必須從使用者選擇的 radio button 來決定;由於本範例中,兩個 radio button 的名稱都是 xml(因為 radio button 只能選一個,所以當然名稱 都一樣),Javascript 用來判斷第一個 radio button(以 document.myform.xml[0] 代表)是否被選取的方式是由 document.myform.xml[0].checked 是否為真的方式來 決定,因此第 07-10 行利用 if 敘述來決定究竟哪一個 radio button 被使用者 選取,確定之後,就可以把其相對應的值 document.myform.xml[0].value 指定給 option;以 document.myform.xml[0].value 為例,其值為 "url"。 除了 option 的值需要設定之外,還有使用者輸入的 URL 或者檔案名稱;這一個 部分,我們在之前的 display() 以及 callServer() 中,都已經將其 HTML 元件 名稱命名為 file;以 display() 為例,它是一個文字欄位,程式的設計如下: (內容與之前的程式碼相同,我們只是利用綠色字體將文字欄位特別標示出來)
      function display() {
        document.getElementById("label").innerHTML = '請輸入網址:' +
        '<input type="text" name="file"></input><input type="button" value="確定" onClick="dispXML();"></input>';
        document.getElementById("rssBox").innerHTML = '';
      }
    
    至於 callServer() 則是把下拉式選單也命名為 file。請注意,在本範例中, 由於只有兩個 radio buttion,因此我們使用簡單的 if 敘述;可是一般比較常用 的處理方式是利用 for 迴圈來處理,因為 document.myform.xml 是一個 陣列,這部份留給你們練習用。
  • 由於 DOMBox.java 執行的方式是把使用者指定的 XML 檔案打開,然後一次 讀一行,然後再一行一行的送到 AJAX 網頁,因此我們在 showXML() 中必須把從 server 收到的 < 轉換成 &lt;、 > 轉換成 &gt;、以及換行的特殊 字元轉換成 <br/>。showXML() 的程式碼如下:
      var restext;
      function showXML(http_request) {
        if (http_request.readyState == 4) {
          if (http_request.status == 200) {
            restext = http_request.responseText;
    
    
            // 將 <> 轉換成 &lt; &gt;
            var regex = new RegExp("<", "gi");
            restext = restext.replace(regex, "&lt;");
            regex = new RegExp(">", "gi");
            restext = restext.replace(regex, "&gt;");
            regex = new RegExp("\n", "gi");
            restext = restext.replace(regex, "<br/>");
    
    
            document.getElementById("rssBox").innerHTML = restext;
            //alert(http_request.responseText);
          } else {
            alert('There was a problem with the request.');
          }
        }
      }
    
    如程式碼中,綠色字體的部份,我們利用 Javascript 中的類別 RegExp 做轉換;例如,需要將 < 轉換成 &lt;,我們必須先 new 一個 RegExp 的物件,而其建構元的第一個參數代表需要被轉換的對象,也就是 <,而第二個參數代表文件中所有的 < 都需要轉換。然後,我們進行 轉換的處理,我們把剛剛的 RegExp 物件當成 replace() 的第一個參數,而 第二個參數代表轉換後的文字,在範例中就是 &lt;。當執行完 replace() 之後,restext 字串內的所有 < 都變成 &lt;; 其他的敘述依此類推。 在我們常用的編輯器,我們也經常使用類似 RegExp 的作法。以筆記本為例, 當我們需要取代(Replace)文字檔中的某一個文字(例如 VB)成另一個文字 (例如 Java),我們會將 VB 設定為"尋找目標",然後將"取代為"設為 Java;當我們按下"取代",只有第一個被找尋到的目標會被取代;如果我們 需要取代所有的 VB,則我們按下"全部取代",而這個就是類似剛剛的 "gi" 的設定。
    RegExp 是一個 Javascript 的類別,它提供了 regular expression 的功能; 依據 Wiki 的定義,regular expression 是一種表示式(expression),而該 表示式可以用來尋找符合某一定格式(pattern)的文字集合。例如,假設某一個 文字檔中包含了 "this is a book" 的文字,如果 regular expression 表示要找尋 "is" 文字,那麼總共有兩個 "is" 被找到,如文字中的 綠色字體所示。regular expression 是一個功能非常強大的機制,許多高階 語言都支援該項特色,至於進一步的學習不在本文件的範圍內,所以就不再 多談。
  • 完整原始碼:
      function display() {
        // 顯示文字欄位
        document.getElementById("label").innerHTML = '請輸入網址:' + 
        '<input type="text" name="file" size="40"></input><input type="button" value="確定" onClick="dispXML();"></input>';
        document.getElementById("rssBox").innerHTML = '';
      }
    
      function callServer() {
        document.getElementById("rssBox").innerHTML = "";
        var http_request = false;
    
        if (window.XMLHttpRequest) { // Mozilla, Safari,...
          http_request = new XMLHttpRequest();
        } else if (window.ActiveXObject) { // IE
          try {
            http_request = new ActiveXObject("Msxml2.XMLHTTP");
          } catch (e) {
            try {
              http_request = new ActiveXObject("Microsoft.XMLHTTP");
            } catch (e) {}
          }
        }
    
        if (!http_request) {
          alert('Giving up :( Cannot create an XMLHTTP instance');
          return false;
        }
        // 定義事件處理函數為 alterContents()
        http_request.onreadystatechange = function() { 
                                          alertContents(http_request); };
        var url = "/jlu/servlet/retFiles";
        http_request.open('GET', url, true);
        http_request.send(null);
      }
    
      function alertContents(http_request) {
        if (http_request.readyState == 4) {
          if (http_request.status == 200) {
            var restext = http_request.responseText.split("|");
            var mesg = '<select name="file">';
            for(var i=0; i<restext.length-1; i++) {
              mesg += '<option value="' + restext[i];
              if(i == 0)
                mesg += '" selected="1">';
              else
                mesg += '">';
              mesg += restext[i] + '</option>';
            }
            mesg += '</select>';
            mesg += '<input type="button" value="確定" onClick="dispXML();"></input>';
            document.getElementById("label").innerHTML = mesg;
          } else {
            alert('There was a problem with the request.');
          }
        }
      }
    
      function dispXML() {
        document.getElementById("rssBox").innerHTML = "Loading...";
        var http_request = false;
    
        if (window.XMLHttpRequest) { // Mozilla, Safari,...
          http_request = new XMLHttpRequest();
        } else if (window.ActiveXObject) { // IE
          try {
            http_request = new ActiveXObject("Msxml2.XMLHTTP");
          } catch (e) {
            try {
              http_request = new ActiveXObject("Microsoft.XMLHTTP");
            } catch (e) {}
          }
        }
    
        if (!http_request) {
          alert('Giving up :( Cannot create an XMLHTTP instance');
          return false;
        }
        http_request.onreadystatechange = function() { 
                                          showXML(http_request); };
    
        var option;
        if(document.myform.xml[0].checked)
          option = document.myform.xml[0].value;
        else
          option = document.myform.xml[1].value;
        var url = "/jlu/servlet/DOMBox?xml=" + option +
                  "&file=" + document.myform.file.value;
        http_request.open('GET', url, true);
        http_request.send(null);
      }
    
      var restext;
      function showXML(http_request) {
        if (http_request.readyState == 4) {
          if (http_request.status == 200) {
            restext = http_request.responseText;
    
            var regex = new RegExp("<", "gi");
            restext = restext.replace(regex, "&lt;");
            regex = new RegExp(">", "gi");
            restext = restext.replace(regex, "&gt;");
            regex = new RegExp("\n", "gi");
            restext = restext.replace(regex, "<br/>");
    
            document.getElementById("rssBox").innerHTML = restext;
          } else {
            alert('There was a problem with the request.');
          }
        }
      }
    





Written by: 國立中興大學資管系呂瑞麟

1 則留言: