繁体   English   中英

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

[英]PHP DOMDocument - remove span by style attributes

我正在尝试删除具有特定样式的跨度标签(保留文本),但不明白为什么结果将跨度文本放在此示例中的第一个跨度内?

    $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()并保存 HTML 相对于<body>元素。

    然而 DOMDocument 令人沮丧地没有简单的方法来 output 节点的“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);

    ...然后相应地调整saveHTML()策略。

    请注意我说“天真”,因为上述方法可能会在<html>\s*<body>以某种方式与预期之外的其他地方匹配的(不太可能)事件中失败,或者您可能有一个<html><head><body> (或类似的)结构。 所以也许你需要想出一个更强大的测试。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM