首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >如何在没有超文本标记语言包装器的情况下saveHTML DOMDocument?

如何在没有超文本标记语言包装器的情况下saveHTML DOMDocument?
EN

Stack Overflow用户
提问于 2011-02-03 05:15:16
回答 30查看 64.1K关注 0票数 124

我是下面的函数,我正在努力在输出内容之前不附加XML、HTML、body和p标记包装器的情况下输出DOMDocument。建议的修复方法:

代码语言:javascript
复制
$postarray['post_content'] = $d->saveXML($d->getElementsByTagName('p')->item(0));

仅当内容中没有块级元素时才有效。但是,当它这样做时,就像下面使用h1元素的示例中一样,来自saveXML的结果输出被截断为...

有人指出这篇文章是一种可能的变通方法,但我不明白如何在这个解决方案中实现它(参见下面注释掉的尝试)。

有什么建议吗?

代码语言:javascript
复制
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;
}
EN

回答 30

Stack Overflow用户

发布于 2014-03-19 04:58:07

所有这些答案现在都是错误的,因为从PHP5.4和Libxml2.6开始,loadHTML现在有一个$option参数,该参数指示Libxml应该如何解析内容。

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

代码语言:javascript
复制
$html->loadHTML($content, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);

在执行saveHTML()时,将不会有doctype<html><body>

LIBXML_HTML_NOIMPLIED关闭自动添加隐含的html/正文元素LIBXML_HTML_NODEFDTD会阻止在找不到默认文档类型时添加该文档类型。

有关Libxml参数的完整文档请参阅here

(请注意,loadHTML文档说需要Libxml2.6,但LIBXML_HTML_NODEFDTD仅在Libxml 2.7.8中可用,LIBXML_HTML_NOIMPLIED在Libxml 2.7.7中可用)

票数 243
EN

Stack Overflow用户

发布于 2011-08-05 17:00:32

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

代码语言:javascript
复制
# remove <!DOCTYPE 
$doc->removeChild($doc->doctype);           

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

Stack Overflow用户

发布于 2017-07-02 08:06:45

顶部答案的问题是LIBXML_HTML_NOIMPLIED 是不稳定的

它可以重新排序元素(特别是将顶部元素的结束标记移到文档的底部),添加随机的p标记,也许还可以处理各种其他问题[1]。它可能会为您删除htmlbody标记,但代价是行为不稳定。在生产中,这是一个危险信号。简而言之:

不使用 LIBXML_HTML_NOIMPLIED.的请改用 substr.代替

想想看。<html><body></body></html>的长度是固定的,并且在文档的两端-它们的大小和位置都不会改变。这使我们可以使用substr将它们去掉:

代码语言:javascript
复制
$dom = new domDocument; 
$dom->loadHTML($html, LIBXML_HTML_NODEFDTD);

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

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

我们将12从文档的开头去掉,因为<html><body> = 12个字符(<<>>+html+body = 4+4+4),我们向后退,去掉15个字符,因为\n</body></html> = 15个字符(\n+//+<<>>+body+html =1+2+4+4+ 4)

请注意,我仍然使用LIBXML_HTML_NODEFDTD,省略了包含的!DOCTYPE。首先,这简化了substr删除HTML/BODY标记的过程。其次,我们不会用substr删除文档类型,因为我们不知道'default doctype‘是否会一直是一个固定的长度。但是,最重要的是,LIBXML_HTML_NODEFDTD阻止DOM解析器将非HTML5doctype应用于文档-这至少防止解析器将它不能识别的元素视为松散文本。

我们知道HTML/BODY标记的长度和位置是固定的,而且我们知道,如果没有某种类型的弃用通知,像LIBXML_HTML_NODEFDTD这样的常量是永远不会被删除的,所以上面的方法应该会在未来得到很好的应用,但是...

唯一要注意的是,DOM实现可能会改变...the /BODY标记在文档中的放置方式-例如,删除文档末尾的换行符、在标记之间添加空格或添加换行符。

这可以通过搜索body的开始和结束标记的位置并使用这些偏移量来修剪我们的长度来解决。我们使用strposstrrpos分别从前面和后面找到偏移量:

代码语言:javascript
复制
$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);

在结束时,重复了最终的、面向未来的答案

代码语言:javascript
复制
$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);

没有doctype,没有html标签,没有body标签。我们只能希望DOM解析器很快就能焕然一新,我们可以更直接地消除这些不需要的标记。

票数 22
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/4879946

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档