2010-05-26 19 views
18

Estoy siguiendo la sugerencia de esta pregunta Robust, Mature HTML Parser for PHP, sobre el análisis de html que puede estar mal formado con DOMDocument.Loop sobre DOMDocument

¿Hay alguna manera fácil de recorrer el documento analizado? Así que me gustaría hacer un bucle sobre html como este.

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

Y obtenga resultados algo como esto.

ul: 
li:value1 
li:value2 
li:value3 
p:subvalue 
p:hello world 

Usando $doc->childNodes por sí mismo en realidad no hago lo que quiero. Ya que no parece bajar a ramas inferiores en el árbol. Usé el código sugerido por halfdan y obtengo resultados como este.

html: 
html:value1 
     value1 
     value3 
      subvalue 

     hello world 
+0

Los objetos DOM pueden tener (pero no siempre) una propiedad llamada $ childNodes sobre la que puede iterar. Puede verificar la presencia o no de esta propiedad con el método hasChildNodes(). – GordonM

Respuesta

25

Prueba esto:

$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

Gracias, he actualizado mi pregunta para ser más claro. No creo que '$ doc-> childNodes' en sí mismo haga lo que quiero. Básicamente, quiero visitar cada nodo en el árbol, no solo ver todos los nodos en un nivel. – Zoredache

+0

Bien, dame un segundo y actualizaré mi publicación. – halfdan

1

que estaba teniendo problemas con los elementos que tenían datos c, donde incluso los elementos que no tienen hijos, donde regresan que lo hicieron.

No estoy seguro de por qué.

El trabajo en torno a lo que encontré fue a cambiar

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

a

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

Y el código ahora funciona perfectamente.

2

Es necesario utilizar PHP Simple HTML DOM Parser y el siguiente código:

<?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); 

funciona exactamente como se esperaba. Lo comprobé con la entrada que ya ha proporcionado y obtuve los siguientes resultados:

> php test2.php 

ul: 
li: value1 
li: value1 
li: value3 
p: subvalue 
p: hello world 
0

Una forma es recorrer el árbol de la siguiente manera:

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 
    // 
    ... 
} 

Esto funciona para la mayoría de los documentos, sin embargo parece que a veces el parentNode de alguna manera no está correctamente configurado y la función next_node() termina devolviendo la información incorrecta.