Цикл над DOMDocument - PullRequest
       10

Цикл над DOMDocument

20 голосов
/ 26 мая 2010

Я следую предложению из этого вопроса Надежный, Зрелый 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

Ответы [ 4 ]

30 голосов
/ 26 мая 2010

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

$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 голосов
/ 17 ноября 2013

Вам необходимо использовать 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
1 голос
/ 04 сентября 2017

Один из способов - пройтись по дереву следующим образом:

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

1 голос
/ 23 октября 2012

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

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

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

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

до

if($node->childNodes->length != 1) {
        showDOMNode($node);
    }

И код теперь работает отлично.

...