如何使用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 ),可以使用DOMImplementation
的createHTMLDocument
方法,可以通过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') );