判断是否XML文档

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

        }

你可能感兴趣的:(xml)