我试图删除具有特定样式的span标记(保留文本(,但不明白为什么在本例中会将span文本放在第一个span中?
$curr_notes = '<span style="color: rgb(226, 80, 65);"><br></span><span style="color: rgb(0, 0, 0);">TEXT 1</span><br><span style="color: rgb(0, 0, 0);">TEXT2</span>';
$pattern = '//span[@style="color: rgb(0, 0, 0);"]';
$dom = new DOMDocument();
$dom->loadHTML($curr_notes, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
$xpath = new DOMXPath($dom);
foreach ($xpath->query($pattern) as $span) {
while ($span->hasChildNodes()) {
$child = $span->removeChild($span->firstChild);
$span->parentNode->insertBefore($child, $span);
}
$span->parentNode->removeChild($span);
}
// Get the final HTML with span tags stripped
$clean_notes = $dom->saveHTML();
echo $clean_notes;
// <span style="color: rgb(226, 80, 65);"><br>TEXT 1<br>TEXT2</span>
// am expecting
// <span style="color: rgb(226, 80, 65);"><br></span>TEXT 1<br>TEXT2
DOMDocument
不适合处理这样的HTML片段,因为当HTML片段在顶层包含多个节点时,DOMDocument
需要一个根元素节点。因此,在解析时,DOMDocument
将所有后续节点放在它找到的第一个元素节点下。
理想情况下,我们将通过创建DOMDocumentFragment
(DOMDocument::createDocumentFragment()
(来处理此问题。然而,不幸的是,DOMDocumentFragment
只有一个appendXML()
方法,没有appendHTML()
方法,这意味着您的HTML必须是有效的XML才能正常工作。
处理这一切变得非常模糊真的很快:
-
如果您确信您的HTML永远不会包含
<html><body>...
等元素,那么您可以在不带LIBXML_HTML_NOIMPLIED
标志的情况下调用loadHTML()
,并相对于<body>
元素保存HTML。然而,令人沮丧的是,DOMDocument没有一种简单的方法来输出";innerHTML";的子节点,因此您必须将
<body>
的子节点与以下内容连接起来:$curr_notes = '<span style="color: rgb(226, 80, 65);"><br></span><span style="color: rgb(0, 0, 0);">TEXT 1</span><br><span style="color: rgb(0, 0, 0);">TEXT2</span>'; $pattern = '//span[@style="color: rgb(0, 0, 0);"]'; $dom = new DOMDocument(); $dom->loadHTML($curr_notes, LIBXML_HTML_NODEFDTD); $xpath = new DOMXPath($dom); foreach ($xpath->query($pattern) as $span) { while ($span->hasChildNodes()) { // no need to save $span->firstChild in $child variable first $span->parentNode->insertBefore($span->firstChild, $span); } $span->parentNode->removeChild($span); } // get the <body> $body = $dom->getElementsByTagName('body')[0]; // let's make sure we have a <body> if(!is_null($body)) { $clean_notes = ''; // concatenate to get the "innerHTML" of <body> foreach($body->childNodes as $child) { $clean_notes .= $dom->saveHTML($child); } echo $clean_notes; }
-
如果您不确定HTML是否包含
<html><body>...
结构,它会变得更加模糊,因为现在您不知道用saveHTML()
保存哪个节点(整个文档,还是只是<body>
的子节点?(。所以,现在你必须先进行一些探测,看看是哪种情况。一种有点天真的方法可能是用之类的东西测试原始HTML字符串是否存在<html><body>...
$isFullDocument = (bool) preg_match('/<html>s*<body>/', $curr_notes);
然后相应地调整CCD_ 18策略。
请注意我说";天真";,因为上述方法可能会在
<html>s*<body>
在预期之外的其他地方匹配的(不太可能的(事件中失败,或者您可能有<html><head><body>
(或类似的(结构。所以,也许你需要想出一个更健壮的测试。