php - ¿Cómo obtener el nivel DiVs?

CorePress2024-01-25  11

$html ='<html>
<head>
    <title></title>
</head>
<body>
    <div class="">
        <div class="">
           <p><strong><span style="color:#FF0000"> Content1 </span></strong></p>
           <p style="text-align:center"> Content2 <img src="https://example.com/bla1.jpg"/></p>
        </div>
       
        <h2> Header </h2>
        <div class=""><p><strong> Content3 </strong></p> </div>

    </div>

    <div class=""> Content4 </div>
    <div class="">
                   <p> Content5 </p>  
                   <p> Content6 </p> 
                   <span> blah.. </span>
    </div>
</body></html>';

Necesito tener una matriz de este tipo:

Esto significa si cada DIV (incluido P) tiene un DIV secundario o principal.

¿Por qué utilizar específicamente getElementsByTagName? Si usas XPath esta tarea sería mucho más sencilla

- Profesor Abronsius

28 de marzo de 2021 a las 8:41

No conozco xpath, ¿puedes ayudarme con un ejemplo?

-yaradan

28/03/2021 a las 10:33



------------------------------------

A menos que esté comprometido a utilizar sólo getElementsByTagName en combinación con selectores principales/secundarios, probablemente encontrará que una consulta XPath simple es el enfoque más simple para encontrar los elementos p ubicados dentro de elementos div.

$html ='<html>
<head>
    <title></title>
</head>
<body>
    <div class="">
        <div class="">
           <p><strong><span style="color:#FF0000"> Content1 </span></strong></p>
           <p style="text-align:center"> Content2 <img src="https://example.com/bla1.jpg"/></p>
        </div>
       
        <h2> Header </h2>
        <div class=""><p><strong> Content3 </strong></p> </div>

    </div>

    <div class=""> Content4 </div>
    <div class="">
                   <p> Content5 </p>  
                   <p> Content6 </p> 
                   <span> blah.. </span>
    </div>
</body></html>';


$tmp=array();


$dom=new DOMDocument;
$dom->loadHTML( $html );

$xp=new DOMXPath( $dom );
$col=$xp->query('//div/p');

if( $col && $col->length > 0 ){
    foreach( $col as $node )$tmp[]=$node->textContent;
}

printf('<textarea cols=100 rows=10>%s</textarea>',print_r( $tmp, true ) );

Lo cual produce:

Actualización:

En lugar de almacenar el valor de nodo/contenido de texto, desea almacenar el HTML completo contenido dentro del nodo para, con ese fin, clonar el nodo (y su contenido) y guardarlo en la matriz de salida.

$tmp=array();


$dom=new DOMDocument;
$dom->loadHTML( $html );

$xp=new DOMXPath( $dom );
$col=$xp->query('//div/p');

if( $col && $col->length > 0 ){
    foreach( $col as $node ){
        $clone=$node->cloneNode( true ); //clone node with ALL children
        $tmp[]=$dom->saveHTML( $clone ); // save the HTML within
    }
}

printf('<textarea cols=100 rows=10>%s</textarea>',print_r( $tmp, true ) );

3

muchas gracias. Pero necesito exactamente el formato anterior para la salida. Con la estructura html original

-yaradan

28/03/2021 a las 10:27

OK: hice un cambio anterior que creo que satisface tus requisitos

-Profesor Abronsius

28/03/2021 a las 10:55

Gracias de nuevo. Este código está muy cerca de mi objetivo. Pero necesito obtener los párrafos (etiquetas P) en divisiones separadas (divs). En mi ejemplo hay tres 'divs' (anidados y no anidados) que contienen 'etiquetas P' . Como resultado, la salida debe contener tres celdas de la matriz. Como arriba.

-yaradan

28/03/2021 a las 11:31



------------------------------------

El suyo es un buen intento, pero preferiría obtener todas las etiquetas p y luego ascender en la jerarquía de nodos DOM si div es el padre del nodo p actual. De esta manera, solo recopilará aquellos p nodos que tengan div como padre y no de otra manera. En otras palabras, es como el selector CSS div > pág.

$ps = array();
$doc = new DomDocument('1.0', 'UTF-8');
$doc->loadHTML(mb_convert_encoding($HTML, 'HTML-ENTITIES', 'UTF-8'));

foreach($doc->getElementsByTagName('p') as $p){
   $curr_node = $p->parentNode;
   while(property_exists($curr_node,'tagName')){
      if($curr_node->tagName == 'div'){
        $ps[] = $p;
        break;
      }
      $curr_node = $curr_node->parentNode;
      if($curr_node === null) break;
   }
}

print_r($ps);

Actualización n.º 1:

Para obtener ps por div, puede recorrer de forma recursiva todos los nodos secundarios por div y recopilar todos los ps y agregarlos al resultado como se muestra a continuación:

function getPs($node,&$result){
    foreach ($node->childNodes as $c_node) {
        if(property_exists($c_node, 'tagName') && $c_node->tagName == 'p'){
            $result[] = $c_node;
        }
        getPs($c_node,$result);
    }
}

$ps = [];

foreach($doc->getElementsByTagName('div') as $div){
   $child_ps = [];
   getPs($div,$child_ps);
   if(count($child_ps) > 0) $ps[] = $child_ps;
}

echo "<pre>";
print_r($ps);

Actualización n.º 2:

Para obtener la representación de cadena HTML del nodo p, cambie

$result[] = $c_node;

a

$result[] = $c_node->ownerDocument->saveXML( $c_node );

7

muchas gracias. Pero necesito exactamente el formato anterior para la salida. Con la estructura html original

-yaradan

28/03/2021 a las 10:27

@yaradan Simplemente agrupa los datos por div principal usando matrices asociativas o usa la recursividad para recorrer todos los nodos secundarios de un div

-nice_dev

28/03/2021 a las 11:28

@yaradan Actualicé mi respuesta. Puedes usar ->textNode, creo, para obtener la parte HTML.

-nice_dev

28/03/2021 a las 12:28

1

Muchas gracias. Este código funciona muy bien. ¿Cómo puedo usar saveHTML en la salida? Es decir, en lugar de "contenido", tengo "el elemento completo". Es decir, en lugar de "Contenido1", "<p><strong><span style="color:#FF0000"> Contenido1 </span></strong></p>" debe imprimirse

-yaradan

28/03/2021 a las 14:09

@yaradan ¿Algún problema?

-nice_dev

3 de abril de 2021 a las 6:37

Su guía para un futuro mejor - libreflare
Su guía para un futuro mejor - libreflare