Làm cách nào để lưuHTML của DOMDocument mà không cần trình bao bọc HTML?


116

Tôi là hàm bên dưới, tôi đang vật lộn để xuất DOMDocument mà không nối thêm các trình bao bọc thẻ XML, HTML, bodyp trước khi xuất nội dung. Các sửa chữa được đề xuất:

$postarray['post_content'] = $d->saveXML($d->getElementsByTagName('p')->item(0));

Chỉ hoạt động khi nội dung không có thành phần cấp khối bên trong nó. Tuy nhiên, khi thực hiện, như trong ví dụ dưới đây với phần tử h1, kết quả đầu ra từ saveXML bị cắt cụt thành ...

<p> Nếu bạn thích </ p>

Tôi đã được chỉ ra bài đăng này như một cách giải quyết có thể, nhưng tôi không thể hiểu làm thế nào để triển khai nó vào giải pháp này (xem các nỗ lực bình luận bên dưới).

Bất kỳ đề xuất?

function rseo_decorate_keyword($postarray) {
    global $post;
    $keyword = "Jasmine Tea"
    $content = "If you like <h1>jasmine tea</h1> you will really like it with Jasmine Tea flavors. This is the last ocurrence of the phrase jasmine tea within the content. If there are other instances of the keyword jasmine tea within the text what happens to jasmine tea."
    $d = new DOMDocument();
    @$d->loadHTML($content);
    $x = new DOMXpath($d);
    $count = $x->evaluate("count(//text()[contains(translate(., 'ABCDEFGHJIKLMNOPQRSTUVWXYZ', 'abcdefghjiklmnopqrstuvwxyz'), '$keyword') and (ancestor::b or ancestor::strong)])");
    if ($count > 0) return $postarray;
    $nodes = $x->query("//text()[contains(translate(., 'ABCDEFGHJIKLMNOPQRSTUVWXYZ', 'abcdefghjiklmnopqrstuvwxyz'), '$keyword') and not(ancestor::h1) and not(ancestor::h2) and not(ancestor::h3) and not(ancestor::h4) and not(ancestor::h5) and not(ancestor::h6) and not(ancestor::b) and not(ancestor::strong)]");
    if ($nodes && $nodes->length) {
        $node = $nodes->item(0);
        // Split just before the keyword
        $keynode = $node->splitText(strpos($node->textContent, $keyword));
        // Split after the keyword
        $node->nextSibling->splitText(strlen($keyword));
        // Replace keyword with <b>keyword</b>
        $replacement = $d->createElement('strong', $keynode->textContent);
        $keynode->parentNode->replaceChild($replacement, $keynode);
    }
$postarray['post_content'] = $d->saveXML($d->getElementsByTagName('p')->item(0));
//  $postarray['post_content'] = $d->saveXML($d->getElementsByTagName('body')->item(1));
//  $postarray['post_content'] = $d->saveXML($d->getElementsByTagName('body')->childNodes);
return $postarray;
}

Câu trả lời:


216

Tất cả các câu trả lời này đều sai , vì phiên bản PHP 5.4 và Libxml 2.6 loadHTMLhiện có một $optiontham số hướng dẫn Libxml về cách phân tích nội dung.

Do đó, nếu chúng tôi tải HTML bằng các tùy chọn này

$html->loadHTML($content, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);

khi làm saveHTML()sẽ không có doctype, không <html>và không <body>.

LIBXML_HTML_NOIMPLIEDtắt tự động thêm các phần tử html / cơ thể ngụ ý LIBXML_HTML_NODEFDTDngăn không cho thêm một loại tài liệu mặc định khi không tìm thấy.

Tài liệu đầy đủ về các thông số Libxml có ở đây

(Lưu ý rằng các loadHTMLtài liệu nói rằng Libxml 2.6 là cần thiết, nhưng LIBXML_HTML_NODEFDTDchỉ có sẵn trong Libxml 2.7.8 và LIBXML_HTML_NOIMPLIEDcó sẵn trong Libxml 2.7.7)


10
Công việc này như một cái duyên vậy. Nên là câu trả lời được chấp nhận. Tôi vừa thêm một lá cờ và tất cả những cơn đau đầu của tôi biến mất ;-)
Just Plain High

8
Điều này không hoạt động với PHP 5.4 và Libxml 2.9. loadHTML không chấp nhận bất kỳ tùy chọn nào :(
Acyra

11
Lưu ý rằng điều này không hoàn hảo. Xem stackoverflow.com/questions/29493678/ Mạnh
Josh Levinson

4
Xin lỗi, nhưng đây dường như không phải là một giải pháp tốt (ít nhất là không thực tế). Nó thực sự không nên là câu trả lời được chấp nhận. Bên cạnh các vấn đề đã đề cập, cũng có một vấn đề mã hóa khó chịu với DOMDocumentđiều đó cũng ảnh hưởng đến các mã trong câu trả lời này. Afaik, DOMDocumentluôn diễn giải dữ liệu đầu vào là latin-1 trừ khi đầu vào chỉ định một bộ ký tự khác . Nói cách khác: <meta charset="…">Thẻ dường như cần thiết cho dữ liệu đầu vào không phải là latin-1. Nếu không, đầu ra sẽ bị phá vỡ, ví dụ như các ký tự đa nhân UTF-8.
mermshaus

1
LIBXMLTube_NOIMPLIED cũng làm rối mã HTML bằng cách xóa các tab, thụt lề và ngắt dòng
Zoltán Süle

72

Chỉ cần loại bỏ các nút trực tiếp sau khi tải tài liệu bằng loadHTML ():

# remove <!DOCTYPE 
$doc->removeChild($doc->doctype);           

# remove <html><body></body></html> 
$doc->replaceChild($doc->firstChild->firstChild->firstChild, $doc->firstChild);

đây là câu trả lời sạch hơn cho tôi
KnF

39
cần lưu ý rằng điều này hoạt động nếu <body> chỉ có một nút con.
Yann Milin

Làm việc tuyệt vời. Cảm ơn bạn! Sạch sẽ hơn và nhanh hơn các câu trả lời preg khác.
Ligemer

Cảm ơn vì điều này! Tôi chỉ cần thêm một snip ở phía dưới để xử lý các nút trống.
redaxmedia

2
Các mã để loại bỏ <!DOCTYPE các công trình. Dòng thứ hai ngắt nếu <body>có nhiều hơn một ghi chú con.
Cấp tiến miễn phí

21

Sử dụng saveXML()thay thế và truyền tài liệu bổ sung làm đối số cho nó.

$innerHTML = '';
foreach ($document->getElementsByTagName('p')->item(0)->childNodes as $child) {
    $innerHTML .= $document->saveXML($child);
}
echo $innerHTML;

http://php.net/domdocument.savexml


Điều đó tốt hơn, nhưng tôi vẫn nhận được <html> <body> <p> gói nội dung.
Scott B


2
Cần lưu ý rằng saveXML () sẽ lưu XHTML chứ không phải HTML.
alexantd

@Scott: Điều đó thực sự kỳ lạ. Nó cho thấy những gì bạn đang cố gắng thực hiện ngay trong phần ví dụ. Bạn có chắc chắn rằng bạn không có HTML đó trong DOM của mình không? Chính xác HTML là gì trong DOMDocument của bạn? Có thể là chúng ta cần truy cập vào một nút con.
Giô-na

@Jonah không có gì lạ. Khi bạn làm loadHTMLlibxml, hãy sử dụng mô-đun trình phân tích cú pháp HTML và điều đó sẽ chèn bộ xương HTML bị thiếu. Do đó, $dom->documentElementsẽ là phần tử HTML gốc. Tôi đã sửa mã ví dụ của bạn. Bây giờ nó nên làm những gì Scott đang yêu cầu.
Gordon

18

Vấn đề với câu trả lời hàng đầu LIBXML_HTML_NOIMPLIEDlà không ổn định .

Nó có thể sắp xếp lại các phần tử (đặc biệt, di chuyển thẻ đóng của phần tử trên xuống dưới cùng của tài liệu), thêm các pthẻ ngẫu nhiên và có thể là một loạt các vấn đề khác [1] . Nó có thể loại bỏ các thẻ htmlbodythẻ cho bạn, nhưng với chi phí cho hành vi không ổn định. Trong sản xuất, đó là một lá cờ đỏ. Nói ngắn gọn:

Đừng sử dụngLIBXML_HTML_NOIMPLIED . Thay vào đó, sử dụngsubstr .


Hãy suy nghĩ về nó. Độ dài <html><body></body></html>được cố định và ở cả hai đầu của tài liệu - kích thước của chúng không bao giờ thay đổi và cũng không làm vị trí của chúng. Điều này cho phép chúng tôi sử dụng substrđể cắt chúng đi:

$dom = new domDocument; 
$dom->loadHTML($html, LIBXML_HTML_NODEFDTD);

echo substr($dom->saveHTML(), 12, -15); // the star of this operation

( ĐÂY KHÔNG PHẢI LÀ GIẢI PHÁP CUỐI CÙNG TUYỆT VỜI! Xem bên dưới để biết câu trả lời đầy đủ , tiếp tục đọc theo ngữ cảnh)

Chúng tôi cắt 12bỏ phần đầu của tài liệu vì <html><body>= 12 ký tự ( <<>>+html+body= 4 + 4 + 4) và chúng tôi đi lùi và cắt 15 phần cuối vì \n</body></html>= 15 ký tự (\n+//+<<>>+body+html = 1 + 2 + 4 + 4 + 4)

Lưu ý rằng tôi vẫn sử dụng LIBXML_HTML_NODEFDTDbỏ qua !DOCTYPEtừ được bao gồm. Đầu tiên, điều này giúp đơn giản hóa việc substrloại bỏ các thẻ HTML / BODY. Thứ hai, chúng tôi không xóa loại tài liệu này substrvì chúng tôi không biết liệu ' default doctype' sẽ luôn là thứ gì đó có độ dài cố định. Nhưng, quan trọng nhất, LIBXML_HTML_NODEFDTDngăn trình phân tích cú pháp DOM áp dụng loại tài liệu không phải HTML5 cho tài liệu - điều này ít nhất ngăn trình phân tích cú pháp xử lý các phần tử mà nó không nhận ra là văn bản lỏng lẻo.

Chúng tôi biết rằng thực tế là các thẻ HTML / BODY có độ dài và vị trí cố định và chúng tôi biết rằng các hằng số như LIBXML_HTML_NODEFDTDkhông bao giờ bị xóa mà không có một số loại thông báo khấu hao, vì vậy phương pháp trên sẽ đi sâu vào tương lai, NHƯNG ...


... lưu ý duy nhất là việc triển khai DOM có thể thay đổi cách đặt các thẻ HTML / BODY trong tài liệu - ví dụ: xóa dòng mới ở cuối tài liệu, thêm khoảng trắng giữa các thẻ hoặc thêm dòng mới.

Điều này có thể được khắc phục bằng cách tìm kiếm vị trí của các thẻ mở và đóng body, và sử dụng các độ lệch đó như độ dài của chúng tôi để cắt bớt. Chúng tôi sử dụng strposstrrposđể tìm các offset từ phía trước và phía sau, tương ứng:

$dom = new domDocument; 
$dom->loadHTML($html, LIBXML_HTML_NODEFDTD);

$trim_off_front = strpos($dom->saveHTML(),'<body>') + 6;
// PositionOf<body> + 6 = Cutoff offset after '<body>'
// 6 = Length of '<body>'

$trim_off_end = (strrpos($dom->saveHTML(),'</body>')) - strlen($dom->saveHTML());
// ^ PositionOf</body> - LengthOfDocument = Relative-negative cutoff offset before '</body>'

echo substr($dom->saveHTML(), $trim_off_front, $trim_off_end);

Kết thúc, lặp lại câu trả lời cuối cùng, bằng chứng trong tương lai :

$dom = new domDocument; 
$dom->loadHTML($html, LIBXML_HTML_NODEFDTD);

$trim_off_front = strpos($dom->saveHTML(),'<body>') + 6;
$trim_off_end = (strrpos($dom->saveHTML(),'</body>')) - strlen($dom->saveHTML());

echo substr($dom->saveHTML(), $trim_off_front, $trim_off_end);

Không có doctype, không có thẻ html, không có thẻ body. Chúng tôi chỉ có thể hy vọng trình phân tích cú pháp DOM sẽ sớm nhận được một lớp sơn mới và chúng tôi có thể loại bỏ trực tiếp hơn các thẻ không mong muốn này.


Câu trả lời tuyệt vời, một bình luận nhỏ, tại sao không $html = $dom -> saveHTML();thay vì $dom -> saveHTML();lặp đi lặp lại?
Steven

15

Một mẹo gọn gàng là sử dụng loadXMLvà sau đó saveHTML. Các thẻ htmlbodyđược chèn vào loadgiai đoạn, không phải savegiai đoạn.

$dom = new DOMDocument;
$dom->loadXML('<p>My DOMDocument contents are here</p>');
echo $dom->saveHTML();

Lưu ý rằng đây là một chút hack và bạn nên sử dụng câu trả lời của Jonah nếu bạn có thể làm cho nó hoạt động.


4
Điều này sẽ thất bại cho HTML không hợp lệ mặc dù.
Gordon

1
@Gordon Chính xác là tại sao tôi lại từ chối trách nhiệm!
lonesomeday

1
Khi tôi thử điều này và lặp lại $ dom-> saveHTML (), nó sẽ trả về một chuỗi trống. Như thể loadXML ($ nội dung) trống. Khi tôi làm tương tự với $ dom-> loadHTML ($ content), sau đó lặp lại $ dom-> saveXML () tôi nhận được nội dung như mong đợi.
Scott B

Sử dụng loadXML khi sẵn sàng tải HTMl là ngón tay cái. Đặc biệt vì LoadXML không biết cách xử lý HTML.
botenvouwer

15

sử dụng DOMDocumentFragment

$html = 'what you want';
$doc = new DomDocument();
$fragment = $doc->createDocumentFragment();
$fragment->appendXML($html);
$doc->appendChild($fragment);
echo $doc->saveHTML();

3
Câu trả lời rõ ràng nhất cho php5.4 trước.
Nick Johnson

Điều này hoạt động với tôi, cả cũ và mới hơn phiên bản Libxml 2.7.7. Tại sao điều này chỉ dành cho php5.4?
RobbertT

Điều này nên có nhiều phiếu hơn. Tùy chọn tuyệt vời cho các phiên bản libxml không hỗ trợ LIBXMLTube_NOIMPLIED | LIBXMLET_NODEFDTD. Cảm ơn!
Marty Mulligan

13

Đó là năm 2017 và đối với Câu hỏi năm 2011 này, tôi không thích bất kỳ câu trả lời nào. Rất nhiều regex, các lớp lớn, loadXML, v.v ...

Giải pháp dễ dàng giải quyết các vấn đề đã biết:

$dom = new DOMDocument();
$dom->loadHTML( '<html><body>'.mb_convert_encoding($html, 'HTML-ENTITIES', 'UTF-8').'</body></html>' , LIBXML_HTML_NODEFDTD);
$html = substr(trim($dom->saveHTML()),12,-14);

Dễ dàng, đơn giản, vững chắc, nhanh chóng. Mã này sẽ hoạt động liên quan đến thẻ HTML và mã hóa như:

$html = '<p>äöü</p><p>ß</p>';

Nếu bất cứ ai tìm thấy một lỗi, xin vui lòng cho biết, tôi sẽ sử dụng bản thân mình.

Chỉnh sửa , Các tùy chọn hợp lệ khác hoạt động không có lỗi (rất giống với các tùy chọn đã được cung cấp):

@$dom->loadHTML(mb_convert_encoding($html, 'HTML-ENTITIES', 'UTF-8'));
$saved_dom = trim($dom->saveHTML());
$start_dom = stripos($saved_dom,'<body>')+6;
$html = substr($saved_dom,$start_dom,strripos($saved_dom,'</body>') - $start_dom );

Bạn có thể tự thêm cơ thể để ngăn chặn bất kỳ điều lạ trên lông.

Lựa chọn thứ ba mươi:

 $mock = new DOMDocument;
 $body = $dom->getElementsByTagName('body')->item(0);
  foreach ($body->childNodes as $child){
     $mock->appendChild($mock->importNode($child, true));
  }
$html = trim($mock->saveHTML());

3
Bạn nên cải thiện câu trả lời của mình bằng cách tránh đắt hơn mb_convert_encodingvà thay vào đó thêm <html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"></head><body>và sửa đổi cho substrphù hợp. Btw, của bạn là giải pháp thanh lịch nhất ở đây. Nâng cao.
Hlsg

10

Tôi hơi muộn trong câu lạc bộ nhưng không muốn không chia sẻ một phương pháp tôi đã phát hiện ra về. Trước hết tôi đã có các phiên bản phù hợp cho loadHTML () để chấp nhận các tùy chọn đẹp này, nhưng LIBXML_HTML_NOIMPLIEDkhông hoạt động trên hệ thống của tôi. Ngoài ra người dùng báo cáo vấn đề với trình phân tích cú pháp (ví dụ ở đâyở đây ).

Giải pháp tôi tạo ra thực sự khá đơn giản.

HTML được tải được đặt trong một <div>phần tử để nó có một thùng chứa tất cả các nút được tải.

Sau đó, phần tử container này được xóa khỏi tài liệu (nhưng DOMEuity của nó vẫn tồn tại).

Sau đó tất cả trẻ em trực tiếp từ tài liệu được loại bỏ. Điều này bao gồm bất kỳ bổ sung <html>, <head><body>các thẻ (có hiệu quả LIBXML_HTML_NOIMPLIEDtùy chọn) cũng như <!DOCTYPE html ... loose.dtd">tuyên bố (hiệu quả LIBXML_HTML_NODEFDTD).

Sau đó, tất cả các con trực tiếp của container được thêm vào tài liệu một lần nữa và nó có thể được xuất ra.

$str = '<p>Lorem ipsum dolor sit amet.</p><p>Nunc vel vehicula ante.</p>';

$doc = new DOMDocument();

$doc->loadHTML("<div>$str</div>");

$container = $doc->getElementsByTagName('div')->item(0);

$container = $container->parentNode->removeChild($container);

while ($doc->firstChild) {
    $doc->removeChild($doc->firstChild);
}

while ($container->firstChild ) {
    $doc->appendChild($container->firstChild);
}

$htmlFragment = $doc->saveHTML();

XPath hoạt động như bình thường, chỉ cần lưu ý rằng hiện tại có nhiều phần tử tài liệu, vì vậy không phải là một nút gốc duy nhất:

$xpath = new DOMXPath($doc);
foreach ($xpath->query('/p') as $element)
{   #                   ^- note the single slash "/"
    # ... each of the two <p> element

  • PHP 5.4.36-1 + deb.sury.org ~ chính xác + 2 (cli) (được xây dựng: ngày 21 tháng 12 năm 2014 20:28:53)

nó không hoạt động với tôi với nguồn HTML phức tạp hơn. Nó cũng loại bỏ một phần của HTML.
Zoltán Süle

4

Không có giải pháp nào khác tại thời điểm viết bài này (tháng 6 năm 2012) có thể đáp ứng hoàn toàn nhu cầu của tôi, vì vậy tôi đã viết một giải pháp xử lý các trường hợp sau:

  • Chấp nhận nội dung văn bản thuần túy không có thẻ cũng như nội dung HTML.
  • Không thêm bất kỳ thẻ (bao gồm <doctype>, <xml>, <html>, <body>, và <p>thẻ)
  • Lá bất cứ thứ gì bọc trong <p>một mình.
  • Lá văn trống một mình.

Vì vậy, đây là một giải pháp khắc phục những vấn đề đó:

class DOMDocumentWorkaround
{
    /**
     * Convert a string which may have HTML components into a DOMDocument instance.
     *
     * @param string $html - The HTML text to turn into a string.
     * @return \DOMDocument - A DOMDocument created from the given html.
     */
    public static function getDomDocumentFromHtml($html)
    {
        $domDocument = new DOMDocument();

        // Wrap the HTML in <div> tags because loadXML expects everything to be within some kind of tag.
        // LIBXML_NOERROR and LIBXML_NOWARNING mean this will fail silently and return an empty DOMDocument if it fails.
        $domDocument->loadXML('<div>' . $html . '</div>', LIBXML_NOERROR | LIBXML_NOWARNING);

        return $domDocument;
    }

    /**
     * Convert a DOMDocument back into an HTML string, which is reasonably close to what we started with.
     *
     * @param \DOMDocument $domDocument
     * @return string - The resulting HTML string
     */
    public static function getHtmlFromDomDocument($domDocument)
    {
        // Convert the DOMDocument back to a string.
        $xml = $domDocument->saveXML();

        // Strip out the XML declaration, if one exists
        $xmlDeclaration = "<?xml version=\"1.0\"?>\n";
        if (substr($xml, 0, strlen($xmlDeclaration)) == $xmlDeclaration) {
            $xml = substr($xml, strlen($xmlDeclaration));
        }

        // If the original HTML was empty, loadXML collapses our <div></div> into <div/>. Remove it.
        if ($xml == "<div/>\n") {
            $xml = '';
        }
        else {
            // Remove the opening <div> tag we previously added, if it exists.
            $openDivTag = "<div>";
            if (substr($xml, 0, strlen($openDivTag)) == $openDivTag) {
                $xml = substr($xml, strlen($openDivTag));
            }

            // Remove the closing </div> tag we previously added, if it exists.
            $closeDivTag = "</div>\n";
            $closeChunk = substr($xml, -strlen($closeDivTag));
            if ($closeChunk == $closeDivTag) {
                $xml = substr($xml, 0, -strlen($closeDivTag));
            }
        }

        return $xml;
    }
}

Tôi cũng đã viết một số bài kiểm tra sẽ sống trong cùng một lớp:

public static function testHtmlToDomConversions($content)
{
    // test that converting the $content to a DOMDocument and back does not change the HTML
    if ($content !== self::getHtmlFromDomDocument(self::getDomDocumentFromHtml($content))) {
        echo "Failed\n";
    }
    else {
        echo "Succeeded\n";
    }
}

public static function testAll()
{
    self::testHtmlToDomConversions('<p>Here is some sample text</p>');
    self::testHtmlToDomConversions('<div>Lots of <div>nested <div>divs</div></div></div>');
    self::testHtmlToDomConversions('Normal Text');
    self::testHtmlToDomConversions(''); //empty
}

Bạn có thể kiểm tra xem nó hoạt động cho chính mình. DomDocumentWorkaround::testAll()trả lại cái này

    Succeeded
    Succeeded
    Succeeded
    Succeeded

1
HTML = / = XML, bạn nên sử dụng trình tải HTML cho HTML.
hakre

4

Được rồi tôi tìm thấy một giải pháp thanh lịch hơn, nhưng nó chỉ tẻ nhạt:

$d = new DOMDocument();
@$d->loadHTML($yourcontent);
...
// do your manipulation, processing, etc of it blah blah blah
...
// then to save, do this
$x = new DOMXPath($d);
$everything = $x->query("body/*"); // retrieves all elements inside body tag
if ($everything->length > 0) { // check if it retrieved anything in there
      $output = '';
      foreach ($everything as $thing) {
           $output .= $d->saveXML($thing);
      }
      echo $output; // voila, no more annoying html wrappers or body tag
}

Được rồi, hy vọng điều này không bỏ sót bất cứ điều gì và giúp đỡ ai đó?


2
Không xử lý trường hợp khi loadHTML tải một chuỗi mà không đánh dấu
copndz

3

Sử dụng chức năng này

$layout = preg_replace('~<(?:!DOCTYPE|/?(?:html|head|body))[^>]*>\s*~i', '', $layout);

13
Có thể có một số độc giả đã tình cờ thấy bài đăng này qua bài đăng này , đã quyết định không sử dụng regex để phân tích HTML của họ và sử dụng trình phân tích cú pháp DOM thay vào đó, và cuối cùng có khả năng cần một câu trả lời regex để đạt được một giải pháp hoàn chỉnh ... mỉa mai
Robbie Averill

Tôi không hiểu tại sao noboy chỉ trả về nội dung của CƠ THỂ. Có phải thẻ đó không được cung cấp để luôn luôn xuất hiện khi trình phân tích cú pháp thêm toàn bộ tiêu đề / doctype tài liệu? Regex ở trên thậm chí sẽ ngắn hơn.
sergio

@boksiora "nó thực hiện công việc" - vậy thì tại sao chúng ta lại sử dụng các phương thức phân tích cú pháp DOM ở vị trí đầu tiên?
Cảm ơn bạn

@naomik Tôi đã nói không sử dụng trình phân tích cú pháp DOM, tất nhiên có nhiều cách khác nhau để đạt được kết quả tương tự, tùy thuộc vào bạn, tại thời điểm tôi sử dụng chức năng này, tôi gặp vấn đề với php dom tích hợp trình phân tích cú pháp không phân tích cú pháp html5 chính xác.
boksiora

1
Tôi đã phải sử dụng preg_replacevì sử dụng các phương pháp loại bỏ các thẻ html và thẻ cơ thể dựa trên DOMDocument không bảo toàn mã hóa UTF-8 :(
wizonesolutions

3

Nếu giải pháp cờ được trả lời bởi Alessandro Vendruscolo không hoạt động, bạn có thể thử điều này:

$dom = new DOMDocument();
$dom->loadHTML($content);

//do your stuff..

$finalHtml = '';
$bodyTag = $dom->documentElement->getElementsByTagName('body')->item(0);
foreach ($bodyTag->childNodes as $rootLevelTag) {
    $finalHtml .= $dom->saveHTML($rootLevelTag);
}
echo $finalHtml;

$bodyTagsẽ chứa mã HTML được xử lý đầy đủ của bạn mà không cần tất cả các kết thúc HTML đó, ngoại trừ <body>thẻ, đó là gốc của nội dung của bạn. Sau đó, bạn có thể sử dụng hàm regex hoặc hàm trim để xóa nó khỏi chuỗi cuối cùng (sau saveHTML) hoặc, như trong trường hợp trên, lặp lại tất cả các con của nó, lưu nội dung của chúng vào một biến tạm thời $finalHtmlvà trả lại nó (điều tôi tin là an toàn hơn).


3

Tôi đang vật lộn với điều này trên RHEL7 chạy PHP 5.6.25 và LibXML 2.9. (Những thứ cũ trong năm 2018, tôi biết, nhưng đó là Red Hat cho bạn.)

Tôi đã thấy rằng giải pháp nâng cao được đề xuất bởi Alessandro Vendruscolo phá vỡ HTML bằng cách sắp xếp lại các thẻ. I E:

<p>First.</p><p>Second.</p>'

trở thành:

<p>First.<p>Second.</p></p>'

Điều này áp dụng cho cả hai tùy chọn mà anh ấy đề nghị bạn sử dụng: LIBXML_HTML_NOIMPLIEDLIBXML_HTML_NODEFDTD.

Giải pháp được đề xuất bởi Alex đi một nửa để giải quyết nó, nhưng nó không hoạt động nếu <body>có nhiều hơn một nút con.

Giải pháp phù hợp với tôi là follwing:

Đầu tiên, để tải DOMDocument, tôi sử dụng:

$doc = new DOMDocument()
$doc->loadHTML($content);

Để lưu tài liệu sau khi mát xa DOMDocument, tôi sử dụng:

// remove <!DOCTYPE 
$doc->removeChild($doc->doctype);  
$content = $doc->saveHTML();
// remove <html><body></body></html> 
$content = str_replace('<html><body>', '', $content);
$content = str_replace('</body></html>', '', $content);

Tôi là người đầu tiên đồng ý rằng đây không phải là một giải pháp rất thanh lịch - nhưng nó hoạt động.


2

Thêm <meta>thẻ sẽ kích hoạt hành vi sửa lỗi củaDOMDocument . Phần tốt là bạn không cần phải thêm thẻ đó. Nếu bạn không sử dụng mã hóa cho lựa chọn của mình, hãy chuyển nó làm đối số của hàm tạo.

http://php.net/manual/en/domdocument.construct.php

$doc = new DOMDocument('1.0', 'UTF-8');
$node = $doc->createElement('div', 'Hello World');
$doc->appendChild($node);
echo $doc->saveHTML();

Đầu ra

<div>Hello World</div>

Cảm ơn @Bart


2

Tôi cũng có yêu cầu này và thích giải pháp được đăng bởi Alex ở trên. Tuy nhiên, có một số vấn đề - nếu <body>phần tử chứa nhiều phần tử con, tài liệu kết quả sẽ chỉ chứa phần tử con đầu tiên <body>, không phải tất cả các phần tử . Ngoài ra, tôi cần tước để xử lý mọi thứ một cách có điều kiện - chỉ khi bạn có tài liệu với các tiêu đề HTML. Vì vậy, tôi tinh chỉnh nó như sau. Thay vì loại bỏ <body>, tôi đã chuyển đổi nó thành a <div>và loại bỏ khai báo XML và <html>.

function strip_html_headings($html_doc)
{
    if (is_null($html_doc))
    {
        // might be better to issue an exception, but we silently return
        return;
    }

    // remove <!DOCTYPE 
    if (!is_null($html_doc->firstChild) &&
        $html_doc->firstChild->nodeType == XML_DOCUMENT_TYPE_NODE)
    {
        $html_doc->removeChild($html_doc->firstChild);     
    }

    if (!is_null($html_doc->firstChild) &&
        strtolower($html_doc->firstChild->tagName) == 'html' &&
        !is_null($html_doc->firstChild->firstChild) &&
        strtolower($html_doc->firstChild->firstChild->tagName) == 'body')
    {
        // we have 'html/body' - replace both nodes with a single "div"        
        $div_node = $html_doc->createElement('div');

        // copy all the child nodes of 'body' to 'div'
        foreach ($html_doc->firstChild->firstChild->childNodes as $child)
        {
            // deep copies each child node, with attributes
            $child = $html_doc->importNode($child, true);
            // adds node to 'div''
            $div_node->appendChild($child);
        }

        // replace 'html/body' with 'div'
        $html_doc->removeChild($html_doc->firstChild);
        $html_doc->appendChild($div_node);
    }
}

2

Giống như các thành viên khác, lần đầu tiên tôi say sưa về sự đơn giản và sức mạnh tuyệt vời của câu trả lời @Alessandro Vendruscolo. Khả năng chuyển đơn giản trong một số hằng được gắn cờ cho hàm tạo có vẻ quá tốt là đúng. Đối với tôi đó là. Tôi có các phiên bản chính xác của cả LibXML cũng như PHP, tuy nhiên dù thế nào nó vẫn sẽ thêm thẻ HTML vào cấu trúc nút của đối tượng Tài liệu.

Giải pháp của tôi hoạt động tốt hơn so với sử dụng ...

$html->loadHTML($content, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);

Cờ hoặc ....

# remove <!DOCTYPE 
$doc->removeChild($doc->firstChild);            

# remove <html><body></body></html>
$doc->replaceChild($doc->firstChild->firstChild->firstChild, $doc->firstChild);

Loại bỏ nút, bị lộn xộn mà không có thứ tự cấu trúc trong DOM. Một lần nữa các đoạn mã không có cách nào để xác định trước cấu trúc DOM.

Tôi đã bắt đầu hành trình này muốn có một cách đơn giản để thực hiện DOM traverse cách JQuery thực hiện hoặc ít nhất là trong một số thời trang có dữ liệu có cấu trúc được đặt liên kết đơn, liên kết đôi hoặc chuyển đổi nút cây. Tôi không quan tâm chừng nào tôi có thể phân tích một chuỗi theo cách HTML thực hiện và cũng có sức mạnh đáng kinh ngạc của các thuộc tính lớp thực thể nút để sử dụng trên đường đi.

Cho đến nay, đối tượng DOMDocument đã khiến tôi muốn ... Cũng như nhiều lập trình viên khác, có vẻ như ... Tôi biết tôi đã thấy rất nhiều sự thất vọng trong câu hỏi này vì vậy tôi đã HOÀN TOÀN .... (sau khoảng 30 giờ thử và thất bại kiểm tra loại) Tôi đã tìm thấy một cách để có được tất cả. Tôi hi vọng điêu nay se giup được ai đo...

Trước hết, tôi hoài nghi về MỌI THỨ ... lol ...

Tôi đã đi cả đời trước khi đồng ý với bất kỳ ai rằng lớp bên thứ ba dù sao cũng cần thiết trong trường hợp sử dụng này. Tôi rất nhiều và KHÔNG phải là người thích sử dụng bất kỳ cấu trúc lớp bên thứ ba nào, tuy nhiên tôi tình cờ gặp một trình phân tích cú pháp tuyệt vời. (khoảng 30 lần trong Google trước khi tôi nhượng bộ vì vậy đừng cảm thấy cô đơn nếu bạn tránh điều đó vì nó trông có vẻ không chính thức theo bất kỳ cách nào ...)

Nếu bạn đang sử dụng các đoạn mã và cần, mã sạch và không bị ảnh hưởng bởi trình phân tích cú pháp theo bất kỳ cách nào, mà không sử dụng các thẻ bổ sung thì hãy sử dụng SimplePHPParser .

Thật tuyệt vời và hoạt động rất giống JQuery. Tôi không thường xuyên ấn tượng nhưng lớp này sử dụng rất nhiều công cụ tốt và tôi chưa có lỗi phân tích cú pháp nào. Tôi là một fan hâm mộ lớn của việc có thể làm những gì lớp này làm.

Bạn có thể tìm thấy các tệp của nó để tải xuống ở đây , hướng dẫn khởi động ở đây và API của nó ở đây . Tôi đặc biệt khuyên bạn nên sử dụng lớp này với các phương thức đơn giản có thể thực hiện .find(".className")giống như cách mà phương thức tìm kiếm JQuery sẽ được sử dụng hoặc thậm chí là các phương thức quen thuộc như getElementByTagName()hoặc getElementById()...

Khi bạn lưu một cây nút trong lớp này, nó không thêm bất cứ thứ gì cả. Bạn có thể chỉ cần nói $doc->save();và nó xuất toàn bộ cây thành một chuỗi mà không có bất kỳ phiền phức nào.

Bây giờ tôi sẽ sử dụng trình phân tích cú pháp này cho tất cả các dự án, không giới hạn băng thông, trong tương lai.


2

Tôi có PHP 5.3 và các câu trả lời ở đây không phù hợp với tôi.

$doc->replaceChild($doc->firstChild->firstChild->firstChild, $doc->firstChild);thay thế tất cả tài liệu chỉ có đứa con đầu tiên, tôi có nhiều đoạn và chỉ có đoạn đầu tiên được lưu, nhưng giải pháp đã cho tôi một điểm khởi đầu tốt để viết một cái gì đó mà regextôi không để lại một số bình luận và tôi khá chắc chắn rằng điều này có thể được cải thiện nhưng nếu ai đó có cùng một vấn đề như tôi nó có thể là một điểm khởi đầu tốt.

function extractDOMContent($doc){
    # remove <!DOCTYPE
    $doc->removeChild($doc->doctype);

    // lets get all children inside the body tag
    foreach ($doc->firstChild->firstChild->childNodes as $k => $v) {
        if($k !== 0){ // don't store the first element since that one will be used to replace the html tag
            $doc->appendChild( clone($v) ); // appending element to the root so we can remove the first element and still have all the others
        }
    }
    // replace the body tag with the first children
    $doc->replaceChild($doc->firstChild->firstChild->firstChild, $doc->firstChild);
    return $doc;
}

Sau đó chúng ta có thể sử dụng nó như thế này:

$doc = new DOMDocument();
$doc->encoding = 'UTF-8';
$doc->loadHTML('<p>Some html here</p><p>And more html</p><p>and some html</p>');
$doc = extractDOMContent($doc);

Lưu ý rằng appendChildchấp nhận DOMNodevì vậy chúng tôi không cần tạo các phần tử mới, chúng tôi chỉ có thể sử dụng lại các phần tử hiện có DOMNodenhư vậy DOMElementcó thể rất quan trọng để giữ mã "lành mạnh" khi thao tác nhiều tài liệu HTML / XML


Điều này sẽ không hoạt động đối với các đoạn, chỉ cho một phần tử con duy nhất mà bạn muốn tạo phần đầu tiên của tài liệu. Điều này là khá hạn chế và thực sự không làm công việc của LIBXML_HTML_NOIMPLIEDnó như nó chỉ làm một phần. Loại bỏ các tài liệu là hiệu quả LIBXML_HTML_NODEFDTD.
hakre

2

Tôi đã xem qua chủ đề này để tìm cách xóa trình bao bọc HTML. Sử dụng LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTDcông việc tuyệt vời, nhưng tôi có một vấn đề với utf-8. Sau nhiều nỗ lực tôi đã tìm ra giải pháp. Tôi đăng nó dưới đây cho bất cứ ai có cùng một vấn đề.

Sự cố gây ra vì <meta http-equiv="Content-Type" content="text/html; charset=utf-8">

Vấn đề:

$dom = new DOMDocument();
$dom->loadHTML('<meta http-equiv="Content-Type" content="text/html; charset=utf-8">' . $document, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
$dom->saveHTML();

Giải pháp 1:

$dom->loadHTML(mb_convert_encoding($document, 'HTML-ENTITIES', 'UTF-8'), LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
    $dom->saveHTML($dom->documentElement));

Giải pháp 2:

$dom->loadHTML($document, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
utf8_decode($dom->saveHTML($dom->documentElement));

1
Tôi thấy thật tuyệt khi bạn chia sẻ những phát hiện của mình, nhưng Giải pháp 2 đã có mặt với câu hỏi chính xác này ở đây và Giải pháp 1 ở nơi khác. Ngoài ra, đối với Bài toán 1, câu trả lời không rõ ràng. Tôi tôn trọng ý định tốt của bạn, nhưng xin lưu ý rằng nó có thể tạo ra nhiều tiếng ồn cũng như cản trở người khác tìm ra giải pháp họ đang tìm kiếm mà tôi đoán là trái ngược với những gì bạn muốn đạt được với câu trả lời của bạn. Stackoverflow hoạt động tốt nhất nếu bạn xử lý một câu hỏi tại một thời điểm. Chỉ là một gợi ý.
hakre

2

Tôi phải đối mặt với 3 vấn đề với DOMDocumentlớp học.

1- Lớp này tải html với mã hóa ISO và các ký tự utf-8 không hiển thị ở đầu ra.

2- Ngay cả khi chúng ta choLIBXML_HTML_NOIMPLIEDlá cờ để phương pháp loadHtml, cho đến khi html đầu vào của chúng tôi không chứa một thẻ root, nó sẽ không được phân tích một cách chính xác.

3- Lớp này coi các thẻ HTML5 không hợp lệ.

Vì vậy, tôi đã ghi đè lớp này để giải quyết các vấn đề này và tôi đã thay đổi một số phương thức.

class DOMEditor extends DOMDocument
{
    /**
     * Temporary wrapper tag , It should be an unusual tag to avoid problems
     */
    protected $tempRoot = 'temproot';

    public function __construct($version = '1.0', $encoding = 'UTF-8')
    {
        //turn off html5 errors
        libxml_use_internal_errors(true);
        parent::__construct($version, $encoding);
    }

    public function loadHTML($source, $options = LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD)
    {
        // this is a bitwise check if LIBXML_HTML_NOIMPLIED is set
        if ($options & LIBXML_HTML_NOIMPLIED) {
            // it loads the content with a temporary wrapper tag and utf-8 encoding
            parent::loadHTML("<{$this->tempRoot}>" . mb_convert_encoding($source, 'HTML', 'UTF-8') . "</{$this->tempRoot}>", $options);
        } else {
            // it loads the content with utf-8 encoding and default options
            parent::loadHTML(mb_convert_encoding($source, 'HTML', 'UTF-8'), $options);
        }
    }

    private function unwrapTempRoot($output)
    {
        if ($this->firstChild->nodeName === $this->tempRoot) {
            return substr($output, strlen($this->tempRoot) + 2, -strlen($this->tempRoot) - 4);
        }
        return $output;
    }

    public function saveHTML(DOMNode $node = null)
    {
        $html = html_entity_decode(parent::saveHTML($node));
        if (is_null($node)) {
            $html = $this->unwrapTempRoot($html);
        }
        return $html;
    }

    public function saveXML(DOMNode $node = null, $options = null)
    {
        if (is_null($node)) {
            return '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>' . PHP_EOL . $this->saveHTML();
        }
        return parent::saveXML($node);
    }

}

Bây giờ tôi đang sử dụng DOMEditorthay vì DOMDocumentvà nó đã hoạt động tốt cho tôi cho đến nay

        $editor = new DOMEditor();
        $editor->loadHTML($html, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
        // works like a charm!
        echo $editor->saveHTML();

Điểm 1. của bạn được giải quyết bằng cách sử dụng mb_convert_encoding (chuỗi $, 'HTML-ENT khoáng', 'UTF-8'); trước khi sử dụng loadHTML () và 2.nd bằng cách sử dụng thẻ DIV xung quanh trong hàm trợ giúp của bạn, xung quanh mb_convert_encoding () bạn sử dụng chẳng hạn. Làm việc cho tôi đủ tốt. Thật vậy, nếu không có DIV, thì nó sẽ tự động thêm một đoạn trong trường hợp của tôi, điều này gây bất tiện vì thông thường họ có một số lề được áp dụng (bootstrap ..)
trainoocation

0

Tôi đã gặp vấn đề này là tốt.

Thật không may, tôi không cảm thấy thoải mái khi sử dụng bất kỳ giải pháp nào được cung cấp trong chuỗi này, vì vậy tôi đã đi kiểm tra một giải pháp sẽ làm tôi hài lòng.

Đây là những gì tôi tạo ra và nó hoạt động mà không có vấn đề:

$domxpath = new \DOMXPath($domDocument);

/** @var \DOMNodeList $subset */
$subset = $domxpath->query('descendant-or-self::body/*');

$html = '';
foreach ($subset as $domElement) {
    /** @var $domElement \DOMElement */
    $html .= $domDocument->saveHTML($domElement);
}

Về bản chất, nó hoạt động theo cách tương tự như hầu hết các giải pháp được cung cấp ở đây, nhưng thay vì thực hiện lao động thủ công, nó sử dụng bộ chọn xpath để chọn tất cả các thành phần trong cơ thể và nối mã html của chúng.


Giống như tất cả các giải pháp ở đây, nó không hoạt động cho mọi trường hợp: nếu chuỗi được tải không bắt đầu bằng đánh dấu, <p> </ p> đã được thêm, thì mã của bạn không hoạt động, vì nó sẽ thêm Đánh dấu <p> </ p> trong nội dung đã lưu
copndz

Để công bằng, tôi đã không thử nghiệm nó với văn bản thô, nhưng trên lý thuyết nên hoạt động. Đối với trường hợp cụ thể của bạn, bạn có thể cần phải thay đổi xpath thành một cái gì đó như descendant-or-self::body/p/*.
Nikola Petkanski

0

máy chủ của tôi có php 5.3 và không thể nâng cấp nên các tùy chọn đó

LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD

không dành cho tôi

Để giải quyết vấn đề này, tôi nói với Hàm SaveXML để in phần tử Body và sau đó chỉ cần thay thế "body" bằng "div"

Đây là mã của tôi, hy vọng nó sẽ giúp được ai đó:

<? 
$html = "your html here";
$tabContentDomDoc = new DOMDocument();
$tabContentDomDoc->loadHTML('<?xml encoding="UTF-8">'.$html);
$tabContentDomDoc->encoding = 'UTF-8';
$tabContentDomDocBody = $tabContentDomDoc->getElementsByTagName('body')->item(0);
if(is_object($tabContentDomDocBody)){
    echo (str_replace("body","div",$tabContentDomDoc->saveXML($tabContentDomDocBody)));
}
?>

utf-8 là để hỗ trợ tiếng Do Thái.


0

Câu trả lời của Alex là đúng, nhưng có thể gây ra lỗi sau trên các nút trống:

Đối số 1 được truyền cho DOMNode :: removeChild () phải là một phiên bản của DOMNode

Đây là mod nhỏ của tôi:

    $output = '';
    $doc = new DOMDocument();
    $doc->loadHTML($htmlString); //feed with html here

    if (isset($doc->firstChild)) {

        /* remove doctype */

        $doc->removeChild($doc->firstChild);

        /* remove html and body */

        if (isset($doc->firstChild->firstChild->firstChild)) {
            $doc->replaceChild($doc->firstChild->firstChild->firstChild, $doc->firstChild);
            $output = trim($doc->saveHTML());
        }
    }
    return $output;

Thêm trim () cũng là một ý tưởng tốt để loại bỏ khoảng trắng.


0

Tôi có thể quá muộn. Nhưng có lẽ ai đó (như tôi) vẫn có vấn đề này.
Vì vậy, không ai ở trên làm việc cho tôi. Bởi vì $ dom-> loadHTML cũng đóng các thẻ mở, không chỉ thêm các thẻ html và thẻ body.
Vì vậy, thêm một phần tử <div> không hoạt động đối với tôi, vì đôi khi tôi có khoảng 3-4 div không được tiết lộ trong đoạn html.
Giải pháp của tôi:

1.) Thêm điểm đánh dấu để cắt, sau đó tải đoạn html

$html_piece = "[MARK]".$html_piece."[/MARK]";
$dom->loadHTML($html_piece);

2.) làm bất cứ điều gì bạn muốn với tài liệu
3.) lưu html

$new_html_piece = $dom->saveHTML();

4.) trước khi bạn trả lại, hãy xóa các thẻ <p> </ p> khỏi điểm đánh dấu, thật lạ là nó chỉ xuất hiện trên [MARK] chứ không xuất hiện trên [/ MARK] ...!?

$new_html_piece = preg_replace( "/<p[^>]*?>(\[MARK\]|\s)*?<\/p>/", "[MARK]" , $new_html_piece );

5.) xóa mọi thứ trước và sau khi đánh dấu

$pattern_contents = '{\[MARK\](.*?)\[\/MARK\]}is';
if (preg_match($pattern_contents, $new_html_piece, $matches)) {
    $new_html_piece = $matches[1];
}

6.) trả lại

return $new_html_piece;

Sẽ dễ dàng hơn rất nhiều nếu LIBXMLTube_NOIMPLIED làm việc cho tôi. Nó schould, nhưng nó không phải là. PHP 5.4.17, libxml Phiên bản 2.7.8.
Tôi thấy thực sự lạ, tôi sử dụng trình phân tích cú pháp DOM DOM và sau đó, để khắc phục "điều" này tôi phải sử dụng regex ... Toàn bộ vấn đề là, không sử dụng regex;)


Có vẻ nguy hiểm những gì bạn làm ở đây, stackoverflow.com/a/29499718/367456 sẽ làm công việc cho bạn.
hakre 4/12/2016

Thật không may, điều này ( stackoverflow.com/questions/4879946/ Google ) sẽ không hoạt động với tôi. Như tôi đã nói: "Vì vậy, việc thêm một phần tử <div> không hoạt động với tôi, vì đôi khi tôi thích 3-4 div không được tiết lộ trong đoạn html" Vì một số lý do, DOMDocument muốn đóng tất cả các phần tử "không đóng". Trong trường hợp có thể, tôi sẽ nhận được một sự giải thoát trong một shortcode hoặc điểm đánh dấu khác, loại bỏ sự tự do và tôi muốn thao tác với phần khác của tài liệu, khi tôi thực hiện xong điều đó, tôi sẽ chèn lại phần giải phóng đó.
Joe

Có thể bỏ phần tử div ra và hoạt động trên phần tử cơ thể sau khi tải nội dung của riêng bạn. Phần tử cơ thể nên được thêm ngầm khi bạn tải một đoạn.
hakre

Vấn đề của tôi là, thẻ giải phóng không rõ ràng của tôi. Nó vẫn chưa được tiết lộ và DOMDocument sẽ đóng các phần tử đó. Giải thích như : < div >< div > ... < /div >. Tôi vẫn đang tìm giải pháp.
Joe

Hmm, tôi nghĩ rằng thẻ div luôn có một cặp đóng. Có lẽ Tidy có thể xử lý việc đó, nó cũng có thể hoạt động với các mảnh vỡ.
hakre

0

Đối với bất kỳ ai sử dụng Drupal, có một chức năng tích hợp để thực hiện việc này:

https://api.drupal.org/api/drupal/modules!filter!filter.module/feft/filter_dom_serialize/7.x

Mã để tham khảo:

function filter_dom_serialize($dom_document) {
  $body_node = $dom_document->getElementsByTagName('body')->item(0);
  $body_content = '';

  if ($body_node !== NULL) {
    foreach ($body_node->getElementsByTagName('script') as $node) {
      filter_dom_serialize_escape_cdata_element($dom_document, $node);
    }

    foreach ($body_node->getElementsByTagName('style') as $node) {
      filter_dom_serialize_escape_cdata_element($dom_document, $node, '/*', '*/');
    }

    foreach ($body_node->childNodes as $child_node) {
      $body_content .= $dom_document->saveXML($child_node);
    }
    return preg_replace('|<([^> ]*)/>|i', '<$1 />', $body_content);
  }
  else {
    return $body_content;
  }
}

Nâng cao. Sử dụng chức năng này từ API Drupal hoạt động tốt trên trang web Drupal 7 của tôi. Tôi đoán những người không sử dụng Drupal chỉ có thể sao chép chức năng vào trang web của riêng họ - vì không có gì cụ thể về Drupal về điều này.
Cấp tiến miễn phí

0

Bạn có thể sử dụng gọn gàng với chỉ hiển thị cơ thể:

$tidy = new tidy();
$htmlBody = $tidy->repairString($html, [
  'indent' =>  true,
  'output-xhtml' => true,
  'show-body-only' => true
], 'utf8');

Nhưng, remeber: gọn gàng xóa một số thẻ như biểu tượng Font Awesome: Sự cố thụt lề HTML (5) với PHP


-1
#remove doctype tag
$doc->removeChild($doc->doctype); 

#remove html & body tags
$html = $doc->getElementsByTagName('html')[0];
$body = $html->getElementsByTagName('body')[0];
foreach($body->childNodes as $child) {
    $doc->appendChild($child);
}
$doc->removeChild($html);

Muốn chia sẻ tại sao -1?
Dylan Maxey

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.