不同瀏覽器對XML的解析問題(解決了多天困擾的問題)

[轉自]http://book.51cto.com/art/200806/75667.htm
 
第11章  Ajax標準通信載體——XML語言
XML語言可以有複雜的層次性結構,因此它可以表示任意複雜的數據信息。同時XML是用純文本編寫的,便於人工閱讀和修改。在Ajax中,XML起着很重要的作用,本章將集中講解XML的相關知識。
11.1  XML概述
XML是Extensible Markup Language(取Extensible的X)的縮寫,即可擴展標記語言。它是W3C提出的一種用來描述數據的標準語言。它的通性使開發人員無需爲每個應用程序都單獨設計一種數據表示,這給不同類型程序間的數據通信帶來了很大的方便。比如Web服務通信中的SOAP協議使用的就是XML語言,網絡上到處可見的RSS也是基於XML的。
11.1.1  一個簡單的XML實例
從某種程度上說,XML與HTML的語法相當類似,它們都是由文本以及包含文本的標記組成的。下面是一段簡單的HTML代碼,其中<u>和<i>標記分別表示下劃線顯示和斜體顯示效果,代碼如下:
<dl>
<dt><u>標題</u></dt>
<dd><i>條目1</i></dd>
<dd><i>條目2</i></dd>
<dd><i>條目3</i></dd>
</dl>
運行這段代碼的效果如圖11.1所示。
下面是一段內容類似的XML代碼:
<?xml version="1.0" encoding="GB2312"?>
<items>
<title>標題</title>
<item>條目1</item>
<item>條目2</item>
<item>條目3</item>
</items>
運行這段程序的效果如圖11.2所示。
對比以上兩段代碼,可以發現幾個不同點。一是HTML中的標記都是特定的,每個標記都有特定含義;而XML中的標記則完全可以由用戶自己定義。二是HTML的標記主要用於說明數據的顯示方式,比如下劃線、斜體、列表等;而XML只關心數據的內容,不關心數據如何顯示。
提示:事實上,W3C規定的另外一個標準XSLT可以爲XML指定顯示方式。
11.1.2  XML的基本概念
按照W3C的DOM模型,XML中的基本單位稱爲結點(Node),結點可以有很多種類型,比如文檔(Document)、元素(Element)、屬性(Attribute)、文本(Text)等。
文檔結點是整個文檔最上層的結點,即根結點;元素結點可以包含子結點,子結點可以是屬性、文本甚至一個元素,即元素是可以嵌套的。比如上面的例子中,“<title>標題</title>”是一個元素,整個“<items>……</items>”也是一個元素。其中title這個元素的內容“標題”就是一個文本結點,它在DOM模型中作爲title的子結點出現。整個XML文檔就形成了一個結點樹的結構。
而元素結點的標識是由標記(Tag)來完成的。XML中的標記是由小於號(<)開始,以大於號(>)結束。對於標記內容來說,若以斜槓(/)開頭,則認爲這是一個結束標記,表示一個元素的結束。否則這個標記就是一個開始標記,表示一個元素的開始。同時,在標記內也可以附加一些屬性(Attribute),代碼爲:
<item name="itemname"></item>
這裏,爲item標記附加了一個name屬性,其值爲itemname。
注意:有些標記不包含任何內容,可以直接在開始標記的結束符號(大於號)前加一個斜槓表示該標記的結束,如上面屬性的例子可以寫爲:<item name="itemname"/>
在編寫XML的時候,需要特別注意以下幾個問題。
• XML標記是區別大小寫的,這與HTML不同;
• XML的屬性值一定要加引號(單引或雙引),而HTML中可以忽略;
• XML中的所有標記都要“有始有終”,而HTML中的某些標記可以沒有結束標記,如<br>、<img>;
• “<![CDATA[”和“]]>”可以用來包含有特殊字符(如大於號小於號)的文本,如<![CDATA[<item>text</item>]]>在XML就表示<item>text</item>這一段文本(注意:這裏的item因爲被CDATA包含,已經不是一個標記了)。
11.1.3  XML在Ajax中的作用
XML的優勢在於其通用性,和較強的表達能力,因此用XML作爲數據交換的一個標準格式無疑具有一定的吸引力。Ajax中客戶端與服務器端之間的通信也可以採用這種辦法。
實際上,在Ajax最初的定義中,XML是作爲一個客戶端與服務器端的通信載體出現的。例如可以將客戶端對服務器端的請求用XML包裝起來,也可以將客戶端提交的一個表單內容轉化成一個XML片段傳給服務器端進行處理。下面的XML片段可以代表一個註冊表單提交的內容,代碼如下:
<id>Richard</id>
<password>pass123</password>
<sex>男</sex>
<email>[email][email protected][/email]</email>
<address>南京大學鼓樓校區</address>
在Ajax中使用XML的另一個原因是,它可以進一步降低客戶端和服務器端的耦合性。由於XML的中立性,客戶端和服務器端使用的開發語言、平臺等一些細節都有自由選擇的空間,這與客戶端服務器架構的理念是一致的,即客戶端和服務器端應當相對獨立。
11.2  使用Javascript操作XML
11.2.1  MSXML介紹
在IE中,微軟提供了MSXML控件來支持XML操作。每個系統安裝的MSXML版本都有可能不同,因此在編寫程序的時候要注意版本的確定。目前MSXML從舊到新有以下幾個版本。
• Microsoft.XmlDom (最初的版本)
• MSXML2.DOMDocument
• MSXML2.DOMDocument.3.0
• MSXML2.DOMDocument.4.0
• MSXML2.DOMDocument.5.0
下面的函數用來獲取一個系統中可用的最新版本的DomDocument對象,若都不存在,則返回空,代碼如下:
function createDomDoc()
{
var signatures=["Msxml2.DOMDocument.5.0",
"Msxml2.DOMDocument.4.0",
"Msxml2.DOMDocument.3.0",
"Msxml2.DOMDocument",
"Microsoft.XmlDom"];
for(var i=0;i<signatures.length;i++)
{
try{
var domDoc = new ActiveXObject(signatures[i]);
return domDoc;
} catch(e) {
//忽略錯誤,繼續循環嘗試下一個版本
}
}
return null;
}
11.2.2  在IE瀏覽器中創建XML片段
下面介紹如何通過DomDocument對象創建一個XML片段,以11.1.3節中的XML片段爲例。下面是代碼,返回的則是XML文本。
function createXml(doc)
{
var root = doc.createElement("items");
var title = doc.createElement("title");
title.text = '標題';
root.appendChild(title);    //添加title子結點
for(var i=0;i<3;i++)
{
var item = doc.createElement("item");
item.text = '條目'+i;
root.appendChild(item);   //添加item子結點
}
doc.appendChild(root);    //設置root結點
return doc.xml;
}
在這段代碼中,createElement方法用來建立一個新的元素結點,參數是這個結點標記的名稱。結點的text屬性可以用來設置其內容(嚴格說,就是設置其文本子結點的內容)。
appendChild方法可以在某個元素結點下添加子結點。在創建XML片段的時候,需要使用該方法將構建好的XML附加到DomDocument對象上。XML屬性則可以將DomDocument序列化,使其成爲一段文本。
在程序中加入下列執行代碼:
var domDoc = createDomDoc();
if(domDoc!=null)
{
var xml=createXml(domDoc);
alert(xml);
}
else
{
alert('未安裝MSXML控件');
}
運行結果如圖11.3所示。
圖11.3  通過XML DOM對象創建的XML文本
11.2.3  在IE瀏覽器中解析XML文本
下面介紹如何通過DomDocument對象來解析已有的XML文本。在IE中有2種導入XML文本的辦法。一種是通過load方法,其語法代碼如下。
domDoc.load("test.xml"); //導入test.xml文件中的內容
該方法只能導入JavaScript所在的本地文件,而不支持遠程導入。
第二種方法是通過loadXML方法直接導入,代碼是:
xml = "";
domDoc.loadXML(xml); //直接解析xml中包含的XML文本
另外,由於解析XML有時會花費較長的時間,MSXML還提供了異步機制,代碼如下:
domDoc.async = true; //異步調用
domDoc.onreadystatechange = function ()  //觸發函數
{
if(domDoc.readyState==4) {
doc = domDoc;
document.write("
");
var root = doc.documentElement;
document.write("
"+root.childNodes.item(0).text+"");
for(var i=1;i{
node = root.childNodes.item(i);
document.write("
"+node.text+"");
}
document.write("
");
}
};
domDoc.loadXML(xml);
通過這段代碼可以看出:設置DomDocument的async屬性可以進行異步解析;childNodes屬性含有一個包含所有子結點的列表,可以通過childNodes.item(i)來獲取索引值爲i的子結點;通過childNodes的length屬性可以獲得子結點的個數;結點的text屬性則可以用來獲取某個元素結點的內容(或者說是其文本子結點的內容)。
另外,觸發函數中的readyState取值有其特定的含義。
• 1:表示正在載入,還沒開始解析;
• 2:表示數據已經載入完畢,開始解析,但是DOM仍不可用;
• 3:表示一些數據已經解析完成,DOM已經可以使用,但還不完整,只包含已解析部分的數據。另外,此時的DOM是隻讀的;
• 4:表示數據解析已經全部完成,DOM已經可以正常使用。
運行這段代碼,將會得到如圖11.4所示的效果。
通過運行的結果可以看出,觸發函數生成的實際上就是本章最開始給出的HTML代碼。
11.2.4  使用Mozilla瀏覽器支持的DOM模型創建XML片段
在基於Mozilla的瀏覽器中(如Mozilla、Firefox、Netscape 6+等),對XML操作的支持是集成在瀏覽器內部的,這與IE瀏覽器使用外部控件的方式不同。
Mozilla瀏覽器的DOM模型對XML的操作方式也與IE瀏覽器有所不同,IE瀏覽器中的XML操作均集成在DomDocument對象中,而Mozilla瀏覽器中對XML的操作主要可以分爲3個對象。
• Document對象:主要存放XML的數據及其結構;
• XMLSerializer對象:負責Document對象的序列化;
• DOMParser對象:負責解析XML文本。
創建一個XML片段,代碼如下:
function createXml(doc)
{
var root = doc.createElement("items");
var title = doc.createElement("title");
title.textContent = '標題'; //注意Mozilla瀏覽器中使用的是textContent屬性
root.appendChild(title);
for(var i=0;i<3;i++)
{
var item = doc.createElement("item");
item.textContent = '條目'+i;
root.appendChild(item);
}
doc.appendChild(root);
var serializer = new XMLSerializer(); //序列化方式也與IE瀏覽器中不同
var xml = serializer.serializeToString(doc);
return xml;
}
var domDoc = document.implementation.createDocument("", "", null); //創建Document對象
var xml=createXml(domDoc);
alert(xml);
Document對象的創建是通過createDocument來進行的,createDocument是DOM模型規定的一個標準方法,它的原型代碼如下:
Document createDocument(in DOMString namespaceURI,
in DOMString qualifiedName,
in DocumentType doctype) raises(DOMException);
其中namespaceURI爲文檔的名字空間,qualifiedName是文檔的限定名,docType則是文檔的類型。一般情況下全部傳空值就可以了。上述代碼在Firefox瀏覽器運行的結果如圖11.5所示。
圖11.5  Firefox瀏覽器下運行XML DOM對象
可以看出,在Mozilla瀏覽器中對XML的操作實際上跟IE瀏覽器中是類似的,兩者均是W3C的DOM模型的一個實現。但是兩者也有一些不同。
• 一是IE瀏覽器中結點的text屬性在Mozilla瀏覽器中變成了textContent屬性;
• 二是序列化。IE瀏覽器中的序列化簡單地使用xml屬性即可,Mozilla瀏覽器中則需要引入XMLSerializer對象。
爲了提高可移植性,可以不使用text或textContent屬性,而利用文本子結點來創建XML片段,代碼如下:
var text = doc.createTextNode("條目"+i);
item.append(text);
11.2.5  使用Mozilla瀏覽器支持的DOM模型解析XML片段
下面介紹在Mozilla瀏覽器中解析XML的方式。
function traverse(doc)
{
document.write("<dl>");
var root = doc.documentElement;
document.write("<dt><u>"+root.childNodes.item(0).textContent+"</u></dt>");
for(var i=1;i<root.childNodes.length;i++)
{
node = root.childNodes.item(i);
document.write("<dd><i>"+node.textContent+"</i></dd>");
}
document.write("</dl>");
}
var parser = new DOMParser();
var doc = parser.parseFromString(xml, "text/xml");
traverse(doc);
這段解析XML的代碼與IE瀏覽器中的也非常類似,其運行結果如圖11.6所示。
圖11.6  Firefox瀏覽器運行XML DOM對象
11.2.6  基於Javascript的XML解析程序
在IE瀏覽器和Mozilla瀏覽器中操作XML的2種辦法都是基於DOM模型的,功能都相當強大,然而2個平臺上的可移植性卻是個問題。可以通過JavaScript開發一個解析程序,來解決這個可移植性的問題。在國外,已經有人寫出了類似的程序,稱做xparse。
提示:關於xparse,可以在[url]http://jeremie.com/Dev/XML/[/url]找到其主頁。
下載xparse以後可以直接使用,但是要注意,xparse只提供讀操作。下面是一段解析XML文本的示例代碼,這段代碼在IE瀏覽器和Firefox瀏覽器中均運行正常。
<script src="xparse.js"></script>
<script>
var xml = "<items><title>標題</title><item>條目0</item><item>條目1</item><item>條目2</item></items>";
var tag = Xparse(xml);
var root = tag.contents[0];
document.write("<dl>");
document.write("<dt><u>"+root.contents[0].contents[0].value+"</u></dt>");
for(var i=1;i<root.contents.length;i++)
{
document.write("<dd><i>"+root.contents[i].contents[0].value+"</i></dd>");
}
document.write("</dl>");
</script>
運行後可以發現運行結果與前面2種方法解析的完全相同。
xparse並不遵循DOM規範,因此使用起來比較困難,可讀性也較差。contents屬性相當於DOM中的childNodes屬性,每個結點常用的屬性包括value和type,分別表示結點的值和類型。
注意:xparse沒有提供類似text或者textContent的屬性,因此代碼中使用2個連續的contents來取得文本子結點。
xparse解決了移植性問題,但是由於它是使用JavaScript編寫的,與IE和Mozilla的二進制代碼相比,其效率必然較低。而且,由於其缺乏對DOM規範的支持,使用很不方便。但對於Ajax而言,在傳輸的數據量都不會太大的情況下,xparse仍然不失爲一種好的解決方案。
 

0

收藏

phelpszy

31篇文章,6W+人氣,0粉絲

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