PHP DOMDocument-按样式删除跨度属性



我试图删除具有特定样式的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才能正常工作。

处理这一切变得非常模糊真的很快:

  1. 如果您确信您的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;
    }
    
  2. 如果您不确定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>(或类似的(结构。所以,也许你需要想出一个更健壮的测试。

最新更新