最可靠方案是用 DOMParser 解析 HTML 属性值:调用 parseFromString(htmlStr, 'text/html'),再取 doc.documentElement.innerText(回退 doc.body?.innerText),可正确处理嵌套、实体、自闭合标签等全部合法语法。

直接用 DOMParser 解析 title 等属性值最可靠
HTML 属性(比如 title、data-html、aria-label)里存的常常是带标签的 HTML 字符串,不能当纯文本直接用。有人试过 .replace(/]*>/g, ''),但一遇到 <img src="a>b.png"> 或未闭合的 <i></i> 就崩,根本不可靠。
浏览器原生的 DOMParser 是唯一能正确处理所有合法 HTML 语法的方案:自闭合标签、嵌套、属性含 >、实体编码(&、<)、注释、CDATA —— 全部自动识别。
- 必须用
parseFromString(htmlStr, 'text/html'),传'text/xml'会失败 - 优先取
doc.documentElement.innerText,回退到doc.body?.innerText更稳妥 - 别用
textContent:它会把<script></script>和隐藏元素里的内容也拉出来,而innerText模拟真实渲染逻辑,更符合语义预期
innerHTML + textContent 临时 div 方案在简单场景够用但有坑
快速原型或兼容老项目时,有人写 const temp = document.createElement('div'); temp.innerHTML = attrValue; return temp.textContent;。这确实比正则强,但要注意几个硬伤:
- 如果属性值本身是片段(如
"<span>hello</span><br>world"
),temp.innerHTML会被浏览器自动包裹进...,一般不影响;但如果属性值含<base>或<script></script>,可能触发副作用 -
textContent不过滤隐藏元素(display: none或visibility: hidden的内容仍计入),而innerText会跳过——对title这类用户可见提示,innerText更准 - IE8 及更早不支持
DOMParser,但这类浏览器现在基本可忽略;若真要兼容,只能用innerText+ 临时 div,且得手动清理<script></script>和<style></style>子节点
PHP 里用 DOMDocument::loadHTML() 提取前必须关错误报告
PHP 的 DOMDocument 解析 HTML 属性值(比如从 data-desc 中提取)时,哪怕输入只是 "<p>test</p><div class="aritcle_card flexRow">
<div class="artcardd flexRow">
<a class="aritcle_card_img" href="/xiazai/skill7761" title="Article To Html"><img
src="https://img.php.cn/upload/skill/000/000/081/179168408018805.jpg" alt="Article To Html" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a>
<div class="aritcle_card_info flexColumn">
<a href="/xiazai/skill7761" title="Article To Html">Article To Html</a>
<p>文章转信息图。将文章/笔记转化为手机可读的 HTML 信息图,自动匹配视觉风格。触发场景:文章转图、笔记转图、信息图、转小红书图、做张图、可视化这篇文章、文生图。</p>
</div>
<a href="/xiazai/skill7761" title="Article To Html" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span> </a>
</div>
</div>
<p><span>立即学习</span>“<a href="https://pan.quark.cn/s/cb6835dc7db1" style="text-decoration: underline !important; color: blue; font-weight: bolder;" rel="nofollow" target="_blank">前端免费学习笔记(深入)</a>”;</p>",也会因缺少 <html> 头报 warning。不处理就会污染输出,甚至让 JSON 接口返回乱码。
- 务必在
loadHTML()前调用libxml_use_internal_errors(true) - 解析后用
$dom->documentElement->textContent取文本,不是$dom->textContent(后者可能含 doctype 文本节点) - 如果属性值来自不可信来源,
loadHTML()本身不防 XSS,但提取纯文本后已无执行风险;真正要防的是后续再把这文本插回 DOM 时没转义
别碰正则提取 HTML 属性文本——这不是性能问题,是逻辑不可能
你写的 .replace(/]*>/g, '') 看似简洁,但它连最基础的边界都守不住:
-
<img src="a>b.png">:正则在第一个>就停了,后面全被当文本吞掉 -
<i class="icon">ok</i>若写成<i class="icon">ok(没闭合),正则会一路吃到下一个</,误删大段内容 -
、©这类实体不会被还原,结果出现一堆乱码符号 - 每加一种新标签(比如
<svg></svg>或<math></math>),就得补一条.replace(),维护成本指数级上升
DOM 解析器不是“更慢的替代方案”,它是唯一能覆盖 HTML 规范全集的工具。所谓“小字符串没必要用 DOM”,本质是拿不可靠换省事——一旦属性值来自富文本编辑器或 CMS 后台,崩溃只是时间问题。


















