開啟XML
首先,直接從瀏覽器中開啟XML檔案,瀏覽器會對其進行格式良好性檢查,如果不符合XML語法規範則顯示出錯,如果格式良好,再檢查是否包含樣式表(CSS或XSL),如果包含樣式表,則用樣式表格式化XML文件然後顯示,如果沒有,則顯示經過格式化的XML原始碼(不同瀏覽器顯示方式不一樣).注意,瀏覽器只對XML進行格式良好性檢查,而不對其進行有效性檢查!如何在XML文件中引入樣式表?示例:
<?xml version="1.0" standalone="no"?> <?xml-stylesheet type="text/css" href="test.css"?>
如果是使用XSL,只需將上面的type屬性值改成text/xsl即可!
XMLHttpRequest物件的responseXML屬性
XMLHttpRequest物件的responseXML屬性用來獲取從伺服器端返回的XML檔案,如果沒有則為null.注意,只有在伺服器環境下,請求一個以.xml為字尾的檔案返回的才會是一個XML DOM,在本地請求一個XML檔案,返回的仍是文字檔案.如果要使用伺服器指令碼生成字串,要返回XML,必須加上一些頭資訊
//JS Code var xhr = XHR();//XHR為之前所寫的可以跨瀏覽器建立XMLHttpRequest物件的函式 xhr.open("get","test.php",true); xhr.onreadystatechange = function () { if (xhr.readyState==4 && xhr.status == 200) { //輸出root alert(xhr.responseXML.documentElement.nodeName);//可以使用DOM 2 Core的一些屬性和方法 } }; xhr.send(null); //PHP Code header("Content-Type:text/xml");//傳送MIME資訊 echo <<<XML <?xml version="1.0" encoding="gbk"?> <root /> XML;
更簡單的方法:直接載入XML檔案
瀏覽器也提供了直接載入XML檔案的方法,但也僅僅火狐與Windows平臺上的IE支援而已.同樣,兩者之間的實現也有很大的差別的!
IE中的XML DOM
微軟在JavaScript中引入了用於建立ActiveX物件的ActiveXObject類。ActiveXObject的建構函式只有一個引數——要進行例項化的ActiveX物件的字串代號。例如,XML DOM物件的第一個版本稱為Microsoft.XmlDom。所以,要建立這個物件的例項,使用以下程式碼:
var xmlDom = new ActiveXObject("Microsoft.XmlDom");
IE中的XML DOM支援的最新版本是5.0,IE中存在以下版本的XML DOM實現:
- Microsoft.XmlDom(最原始的)
- MSXML2.DOMDocument
- MSXML2.DOMDocument.3.0
- MSXML2.DOMDocument.4.0
- MSXML2.DOMDocument.5.0
自然地,只要可能,大家都會選擇最新的XML DOM的版本,因為新版會提高速度,新增一些新的功能如驗證等。但是,如果嘗試建立不存在於客戶端機器上的ActiveX物件,IE就會丟擲錯誤並停止所有執行。所以,為確保使用了正確的XML DOM版本,也為避免任何其他錯誤,我們可以建立一個函式來測試每個XML DOM字串,出現錯誤即捕獲:
function XMLDOM() { var xmlDomVers = [ "Microsoft.XmlDom", "MSXML2.DOMDocument", "MSXML2.DOMDocument.3.0", "MSXML2.DOMDocument.4.0", "MSXML2.DOMDocument.5.0" ]; for (var i=xmlDomVers.length-1;i>=0;i--) { try { var xmlDom = new ActiveXObject(xmlDomVers[i]); return xmlDom; } catch(e) {continue;} } }
接下來就是載入XML. 微軟的XML DOM有兩種載入XML的方法:loadXML()和load()。loadXML()方法可直接向XML DOM輸入XML字串.load()方法用於從伺服器上載入XML檔案。不過,load()方法只可以載入與包含JavaScript的頁面儲存於同一伺服器上的檔案,也就是說,不可以通過其他人的伺服器載入XML檔案。 load方法還有兩種載入檔案的模式:同步和非同步。以同步模式載入檔案時,JavaScript程式碼會等待檔案完全載入後才繼續執行程式碼;而以非同步模式載入時,不會等待,可以使用事件處理函式來判斷檔案是否完全載入了。預設情況下,檔案按照非同步模式載入。要進行同步載入,只需設定async特性為false:
//Only For IE var xmlDom = XMLDOM(); xmlDom.loadXML("<root />"); alert(xmlDom.documentElement.nodeName); var xml = XMLDOM(); xml.async = false;//同步載入 xml.load("test.xml"); alert(xml.documentElement.firstChild.nodeValue); //同步載入時需要使用readystatechange事件監聽 var xml2 = XMLDOM(); xml2.async=true;//可以不指定,預設是非同步載入的 xml2.onreadystatechange = function () {//必須在呼叫load方法前分配此事件處理函式 if (xml2.readyState==4) {//readyState的含義和XHR物件是一樣的 //注意這裡沒有使用this,因為IE下的ActiveXObject很特殊,使用this會出錯 alert(xml2.xml);//與innerHTML屬性類似,IE中的xml屬性返回XML字串形式的原始碼 //但注意,IE中的XMLDOM物件的xml屬性是隻讀的 } }; xml2.load("test.xml");
在嘗試將XML載入到XML DOM物件中時,無論使用loadXML()方法還是load()方法,都有可能出現XML格式不正確的情況。為解決這個問題,微軟的XML DOM的parseError的特性包含了關於解析XML程式碼時所遇到的問題的所有資訊。
parseError特性實際上是包含以下特性的物件:
- errorCode——表示所發生的錯誤型別的數字代號(當沒有錯誤時為0)
- filePos——錯誤發生在檔案中的位置
- line——遇到錯誤的行號
- linepos——在遇到錯誤的那一行上的字元的位置
- reason——對錯誤的一個解釋
- srcText——造成錯誤的程式碼
- url——造成錯誤的檔案的URL(如果可用)
當直接對parseError自身取值,它會返回errorCode的值,也就是說可以這樣進行檢查
if (xmlDom.parseError===0) { alert("沒有出錯!"); } else { var er = xmlDom.parseError; alert("XML解析出錯!錯誤資訊如下:\n\ 錯誤代號:"+er.errorCode+"\n\ 檔案:"+er.filePos+"\n\ 行:"++er.line+"\n\ 字元:"+er.linepos+"\n\ 相關資訊:"+er.reason+"\n\"); }
Mozilla中的XML DOM
與Mozilla其他方面一樣,它提供的XML DOM版本要比IE的更加標準。 Mozilla中的XML DOM實際上是它的JavaScript實現,也就是說它不僅與瀏覽器一起衍化,同時它能可靠地在Mozilla支援的所有平臺上使用。因此與不能在Macintosh上使用XML DOM的IE不同,Mozilla的支援跨越了平臺的界限。另外,Mozilla的XML DOM實現了支援DOM Level 2 的功能,而微軟的,僅支援DOM Level 1。
DOM標準指出,document.implementation物件有個可用的createDocument()方法。Mozilla嚴格遵循了這個標準,可以這樣建立XML DOM:
var xmlDom = document.implementation.createDocument("","",null);
createDocument()的三個引數分別是文件的名稱空間URL,文件元素的標籤名以及一個文件型別物件(總是為null,因為在Mozilla中還沒有對文件型別物件的支援)。前面這行程式碼建立一個空的XML DOM。要建立包含一個文件元素的XML DOM,只需將標籤名作為第二個引數:
var xmlDom = document.implementation.createDocument("","root",null);
這行程式碼建立了代表XML程式碼<root/>的XML DOM。如果在第一個引數中指定了名稱空間URL,可進一步定義文件元素:
var xmlDom = document.implementation.createDocument("http://www.x-do.org","root",null);
這行程式碼建立了表示<root xmlns="http://www.x-do.org"/>的XML DOM
與微軟的XML DOM不同,Mozilla只支援一個載入資料的方法:load()。Mozilla中的load()方法和IE中的load()工作方式一樣。只要指定要載入的XML檔案,以及同步還是非同步(預設)載入。如果同步載入XML檔案,程式碼基本上IE差不多:
var xmlDom = document.implementation.createDocument("","root",null); xmlDom.async = false;//同步載入 xmlDom.load("test.xml");
與IE不同的是,同步載入時,並沒有readychange事件,而只有load事件,並且只有載入完畢一種狀態!
var xmlDom = document.implementation.createDocument("","root",null); xmlDom.async = true;//非同步載入 xmlDom.onload = function () { alert(this.documentElement.childNodes.item(0).tagName); //對於JS,訪問節點列表既可以用item方法,又可用數字下標,而其它語言則不一定能使用下標 }; xmlDom.load("test.xml");
另外,麻煩的是,Mozilla的XML DOM不支援loadXML()方法。要將XML字串解析為DOM,必須使用DOMParser物件,使用其parseFromString方法傳入XML字串表現形式:
var xmlParser = new DOMParser(); var xmlDom = xmlParser.parseFromString("<root />","text/xml");//該方法返回一個XML DOM物件 //第二個引數text/xml也可以是application/xml,兩者都用來解析XML //還可以是application/xhtml+xml,用來解析XHTML,只能用這三種MIME
與直接解析XML字串相對應的獲取XML字串的方法,IE中XML DOM物件具有隻讀的xml屬性,而Mozilla 則沒有相對應的屬性,但是,Mozilla提供了可以用於同樣的目的的XMLSerializer物件:
var serializer= new XMLSerializer(); var xmlStr = serializer.serializeToString(xmlDom,"text/xml"); //xmlDom為一個XML DOM節點物件 //而text/xml也可為application/xml
對於XML 解析錯誤,Mozilla的實現方式非常麻煩,它不像IE那樣提供一個物件來表示錯誤,而是將錯誤資訊作為一個XML文件返回,要獲取具體的錯誤資訊,還必須用解析其中的字串!
var xmlParser = new DOMParser(); var xmlDom = xmlParser.parseFromString("<root><child></root>","text/xml"); alert(xmlDom.documentElement.nodeName);//將返回parsererror,因為文件解析出錯時 var serializer = new XMLSerializer(); var str = serializer.serializeToString(xmlDom,"text/xml"); alert(str);//將輸出類似下面內容 <parsererror xmlns="http://www.mozilla.org/newlayout/xml/parsererror.xml"> XML解析錯誤:不符合的記號.預期:</child>。 位置:file:///E:/XML/test.html 行:1,列:16:<sourcetext><root><child></root> ---------------^</sourcetext></parsererror>
而從其中抽取出諸如行號這些錯誤資訊,只好使用正規表示式了!但是由於瀏覽器的語言設定不同,使用正規表示式也是困難重重的! 可以看到,雖然Mozilla對XML DOM的實現更標準,但是使用起來是非常不方便的!
跨瀏覽器的XML DOM建構函式
說它跨瀏覽器,其實也僅僅是相容Mozilla與Windows上的IE而已,而對於其它瀏覽器,則可以降級,考慮使用XHR的responseXML,雖然XHR物件該屬性沒有提供什麼高階的方便的方法,但用於讀取XML已經足夠了!
if (document.implementation && document.implementation.createDocument) { //W3C var getXMLDOM=function () {//獲取一個XMLDOM物件 return document.implementation.createDocument("","",null); }, loadXMLFile=function (xmlDom,url,callback) { if (xmlDom.async===true) { xmlDom.onload=function () { if (xmlDom.documentElement.nodeName=="parsererror") { throw new Error("XML Parse Error:"+xmlDom.documentElement.firstChild.nodeValue); } else { callback.call(xmlDom); } }; } xmlDom.load(url); return xmlDom; }, loadXMLString=function (xmlDom,s) { var p = new DOMParser(); var newDom=p.parseFromString(s,"text/xml"); if (newDom.documentElement.nodeName=="parsererror") { throw new Error("XML Parse Error:"+newDom.documentElement.firstChild.nodeValue); } while (xmlDom.firstChild) { xmlDom.removeChild(xmlDom.firstChild); } for (var i=0,n;i<newDom.childNodes.length;i++) { n=xmlDom.importNode(newDom.childNodes[i],true); //importNode用於把其它文件中的節點匯入到當前文件中 //true引數同時匯入子節點 xmlDom.appendChild(n); } return xmlDom; }, getXML=function (xmlNode) { var s= new XMLSerializer(); return s.serializeToString(xmlNode,"text/xml"); }; } else if (window.ActiveXObject) { //IE var getXMLDOM=function () { return new ActiveXObject("Microsoft.XmlDom"); },loadXMLFile=function (xmlDom,url,callback) { xmlDom.onreadystatechange=function () { if (xmlDom.readyState===4) { if (xmlDom.parseError.errorCode===0) { callback.call(xmlDom); } else { throw new Error("XML Parse Error:"+xmlDom.parseError.reason); } } }; xmlDom.load(url); return xmlDom; },loadXMLString=function (xmlDom,s) { xmlDom.loadXML(s); if (xmlDom.parseError.errorCode!==0) { throw new Error("XML Parse Error:"+xmlDom.parseError.reason); } return xmlDom; }, getXML=function (xmlNode) { return xmlNode.xml; }; }