PostgreSQL et contenu HTML
J’ai rencontré dernièrement la problématique d’avoir à traiter dans une BDD PostgreSQL du contenu provenant d’une application Web qui renseignait certaines colonnes avec du contenu HTML. Si on n’a aucun problème à enregistrer et restituer ce type de contenu, les ennuis arrivent dès que l’on veut indexer ces textes ou récupérer les texte débarrassé des tags HTML.
De prime abord, la première idée est de chercher à faire le job via des expressions régulières pour ce qui est de se débarrasser des tags ; et effectivement après quelques recherches sur le net, on arrive à trouver des expressions qui semblent fonctionner.
Par contre, çà se complique au niveau de la transformation des éventuelles entités HTML par de jolis caractères accentués encodés en UTF-8 : faire une table de correspondances et rechercher / remplacer tout çà dans le contenu … Houlà, c’est sûr, je vais sûrement en oublier, bien probablement me tromper, et çà finira tôt ou tard par un loupé !
La seconde voie, et celle qui me semble à priori la moins coûteuse en temps et la plus fiable, consisterait à faire appel à l’un des langages de script embarqués (ou embarquables) dans PostgreSQL : plpgsql ne comporte pas ce genre de fonction, reste à utiliser un langage généraliste embarqué plperl ou plpython, d’autant qu’il sera alors possible d’utiliser une librairie couramment utilisée et bien testée écrite pour ces langages !
Au final, ce sera du Perl pour lequel la librairie HTML est disponible et semble pouvoir fournir l’ensemble des fonctionnalités requises.
Pour ce faire, il faudra me installer dans ma Debian les dépendances nécessaires :
apt-get install postgresql-plperl-9.4
pour l’extension Perl de PostgreSQL
apt-get install libhtml-strip-perl
apt-get install libhtml-parser-perl
pour les librairies Perl que je souhaite utiliser.
puis activer l’extention plperl dans PostgreSQL :
CREATE EXTENSION plperlu;
(il faudra bien activer plperlu car plperl n’aurait pas accès aux librairies externes) et finir par créer mes 2 fonctions :
CREATE OR REPLACE FUNCTION pl_strip_tags(html text)
RETURNS text AS
$BODY$
use HTML::Strip;
my $hs = HTML::Strip->new();
my $clean = $hs->parse($_[0]);
$hs->eof;
return $clean;
$BODY$
LANGUAGE plperlu VOLATILE
COST 100;
pour réaliser la suppression des tags HTML
et
CREATE OR REPLACE FUNCTION pl_entity2char(html text)
RETURNS text AS
$BODY$
use HTML::Entities;
return decode_entities($_[0]);
$BODY$
LANGUAGE plperlu VOLATILE
COST 100;
Pour le décodage des entités HTML
qui s’utilisent facilement :
SELECT * FROM pl_strip_tags('<p>
TEST</p>’);
retourne TEST en ayant bien supprimé les balises <p>
SELECT * FROM pl_entity2char('étéé');
retourne ‘été’
Au final, même s’il est possible qu’on perde un peu en performances (bien que çà reste encore à démontrer …) je pense que cette méthode permet de gagner en fiabilité et surtout en facilité de mise en œuvre !