如何使用JavaScript创buildDocument对象

基本上这是一个问题,如何在javascript中dynamic地从HTML中构build一个Document对象?

规范中定义了两个方法,DOM Core Level 2的createDocument和HTML5的createHTMLDocument 。 前者创build一个XML文档(包括XHTML),后者创build一个HTML文档。 两者都作为函数驻留在DOMImplementation接口上。

 var impl = document.implementation, xmlDoc = impl.createDocument(namespaceURI, qualifiedNameStr, documentType), htmlDoc = impl.createHTMLDocument(title); 

实际上,这些方法相当年轻,只有在最近的浏览器版本中才能实现。 根据http://quirksmode.org和MDN ,以下浏览器支持createHTMLDocument

  • Chrome 4
  • Opera 10
  • Firefox 4
  • Internet Explorer 9
  • Safari 4

有趣的是,您可以(使用ActiveXObject )在旧版本的Internet Explorer中创build一个HTML文档:

 var htmlDoc = new ActiveXObject("htmlfile"); 

生成的对象将是一个新的文档,可以像任何其他文档一样操作。

假设你试图从标记和内容types的string中创build一个完全parsing的Document对象,你也碰巧知道(也许是因为你从xmlhttprequest获得了html,从而得到了Content-Type http中的content-type头文件;可能通常是text/html ) – 应该是这样简单的:

 var doc = (new DOMParser).parseFromString(markup, mime_type); 

在一个理想的未来世界中,浏览器的DOMParser实现和它们的文档渲染一样强大而且胜任 – 也许这对于未来的HTML6标准工作来说是一个好的梦想。 事实certificate,目前没有浏览器做,但。

你可能有一个更容易(但仍然混乱)的问题,有一个你想获得一个完全parsing的Document对象的HTMLstring。 这里是另一个如何做到这一点,这也应该在所有的浏览器工作 – 首先你做一个HTML Document对象:

 var doc = document.implementation.createHTMLDocument(''); 

然后用你的HTML片段填充它 :

 doc.open(); doc.write(html); doc.close(); 

现在你应该在doc中有一个完全parsing的DOM,你可以运行alert(doc.title) ,使用doc.querySelectorAll('p')或者使用doc.evaluate cssselect器。

这实际上适用于Chrome和Safari等现代WebKit浏览器(我只是分别在Chrome 22和Safari 6中testing过) – 这里是一个例子,它取得当前页面的源代码,在一个新的文档variablessrc重新创build它,读出它的标题,用相同源代码的html引用版本覆盖它,并在iframe中显示结果: http : //codepen.io/johan/full/KLIeE

可悲的是,我不认为其他当代浏览器还有相当稳定的实现。

根据规范( doc ),可以使用DOMImplementationcreateHTMLDocument方法,可以通过document.implementation访问,如下所示:

 var doc = document.implementation.createHTMLDocument('My title'); var body = document.createElementNS('http://www.w3.org/1999/xhtml', 'body'); doc.documentElement.appendChild(body); // and so on 
  • jsFiddle: http : //jsfiddle.net/9Fh7R/
  • DOMImplementation MDN文档: https : //developer.mozilla.org/en/DOM/document.implementation
  • DOMImplementation.createHTMLDocument MDN文档: https : //developer.mozilla.org/En/DOM/DOMImplementation.createHTMLDocument

随着DOMparser的发展,更新了2014年的答案。 这可以在我能find的所有当前浏览器中使用,并且应该在早期版本的IE中使用ecManaut的document.implementation.createHTMLDocument('')方法。

从本质上讲,IE,Opera,Firefox都可以parsing为“text / html”。 Safariparsing为“text / xml”。

不过要注意不能容忍的XMLparsing。 Safariparsing将在非断续空格和其他HTML字符(法语/德语重音符)指定的符号分解。 下面的代码并不是单独处理每个字符,而是用无意义的string“j!J!”replace所有的&符号。 当在浏览器中显示结果时,这个string可以随后重新呈现为&符号(我发现更简单,而不是尝试处理“假”XMLparsing中的&符号)。

 function parseHTML(sText) { try { console.log("Domparser: " + typeof window.DOMParser); if (typeof window.DOMParser !=null) { // modern IE, Firefox, Opera parse text/html var parser = new DOMParser(); var doc = parser.parseFromString(sText, "text/html"); if (doc != null) { console.log("parsed as HTML"); return doc } else { //replace ampersands with harmless character string to avoid XML parsing issues sText = sText.replace(/&/gi, "j!J!"); //safari parses as text/xml var doc = parser.parseFromString(sText, "text/xml"); console.log("parsed as XML"); return doc; } } else { // older IE doc= document.implementation.createHTMLDocument(''); doc.write(sText); doc.close; return doc; } } catch (err) { alert("Error parsing html:\n" + err.message); } } 

以下在大多数常见浏览器中都可以使用,但不是一些。 这应该是多么简单(但不是):

 // Fails if UA doesn't support parseFromString for text/html (eg IE) function htmlToDoc(markup) { var parser = new DOMParser(); return parser.parseFromString(markup, "text/html"); } var htmlString = "<title>foo bar</title><div>a div</div>"; alert(htmlToDoc(htmlString).title); 

为了说明用户代理变幻莫测,下面可能会更好(请注意归属地):

 /* * DOMParser HTML extension * 2012-02-02 * * By Eli Grey, http://eligrey.com * Public domain. * NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. * * Modified to work with IE 9 by RobG * 2012-08-29 * * Notes: * * 1. Supplied markup should be avalid HTML document with or without HTML tags and * no DOCTYPE (DOCTYPE support can be added, I just didn't do it) * * 2. Host method used where host supports text/html */ /*! @source https://gist.github.com/1129031 */ /*! @source https://developer.mozilla.org/en-US/docs/DOM/DOMParser */ /*global document, DOMParser*/ (function(DOMParser) { "use strict"; var DOMParser_proto; var real_parseFromString; var textHTML; // Flag for text/html support var textXML; // Flag for text/xml support var htmlElInnerHTML; // Flag for support for setting html element's innerHTML // Stop here if DOMParser not defined if (!DOMParser) return; // Firefox, Opera and IE throw errors on unsupported types try { // WebKit returns null on unsupported types textHTML = !!(new DOMParser).parseFromString('', 'text/html'); } catch (er) { textHTML = false; } // If text/html supported, don't need to do anything. if (textHTML) return; // Next try setting innerHTML of a created document // IE 9 and lower will throw an error (can't set innerHTML of its HTML element) try { var doc = document.implementation.createHTMLDocument(''); doc.documentElement.innerHTML = '<title></title><div></div>'; htmlElInnerHTML = true; } catch (er) { htmlElInnerHTML = false; } // If if that failed, try text/xml if (!htmlElInnerHTML) { try { textXML = !!(new DOMParser).parseFromString('', 'text/xml'); } catch (er) { textHTML = false; } } // Mess with DOMParser.prototype (less than optimal...) if one of the above worked // Assume can write to the prototype, if not, make this a stand alone function if (DOMParser.prototype && (htmlElInnerHTML || textXML)) { DOMParser_proto = DOMParser.prototype; real_parseFromString = DOMParser_proto.parseFromString; DOMParser_proto.parseFromString = function (markup, type) { // Only do this if type is text/html if (/^\s*text\/html\s*(?:;|$)/i.test(type)) { var doc, doc_el, first_el; // Use innerHTML if supported if (htmlElInnerHTML) { doc = document.implementation.createHTMLDocument(""); doc_el = doc.documentElement; doc_el.innerHTML = markup; first_el = doc_el.firstElementChild; // Otherwise use XML method } else if (textXML) { // Make sure markup is wrapped in HTML tags // Should probably allow for a DOCTYPE if (!(/^<html.*html>$/i.test(markup))) { markup = '<html>' + markup + '<\/html>'; } doc = (new DOMParser).parseFromString(markup, 'text/xml'); doc_el = doc.documentElement; first_el = doc_el.firstElementChild; } // RG: I don't understand the point of this, I'll leave it here though // In IE, doc_el is the HTML element and first_el is the HEAD. // // Is this an entire document or a fragment? if (doc_el.childElementCount == 1 && first_el.localName.toLowerCase() == 'html') { doc.replaceChild(first_el, doc_el); } return doc; // If not text/html, send as-is to host method } else { return real_parseFromString.apply(this, arguments); } }; } }(DOMParser)); // Now some test code var htmlString = '<html><head><title>foo bar</title></head><body><div>a div</div></body></html>'; var dp = new DOMParser(); var doc = dp.parseFromString(htmlString, 'text/html'); // Treat as an XML document and only use DOM Core methods alert(doc.documentElement.getElementsByTagName('title')[0].childNodes[0].data); 

不要被代码量拖延,有很多评论,它可以缩短很多,但变得不那么可读。

哦,如果标记是有效的XML,生活就简单多了:

 var stringToXMLDoc = (function(global) { // W3C DOMParser support if (global.DOMParser) { return function (text) { var parser = new global.DOMParser(); return parser.parseFromString(text,"application/xml"); } // MS ActiveXObject support } else { return function (text) { var xmlDoc; // Can't assume support and can't test, so try..catch try { xmlDoc = new ActiveXObject("Microsoft.XMLDOM"); xmlDoc.async="false"; xmlDoc.loadXML(text); } catch (e){} return xmlDoc; } } }(this)); var doc = stringToXMLDoc('<books><book title="foo"/><book title="bar"/><book title="baz"/></books>'); alert( doc.getElementsByTagName('book')[2].getAttribute('title') );