Fournir un flux XML et RSS valide à partir d'une vue Drupal
Il vous est peut-être arrivé de rencontrer des erreurs de validation de vos flux RSS, ou de tout flux XML générés avec des vues Drupal. Cet article propose des pistes de réponses pour assurer leur validation. A noter que je m'intéresse ici à une solution Drupal, cependant cette démarche est tout à fait adaptable à d'autres CMS/technologies.
Caractères interdits et sections CDATA
Une histoire de norme Unicode
Les flux XML doivent se contraindre à des standards établis par le w3c, parmis ces standards il existe une norme qui va nous intéresser tout particulièrement pour nos sites Drupal : celle concernant l'encodage des caractères de nos flux. Celle-ci précise que tous les caractères à l'intérieur de vos balises xml doivent se plier à la norme ISO/IEC 10646.
Il arrive que certain caractères saisis dans vos contenus, ne valident pas la norme ISO/IEC 10646. Ceci arrive notemment lorsque l'on créé des contenus à partir de copier/coller sauvages à partir d'un logiciel tier. Conséquence directe, notre flux ne passe pas la validation et une belle erreur est listée sur le validateur w3c :
Line 79, Column 68: non SGML character number 31
Nous allons voir comment chasser ces caractères indésirables.
Utilisation des sections CDATA pour assurer la compatibilité de vos flux
Une erreur classique dans la génération d'un flux xml est la présence de markup html dans les balises XML.
Pour éviter ce problème, Drupal converti en entitées HTML le contenu des champs lors de la génération de l'affichage de votre vue (et donc de votre flux).
Cependant certaines visionneuses de flux ou logiciels d'importation peuvent avoir du mal à gérer les entitées HTML et se comportent mieux avec du code HTML "brut". Pour permettre l'inclusion de balises HTML dans notre XML, une solution toute simple est d'utiliser les sections CDATA :
<item>
<title>Titre de mon article</title>
<link>http://blog.alantondelier.net/lien</link>
<description>
<![CDATA[ <h1>Ceci est un titre</h1> <img src="http://blog.alantondelier.net/uneimage.jpg" alt="Une image dans mon flux" /> <p>Blabla</p> ]]>
</description>
</item>
Couplées à la fonction html_entity_decode pour retrouver notre markup, les sections CDATA permettent d'assurer la compatibilité de nos flux XML tout en laissant le code valide.
Mise en place de la solution
Intéressons-nous à la mise en place d'une solution pour filtrer les mauvais caractères et pour ajouter les sections <[CDATA[]]>.
Nous allons intervenir au niveau du theming Drupal, et plus particulièrement au niveau du template de views générant le code pour chaque élément du flux.
Prenons l'exmple le plus courant : celui d'un flux RSS basique généré par views. Pour les autres cas la méthode présentée est à adapter selon vos besoins.
Pour les flux RSS, le template appelé sera views-view-row-rss.tpl.php. Placez une copie de ce template dans votre theme et ouvrez le :
<?php
/**
* @file
* Default view template to display a item in an RSS feed.
*
* @ingroup views_templates
*/
?>
<item>
<title><?php print $title; ?></title>
<link><?php print $link; ?></link>
<description><?php print $description; ?></description>
<?php print $item_elements; ?>
</item>
Nous allons commencer par modifier le template pour décoder l'HTML et ajouter une section CDATA dans notre balise <description> (il est possible d'effectuer la même opération sur <title> si vous y affichez de l'html "brut").
<description>
<![CDATA[ <?php print html_entity_decode($description); ?> ]]>
</description>
Il faut également retirer tous les caractères interdits par la norme XML. On utilise une fonction PHP de traitement de chaîne, empruntée ici, que l'on ajoute au template.php de notre theme :
/**
* Removes invalid XML
*
* @access public
* @param string $value
* @return string
*/
function montheme_xmlcleaner($value)
{
$ret = "";
$current;
if (empty($value))
{
return $ret;
}
$length = strlen($value);
for ($i=0; $i < $length; $i++)
{
$current = ord($value{$i});
if (($current == 0x9) ||
($current == 0xA) ||
($current == 0xD) ||
(($current >= 0x20) && ($current <= 0xD7FF)) ||
(($current >= 0xE000) && ($current <= 0xFFFD)) ||
(($current >= 0x10000) && ($current <= 0x10FFFF)))
{
$ret .= chr($current);
}
else
{
$ret .= " ";
}
}
return $ret;
}
On termine par ajouter l'appel à cette fonction dans notre template views-view-row-rss.tpl.php :
<?php
/**
* @file
* Default view template to display a item in an RSS feed.
*
* @ingroup views_templates
*/?>
<item>
<title><?php print montheme_xmlcleaner($title); ?></title>
<link><?php print $link; ?></link>
<description>
<![CDATA[ <?php print montheme_xmlcleaner(html_entity_decode($description)); ?> ]]>
</description>
<?php print $item_elements; ?>
</item>
La magie opère : votre flux xml est valide.
N'hésitez pas à partager vos expériences sur les flux xml & Drupal en commentaire ou si vous avez rencontré un problème différent sur le sujet.