PHP Dom Documents: получение textContent, игнорирование скриптовых тегов и комментариев - PullRequest
5 голосов
/ 28 августа 2011

я использую 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> также были включены.Как мне удалить их и сохранить только реальный текстовый контент?

Ответы [ 2 ]

5 голосов
/ 28 августа 2011

Для этого вы можете использовать XPath .

Заимствование арно HTML, использованного в приведенном выше примере:

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

Вы просто запрос все текстовые узлы , которые не являются , не являются потомками тега сценария и , не оцениваются как пустая строка .Вы также убедитесь, что вы не 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"
5 голосов
/ 28 августа 2011

Вы должны посетить все узлы и вернуть их текст. Если некоторые содержат другой узел, посетите их тоже.

Это можно сделать с помощью этого базового рекурсивного алгоритма:

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

Это вернет textContent данного $ узла, игнорируя теги скрипта и комментарии.

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

Попробуйте здесь: http://codepad.org/CS3nMp7U

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...