如何用PHP XPath简化TinyMCE Checklist转TCPDF兼容格式的代码?
简化TinyMCE复选列表转TCPDF兼容格式的PHP XPath代码
我通过TinyMCE编辑器创建包含{NAME}、{SURNAME}等占位符的模板(比如文本、发票),在Web应用的其他页面用PHP替换占位符后,再用TCPDF类生成最终PDF。现在需要处理TinyMCE checklist插件生成的内容,把编辑器里的复选列表转换为TCPDF可识别的[ ]/[X]格式。我知道可以用PHP XPath实现,但之前没接触过,不清楚如何定位这类复杂文本片段。
TinyMCE生成的复选框HTML示例
<ul class="tox-checklist"> <li> checkbox 1</li> <li class="tox-checklist--checked"> checkbox 2</li> </ul>
目标TCPDF兼容格式
<p>[ ] checkbox 1</p> <p>[X] checkbox 2</p>
已知插件用.tox-checklist类标记UL列表,.tox-checklist--checked类标记已选中的复选框,模板中可能存在多个这类列表。我已经实现了功能,但代码过于繁琐,希望简化现有的PHP XPath代码:
现有繁琐代码
$contenuto = '<ul class="tox-checklist"><li> checkbox 1</li><li class="tox-checklist--checked"> checkbox 2</li></ul>'; $dom = new DOMDocument(); $dom->loadHTML($contenuto); $xpath = new DOMXpath($dom); $selector = $xpath->query('//ul[contains(@class,"tox-checklist")]/li[not(contains(@class,"tox-checklist--checked"))]'); foreach ($selector as $node) { $testo_checkbox = "[ ]" . $node->nodeValue; $parent = new DomDocument; $parent_node = $parent->createElement('p', $testo_checkbox); $parent->appendChild($parent_node); $newnode = $dom->importNode($parent->documentElement, true); $node->parentNode->replaceChild($newnode, $node); } $contenuto = $dom->saveHTML(); $dom = new DOMDocument(); $dom->loadHTML($contenuto); $xpath = new DOMXpath($dom); $selector = $xpath->query('//ul[contains(@class,"tox-checklist")]/li[contains(@class,"tox-checklist--checked")]'); foreach ($selector as $node) { $testo_checkbox = "[ X ]" . $node->nodeValue; $parent = new DomDocument; $parent_node = $parent->createElement('p', $testo_checkbox); $parent->appendChild($parent_node); $newnode = $dom->importNode($parent->documentElement, true); $node->parentNode->replaceChild($newnode, $node); } $contenuto = $dom->saveHTML(); $dom = new DOMDocument(); $dom->loadHTML($contenuto); $xpath = new DOMXpath($dom); $selector = $xpath->query('//ul[contains(@class,"tox-checklist")]'); foreach ($selector as $node) { $newParent = $node->parentNode; foreach ( $node->childNodes as $child ){ $newParent->insertBefore($child->cloneNode(true), $node); } $newParent->removeChild($node); } $contenuto = $dom->saveHTML();
简化后的代码
可以通过一次加载DOM文档,统一处理所有复选列表项,最后移除原UL容器,大幅减少重复代码:
$contenuto = '<ul class="tox-checklist"><li> checkbox 1</li><li class="tox-checklist--checked"> checkbox 2</li></ul>'; // 加载HTML到DOM,抑制解析错误避免结构问题干扰 libxml_use_internal_errors(true); $dom = new DOMDocument(); $dom->loadHTML($contenuto); libxml_clear_errors(); $xpath = new DOMXpath($dom); // 一次性获取所有目标列表项 $listItems = $xpath->query('//ul[contains(@class, "tox-checklist")]/li'); foreach ($listItems as $li) { // 判断是否为选中状态 $isChecked = str_contains($li->getAttribute('class'), 'tox-checklist--checked'); // 生成对应复选框前缀 $checkboxPrefix = $isChecked ? '[X]' : '[ ]'; // 创建p元素并填充内容 $p = $dom->createElement('p'); $p->nodeValue = $checkboxPrefix . $li->nodeValue; // 替换原li元素 $li->parentNode->replaceChild($p, $li); } // 移除所有空的UL容器 $ulLists = $xpath->query('//ul[contains(@class, "tox-checklist")]'); foreach ($ulLists as $ul) { // 将UL的子元素移到父节点下 while ($ul->firstChild) { $ul->parentNode->insertBefore($ul->firstChild, $ul); } // 删除UL容器 $ul->parentNode->removeChild($ul); } // 输出处理后的HTML $contenuto = $dom->saveHTML();
简化说明
- 单次DOM解析:只初始化一次DOM和XPath实例,避免重复加载HTML
- 统一处理列表项:用一个XPath查询获取所有目标li,循环内判断选中状态并生成对应p元素,无需拆分两次处理
- 高效清理UL容器:直接移动子元素后删除空UL,省去节点克隆操作
- 错误抑制:添加libxml错误处理,避免因HTML结构不完整导致的解析报错
内容的提问来源于stack exchange,提问作者itajackass
相关产品推荐
相关产品推荐

