如何在Node.js中解析修改支持HTML实体和CDATA的XHTML?
可行解决方案
方案1:实体预解析+Cheerio组合方案(推荐)
这个方案可以完美兼容你现有的Cheerio使用习惯,不需要更换DOM操作库:
- 前置依赖安装:
npm install cheerio entities
- 核心实现逻辑:
先隔离CDATA区段避免被实体解析影响,再预解析所有HTML命名实体为Unicode字符,最后用Cheerio的XML模式加载处理:
import cheerio from 'cheerio'; import { decodeHTML } from 'entities'; const xhtml = `<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html><body><span>ö<![CDATA[ä]]></span></body></html>`; // 步骤1:暂存所有CDATA区段,用占位符替换避免被实体解析修改 const cdataList = []; let processedContent = xhtml.replace(/<!\[CDATA\[(.*?)\]\]>/gs, (_, content) => { cdataList.push(content); return `__CDATA__${cdataList.length - 1}__`; }); // 步骤2:解析所有HTML实体为Unicode字符 processedContent = decodeHTML(processedContent); // 步骤3:还原CDATA区段 processedContent = processedContent.replace(/__CDATA__(\d+)__/g, (_, idx) => { return `<![CDATA[${cdataList[Number(idx)]}]]>`; }); // 步骤4:用Cheerio XML模式加载,关闭自动实体解码避免双重转义 const $ = cheerio.load(processedContent, { xmlMode: true, decodeEntities: false }); // 测试结果 console.log($('body').html()); // 输出:<span>ö<![CDATA[ä]]></span> console.log($('body').text()); // 输出:öä
你可以正常使用Cheerio的所有DOM操作API修改内容,最终输出的XHTML会完整保留CDATA区段和正确的字符。
方案2:使用libxmljs2原生XML解析库
如果你需要更标准的XML/XHTML解析能力,可以使用基于libxml的libxmljs2库,它原生支持DTD实体加载和CDATA解析:
- 前置依赖安装:
npm install libxmljs2
- 实现示例:
import libxml from 'libxmljs2'; const xhtml = `<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html><body><span>ö<![CDATA[ä]]></span></body></html>`; // 解析时开启DTD加载支持实体解析 const doc = libxml.parseXml(xhtml, { dtdload: true, noent: true }); // 操作DOM示例 const span = doc.get('//span'); span.text('测试' + span.text()); // 序列化输出 console.log(doc.toString()); // 完整保留CDATA和实体转换后的内容
该方案符合W3C XML解析标准,但因为是原生绑定库,部分轻量化Serverless环境可能存在兼容性问题。
内容的提问来源于stack exchange,提问作者cdauth
相关产品推荐
相关产品推荐

