Estamos haciendo una consulta a una tabla, y vemos que la tabla tiene un texto. Pero dicho texto contiene etiquetas HTML que nos molestan o no deberían estar ahí (puede que el valor lo hayamos extraído de un campo WYSIWYG) y cuando vamos a extraer la información nos molesta.
Pero tenemos prisa y tendríamos que modificar o crear un programa y no tenemos tiempo. ¿Qué hacemos? Pues nada, implementar strip_tags() dentro de MySQL y luego pegarnos un baile.
Preparamos nuestra prueba
Primero vamos a preparar un ejemplo. No os puedo mostrar mi caso real porque contiene información confidencial (qué importante suena). Además, contiene muchos campos y nos sobran la mitad de los datos para el ejemplo; por tanto, vamos a crear una tabla y a meter algunos datos:
1 2 3 4 5 6 7 8 9 10 11 12 | CREATE SCHEMA POESIA; CREATETABLEIFNOTEXISTS`POESIA`.`PRUEBAS`( `id`BIGINTNOTNULLAUTO_INCREMENT, `Key`VARCHAR(150)NOTNULL, `Value` TEXT NULL, PRIMARYKEY(Id) ) ENGINE = InnoDB; INSERTINTO POESIA.PRUEBAS VALUES(NULL,'Enlace','<a href="http://totaki.com/poesiabinaria/">Poesía Binaria</a>'); INSERTINTO POESIA.PRUEBAS VALUES(NULL,'LoremIpsum','<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent nisl mi, volutpat nec ipsum vitae, vehicula viverra metus.</p>'); INSERTINTO POESIA.PRUEBAS VALUES(NULL,'Test','<p>This is a <span>test</span>.</p>'); INSERTINTO POESIA.PRUEBAS VALUES(NULL,'Header','<h1 class="cabecera">This is a header</h1>'); |
Veamos el problema
El caso es que cuando hacemos un SELECT a la tabla anterior, nos devolvería esto:
[simterm]
> SELECT * FROM POESIA.PRUEBAS;
| id | Key | Value |
| 1 | Enlace | Poesía Binaria |
| 2 | LoremIpsum |
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent nisl mi, volutpat nec ipsum vitae, vehicula viverra metus.
|
| 3 | Test |
This is a test.
|
| 4 | Header |
This is a header
|
4 rows in set (0.00 sec)
[/simterm]
Que no sería gran problema si son sólo estos cuatro campos, pero se vuelve un verdadero marrón cuando son varios miles de campos. Tanto si los tiene que procesar una aplicación o vamos a exportarlos como CSV…
Primero, pensemos
Es lo primero que hay que hacer siempre. Y es que si las etiquetas son siempre las mismas, o en definitiva son un número acotable a primera vista, es decir, sólo vemos <p> y <span> podemos utilizar un simple REPLACE y nos quitamos de líos:
[simterm]
> SELECT id, `Key`, REPLACE(REPLACE(REPLACE(REPLACE(Value, ‘
‘, ”), ‘
‘, ”), ‘‘, ”), ‘‘, ”) AS Value FROM POESIA.PRUEBAS;
| id | Key | Value |
| 1 | Enlace | Poesía Binaria
| 2 | LoremIpsum | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent nisl mi, volutpat nec ipsum vitae, vehicula viverra metus. |
| 3 | Test | This is a test.
| 4 | Header |
This is a header
4 rows in set (0.00 sec)
[/simterm]
Aunque vemos que no vale para todas las etiquetas, y por desgracia en MySQL no tenemos un método fácil para hacer muchos reemplazos juntos. Podríamos crear una tabla temporal y montar un procedimiento almacenado que guardara valores temporales de los replaces (uno por fila), pero sería muy pesado…
MariaDB y expresiones regulares
En MySQL tampoco hay una forma fácil de reemplazar con expresiones regulares. Y digo fácil, porque siempre es posible crear un módulo en C para MySQL (o bajártelo. Podemos utilizar este, aunque tiene algunos años), pero claro, en un servidor de producción no te vas a poner a compilar nada. Es más, si te pilla el sysadmin no sales vivo.
Pero si utilizas MariaDB, desde la versión 10.0.5 tenemos la función REGEXP_REPLACE() que nos ayudará con ésta y muchas otras cosas…
[simterm]
> SELECT id, `Key`, REGEXP_REPLACE(Value, ‘<.>‘, ”) AS Value FROM POESIA.PRUEBAS;
| id | Key | Value
| 1 | Enlace | Poesía Binaria
| 2 | LoremIpsum | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent nisl mi, volutpat nec ipsum vitae, vehicula viverra metus. |
| 3 | Test | This is a test.
| 4 | Header | This is a header
4 rows in set (0.00 sec)
[/simterm]
MySQL strip_tags()
Pero claro, si no vamos a instalar software en el servidor de producción y estamos utilizando MySQL, no vamos a pasarlo todo a MariaDB. Así que al menos, vamos a crear un procedimiento almacenado que nos quite las etiquetas de un campo de la base de datos y lo podamos llamar para devolver todos los campos filtrados.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | DROPFUNCTIONIFEXISTS fnStripTags; DELIMITER $$ CREATEFUNCTION fnStripTags( Dirty TEXT) RETURNSTEXT DETERMINISTIC BEGIN DECLARE iStart, iEnd, iLength int; WHILE Locate('<', Dirty )>0AndLocate('>', Dirty,Locate('<', Dirty ))>0DO BEGIN SET iStart =Locate('<', Dirty ), iEnd =Locate('>', Dirty,Locate('<', Dirty )); SET iLength =( iEnd - iStart)+1; IF iLength >0THEN BEGIN SET Dirty =Insert( Dirty, iStart, iLength,''); END; ENDIF; END; END WHILE; RETURN Dirty; END; $$ DELIMITER ; |
La función es de Peter Brawley, que a su vez hizo un port a MySQL de una función de Robert Davis. Ahora cuando hacemos:
[simterm]
> SELECT id, `Key`, fnStripTags(Value) AS Value FROM POESIA.PRUEBAS;
| id | Key | Value
| 1 | Enlace | Poesía Binaria
| 2 | LoremIpsum | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent nisl mi, volutpat nec ipsum vitae, vehicula viverra metus. |
| 3 | Test | This is a test.
| 4 | Header | This is a header
4 rows in set (0.00 sec)[/simterm]
[/simterm]
Todo funciona bien.
O podríamos utilizar también esta función:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | DROPFUNCTIONIFEXISTS`strip_tags`; DELIMITER $$ CREATEFUNCTION`strip_tags`($str text)RETURNStext BEGIN DECLARE $start, $end INTDEFAULT1; LOOP SET $start =LOCATE("<", $str, $start); IF(!$start)THEN RETURN $str;ENDIF; SET $end =LOCATE(">", $str, $start); IF(!$end)THENSET $end = $start;ENDIF; SET $str =INSERT($str, $start, $end - $start +1,""); END LOOP; END; $$ DELIMITER ; |
Mucho más sencilla y también efectiva (Quién mira Stack Overflow?).
The post Formas de eliminar etiquetas XML/HTML desde MySQL o MariaDb. strip_tags en MySQL appeared first on Poesía Binaria.