xhtml的昙花一现带来不少问题,它的目的是让html表现得更像xml,所以才叫xhtml。但是出师未捷身先死,我们讨论一下如何判定文档是XML吧。
印象中jQuery对此方法重复实现了许多次,应该比较权威,也说明这判定比较难搞。看jQuery1.42的实现:
var isXML = function(elem){
// documentElement is verified for cases where it doesn't yet exist
// (such as loading iframes in IE - #4833)
var documentElement = (elem ? elem.ownerDocument || elem : 0).documentElement;
return documentElement ? documentElement.nodeName !== "HTML" : false;
};
好,做一个实验:
window.onload = function(){
try{
var doc = document.implementation.createDocument(null, 'HTML', null);//只限标准浏览器,创建一个XML文档
alert(doc.documentElement)
alert(isXML(doc))//应该返回true
}catch(e){
alert("不支持creatDocument方法")
}
}
另一个实验:
评测结果,它能判定XHTML文档,但无法判定第一个元素为HTML的XML文档。
看来我们需要一些更可靠的特征侦探。我们知道IE的HTML不支持xpath,而XML支持,这个可以利用。对于标准浏览器,参见我另一篇博文《javascript 跨文档调用技术》提到的一系列方法。既然有createHTMLDocument,应该拥有HTMLDocument这个对象,标准浏览器向来比较慷慨,暴露了许多比较底层的方法供我们扩展,如__proto__, Node,Window, Element, HTMLElement什么的。测试一下,真的有这东西。
在火狐官网还看到这样一个判定,这是基于XUL的,仅对火狐有效。
//https://developer.mozilla.org/En/XML/Identifying_XML_elements_and_documents
function isXMLDoc (doc) {
var Ci = Components.interfaces;
// Remove the second condition if only wish to test for XML, not XUL
return (doc instanceof Ci.nsIDOMXMLDocument)||
(doc instanceof Ci.nsIDOMXULDocument);
}
不管怎么样,既然获知HTMLDocument这个类,就简单了。下面是我的实现:
var isXML = (function(){
if(-[1,]){
return function(doc){
return !(doc instanceof HTMLDocument)
}
}else{
return function(doc){
return "selectNodes" in doc
}
}
})();
下面是测试代码:
var createXML = function (str) {
if (typeof DOMParser !== "undefined") {
return (new DOMParser()).parseFromString(str, "application/xml");
}else if (ActiveXObject) {
var xml = new ActiveXObject("Microsoft.XMLDOM");
xml.async="false";
xml.loadXML(str);
return xml
}
}
window.onload = function(){
var xml = createXML('<HTML><body><book><title>司徒正美</title></book></body></HTML>');
alert(isXML(xml))
}
可能有人会问,为什么不用XMLDocumet?好问题,因为XMLDocumet在opera中支持得比较晚。大抵是opera9.6才支持,这是我以前在日本博客看到的数据。不过opera是个小众的浏览器,你大可以不管它比较旧的版本,而直接用XMLDocument。
补充一下,我以前是使用以下判定的,一样可行,但是要创建两个元素对象。在IE7中,没有加入DOM树的元素节点不会被回收,需要特殊处理一下,比较麻烦,遂放弃之。
var isXML = function (doc) {
return doc.createElement("p").nodeName !== doc.createElement("P").nodeName;
};
// Safari 2 missing document.compatMode property
// makes harder to detect Quirks vs. Strict mode
var isQuirks =
function(document) {
return (document.compatMode ?
(document.compatMode.indexOf('CSS') < 0) :
(function() {
var div = document.createElement('div'),
isStrict = div.style &&
(div.style.width = 1) &&
div.style.width != '1px';
div = null;
return !isStrict;
})());
},
// XML is functional in W3C browsers
isXML = 'xmlVersion' in doc ?
function(document) {
return !!document.xmlVersion ||
(/xml$/).test(document.contentType) ||
!(/html/i).test(document.documentElement.nodeName);
} :
function(document) {
return document.firstChild.nodeType == 7 &&
(/xml/i).test(document.firstChild.nodeName) ||
!(/html/i).test(document.documentElement.nodeName);
};
// reset and reused dynamically for each selection
isQuirksMode = isQuirks(doc),
// reset and reused dynamically for each selection
isXMLDocument = isXML(doc),
function isXML(context) {
context = context.ownerDocument || document;
return context.createElement("p").nodeName !== context.createElement("P").nodeName
}