如何使用jsdom将HTML按<h2>分割并包裹为<div>区块
问题:将每个
<h2>及其后续内容包裹到<div>中 原始HTML结构:
<!DOCTYPE html> <html> <body> <h1>My First Heading</h1> <p>My first paragraph.</p> <h2>Subheading A</h2> <p>Subheading content 1</p> <ul> <li>bla</li> </ul> <p>Subheading content 2</p> <h2>Subheading B</h2> <p>Subheading content 1</p> <p>Subheading content 2</p> <p>Subheading content 3</p> </body> </html>
HTML特点
- 可包含任意数量的
<h2>子标题; - 子标题间可存在任意数量HTML元素;
需求
将每个<h2>及其后续元素包裹到<div>中,目标效果:
<!DOCTYPE html> <html> <body> <h1>My First Heading</h1> <p>My first paragraph.</p> <div> <h2>Subheading A</h2> <p>Subheading content 1</p> <ul> <li>bla</li> </ul> <p>Subheading content 2</p> </div> <div> <h2>Subheading B</h2> <p>Subheading content 1</p> <p>Subheading content 2</p> <p>Subheading content 3</p> </div> </body> </html>
用户尝试的jsdom代码:
const dom = new JSDOM(myHtmlString); orig_html = dom.window.document.getElementById("h2").innerHTML; new_html = "<div>" + org_html + "</div>"; dom.window.document.getElementById("h2").innerHTML = new_html;
疑问:如何筛选每个<h2>对应的后续元素并完成HTML分割?使用jsdom是否最优,还是文本处理更合适?
解决方案
一、使用jsdom的最优实现
用DOM操作处理HTML是更可靠的方式,因为文本处理容易因HTML格式不规范(比如标签换行、属性带特殊字符)出错。以下是完整实现:
const { JSDOM } = require('jsdom'); function wrapH2WithDiv(htmlString) { const dom = new JSDOM(htmlString); const document = dom.window.document; const body = document.body; const h2Elements = Array.from(body.querySelectorAll('h2')); h2Elements.forEach(h2 => { // 创建包裹用的div const wrapper = document.createElement('div'); // 将当前h2移动到div中 wrapper.appendChild(h2); // 遍历h2之后的兄弟元素,直到遇到下一个h2或没有更多元素 let nextSibling = h2.nextElementSibling; while (nextSibling && nextSibling.tagName !== 'H2') { // 移动兄弟元素到div里 wrapper.appendChild(nextSibling); // 更新nextSibling为下一个兄弟(因为当前的已经被移走了) nextSibling = h2.nextElementSibling; } // 将wrapper插入到原来h2的位置 body.insertBefore(wrapper, h2); }); return dom.serialize(); } // 使用示例 const myHtmlString = `<!DOCTYPE html> <html> <body> <h1>My First Heading</h1> <p>My first paragraph.</p> <h2>Subheading A</h2> <p>Subheading content 1</p> <ul> <li>bla</li> </ul> <p>Subheading content 2</p> <h2>Subheading B</h2> <p>Subheading content 1</p> <p>Subheading content 2</p> <p>Subheading content 3</p> </body> </html>`; console.log(wrapH2WithDiv(myHtmlString));
代码说明
- 先获取所有
<h2>元素,转为数组方便遍历; - 对每个
<h2>,创建一个<div>作为容器,先把<h2>移进去; - 循环获取
<h2>的下一个兄弟元素,只要不是<h2>就移到容器里; - 最后把容器插回原来
<h2>的位置,完成包裹。
二、文本处理的局限性
如果非要用文本处理,需要用正则匹配,但不推荐,因为HTML的结构可能有很多变体(比如<h2>带属性、标签换行、嵌套元素),正则很难覆盖所有情况。比如简单场景下的正则:
function wrapH2WithDivText(htmlString) { // 仅适用于格式非常规范的HTML,实际生产环境容易出错 return htmlString.replace(/(<h2>.*?)(?=<h2>|$)/gs, '<div>$1</div>'); }
但这个正则会忽略<h2>的属性,也无法处理嵌套的复杂结构,所以优先选择DOM操作(jsdom)。
内容的提问来源于stack exchange,提问作者Sergino
相关产品推荐
相关产品推荐

