Цикл над DOMDocument
Я следую предложению из этого вопроса. Надежно, Зрелый HTML-парсер для PHP, о разборе html, который может быть искажен DOMDocument.
Есть ли простой способ перебрать анализируемый документ? Поэтому я хотел бы перебрать html таким образом.
$html='<ul>
<li>value1</li>
<li>value1</li>
<li>value3
<p>subvalue</p>
</li>
</ul>
<p>hello world</p>';
$doc = new DOMDocument();
$doc->loadHTML($html);
???
foreach (??? as $node)
{
print $node->nodeName.':'.$node->nodeValue;
}
И получите несколько результатов.
ul:
li:value1
li:value2
li:value3
p:subvalue
p:hello world
Использование $doc->childNodes
само по себе не делает то, что я хочу. Так как это не похоже на нижние ветки дерева. Я использовал код, предложенный halfdan, и я получаю такие результаты.
html:
html:value1
value1
value3
subvalue
hello world
Ответы
Ответ 1
Попробуйте следующее:
$doc = new DOMDocument();
$doc->loadHTML($html);
showDOMNode($doc);
function showDOMNode(DOMNode $domNode) {
foreach ($domNode->childNodes as $node)
{
print $node->nodeName.':'.$node->nodeValue;
if($node->hasChildNodes()) {
showDOMNode($node);
}
}
}
Ответ 2
Вам нужно использовать PHP Simple HTML DOM Parser и следующий код:
<?php
require_once 'simplehtmldom/simple_html_dom.php';
function iterateHtmlElements($html)
{
$dom = str_get_html($html);
$dom->set_callback('handleElement');
$dom->__toString();
echo "\n";
}
function handleElement(simple_html_dom_node $elem)
{
if($elem->tag == 'text') {
echo $elem->innertext();
}
else {
echo "\n" . $elem->tag . ": ";
}
}
$html='<ul>
<li>value1</li>
<li>value1</li>
<li>value3
<p>subvalue</p>
</li>
</ul>
<p>hello world</p>';
iterateHtmlElements($html);
Он работает точно так, как ожидалось. Я проверил его с предоставленным вами вводом и получил следующие результаты:
> php test2.php
ul:
li: value1
li: value1
li: value3
p: subvalue
p: hello world
Ответ 3
У меня возникли проблемы с элементами, имевшими c-данные, где даже элементы, у которых не было детей, возвращающих их.
Я не уверен, почему это было.
Работа, которую я обнаружил, заключалась в изменении
if($node->hasChildNodes()) {
showDOMNode($node);
}
к
if($node->childNodes->length != 1) {
showDOMNode($node);
}
И теперь код отлично работает.
Ответ 4
Один из способов - следовать дереву следующим образом:
function next_node($node)
{
if($node->firstChild != null)
{
return $node->firstChild;
}
if($node->nextSibling != null)
{
return $node->nextSibling;
}
for($node = $node->parentNode; $node != null; $node = $node->parentNode)
{
if($node->nextSibling != null)
{
return $node->nextSibling;
}
}
return null;
}
for($node = $doc; $node != null; $node = next_node($node))
{
// handle node (read-only mode, if you need read-write
// you have to save all the nodes in an array and then
// use that array
//
...
}
Это работает для большинства документов, однако, похоже, что время parentNode
некорректно задано, а функция next_node()
возвращает неверную информацию.