提问人:stage 提问时间:5/14/2012 最后编辑:isherwoodstage 更新时间:10/25/2023 访问量:754839
使用 JS 解析 HTML 字符串
Parse an HTML string with JS
问:
我想解析一个包含 HTML 文本的字符串。我想在 JavaScript 中做到这一点。
我尝试了纯 JavaScript HTML 解析器库,但它似乎解析了我当前页面的 HTML,而不是从字符串中解析。因为当我尝试下面的代码时,它会更改我页面的标题:
var parser = new HTMLtoDOM("<html><head><title>titleTest</title></head><body><a href='test0'>test01</a><a href='test1'>test02</a><a href='test2'>test03</a></body></html>", document);
我的目标是从我像字符串一样阅读的 HTML 外部页面中提取链接。
你知道一个API来做到这一点吗?
答:
创建一个虚拟 DOM 元素并将字符串添加到其中。然后,您可以像任何 DOM 元素一样操作它。
var el = document.createElement( 'html' );
el.innerHTML = "<html><head><title>titleTest</title></head><body><a href='test0'>test01</a><a href='test1'>test02</a><a href='test2'>test03</a></body></html>";
el.getElementsByTagName( 'a' ); // Live NodeList of your anchor elements
编辑:添加一个jQuery答案来取悦粉丝!
var el = $( '<div></div>' );
el.html("<html><head><title>titleTest</title></head><body><a href='test0'>test01</a><a href='test1'>test02</a><a href='test2'>test03</a></body></html>");
$('a', el) // All the anchor elements
评论
document.createElement('html');
<head>
<body>
parse()
解决方案更可重用且更优雅。
如果你愿意使用jQuery,它有一些很好的工具,可以从HTML字符串创建分离的DOM元素。然后可以通过通常的方式查询这些,例如:
var html = "<html><head><title>titleTest</title></head><body><a href='test0'>test01</a><a href='test1'>test02</a><a href='test2'>test03</a></body></html>";
var anchors = $('<div/>').append(html).find('a').get();
编辑 - 刚刚看到@Florian的答案是正确的。这基本上就是他所说的,但使用jQuery。
var doc = new DOMParser().parseFromString(html, "text/html");
var links = doc.querySelectorAll("a");
评论
以下函数将返回:parseHTML
a
文档
(当文件以 doctype 开头时)。a DocumentFragment
,当文件不以 doctype 开头时。
代码:
function parseHTML(markup) {
if (markup.toLowerCase().trim().indexOf('<!doctype') === 0) {
var doc = document.implementation.createHTMLDocument("");
doc.documentElement.innerHTML = markup;
return doc;
} else if ('content' in document.createElement('template')) {
// Template tag exists!
var el = document.createElement('template');
el.innerHTML = markup;
return el.content;
} else {
// Template tag doesn't exist!
var docfrag = document.createDocumentFragment();
var el = document.createElement('body');
el.innerHTML = markup;
for (i = 0; 0 < el.childNodes.length;) {
docfrag.appendChild(el.childNodes[i]);
}
return docfrag;
}
}
如何使用 :
var links = parseHTML('<!doctype html><html><head></head><body><a>Link 1</a><a>Link 2</a></body></html>').getElementsByTagName('a');
评论
trim
这很简单:
const parser = new DOMParser();
const htmlDoc = parser.parseFromString(txt, 'text/html');
// do whatever you want with htmlDoc.getElementsByTagName('a');
根据 MDN 的说法,要在 chrome 中执行此操作,您需要像这样解析为 XML:
const parser = new DOMParser();
const htmlDoc = parser.parseFromString(txt, 'text/xml');
// do whatever you want with htmlDoc.getElementsByTagName('a');
webkit 目前不支持它,您必须遵循 Florian 的答案,并且在大多数情况下,它无法在移动浏览器上运行。
编辑:现在得到广泛支持
评论
documentURL
window
new DOMParser
parse()
解决方案更具可重用性,并且特定于 HTML。但是,如果您需要 XML 文档,这很好。
在 Chrome 和 Firefox 中解析 HTML 的最快方法是 Range#createContextualFragment:
var range = document.createRange();
range.selectNode(document.body); // required in Safari
var fragment = range.createContextualFragment('<h1>html...</h1>');
var firstNode = fragment.firstChild;
我建议创建一个帮助程序函数,该函数使用 createContextualFragment(如果可用),否则回退到 innerHTML。
基准:http://jsperf.com/domparser-vs-createelement-innerhtml/3
评论
innerHTML
<img>
onerror
编辑:下面的解决方案仅适用于HTML“片段”,因为html,head和body已被删除。我想这个问题的解决方案是 DOMParser 的 parseFromString() 方法:
const parser = new DOMParser();
const document = parser.parseFromString(html, "text/html");
对于 HTML 片段,此处列出的解决方案适用于大多数 HTML,但在某些情况下,它不起作用。
例如,尝试解析 。这不适用于 div.innerHTML 解决方案、DOMParser.prototype.parseFromString 或 range.createContextualFragment 解决方案。td 标签丢失,只剩下文本。<td>Test</td>
只有jQuery可以很好地处理这种情况。
所以未来的解决方案(MS Edge 13+)是使用模板标签:
function parseHTML(html) {
var t = document.createElement('template');
t.innerHTML = html;
return t.content;
}
var documentFragment = parseHTML('<td>Test</td>');
对于较旧的浏览器,我已将 jQuery 的 parseHTML() 方法提取到一个独立的要点 - https://gist.github.com/Munawwar/6e6362dbdf77c7865a99
评论
<template>
标签。这取决于您可能还需要填充的自定义元素。事实上,您可能只想使用 Web 组件.js一次性填充自定义元素、模板、shadow dom、promise 和其他一些东西。
const parse = Range.prototype.createContextualFragment.bind(document.createRange());
document.body.appendChild( parse('<p><strong>Today is:</strong></p>') ),
document.body.appendChild( parse(`<p style="background: #eee">${new Date()}</p>`) );
只有父级(开头)中的有效子级 s 才会被解析。否则,可能会出现意外结果:
Node
Node
Range
// <body> is "parent" Node, start of Range
const parseRange = document.createRange();
const parse = Range.prototype.createContextualFragment.bind(parseRange);
// Returns Text "1 2" because td, tr, tbody are not valid children of <body>
parse('<td>1</td> <td>2</td>');
parse('<tr><td>1</td> <td>2</td></tr>');
parse('<tbody><tr><td>1</td> <td>2</td></tr></tbody>');
// Returns <table>, which is a valid child of <body>
parse('<table> <td>1</td> <td>2</td> </table>');
parse('<table> <tr> <td>1</td> <td>2</td> </tr> </table>');
parse('<table> <tbody> <td>1</td> <td>2</td> </tbody> </table>');
// <tr> is parent Node, start of Range
parseRange.setStart(document.createElement('tr'), 0);
// Returns [<td>, <td>] element array
parse('<td>1</td> <td>2</td>');
parse('<tr> <td>1</td> <td>2</td> </tr>');
parse('<tbody> <td>1</td> <td>2</td> </tbody>');
parse('<table> <td>1</td> <td>2</td> </table>');
评论
let content = "<center><h1>404 Not Found</h1></center>"
let result = $("<div/>").html(content).text()
内容: ,
结果:<center><h1>404 Not Found</h1></center>
"404 Not Found"
评论
1 程
用document.cloneNode()
性能是:
调用需要 ~0.22499999977299012 毫秒。document.cloneNode()
也许会更多。
var t0, t1, html;
t0 = performance.now();
html = document.cloneNode(true);
t1 = performance.now();
console.log("Call to doSomething took " + (t1 - t0) + " milliseconds.")
html.documentElement.innerHTML = '<!DOCTYPE html><html><head><title>Test</title></head><body><div id="test1">test1</div></body></html>';
console.log(html.getElementById("test1"));
2 路
用document.implementation.createHTMLDocument()
性能是:
调用需要 ~0.14000000010128133 毫秒。document.implementation.createHTMLDocument()
var t0, t1, html;
t0 = performance.now();
html = document.implementation.createHTMLDocument("test");
t1 = performance.now();
console.log("Call to doSomething took " + (t1 - t0) + " milliseconds.")
html.documentElement.innerHTML = '<!DOCTYPE html><html><head><title>Test</title></head><body><div id="test1">test1</div></body></html>';
console.log(html.getElementById("test1"));
3路
用document.implementation.createDocument()
性能是:
调用需要 ~0.14000000010128133 毫秒。document.implementation.createHTMLDocument()
var t0 = performance.now();
html = document.implementation.createDocument('', 'html',
document.implementation.createDocumentType('html', '', '')
);
var t1 = performance.now();
console.log("Call to doSomething took " + (t1 - t0) + " milliseconds.")
html.documentElement.innerHTML = '<html><head><title>Test</title></head><body><div id="test1">test</div></body></html>';
console.log(html.getElementById("test1"));
4 路
用new Document()
性能是:
调用需要 ~0.13499999840860255 毫秒。document.implementation.createHTMLDocument()
- 注意
ParentNode.append
是2020年的实验技术。
var t0, t1, html;
t0 = performance.now();
//---------------
html = new Document();
html.append(
html.implementation.createDocumentType('html', '', '')
);
html.append(
html.createElement('html')
);
//---------------
t1 = performance.now();
console.log("Call to doSomething took " + (t1 - t0) + " milliseconds.")
html.documentElement.innerHTML = '<html><head><title>Test</title></head><body><div id="test1">test1</div></body></html>';
console.log(html.getElementById("test1"));
我不得不使用在 Angular NGX Bootstrap popover 的弹出窗口中解析的元素的 innerHTML。这是对我有用的解决方案。
public htmlContainer = document.createElement( 'html' );
in 构造函数
this.htmlContainer.innerHTML = ''; setTimeout(() => { this.convertToArray(); });
convertToArray() {
const shapesHC = document.getElementsByClassName('weekPopUpDummy');
const shapesArrHCSpread = [...(shapesHC as any)];
this.htmlContainer = shapesArrHCSpread[0];
this.htmlContainer.innerHTML = shapesArrHCSpread[0].textContent;
}
在 HTML 中
<div class="weekPopUpDummy" [popover]="htmlContainer.innerHTML" [adaptivePosition]="false" placement="top" [outsideClick]="true" #popOverHide="bs-popover" [delay]="150" (onHidden)="onHidden(weekEvent)" (onShown)="onShown()">
要在 node.js 中执行此操作,您可以使用 HTML 解析器,如 node-html-parser。语法如下所示:
import { parse } from 'node-html-parser';
const root = parse('<ul id="list"><li>Hello World</li></ul>');
console.log(root.firstChild.structure);
// ul#list
// li
// #text
console.log(root.querySelector('#list'));
// { tagName: 'ul',
// rawAttrs: 'id="list"',
// childNodes:
// [ { tagName: 'li',
// rawAttrs: '',
// childNodes: [Object],
// classNames: [] } ],
// id: 'list',
// classNames: [] }
console.log(root.toString());
// <ul id="list"><li>Hello World</li></ul>
root.set_content('<li>Hello World</li>');
root.toString(); // <li>Hello World</li>
评论
(await import("https://cdn.skypack.dev/node-html-parser")).default('<ul id="list"><li>Hello World</li></ul>').firstChild.structure
我认为最好的方法是像这样使用这个 API:
//Table string in HTML format
const htmlString = '<table><tbody><tr><td>Cell 1</td><td>Cell 2</td></tr></tbody></table>';
//Parse using DOMParser native way
const parser = new DOMParser();
const $newTable = parser.parseFromString(htmlString, 'text/html');
//Here you can select parts of your parsed html and work with it
const $row = $newTable.querySelector('table > tbody > tr');
//Here i'm printing the number of columns (2)
const $containerHtml = document.getElementById('containerHtml');
$containerHtml.innerHTML = ['Your parsed table have ', $row.cells.length, 'columns.'].join(' ');
<div id="containerHtml"></div>
function parseElement(raw){
let el = document.createElement('div');
el.innerHTML = raw;
let res = el.querySelector('*');
res.remove();
return res;
}
注意:原始字符串不应超过 1 个元素
const html =
`<script>
alert('👋 there ! Wanna grab a 🍺');
</script>`;
const scriptEl = document.createRange().createContextualFragment(html);
parent.append(scriptEl);
我找到了这个解决方案,我认为这是最好的解决方案,它解析 HTML 并在其中执行脚本。
我使用了我从这个博客中引用的 DOMParser 类。
这将返回一个 HTMLCollection 对象,我们可以在其中将元素作为 DOM 元素本身访问。也很容易在HTML文档中插入代码document.body.append(...parseHTML(html_string));
const parseHTML = (htmlString) => {
const parser = new DOMParser();
const page = parser.parseFromString(htmlString, 'text/html');
return page.body.children;
};
稍后谢谢我。
评论
doc.links
)。doc.getElementsByTagName('a')