load(url)與loadXML(xml/string)【ActiveXObject("Microsoft.XMLDOM")】

XML的背景
HTML與XML都是由標準通用標示語言 (Standard Generalized Markup Language,簡稱SGML) 發展而來的。SGML是一種涵蓋範圍很廣的語言,它可以用來產生複雜資料系統 (或應用) 的製作方式,並且定義了資料描述及顯示規則。基本上,HTML是SGML的一個應用;但 XML則是SGML的一個子集,其設計目的是為了提供一個簡單、可使網頁最佳化的資料呈現方式,因為使用這種方式比直接使用完善但複雜的SGML要來得容易多了。

XML的衍生規格
XML在設計當初就有將Web考慮在內,而且提供了SGML所沒有的好處。瀏覽器可以利用XML搭配HTML來做資料的顯示與呈現。而為了支援XML在 Web 上的傳遞,目前還有兩種XML的相關規格被制定出來。
其中一種規格是「延伸連結語言」 (eXtensible Linking Language 簡稱XLL),這種規格描述的是一種超連結架構,用來同時支援傳統的HTML超連結及更進階的延伸超連結,其中後者可以讓單一連結指向多個不同的連結資源。雖然SGML也可以定義超連結機制,不過在SGML的原始規格中並沒有提到。
另一種規格是「延伸樣式語言」 (eXtensible Stylesheet Language 簡稱XSL),這種規格可以提供對XML樣式表架構的支援,這也是SGML規格中沒有涵蓋的部份。樣式表允許設計者建立樣式範本 (例如粗體、斜體等) 或樣式組合,當XML文件顯示時,即可將樣式範本或組合套用到各種XML元件 (Element)上。

簡單來說,XML擁有SGML百分之八十的功能,但其複雜度卻只有SGML的百分之二十。基本上,擁有一種簡單且通用的資料描述方法是十分有用的。舉例來說,由於XML擁有中立的資料交換格式,因此許多不同類型的系統都可以存取其資料。舉例來說,就我們所知,很多老舊的電腦系統是用各種不同的格式來儲存資料的,但是現在已經有一些系統轉換程式,可以讓很多舊系統可以讀取或輸出XML格式的資料。所以,在某個舊系統中用XML製成的資料檔案可以輕易地輸出到其他舊系統上、或發表成 Web 網頁、或輸出到其它支援XML的應用程式中。也就是說,XML可以當作是一個中介的資料格式,讓原本不相容的系統可以互相交換資料。

XML是一種資料
如果HTML是為了「顯示」資訊,那麼,XML就是為了「描述」資訊。XML是一個可以讓資料結構化並描述資料的標準語言,且可以讓不同的應用程式所瞭解。XML最大的威力就是它可以將使用者介面與資料分開。我們來看一個簡單的XML文件,以瞭解 XML 是如何運作的:

<?xml version="1.0"?>
<EMAIL>
<TO>[email protected]</TO>
<FROM>[email protected]</FROM>
<CC>[email protected]</CC>
<SUBJECT>Basic email</SUBJECT>
<BODY>This is an XML-based email.</BODY>
</EMAIL>

這個例子必須注意的重點是,在文件中並沒有描述如何顯示此份文件。換句話說,就是沒有包含樣式的資訊 (如粗體、斜體字、縮排、字體大小等)。因為XML文件的原始碼只是描述有哪些資料,讓讀者可以輕易地瞭解這份文件的內容以及結構。

XML 文件也被稱為「自我描述」 (self-describing) 的文件,因為,每一份 XML文件內都會包含一組資料必須遵循的規則。而由於每一組規則都可以重複使用,因此,文件建立者可以很容易地利用相同類別 (class) 文件的新版本。

類別是出自物件導向的程式觀念,在物件導向的程式中,類別用於描述一羣有相同特性的物件。基於各文件的內容種類,將文件建立類別,可以提供一種很有用的文件分類方法。

有效的與標準的XML文件

XML 最有用的兩個特性是:提供文件結構化的能力,及提供資料自我描述的能力。要有這兩種能力,文件中必須要有遵循結構化 (structual) 與文法化 (grammatical) 的規則。接下來的兩小節,將簡單介紹兩個XML詞彙:「有效的」 (Valid) 和「標準的」 (Well-formed),這兩者描述了文件如何遵循用來控制XML文件的結構化與文法化規則。

有效的(Valid)文件
XML文件處理器 (XML processor) 可強制執行XML文件執行文件內的結構和內容規則。這些規則包括標準XML規格所要求的部份,以及針對該文件所特別定義的規則。其中,第二種規則是以「文件型態定義」 (Document Type Definiton,簡稱DTD) 存在。DTD 和 XML文件中真正的資料部份是分開的,DTD 可以直接包含在XML文件內部;也可以從XML獨立出來,成為一個獨立的文件。一個有效的XML文件必須嚴格地遵守這兩種規則。本書並不會詳細介紹如何撰寫及使用 DTD文件,因為本書只針對簡單且不需DTD的XML例子來說明。您可以在任何專業的XML參考手冊或網站上找到更多撰寫DTD文件的資訊,例如XML in Action這本書 (by William J. Pardi,Microsoft Press 1999) 和 www.w3.org/xml (W3C的XML網站)。正如您等一下看到的,XML文件不是非得要有DTD文件才行。

標準的 (Well-formed) 文件
標準的 (Well-formed) 文件所要遵循的規則遠不如有效文件嚴格。建立一個標準的XML文件其實是非常簡單且直覺的。以下列表會條列出標準化的XML文件主要規則。本章稍後也會舉一些例子。

  • 只有一個根元件 (Root Element,或稱為文件元件Document Element)
  • 根元件部份不能出現在文件中其它元件的內容中
  • 除了根元件之外,文件中其他元件的開始與結束標籤必須構成文件中的同一個巢狀層級。這意思是說,如果開始標籤放在一個元件的資料內容位置上,結束標籤也必須放置在同一個元件的資料內容位置。

如果XML文件不遵循這些規則,瀏覽器將會出現錯誤訊息。在 Internet Explorer瀏覽器中,可以利用Script語言透過物件模型 (Object Model) 來偵測錯誤。本章稍後也會有錯誤處理 (Error handling) 的詳細介紹。

我們來看看一個XML文件的例子:

<?xml version="1.0">
<PLANT>
<COMMON>Columbine</COMMON>
<BOTANICAL>Aquilegia canadensis</BOTANICAL>
</PLANT>

這個文件包含了一個PLANT文件元件 (稱為Document Element或根元件),而COMMON和BOTANICAL是包含在根元件內部的元件。為了要講述這個觀念,以下一個例子是「非」Well-formed的文件,因為它包含了兩個根元件:

<?xml version="1.0">
<COMMON>Columbine</COMMON>
<BOTANICAL>Aquilegia canadensis</BOTANICAL>

元件的巢狀層級可建立父/子元件的關係。每個子元件 (非根元件的元件) 都會放置在其父元件之內,就像我們在第五章所討論的動態物件模型一樣。這個觀念我們用下面的例子來展示:

<ROOT>
<PARENT1>
<CHILD1></CHILD1>
<CHILD2></CHILD2>
</PARENT1>
</ROOT>

子元件絕對不能放在其父元件的其它子元件之內。例如,下面這段原始碼就是一個非well-formed的XML文件:

<ROOT>
<PARENT1>
<CHILD1>
<CHILD2></CHILD1></CHILD2>
</PARENT1>
</ROOT>

同樣地,根元件的前後標籤也都不能放在其任一子元件的內部。下面的原始碼也不是一個Well-formed的XML文件:

<ROOT>
<PARENT1>
<CHILD1></CHILD1>
<CHILD2></CHILD2>
</ROOT>
</PARENT1>

正如您所看到的,XML文件是非常結構化的文件,而且必須遵循嚴格但簡單的規則,以形成well-formed或valid的文件。這種結構加上特定的層級結構,產生了一個有父子元件關係的家族樹狀結構。

XML和Internet Explorer
截至目前為止,我們只介紹了XML的資料特性,而未介紹XML的顯示方式。接著您一定會有這個邏輯上的疑問,那就是該如何在網頁上顯示XML資料? Internet Explorer包含了幾個可以顯示XML資料的物件,最常被用到的就是DOMDocument 物件。這個物件基本上扮演的是資料本身與 Internet Explorer 資料顯示功能的中介角色。

當這個物件在分析一份文件時,它會在記憶體中建立文件內所有元件的樹狀結構;並提供使用XML文件物件模型 (XML Document Object Model) 的方法,也就是允許存取XML資料的介面。這個物件模型會顯露物件的性質、方法、事件、及包含在資料樹中真正的資料部份。詳細的XML 文件物件模型的性質、方法、與事件,在本章稍後的表格21-1到21-3中可找到詳細的列表。物件模型可以讓設計者檢視從根到分支的所有樹狀結構。

程式列表21-1是一個簡單的網頁,它將XML資料送進網頁中,然後將它顯示在螢幕上。圖21-1 顯示的是網頁的瀏覽結果。

<HTML>
<HEAD>
<TITLE>Code Listing 21-1</TITLE>
<SCRIPT LANGUAGE="JavaScript" FOR="window" EVENT="onload">
start()
</SCRIPT>
<SCRIPT LANGUAGE="JavaScript">
var xmlDoc=new ActiveXObject("Microsoft.XMLDOM")
xmlDoc.async=false
xmlDoc.load("email.xml")
function start()
var root=xmlDoc.documentElement
todata.innerText=root.childNodes.item(0).text
fromdata.innerText=root.childNodes.item(1).text
ccdata.innerText=root.childNodes.item(2).text
subjectdata.innerText=root.childNodes.item(3).text
bodydata.innerText=root.childNodes.item(4).text
</SCRIPT>
</HEAD>

<BODY>
<B>To:</B> <SPAN ID="todata"></SPAN><BR>
<B>From:</B> <SPAN ID="fromdata"></SPAN><BR>
<B>CC:</B> <SPAN ID="ccdata"></SPAN><BR>
<B>Subject:</B> <SPAN ID="subjectdata"></SPAN><BR>
<B>Body:</B> <SPAN ID="bodydata"></SPAN><BR>
</BODY>
</HTML>

程式21-1

圖 21-1 一個簡單處理XML文件的 HTML網頁

在<HEAD>中的第一段Script程式碼只是一個很簡單的事件處理器,其作用是在瀏覽器載入網頁後,執行start函式的呼叫。我們等一下會解釋這個函式。注意網頁本身包含了SPAN標籤,這些標籤所定義的區域將會是最後XML資料的顯示空間。

我們先前有提到,XML處理器扮演的是XML文件與HTML網頁 (或任何其它類似的顯示媒體) 的中間媒介層。我們必須先將XML處理器載入,成為網頁上的一個物件,如此我們才能利用Script語言與之溝通。

var xmlDoc=new ActiveXObject("Microsoft.XMLDOM")
xmlDoc.async=false
xmlDoc.load("email.xml")

程式碼的第一行載入一個DOMDocument物件,然後將它設定給變數xmlDoc。如此提供使用XML處理器與物件模型的權利。下一行告訴處理器不要「非同步」(Asychronously) 載入文件,這個意思是說網頁會等到文件的資料完全下載後再繼續顯示網頁;設定值若改為TRUE,則會使資料與網頁的其他部分一起下載,如此一來,就得使用一些偵測 (通常會測試ondataavailable或onreadystatechange事件,或readystate性質),來確定資料在被使用之前已載入。第三行則是讓物件載入本章一開始提到的 email.xml 這個 XML 文件。以下是資料樹狀結構一開始被載入的部份:

DOCUMENT
|---XMLDCL
| |---ATTRIBUTE version "1.0"
+---ELEMENT EMAIL
|---ELEMENT TO
| +---PCDATA "[email protected]"

此樹狀結構是以文件物件 (Document Object) 作為開端,它包含了一個XML宣告。接著是根元件EMAIL,EMAIL元件包含另一個元件,也就是上面結構圖中所顯示TO子元件,其值為[email protected],這是一個叫做 PCDATA 的XML資料型態。

一旦網頁被下載,start函式就會被呼叫。這個函式其實十分簡單,其第一行會建立一個變數稱為root,並且設定給XML文件的根節點 (root node),讓我們可以存取XML資料樹。下一行程式碼利用 innerText 性質,將一段文字設定給ID為todata 的SPAN元件,如此可以讓文字被顯示,而它使用的文字是來自XML根元件的第一個子元件。利用root.childNodes.item(0).text這一段程式碼,即可存取根元件的第一個子元件,以取得文字內容。

如果您能瞭解這段程式,您將會知道如何使用 XMLDocument 控制項來載入一份XML文件,且從XML的結構樹中取得資料。這是處理其他XML文件的基礎。

雖然上面講的文件所要花費的功夫,要比簡單且可得到相同效果的HTML文件來得多。但是,其實一些使用XML會有的優點我們可以從中瞭解,最大的優點是網頁可以變成一個範本資料。上面所建立的HTML網頁可以當作其它可以事先定義模組的XML資料的範本。雖然建立一個HTML文件會需要花一點功夫,但它可重複使用於不同的內容。舉例來說,XML文件即使被翻譯成法語、德語…等其它語言,仍然可以被插入同一個HTML文件中。

除了利用 DOMDocument 物件外,我們還可以用其它的方法可以將XML資料顯示成網頁,例如: XML資料來源物件 (Data Source Object)、XSL、和 XSL Pattern。這些技術加入了更多使用XML將資料結構化和儲存資料的好處,您可以在微軟SBN Workshop網站和隨書附贈光碟中找到更多相關資訊。在隨書CD中,要看 XML 的資料,請在XML TOC (XML Table of Contents) 中選擇任何一個主題即可。若要參考線上版本,可連上MSDN線上資源網站。下面的表格分別列出XML 文件物件模型中的各項性質。

表 21-1 XML文件的性質
性質 說明
async 回傳一個布林值,決定是否允許非同步下載。當允許非同步下載時, 傳回值為TRUE;若不允許則傳回值為FALSE 。讀/寫。
attributes 傳回包含目前節點元件之屬性集合物件。若節點不能有屬性值,則傳 回值為null。唯讀。
childNodes 傳回包含目前節點元件之所有子節點元件的集合。若目前節點沒有任 何子節點,則傳回值為null。唯讀。
doctype 傳回一個包含擁有DTD的文件型態節點。若不含DTD,則傳回值為 null。唯讀。
documentElement 傳回一個包含根元件資料的物件。若沒有根元件,則傳回值為null。 唯讀。
firstChild 傳回一個包含目前節點的第一個子節點元件,若目前節點沒有任何第 一子節點,則傳回值為null。唯讀。
implementation 傳回DOM為目前XML文件實作所得的物件。唯讀。
lastChild 傳回一個包含目前節點的最後一個子節點元件,若目前節點沒有任何 最後一個子節點,則傳回值為null。唯讀。
nextSibling 傳回一個包含目前文件節點在子節點元件集合中的下一個兄弟元件, 若目前節點沒有任何兄弟節點,則傳回值為null。唯讀。
nodeName 傳回一個能代表合格的目前節點(元件,屬性,或實體參考)名稱字 串,唯讀。
nodetype 傳回一個數字,它分別代表目前節點的DOM型態 (元件、屬性、文 字)。唯讀。
enodeValu 傳回特定節點的相關純文字資料,這不是元件的資料值,而是未剖析 相關於節點的純文字,就好像是屬性和處理指令(PI),某種資料型態 會回傳null。讀/寫。
ondataavaiable 設定Ondataavaiable事件處理,只能寫。
onreadystatechange 設定Onreadystatechange事件處理,只能寫。
ownerDocument 傳回一個物件,它包含目前節點的文件之根節點。唯讀。
parentNode 傳回包含目前節點元件之所有父節點元件的集合。若目前節點沒有任 何父節點,則傳回值為null。唯讀。
parseError 傳回一個DOM剖析錯誤物件,它描述了最後的剖析錯誤。若沒有錯 誤發生,則傳回0。唯讀。
previousSibling 傳回一個包含目前文件節點在子節點元件集合中的上一個兄弟元件, 若目前節點沒有任何兄弟節點,則傳回值為null。唯讀。
readyState 傳回一個數字表示目前的XML文件的狀態。唯讀。值如下所示:

0 (尚未初值化) XML物件已經建立,但尚無任何文件載入
1 (載入中) 正在載入,但剖析尚未開始。
2 (載入後) 文件的部分已經下載且開始剖析,但還建立為物件模型。
3 (互動的) 文件已載入的部分之物件模型已經建立。
4 (完成的) 文件完全被載入。這並不表示載入成功。

url 傳回最後一個成功下載文件的URL。若文件只存在記憶體中(非從外 部檔案載入),則傳回null值。唯讀。
validateOnParse 提示給剖析器文件是否被確認。若為True,則當被剖析時文件是被 確認的,若為false,文件並無被確認,且被期望為well-formed。 讀/寫。
xml 傳回特定節點和其子孫的XML呈現。唯讀。

表 21-2 XML文件的方法
方法 說明
abort() 若這個方法在非同步下載期間被呼叫,所有的解析動作將被 停止,在記憶體中文件的任何部分也將被拋棄。
appendChild(newChild) 新增一個節點當作特定節點的最後一個節點。
cloneNode(deep) 建立與一個特定節點完全相同的複製節點,deep參數是一 個布林值,若為True,則不只複製節點而且還複製其子孫元 件。若為False,只有特定節點與其屬性被複製。
createAttribute(name) 建立一個特定名稱的屬性。
createCDATASection(data) 建立一個CDATA區段,其中包含特定字串資料。
createComments(data) 建立一個特定字串的註解。
createCommentFragment() 建立一個新的文件片段,不過並不把它加入文件樹中。若要 將它加入樹中,必須利用insert方法,例如 insertBefore、 replaceChild、或appendChild。
createElement(tagName) 建立一個特定標籤名稱(大小寫不同)的元件。
createEntinyReference 建立一個特定名稱的實體參考,不過並不把它加入文件樹(name) 中。若要將它加入樹中,必須利用insert方法,例如 insertBefore、replaceChild、或appendChild。
createNode(type,name, namespaceURL) 設定特定型態、名稱及名稱空間建立一個新的節點。
createProcessingInstruction(target,data) 建立一個包含特定目標和資料的處理指令,不過並不把它加入文件樹中。 若要將它加入樹中,必須利用insert方法, 例如insertBefore、replaceChild、或 appendChild。
createTextnode(data) 建立一個包含特定資料的新文字節點,不過並不把它加入 文件樹中。若要將它加入樹中,必須利用insert方法,例如 insertBefore、replaceChild、或 appendChild。
getElementsByTagName 傳回一個特定名稱的元件集合。使用 "*" 的標籤名稱設定, (tagname) 則會傳回所有在文件能找到的元件。
haschildnodes() 傳回True 若節點含有子元件,false則沒有。
InsertBefore 在參考節點之前插入一個新子節點,newChild 參數是一個包 (newChild,refChild) 含新子節點位置的物件,而refChild是參考節點的位置。若 不包含refChild參數,新的子節點會被插入在子節點集合的 最後位置。
load(url) 從特定的位置中載入指定的文件,傳回True若文件載入成 功,傳回False則為否。
loadXML(xml/string) 載入一個XML文件,或從字串來的文件片段,傳回True若 文件載入成功,傳回False則為否。
nodeformID(idString) 傳回一個符合特定值的節點,若有符合的物件則傳回此物 件,若此操作失敗,傳回null值。
Parsed 若目前節點和此節點的所有的子孫節點,已經被剖析及, 則傳回值為 True,若節點的任何部分都尚未被剖析,則傳 回null。
removeChild(child) 從節點集合中刪除特定的子節點,child參數就是包含要被 刪除的子節點之元件。
replaceChild 用提供的新節點來取代舊節點。若newChild是null,則舊 (newChild,oldChild) 節點不會被取代,而直接刪除。
selectNodes(patternString) 傳回一個節點集合元件,此元件包含符合提供 XSL pattern 的節點。
selectSingleMode 傳回第一節點符合所提供的XSL pattern,若沒有發現任何 (Pattern String) 符合,則傳回null。
TransformNode(stylesheet) 傳回一個字串包含目前節點的處理結果和它的子節點使用 所提供的XSL樣式。

表 21-3 XML 文件的事件
事件 說明
Ondataavailable 當任何資料可用則會引發此Ondataavailable事件。這個技巧並 不提示在這個文件中有多少資料是可用。
Onreadystatechange 當readystate性質改變,則會引發Onreadystatechange 事件, 但此事件並不會提供ready state的設計值,必須使用readystate 性質來取得目前狀態。

基礎之外的其它Scripting 技術
上面介紹的簡單 E-Mail 範例,示範瞭如何存取XML物件模型,以及使用XML資料。若進一步來觀察這個文件和它的script,我們將會看到簡單所帶來的代價。在我們想盡辦法讓Script簡單一些時,我們加入了一些技巧在其中,以證明script在許多情況下還是不夠理想的。請考慮下面的問題:

  • 用來存取XML文件樹和讀出資料的script程式,會假定我們不僅知道有多少元件存在,同時也知道元件的順序和我們的原始檔是相同的,因為我們是利用索引來使用每個元素。這類的 script 程式也許可以用在一些應用程式上,但在其他應用程式上可能就不太適合了。
  • script程式能分別為每個元件設定位置。這種做法用在小型文件上可能沒什麼問題;可是如果用在大型或複雜的文件上,則整個處理程序會變得過於冗長,而且很可能錯誤百出。
  • HTML文件並不完全是資料獨立的文件,因為用來配置版面和設定格式的HTML標籤會跟文字 (如前一個例中的 To:和 From:) 夾雜在一起。若文件必須要翻譯成其他語言,則會需要同時編輯XML文件與HTML兩種文件。

我們現在就來看一些script 的寫作技巧,以避免我們剛剛所講的問題。

處理XML文件樹
在上一個例子中,設計者必須知道XML文件中元件的數目和類型,但是如果能使用一些XML物件模型中的其它性質和方法,那麼事情就會簡單一些。

在這些有用的性質當中,其中有一個是childNodes,這個性質會傳回目前節點的子節點集合。ChildNodes的length性質會包含子節點的數目。因此,處理節點的子節點將會非常容易。參考如下程式碼 21-2。

<HTML>
<HEAD>
<TITLE>Code Listing 21-2</TITLE>
<SCRIPT LANGUAGE="JavaScript">
var xmlDoc=new ActiveXObject("Microsoft.XMLDOM")
xmlDoc.async=false
xmlDoc.load("email.xml")
root = xmlDoc.documentElement
for (var i=0; i<root.childNodes.length; i++){
   alert(root.childNodes.item(i).nodeName+" = "+root.childNodes.item(i).text)
}
</SCRIPT>
</HEAD>
</HTML>

程式 21-2

圖21-2 對話窗包含第一個元素的名稱與內容

現在載入HTML文件後,應該會一連串產生 5 個對話窗,每個對話窗都會包含元件在 XML 文件中的名稱與內容。第一個對話窗如圖21-2所示。處理的程式利用了root.childNodes.length性質來詢問 XML 文件,以得知根元件包含了多少個子元件。接著,script會進入一個迴圈,巡行檢視根元件的所有子元件,並取得每一個子節點的名稱 (利用nodeName性質) 和文字內容,直到最後一個節點為止。

不過,這個程式處理結構樹的第一層而已,若根元件的任何子元件也有子元件,則會被程式21-2所忽略。Inbox.xml檔案是較為複雜的文件,此文件是一個多層的樹結構。注意第一個email甚至包含一個元件(CC),這是在其它email所沒有的。

<?xml version="1.0"?>
<INBOX>
<EMAIL>
<TO>[email protected]</TO>
<FROM>[email protected]</FROM>
<CC>[email protected]</CC>
<SUBJECT>My document is a tree.</SUBJECT>
<BODY>This is an example of a tree structure.</BODY>
</EMAIL>
<EMAIL>
<TO>[email protected]</TO>
<FROM>[email protected]</FROM>
<SUBJECT>XML is cool.</SUBJECT>
<BODY>This is a simple message.</BODY>
</EMAIL>
<EMAIL>
<TO>[email protected]</TO>
<FROM>[email protected]</FROM>
<SUBJECT>Here is that code.</SUBJECT>
<BODY>I send too many emails.</BODY>
</EMAIL>
</INBOX>

這需要更複雜的script才能得到和程式21-1相同型態的結果,也就是顯示在瀏覽器中的email內容。程式21-3從XML文件起頭開始,然後漸漸地由上往下巡行,並且顯示每一個節點的內容。如果有一個節點有子節點,其子節點將會被檢視,並且顯示其內容。圖21-3顯示執行此程式的結果。

<HTML>
<HEAD>
<TITLE>Code Listing 21-3</TITLE>
<SCRIPT LANGUAGE="JavaScript">
var xmlDoc = new ActiveXObject("microsoft.xmldom")
xmlDoc.async=false
xmlDoc.load("inbox.xml")
root=xmlDoc.documentElement
newHTML=""

function start(){
buildTree(root)
content.innerHTML=newHTML
}

function buildTree(passedNode){
var children = passedNode.childNodes.length
for (var j=0; j<children; j++){
Node=passedNode.childNodes.item(j)
if (Node.nodeName=="EMAIL"){ newHTML+=("<P>"+Node.nodeName+" "+j) }
if (!Node.hasChildNodes()){
newHTML+=( "<BR><B>"+Node.parentNode.nodeName+":</B> "+Node.text )
}
buildTree(Node)
}
}
</SCRIPT>
</HEAD>
<BODY οnlοad="start()">
<SPAN ID="content"></SPAN>
</BODY>
</HTML>

程式 21-3

圖21-3 顯示XML文件的內容

我們一起從頭到尾來看一下這個程式。當文件被載入後,script區塊會載入XML檔案,將XML的根元件設定給變數root,接著建立空白newHTML變數,這個變數等一下在script中會用到。當文件結束載入,在BODY標籤中的onload事件處理會呼叫start函式,此函式會輪流呼叫buildtree函式,並傳送XML根元件給它。

這個例子主要運作是由buildTree函式來完成的,這是一個遞回函式,也就是說當一些特殊情況發生時,它會自己呼叫自己。這個函式基本上可以檢視目前節點,及檢查每個節點多少個子節點。若節點含有子節點,這函式會再次呼叫自己一次,傳入第一個子節點給自己。一旦下達一個沒有子節點的節點,它會加入newHTML變數及一些HTML原始碼,來描述目前節點的資料,然後往上一層回到它的父節點。藉由重複這樣的動作,它可以巡行檢視整個資料樹。接著,來深入看一個函式的片段:

var children = passedNode.childNodes.length
for (var j=0; j<children; j++){

函式一開頭就找出目前有多少子節點,然後將值設定給children變數。下一行由一個for迴圈開始,它會針對目前節點的每一個子節點重複執行。

Node=passedNode.childNodes.item(j)
if (Node.nodeName=="EMAIL"){ newHTML+=("<P>"+Node.nodeName+" "+j) }
if (!Node.hasChildNodes()){
newHTML+=( "<BR><B>"+Node.parentNode.nodeName+":</B>

接著,目前的子節點會被設定給Node變數。由於我們希望資料中的每一個email都可以分開,因此加入了上面的第二行。若節點的名稱為 "EMAIL",則除了這個節點的名稱和號碼之外,還會加入段落標籤 <P>到newHTML中,我們也測試是否Node.parentNode==root,因為只有在root之下的元件纔有可能是EMAIL元件。

BuildTree(Node)
For迴圈的最後一行再次呼叫buildtree函數,並傳目前節點過去。最後,每個元件都呼叫了此函式。更彈性且有完整功能的XML tree 巡行程式可以在http://www.microsoft.com/gallery/sample/xml/tree_viewer/default.asp找到,請參閱Tools and Samples和XML Tree viewer部分。

您應該可以注意到,使用這些技巧可以讓HTML文件更加彈性且功能更強,雖然這個文件只是一個特定類型的XML文件範本而已。但是這樣的技巧卻讓HTML與XML能完美的互相補強。

錯誤處理
XML的物件模型提供了許多方法給設計者來處理 XML 文件所產生的錯誤。其中一個是文件物件的parseError性質,它提供了XML文件發生問題時的資訊,讓設計者可以進行處理。基本上,使用者可能不會需要去處理這樣子的錯誤。

ParseError性質提供了每個可能發生錯誤的程式碼。設計者可以使用這些程式做下列事情:

  • 幫忙為XML文件與script除錯。
  • 告知使用者問題所在,並提供建議的解決方案。
  • 將某種錯誤攔截,然後在背景修復錯誤。

下面的程式碼說明parseError如何告知使用者發生問題。

Var xmlDoc = new ActiveXObject("Microsoft.xmldom");
XmlDoc.load("email.xml");

If (xmlDoc.parseError.reason == " ") {
Alert("Document loaded successfully")
}
else {
alert("The Following error occurred:"+xmlDoc.parseError.errorCode)
}

這個技巧可以用於除錯和讓使用者可以避開錯誤。

XML Data Island
在剛剛的例子,我們將XML 當作一個資料來源,並將HTML當作顯示的方法。當HTML文件被顯示時,XML 與 HTML 會被當作是兩個互相影響的獨立文件。另一個選擇是使用XML data islands。Data islands可以讓設計者在HTML文件直接包括XML片段。不過對於這個方法的效果,目前有正反兩種意見,正面的意見是:

  • 您不需分離出XML文件
  • 您不需利用script載入XML資料
  • 您不需透過使用Object元素或ActiveXObject物件

另外也有一些負面的意見,端視如何使用data islands:

  • XML data 不再獨立於HTML檔案
  • 對於其他應用程式或HTML文件,XML data失去了可攜性
  • 如果XML的原始碼散落在HTML原始碼中,XML 也許會更難管理。XML Data Islands可以是行內XML或外部連結XML文件。

處理行內XML Data Islands
要使用行內XML Data Islands,只要很簡單地直接插入一段XML程式碼到HTML文件就好。XML文件的內容放在<XML></XML>這一組標籤中。為了示範,我們修改程式列表 21-1 ,將email.xml嵌入到html文件中,然後將程式碼改變成程式列表 21-4。產生的結果和先前的例子完全一樣,如圖21-1。

<HTML>
<HEAD>
<TITLE>Code Listing 21-4</TITLE>

<XML ID="email">
<EMAIL>
<TO>[email protected]</TO>
<FROM>[email protected]</FROM>
<CC>[email protected]</CC>
<SUBJECT>Basic email</SUBJECT>
<BODY>This is an XML-based email.</BODY>
</EMAIL>
</XML>

<SCRIPT LANGUAGE="JavaScript">
function start(){
xmlDoc=email
var root=xmlDoc.documentElement
todata.innerText=root.childNodes.item(0).text
fromdata.innerText=root.childNodes.item(1).text
ccdata.innerText=root.childNodes.item(2).text
subjectdata.innerText=root.childNodes.item(3).text
bodydata.innerText=root.childNodes.item(4).text
}
</SCRIPT>
</HEAD>
<BODY οnlοad="start()">
<B>To:</B> <SPAN ID="todata"></SPAN><BR>
<B>From:</B> <SPAN ID="fromdata"></SPAN><BR>
<B>CC:</B> <SPAN ID="ccdata"></SPAN><BR>
<B>Subject:</B> <SPAN ID="subjectdata"></SPAN><BR>
<B>Body:</B> <SPAN ID="bodydata"></SPAN><BR>
</BODY>
</HTML>

程式 21-4

首先注意當行內XML Data包含在<XML>標籤中,<XML>元素並不是根節點。反之,它是一個HTML標籤,讓瀏覽器可以辨別包含在<XML>標籤之內就會被當作是XML。也要注意一下<XML>標籤有ID屬性,所以它可以被script叫用。新的程式碼xmlDoc=email相等於使用XMLDOM ActiveXObject,然後會載入一個特定的XML文件。事實上,使用的還是同一個處理程式;只是用不同的方法來存取而已。除了行內XML Data Island,還有一個方法可以用連結外部的XML文件來使用<XML>標籤。

處理連結XML Data Islands
要利用<XML>標籤來連結XML文件,您只要使用<XML>標籤的SRC屬性就好。我們可以利用下面的程式碼,來取代上述的文件中之整個文件元素。

<XML ID="email" SRC="email.xml"></XML>

此執行結果和前面例子完全相同。這個好處在於XML資料仍然與html文件分離。本質上,這個方法處理的方式十分像ActiveX Control方式,除了瀏覽器必須負責處理control及載入文件以外。

<XML>標籤的屬性
<XML>標籤包含,某些額外的屬性,當文件載入後,發生的事件可提供更多的控制。
VALIDATEONPARSE 屬性指出當它被解析時,文件是否應該被確認。它的預設值為True。下面是一個例子:

<XML ID="xmlDoc" SRC="xmldoc.xml" VALIDATEPARSE="false"></XML>

ASYNC 屬性意指是否文件要非同步下載。它的預設值為True。下面是一個例子:

<XML ID="xmlDoc" SRC="xmldoc.xml" ASYNC="false"></XML>

XML是否為所有發生在web上問題的解決方案?或者只是個誇大的宣傳?事實上都不是。XML已經獲得不同領域的業界所支援,而不僅僅是在Web 上而已。這表示會有許多承諾,特別是在不同的瀏覽器都能支援XML的情況下。本章只是提供十分簡單的 XML 概略說明,您可以在W3C網站,及一本不錯的XML參考手冊( XML in action by William J. Pardi Microsoft Press) 中找到更多XML的資訊。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章