You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用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));

代码说明

  1. 先获取所有<h2>元素,转为数组方便遍历;
  2. 对每个<h2>,创建一个<div>作为容器,先把<h2>移进去;
  3. 循环获取<h2>的下一个兄弟元素,只要不是<h2>就移到容器里;
  4. 最后把容器插回原来<h2>的位置,完成包裹。

二、文本处理的局限性

如果非要用文本处理,需要用正则匹配,但不推荐,因为HTML的结构可能有很多变体(比如<h2>带属性、标签换行、嵌套元素),正则很难覆盖所有情况。比如简单场景下的正则:

function wrapH2WithDivText(htmlString) {
  // 仅适用于格式非常规范的HTML,实际生产环境容易出错
  return htmlString.replace(/(<h2>.*?)(?=<h2>|$)/gs, '<div>$1</div>');
}

但这个正则会忽略<h2>的属性,也无法处理嵌套的复杂结构,所以优先选择DOM操作(jsdom)。


内容的提问来源于stack exchange,提问作者Sergino

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 02:25:28