2010-05-26 2 views
18

Я следую предложению по этому вопросу Robust, Mature HTML Parser for PHP, о разборе html, который может быть искажен с помощью DOMDocument.Loop over 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 
+0

Объекты DOM могут (но не всегда) иметь свойство, называемое $ childNodes, которое вы можете перебрать. Вы можете проверить наличие или иное свойство этого свойства с помощью метода hasChildNodes(). – GordonM

ответ

25

Попробуйте это:

$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); 
     } 
    }  
} 
+0

Спасибо, я уточнил свой вопрос, чтобы быть более понятным. Я не верю, что '$ doc-> childNodes' сам делает то, что я хочу. В основном я хочу посетить каждый узел в дереве, а не просто увидеть все узлы на одном уровне. – Zoredache

+0

Хорошо, дай мне секунду, и я обновлю свой пост. – halfdan

1

У меня были проблемы с элементами, которые имели гр данные, где даже элементы, которые не имеют детей, где возвращающиеся, что они сделали.

Я не уверен, почему это было.

Обходной я нашел, чтобы изменить

if($node->hasChildNodes()) { 
     showDOMNode($node); 
    } 

в

if($node->childNodes->length != 1) { 
     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 
0

Один из способов заключается идти дерево следующим образом:

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() возвращает неверную информацию.