瀏覽器中的XML
打開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; }; }