瀏覽器解析 XML 的不同行為
一個 XML 文件長這個樣子:一個文件類型宣告 (<?xml ?>
)、一個根目錄 element 包含其他的 element。所以當 XMLHttpRequest 物件抓遠端的 XML 回來解析的時候,obj.responseXML 這個 XMLDocument Object 的 .childNodes.length 應該是 1 —— .firstChild 就是 root element 。
問題來啦:以上看似合理的 XML parsing 只發生在 Mozilla 上面。在 IE 裡面 childNodes.length 是 2,firstChild.nodeName 會傳回 … ?xml
!這是怎樣?
那改用 .lastChild 去拿 root element 好了,這總不會出錯了吧。嘿嘿,不行 —— Opera 的 obj.responseXML 更有趣:childNodes.length = 2 ,第一個 childNode 是 ?xml、第二個是 root、第三個是 … #text,nodeValue是長度 0 空字串。我檢查過,這絕對不是 Server 端的問題,因為那邊是用 PHP DOM 在生 well-formed XML 的。
最後我的解法還是用 obj.responseXML.lastChild 拿 root,不過在之前先經過一個判斷式:如果 .lastChild.nodeName == ‘#text’ 就做 removeChild 的動作。
這個解析 XML 的差異是因為各家瀏覽器 XMLHttpRequest 物件行為的不同,與 prototype.js 無關。prototype.js 只做 warpper 而已,裡面搞成這樣它應該是不知道。
還有另外一種解法是不要做 AJAX —— 做 AJAteXt,叫伺服器傳文字進來,再從 obj.responseText 抓出來處理。不是很正統而且還需要而額外寫解析函式的方法,但 GMail 好像就是這樣在抓信件內文的。
XMLHttpRequest on different browsers parses XML in different ways. An XMLDocument Object contains a <?xml ?> doctype declaration and a root element. Anything else should be child nodes under the root. Thus, when the XML file is fetched, obj.responseXML.childNodes.length
should return 1, and firstChild should return the root element.
Sounds right? Not quite. What described above only occurs in Mozilla. In poor-designed IE6, childNodes.length returns 2 — firstChild.nodeName returns ?xml
. Opera behaviors even weirder; childNodes.length returns 3, first two are same as IE, and the their one is a #text
with zero-length string nodeValue.
I ended up using lastChild to retrive the root element after checking its nodeName; if lastChild.nodeName == ‘#test’ { removeChiid(); } .
The other solution is to abandon AJAX – use AJAteXt instead. By parse responseText on your own code, you could avoid these kind of inconsistent behaviors. Kind of non-standard method, but AFAIK, Gmail does use AJAteXt to retrieve mail text.