如何保存没有HTML包装的DOMDocumentHTML?

我是下面的函数,我很努力地输出DOMDocument,而不会在输出内容之前附加XML,HTML, bodyp标记包装。 build议修复:

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

只有当内容中没有块级元素时才能使用。 但是,如果在h1元素下面的例子中,saveXML产生的输出被截断为…

如果你喜欢</ p>

我已经指出这个post是一个可能的解决方法,但我不明白如何实现它到这个解决scheme(请参阅下面的注释尝试)。

有什么build议么?

 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; } 

所有这些答案现在都是错误的 ,因为从PHP 5.4和Libxml 2.6开始, loadHTML现在有一个$option参数,它指示Libxml如何parsing内容。

因此,如果我们加载这些选项的HTML

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

在做saveHTML() ,不会有doctype ,没有<html>和没有<body>

LIBXML_HTML_NOIMPLIEDclosures隐含的HTML / body元素的自动添加LIBXML_HTML_NODEFDTD防止未find默认的文档types时添加。

有关Libxml参数的完整文档在这里

(请注意, loadHTML文档说需要使用Libxml 2.6,但LIBXML_HTML_NODEFDTD仅在Libxml 2.7.8中可用,而LIBXML_HTML_NOIMPLIED在Libxml 2.7.7中可用)

用loadHTML()加载文档后直接删除节点:

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

使用saveXML()代替,并将documentElement作为parameter passing给它。

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

http://php.net/domdocument.savexml

使用DOMDocumentFragment

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

一个巧妙的技巧是使用saveHTML ,然后saveHTMLhtmlbody标签插入到load阶段,而不是save阶段。

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

注意,这有点不好意思,你应该使用约拿的答案,如果你能得到它的工作。

我在俱乐部有点晚,但不想分享我发现的方法。 首先我已经得到了正确的版本loadHTML()来接受这些不错的select,但LIBXML_HTML_NOIMPLIED没有在我的系统上工作。 另外用户报告parsing器的问题(例如这里和这里 )。

我创build的解决scheme其实很简单。

要加载的HTML放在一个<div>元素中,所以它有一个包含所有要加载的节点的容器。

然后这个容器元素从文档中被移除(但它的DOME元素仍然存在)。

然后从文档中删除所有直接的孩子。 这包括任何添加的<html><head><body>标记(实际上是LIBXML_HTML_NOIMPLIED选项)以及<!DOCTYPE html ... loose.dtd">声明(实际上是LIBXML_HTML_NODEFDTD )。

然后将容器的所有直接子项再次添加到文档中并将其输出。

 $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像往常一样工作,只需要注意现在有多个文档元素,所以不是一个根节点:

 $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〜精确+ 2(cli)(内置:Dec 21 2014 20:28:53)

使用此function

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

在撰写本文时(2012年6月),其他解决scheme都没有能够完全满足我的需求,所以我写了一个处理以下情况的解决scheme:

  • 接受没有标签的纯文本内容以及HTML内容。
  • 不添加任何标签(包括<doctype><xml><html><body><p>标签)
  • 只留下<p>任何东西。
  • 单独留下空文本。

所以这是一个解决这些问题的解决scheme:

 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; } } 

我也写了一些testing,可以住在同一个class上:

 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 } 

你可以检查它是否适用于你自己。 DomDocumentWorkaround::testAll()返回这个:

  Succeeded Succeeded Succeeded Succeeded 

好吧,我find了一个更优雅的解决scheme,但是这只是单调乏味的:

 $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 } 

好吧,希望这不会遗漏任何东西,帮助别人?

LIBXML_HTML_NOIMPLIED问题是LIBXML_HTML_NOIMPLIED不稳定

它可以对元素进行重新sorting(特别是将顶层元素的结束标记移动到文档底部),添加随机p标签以及其他各种问题[1] 。 它可能会删除htmlbody标签,但代价是不稳定的行为。 在生产中,这是一面红旗。 简而言之:

请勿使用LIBXML_HTML_NOIMPLIED相反,使用substr


想想看。 <html><body></body></html>长度是固定的,并且在文档的两端 – 它们的大小不会改变,也不会改变它们的位置。 这使我们可以使用substr来切断它们:

 $dom = new domDocument; $dom->loadHTML($html, LIBXML_HTML_NODEFDTD); echo substr($dom->saveHTML(), 12, -15); // the star of this operation 

这不是最终的解决scheme!请参阅下面的完整答案 ,继续阅读上下文)

由于<html><body> = 12个字符( <<>>+html+body = 4 + 4 + 4),所以我们从文档的开始处剪掉了12个字符,而我们后退了15个字符,因为\n</body></html> = 15个字符( \n+//+<<>>+body+html = 1 + 2 + 4 + 4 + 4)

请注意,我仍然使用LIBXML_HTML_NODEFDTD忽略包含的!DOCTYPE 。 首先,这简化了HTML / BODY标签的子删除。 其次,我们不会删除substr的文档types,因为我们不知道' default doctype '是否总是固定长度。 但是,最重要的是, LIBXML_HTML_NODEFDTD阻止DOMparsing器将非HTML5文档types应用于文档 – 至less会阻止parsing器将其不能识别为松散文本的元素处理。

我们知道HTML / BODY标签具有固定的长度和位置,并且我们知道像LIBXML_HTML_NODEFDTD这样的常量不会在没有某种types的弃用通知的情况下被移除,因此上述方法应该在未来得到很好的使用, 但是


…唯一需要注意的是,DOM实现可以改变HTML / BODY标签放置在文档中的方式 – 例如,删除文档末尾的换行符,在标签之间添加空格或添加换行符。

这可以通过searchbody的打开和closures标签的位置来补救,并使用这些偏移来修剪我们的长度。 我们使用strposstrrpos分别从前面和后面find偏移量:

 $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); 

最后,重复最后的,面向未来的答案

 $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); 

没有文档types,没有HTML标签,没有正文标签。 我们只能希望DOMparsing器能很快得到一层新的涂料,我们可以更直接的去除这些不需要的标签。

添加<meta>标签将触发DOMDocument的修复行为。 好的一点是你根本不需要添加标签。 如果你不想使用你select的编码,只要把它作为构造函数parameter passing就可以了。

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(); 

产量

 <div>Hello World</div> 

感谢@Bart

我也有这个要求,喜欢上面Alex发布的解决scheme。 有几个问题 – 如果<body>元素包含多个子元素,则生成的文档将仅包含<body>的第一个子元素,而不是全部。 此外,我需要剥离来有条件地处理事情 – 只有当你有HTML标题的文件。 所以我把它细化如下。 我没有去掉<body> ,而是将其转换为<div> ,并将XML声明和<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); } } 

就像其他成员一样,我首先感受到@Alessandro Vendruscolo的简单和可怕的力量。 简单地将一些被标记的常量传递给构造函数的能力似乎太好了。 对我来说是这样的。 我有正确的版本的LibXML以及PHP,但是不pipe它还将HTML标签添加到Document对象的节点结构。

我的解决scheme的工作方式比使用…

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

标志或….

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

节点移除,在DOM中没有结构化顺序的情况下变得混乱。 代码片段再次无法预先确定DOM结构。

我开始了这个旅程,希望通过一种简单的方法来进行DOM遍历,JQuery是如何实现的,或者至less在某种方式下,具有结构化数据集单独链接,双向链接或树状结点遍历。 我不在乎,只要我可以像HTML那样parsing一个string,并且具有节点实体类属性的惊人力量。

到目前为止DOMDocument对象已经离开了我想要的…像许多其他程序员似乎…我知道我已经看到了很多这个问题的挫折,所以我最后…(经过大约30个小时的尝试和失败typestesting)我已经find了一个方法来获得这一切。 我希望这可以帮助别人

首先,我对一切愤世嫉俗……大声笑…

我会花一辈子的时间才能同意任何人在这个用例中需要第三方的类。 我非常非常喜欢使用任何第三方的类结构,但是我偶然发现了一个很好的parsing器。 (在我投入之前,谷歌大约有30次,所以如果你避免这样做,就不会感到孤独,因为它看起来不像任何非正式的行为)

如果你正在使用代码片段,并且需要,代码干净并且不受parsing器的影响,没有使用额外的标签,那就使用simplePHPParser 。

这太神奇了,和JQuery很像。 我没有经常留下深刻的印象,但是这个类使用了很多很好的工具,而且迄今为止我还没有parsing错误。 我是能够做这个class做的一个巨大的粉丝。

你可以find它的文件在这里下载,其启动说明在这里 ,和它的API 在这里 。 我强烈build议使用这个类的简单方法,可以做一个.find(".className")的方式将使用JQuery查找方法,甚至熟悉的方法,如getElementByTagName()getElementById()

当你在这个类中保存节点树时,它根本不会添加任何东西。 你可以简单地说$doc->save(); 它将整个树输出到一个string没有任何大惊小怪。

现在我将在未来使用这个parsing器来处理所有不带宽的项目。

我有PHP 5.3,这里的答案不适合我。

$doc->replaceChild($doc->firstChild->firstChild->firstChild, $doc->firstChild); 只用第一个孩子取代了所有的文档,我有很多段落,只有第一个被保存,但解决scheme给了我一个不用regex写的东西的好起点我留下了一些意见,我很肯定这可以改善,但如果某人遇到同样的问题,那么这可能是一个很好的起点。

 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; } 

那么我们可以这样使用它:

 $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); 

请注意, appendChild接受一个DOMNode所以我们不需要创build新的元素,我们可以重用实现DOMNode现有元素,比如DOMElement这对于在处理多个HTML / XML文档时保持代码“理智”

我遇到这个话题find一种方法来删除HTML包装。 使用LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD工作的很好,但我有一个utf-8的问题。 经过很多努力,我find了解决办法。 我把它发送给任何人都有同样的问题。

由于<meta http-equiv="Content-Type" content="text/html; charset=utf-8">

问题:

 $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(); 

解决scheme1:

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

解决scheme2:

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

如果Alessandro Vendruscolo回答的标志解决scheme不起作用,您可以试试这个:

 $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; 

$bodyTag将包含完整处理后的HTML代码,除了<body>标记(这是您的内容的根目录)外,不包含所有这些HTML包装。 然后你可以使用正则expression式或trim函数将其从最后一个string中移除(在saveHTML之后),或者像上面那样遍历它的所有$finalHtml ,将它们的内容保存到一个临时variables$finalHtml并返回它我相信更安全)。

这是2017年,对于这个2011年的问题,我不喜欢任何答案。 大量的正则expression式,大类,loadXML等…

解决已知问题的简单解决scheme:

 $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); 

简单,简单,坚实,快速。 此代码将工作有关HTML标记和编码,如:

 $html = '<p>äöü</p><p>ß</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 ); 

你可以自己添加身体,以防止任何奇怪的想法在furure。

Thirt选项:

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

我也遇到了这个问题。

不幸的是,我并没有感觉到使用这个线程提供的任何解决scheme,所以我去检查一个会满足我的。

这就是我所做的,没有任何问题:

 $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); } 

在本质上,它的工作方式与这里提供的大多数解决scheme类似,但是使用xpathselect器来select正文中的所有元素并连接它们的html代码,而不是手动操作。

我的服务器得到了PHP 5.3,不能升级,所以这些选项

 LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD 

不适合我

为了解决这个问题,我告诉SaveXML函数打印Body元素,然后用“div”replace“body”

这里是我的代码,希望这是帮助某人:

 <? $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是希伯来文的支持。

亚历克斯答案是正确的,但可能会导致空节点上的以下错误:

传递给DOMNode :: removeChild()的参数1必须是DOMNode的一个实例

这里是我的小国防部:

  $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; 

添加trim()也是删除空格的好主意。

我也许来不及了。 但也许有人(像我)仍然有这个问题。
所以,以上都没有为我工作。 因为$ dom-> loadHTML也closures了开放标签,不仅添加html和body标签。
所以添加一个<div>元素对我来说并不合适,因为我有时候喜欢在html中使用3-4个未closures的div。
我的解决scheme

1)添加剪切标记,然后加载html片段

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

2.)做任何你想要的文件
3.)保存html

 $new_html_piece = $dom->saveHTML(); 

4.)在返回之前,从标记中删除<p> </ p>标记,奇怪的是它只出现在[MARK]上,而不是[/ MARK] …!

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

5)删除标记前后的所有内容

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

6.)返回它

 return $new_html_piece; 

如果LIBXML_HTML_NOIMPLIED为我工作,那将会容易得多。 它可以,但事实并非如此。 PHP 5.4.17,libxml版本2.7.8。
我觉得很奇怪,我使用HTML DOMparsing器,然后,为了解决这个“事情”,我必须使用正则expression式…整个过程中,不要使用正则expression式;)

For anyone using Drupal, there's a built in function to do this:

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

参考编号:

 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; } }