javascript快速入門25--瀏覽器中的XML

水之原發表於2013-12-04

開啟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解析錯誤:不符合的記號.預期:&lt;/child&gt;。 
    位置:file:///E:/XML/test.html 
    行:1,列:16:<sourcetext>&lt;root&gt;&lt;child&gt;&lt;/root&gt;
    ---------------^</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;
    };
}

 

相關文章