#php #html #parsing #tags #domdocument
#php #HTML #синтаксический анализ #Теги #domdocument
Вопрос:
Я ищу эту функциональность:
Дана эта html-страница:
<body>
<h1>Hello,
<b>world!</b>
</h1>
</body>
Я хочу получить массив, содержащий только ОТДЕЛЬНЫЕ текстовые элементы
(без дубликатов) и массив тегов, которые окружают текстовые элементы:
Результатом приведенного выше «html» будет массив, который выглядит следующим образом:
array =>
"Hello," surrounded by => "h1" and "body"
"world!" surrounded by => "b", "h1" and "body"
Я уже делаю это:
$res=$xpath->query("//body//*/text()");
что дает мне отдельное текстовое содержимое, но в нем отсутствуют html-теги.
Когда я просто делаю это:
$res=$xpath->query("//body//*");
Я получаю повторяющиеся тексты, по одному для каждого созвездия тегов: например: «мир!» будет отображаться 3 раза,
один раз для «тела», один раз для «h1» и один раз для «b», но, похоже, я не могу
получить информацию о том, какие тексты являются актуальнымидубликаты. Простой проверки на наличие дублирующегося текста
недостаточно, поскольку дублирующиеся тексты иногда являются просто подстроками предыдущих текстов, или веб-сайт
может содержать реальный дублирующийся текст, который затем будет удален, что неверно.
Как я мог решить эту проблему?
Большое вам спасибо!!
Томас
Комментарии:
1. Я думаю, что для этого вам нужен xquery. В любом случае использовать технологию XML для HTML нехорошо. HTML может быть неправильно сформирован, и, таким образом, вы получите ошибку синтаксического анализа.
2. @AurelioDeRosa DOM может анализировать неработающий HTML
3. Вы еще не приняли ответ. Не могли бы вы уточнить, что вы ищете в ответе и почему приведенные ответы вас не удовлетворяют.
Ответ №1:
Вы можете перебирать родительские узлы узлов DOMText:
$dom = new DOMDocument;
$dom->loadHTML($html);
$xpath = new DOMXPath($dom);
$textNodes = array();
foreach($xpath->query('/html/body//text()') as $i => $textNode) {
$textNodes[$i] = array(
'text' => $textNode->nodeValue,
'parents' => array()
);
for (
$currentNode = $textNode->parentNode;
$currentNode->parentNode;
$currentNode = $currentNode->parentNode
) {
$textNodes[$i]['parents'][] = $currentNode->nodeName;
}
}
print_r($textNodes);
Обратите внимание, что loadHTML
это добавит подразумеваемые элементы, например, добавит элементы html и head, которые вам нужно будет учитывать при использовании XPath. Также обратите внимание, что любые пробелы, используемые для форматирования, считаются DOMText, поэтому вы, вероятно, получите больше элементов, чем ожидаете. Если вы хотите запрашивать только непустые узлы DOMText, используйте
/html/body//text()[normalize-space(.) != ""]
Ответ №2:
В вашем примере кода $res=$xpath->query("//body//*/text()")
есть несколько DOMNodeList
DOMText
узлов. Для каждого DOMText
из них вы можете получить доступ к содержащему элементу через parentNode
свойство.
Комментарии:
1. Ах, хорошая идея, я только что попробовал, и действительно, я могу получить доступ к родительскому узлу, поэтому я мог вручную перебирать все «более высокие» узлы, чтобы получить окружающие теги. Единственным недостатком может быть производительность. Возможно, есть и другой подход, который делает это всего за один запуск и, следовательно, может быть, более эффективным. Но, тем не менее, хорошая идея от вас, и я хочу поблагодарить вас за это и протестирую ее сейчас, чтобы увидеть ее производительность.