Foros del Web » Programando para Internet » PHP »

Parseando XHTML con Expresiones regulares [Ayuda]

Estas en el tema de Parseando XHTML con Expresiones regulares [Ayuda] en el foro de PHP en Foros del Web. Hola que tal, miren... Ando buscando la forma de analizar archivos xhtml. Y quiero saber si alguien me puede ayudar... Lo que necesito lograr es ...
  #1 (permalink)  
Antiguo 28/09/2009, 14:38
 
Fecha de Ingreso: noviembre-2008
Mensajes: 67
Antigüedad: 15 años, 4 meses
Puntos: 0
Pregunta Parseando XHTML con Expresiones regulares [Ayuda]

Hola que tal, miren... Ando buscando la forma de analizar archivos xhtml. Y quiero saber si alguien me puede ayudar...

Lo que necesito lograr es extraer los tags de uns archivo xhtml a un array de la siguiente forma... Por ej.

Si el xhtml fuese asi:
Código html:
Ver original
  1.         <head>
  2.                 <title>XHTML</title>
  3.         </head>
  4.         <body>
  5.                 <p class="neat">Lorem ipsum dolor sit amet... </p>
  6.         </body>
  7. </html>

yo necesitaria armar una array que me de la siguiente info. tomo como ejemplo el tag p

Código php:
Ver original
  1.         [5] => array(
  2.                 [tag] => "p",
  3.                 [attributes] => " class=\"neat\"",
  4.                 [value] => "Lorem ipsum dolor sit amet... ",
  5.                 [depth] => "2"
  6.         )
  7. )

para hacer mas simple la explicacion... sme conformo solo con saber como extraer tal info.

estve usando una funcion en la cual utilizo la siguiente expresion regular:
Código php:
Ver original
  1. $pattern = '/\<([a-z0-9\-]+)([^\>]+)?\>((.*)\<\/\1\>)?/';

entonces en la function lo q hago es pasar el/los array(s) por referencia utilizando preg_match_all() algo asi:

Código php:
Ver original
  1. function parse($xhtml, &$array, $depth = 0)
  2. {
  3.         preg_match_all($pattern, $xhtml, $matches);
  4.        
  5.         // con un loop ubico la info de $matches (array_push()) en el array... etc.
  6.         for ($i = 0; $i < count($matches[0]; $i++)) {
  7.                 $array[$i]['tag'] = $matches[1][$i];
  8.                 $array[$i]['attributes'] = $matches[2][$i];
  9.                 $array[$i]['value'] = $matches[4][$i];
  10.                 $array[$i]['depth'] = $depth;
  11.         }
  12.         // y repito la funcion pasandole $xhtml = $matches[4][$i] que si se fijan
  13.         // en la regexp. el subpatron 4 seria el valor del tag y depth sumandole uno
  14.         // ya que marca la profundidad... ej el depth del tag html es 0, el de head
  15.         // y el body es 1, ya que estan dentro del tag html, title y p serian 3, etc.
  16.         parse($matches[4], $array, $depth + 1);
  17. }

he aqui el problem:
supongamos q tenemos un xhtml donde usaron un trukito css para ponerle esquinas redondeadas a un div...
Código html:
Ver original
  1.         <head>
  2.                 <title>XHTML</title>
  3.         </head>
  4.         <body>
  5.                 <div id="container">
  6.                         <div id="c1"></div>
  7.                         <div id="c2"></div>
  8.                         <div id="c3"></div>
  9.                         <div id="c4"></div>
  10.                         <p class="neat">Lorem ipsum dolor sit amet... </p>
  11.                 </div>
  12.         </body>
  13. </html>

se llega a obtener muy buenos resultados, pero cuando queremos parsear el valor del <div id="container"> bienen los problemas...

ya que como valor del <div id="c1"> que tendria que ser nulo o sea "", me da este valor:

Código html:
Ver original
  1. </div>
  2.                         <div id="c2"></div>
  3.                         <div id="c3"></div>
  4.                         <div id="c4">
ya que toma como cierre de la divison el de id="c4"... y si cambio el subpatron 4 del a reg exp. haciendo "ungreedy" como se dice jeje, que quedaria... "... (.*?) ..."

tra problemas al parsear el div id="container" y que como valor del container traeria lo siguiente:

Código html:
Ver original
  1. <div id="c1">

ya que me toma como cierre el primer div... y como los divs se usan muchos en los XHTML, uno dentro de otros, creo que seria imposible analizar uno...

probe haciendo un if dentro de la reg exp. pero cuando se solucion un problem, surge otro xD

a ver si alguien me puede ayudar?

Saludos!

PD: Por favor, si me van a contestar algo como "porque no usas DOM?" o algo asi, directamente no respondan xD ya se que exsite DOM y facilitaria las cosas, pero yo quiero encontrarle la vuelta si o si mas o menos de la forma que digo, con regexps. desde ya, gracias a todos

Última edición por thepancher; 28/09/2009 a las 14:45 Razón: Corregido
  #2 (permalink)  
Antiguo 28/09/2009, 17:48
Avatar de abimaelrc
Colaborador
 
Fecha de Ingreso: mayo-2009
Ubicación: En el planeta de Puerto Rico
Mensajes: 14.734
Antigüedad: 14 años, 10 meses
Puntos: 1517
Respuesta: Parseando XHTML con Expresiones regulares [Ayuda]

Creo que de esta forma es que funcionaría
Código PHP:
Ver original
  1. <?php
  2. $s = '<html>
  3.        <head>
  4.                <title>XHTML</title>
  5.        </head>
  6.        <body>
  7.                <div id="container">
  8.                        <div id="c1"></div>
  9.                        <div id="c2"></div>
  10.                        <div id="c3"></div>
  11.                        <div id="c4"></div>
  12.                        <p class="neat">Lorem ipsum dolor sit amet... </p>
  13.                </div>
  14.        </body>
  15. </html>';
  16. $pattern = '/\<([a-z0-9\-]+)([^\>]*)\>((.*)\<\/\1\>)?/';
  17. preg_match_all($pattern, $s, $m);
  18. print_r($m);
__________________
Verifica antes de preguntar.
Los verdaderos amigos se hieren con la verdad, para no perderlos con la mentira. - Eugenio Maria de Hostos

Última edición por abimaelrc; 28/09/2009 a las 18:01
  #3 (permalink)  
Antiguo 28/09/2009, 19:58
 
Fecha de Ingreso: noviembre-2008
Mensajes: 67
Antigüedad: 15 años, 4 meses
Puntos: 0
Respuesta: Parseando XHTML con Expresiones regulares [Ayuda]

Si, eso funciona, pero si te encontras con dos tags o mas en una sola linea bienen los problemas, por eso es necesario parsearlo con los modificadores "i" y "s" o sea:
Código php:
Ver original
  1. $pattern = '/\<([a-z0-9\-]+)([^\>]*)\>((.*)\<\/\1\>)?/is';

la idea es parsear el xhtml sacandole las nuevas lineas "\n" y las tabulaciones "\t", o sea, todo en una sola linea...

si nos encontramos con esto:
Código html:
Ver original
  1. <div id="container"><div id="c1"></div><div id="c2"></div><div id="3"></div><div id="c4"></div></div><div id="otrodiv">Blablablah... </div>

el valor del container seria '<div id="c1"></div><div id="c2"></div><div id="3"></div><div id="c4"></div></div><div id="otrodiv">Blablablah... '

lo cual no es correcto...
  #4 (permalink)  
Antiguo 28/09/2009, 22:11
Avatar de abimaelrc
Colaborador
 
Fecha de Ingreso: mayo-2009
Ubicación: En el planeta de Puerto Rico
Mensajes: 14.734
Antigüedad: 14 años, 10 meses
Puntos: 1517
Respuesta: Parseando XHTML con Expresiones regulares [Ayuda]

Trata de esta forma
Código PHP:
Ver original
  1. <?php
  2. $s = '<html>
  3.        <head>
  4.                <title>XHTML</title>
  5.        </head>
  6.        <body>
  7.                <div id="container">
  8.                        <div id="c1"></div>
  9.                        <div id="c2"></div>
  10.                        <div id="c3"></div>
  11.                        <div id="c4"></div>
  12.                        <p class="neat">Lorem ipsum dolor sit amet... </p>
  13.                </div>
  14.        </body>
  15. </html>';
  16. $pattern = '/<[a-z0-9\-]+([^>]*)>([^<]+)<\/+[a-z0-9\-]+>|<([a-z0-9\-]+)([^>]*)>/is';
  17. preg_match_all($pattern, $s, $m);
  18. print_r($m);
__________________
Verifica antes de preguntar.
Los verdaderos amigos se hieren con la verdad, para no perderlos con la mentira. - Eugenio Maria de Hostos

Última edición por abimaelrc; 28/09/2009 a las 22:59
  #5 (permalink)  
Antiguo 29/09/2009, 01:21
 
Fecha de Ingreso: noviembre-2008
Mensajes: 67
Antigüedad: 15 años, 4 meses
Puntos: 0
Respuesta: Parseando XHTML con Expresiones regulares [Ayuda]

Gracias por tu ayuda, pero nop... No me resulta.

Empiezo a pensar que es imposible hacerlo solo con una regexp xD

voy a ver alguna otra forma. si a alguien se le ocurre ayudarme bienvenido sea!
  #6 (permalink)  
Antiguo 29/09/2009, 01:32
Avatar de abimaelrc
Colaborador
 
Fecha de Ingreso: mayo-2009
Ubicación: En el planeta de Puerto Rico
Mensajes: 14.734
Antigüedad: 14 años, 10 meses
Puntos: 1517
Respuesta: Parseando XHTML con Expresiones regulares [Ayuda]

Pero en el ejemplo que me diste, segun lo que hice si salen todos. Trata el ejemplo que te di. Si tienes algun otro vamos modificandolo hasta que logre lo que quieres, pero ese ejemplo publica todos y ademas te trae la información como tu quieres.
Con este ejemplo
Código PHP:
Ver original
  1. <?php
  2. $s = '<html>
  3.        <head>
  4.                <title>XHTML</title>
  5.        </head>
  6.        <body>
  7.                <div id="container">
  8.                        <div id="c1"></div>
  9.                        <div id="c2"></div>
  10.                        <div id="c3"></div>
  11.                        <div id="c4"></div>
  12.                        <p class="neat">Lorem ipsum dolor sit amet... </p>
  13.                </div>
  14.        </body>
  15. </html>';
  16. $pattern = '/<([a-z0-9\-]+)([^>]*)>([^<]+)<\/+[a-z0-9\-]+>|<([a-z0-9\-]+)([^>]*)>/is';
  17. preg_match_all($pattern, $s, $m);
  18. print_r($m);
Fijate en el resultado
Código codigo:
Ver original
  1. Array
  2. (
  3.     [0] => Array
  4.         (
  5.             [0] => <html>
  6.             [1] => <head>
  7.             [2] => <title>XHTML</title>
  8.             [3] => <body>
  9.             [4] => <div id="container">
  10.             [5] => <div id="c1">
  11.             [6] => <div id="c2">
  12.             [7] => <div id="c3">
  13.             [8] => <div id="c4">
  14.             [9] => <p class="neat">Lorem ipsum dolor sit amet... </p>
  15.         )
  16.  
  17.     [1] => Array
  18.         (
  19.             [0] =>
  20.             [1] =>
  21.             [2] => title
  22.             [3] =>
  23.             [4] =>
  24.             [5] =>
  25.             [6] =>
  26.             [7] =>
  27.             [8] =>
  28.             [9] => p
  29.         )
  30.  
  31.     [2] => Array
  32.         (
  33.             [0] =>
  34.             [1] =>
  35.             [2] =>
  36.             [3] =>
  37.             [4] =>
  38.             [5] =>
  39.             [6] =>
  40.             [7] =>
  41.             [8] =>
  42.             [9] =>  class="neat"
  43.         )
  44.  
  45.     [3] => Array
  46.         (
  47.             [0] =>
  48.             [1] =>
  49.             [2] => XHTML
  50.             [3] =>
  51.             [4] =>
  52.             [5] =>
  53.             [6] =>
  54.             [7] =>
  55.             [8] =>
  56.             [9] => Lorem ipsum dolor sit amet...
  57.         )
  58.  
  59.     [4] => Array
  60.         (
  61.             [0] => html
  62.             [1] => head
  63.             [2] =>
  64.             [3] => body
  65.             [4] => div
  66.             [5] => div
  67.             [6] => div
  68.             [7] => div
  69.             [8] => div
  70.             [9] =>
  71.         )
  72.  
  73.     [5] => Array
  74.         (
  75.             [0] =>
  76.             [1] =>
  77.             [2] =>
  78.             [3] =>
  79.             [4] =>  id="container"
  80.             [5] =>  id="c1"
  81.             [6] =>  id="c2"
  82.             [7] =>  id="c3"
  83.             [8] =>  id="c4"
  84.             [9] =>
  85.         )
  86.  
  87. )

Te dice todos las etiquetas pero en dos partes una se encuentra en el [1] => Array y la otra esta en el [4] => Array
Tambien te dice los id y class pero en dos array uno se encuentra en el [2] => Array y el otro esta en el [5] => Array
Si los quieres unir puedes usar la funcion array_merge()
Código PHP:
Ver original
  1. <?php
  2. $s = '<html>
  3.        <head>
  4.                <title>XHTML</title>
  5.        </head>
  6.        <body>
  7.                <div id="container">
  8.                        <div id="c1"></div>
  9.                        <div id="c2"></div>
  10.                        <div id="c3"></div>
  11.                        <div id="c4"></div>
  12.                        <p class="neat">Lorem ipsum dolor sit amet... </p>
  13.                </div>
  14.        </body>
  15. </html>';
  16. $pattern = '/<([a-z0-9\-]+)([^>]*)>([^<]+)<\/+[a-z0-9\-]+>|<([a-z0-9\-]+)([^>]*)>/is';
  17. preg_match_all($pattern, $s, $m);
  18. print_r($m);
  19. $r = array_merge($m[1],$m[4]);
  20. print_r($r);
__________________
Verifica antes de preguntar.
Los verdaderos amigos se hieren con la verdad, para no perderlos con la mentira. - Eugenio Maria de Hostos

Última edición por abimaelrc; 29/09/2009 a las 01:56
  #7 (permalink)  
Antiguo 29/09/2009, 21:51
 
Fecha de Ingreso: noviembre-2008
Mensajes: 67
Antigüedad: 15 años, 4 meses
Puntos: 0
Respuesta: Parseando XHTML con Expresiones regulares [Ayuda]

si tenes razon, o sea, no me habia fijado en eso.... pero ahora probe otra cosa comun... con otro ejemplo:

Código html:
Ver original
  1.         <head>
  2.                 <title>XHTML</title>
  3.         </head>
  4.         <body>
  5.                 <div id="container">
  6.                         <div id="c1">Lorem ipsum... </div>
  7.                         <div id="c2"></div>
  8.                         <div id="c3"></div>
  9.                         <div id="c4"></div>
  10.                         <p class="neat"><strong>Lorem ipsum</strong> dolor sit amet... </p>
  11.                         Lorem ipsum dolor sit amet...
  12.                 </div>
  13.         </body>
  14. </html>

Fijate que si al html en el contenedir id se le agrega texto plano no lo toma, y si agregamos un <strong> a una frase del "p" se corta el texto... hasta antes del <strong> que es algo muy utilizado...

por eso creo q la idea seria poder tomar todo el valor de un tag sea texto plano o elementos, o los dos mezclados... y creo que mas que una expresion regular, se van a necestar varias y todo un proceso... me puse a pensar varias maneras pero todaia no se me ocurre nada concreto xD

lo que enrealidad quiero lograr es algo parecido al HTMLSQL (http://www.jonasjohn.de/lab/htmlsql.htm) pero como lo mire con toke la parte que extrae los tags, y tiene los errores q te mencione, al principio, que son errores que no quiero cometer...
Atención: Estás leyendo un tema que no tiene actividad desde hace más de 6 MESES, te recomendamos abrir un Nuevo tema en lugar de responder al actual.
Respuesta




La zona horaria es GMT -6. Ahora son las 08:01.