【问题标题】:PHP Dom Documents: getting textContent ignoring script tags and commentsPHP Dom 文档:获取 textContent 忽略脚本标签和注释
【发布时间】:2011-11-05 09:35:24
【问题描述】:

我使用 dom doc 从数据库中加载 html,如下所示:

$doc = new DOMDocument();
@$doc->loadHTML($data);
$doc->encoding = 'utf-8';
$doc->saveHTML();

然后我通过执行以下操作获取正文:

$bodyNodes = $doc->getElementsByTagName("body");
$words = htmlspecialchars($bodyNodes->item(0)->textContent);

我得到的单词包括<body> 中的所有内容。 <scripts> 之类的东西也包括在内。 如何删除它们并只保留真实的文本内容?

【问题讨论】:

  • 你的意思是递归提取@9​​87654325@中每个元素的文本内容?
  • 是的,只有有意义的文本内容,不包括 javascripts 或其他 html cmets 等无用数据。

标签: php xml dom


【解决方案1】:

您可以为此使用XPath

借用上面示例中使用的 HTML arnaud:

$html = <<< HTML
<p>
    test<span>foo<b>bar</b>
</p>
<script>
    ignored
</script>
<!-- comment is ignored -->
<p>test</p>
HTML;

你只是 query 所有 text nodes 不是 not children of a script tagdo not evaluate to an empty string。您还要确保您没有preserveWhiteSpace,因此不考虑用于格式化的空格。

$dom = new DOMDocument;
$dom->preserveWhiteSpace = false;
$dom->loadHtml($html);

$xp    = new DOMXPath($dom);
$nodes = $xp->query('/html/body//text()[
    not(ancestor::script) and
    not(normalize-space(.) = "")
]');

foreach($nodes as $node) {
    var_dump($node->textContent);
}

将输出 (demo)

string(10) "
    test"
string(3) "foo"
string(3) "bar"
string(4) "test"

【讨论】:

  • 这个功能有帮助。它实际上能够将单词的句子识别并拆分为一个字符串。
  • @nuttynibbles 它不识别单词,也不识别句子。 XPath 是一种用于 XML 的查询语言。它不知道 XML 文档的内容,只知道结构。见my answer here for an introduction to DOM concepts
【解决方案2】:

您必须访问所有节点并返回它们的文本。如果一些包含其他节点,请访问它们。

这可以通过这个基本的递归算法来完成:

extractNode:
    if node is a text node or a cdata node, return its text
    if is an element node or a document node or a document fragment node:
        if it’s a script node, return an empty string
        return a concatenation of the result of calling extractNode on all the child nodes
    for everything else return nothing

实施:

function extractText($node) {    
    if (XML_TEXT_NODE === $node->nodeType || XML_CDATA_SECTION_NODE === $node->nodeType) {
        return $node->nodeValue;
    } else if (XML_ELEMENT_NODE === $node->nodeType || XML_DOCUMENT_NODE === $node->nodeType || XML_DOCUMENT_FRAG_NODE === $node->nodeType) {
        if ('script' === $node->nodeName) return '';

        $text = '';
        foreach($node->childNodes as $childNode) {
            $text .= extractText($childNode);
        }
        return $text;
    }
}

这将返回给定 $node 的 textContent,忽略脚本标签和 cmets。

$words = htmlspecialchars(extractText($bodyNodes->item(0)));

在这里试试:http://codepad.org/CS3nMp7U

【讨论】:

  • 我添加了算法的简要说明
猜你喜欢
  • 1970-01-01
  • 2021-06-07
  • 2017-10-30
  • 1970-01-01
  • 2015-12-22
  • 2018-03-10
  • 2015-06-03
  • 2015-01-27
  • 2017-05-25
相关资源
最近更新 更多