Olivier Mengué – Code & rando - Tag - XMLTV2024-03-29T07:17:39+01:00urn:md5:57e646ab8ca85028168daaaa985aa995Dotclearxmltv-fr.appspot.com est en ligne !urn:md5:bad73d92d457285b615d07698ff1b5a82008-09-28T00:10:00+00:002013-08-10T16:21:11+00:00Olivier MenguéXMLTVAppEngineBeautifulSoupPythonwebdevXMLTVxmltv-frXSLT <p>J'annonce <a href="http://xmltv-fr.appspot.com/">xmltv-fr.appspot.com</a>, mon grabber XMLTV qui diffuse la grille de programmes de télévision au format XMLTV.</p>
<p>J'avais déjà développé <a href="http://o.mengue.free.fr/blog/2008/02/11/51-les-programmes-tele-de-telerama-en-xmltv">une solution à base de scripts shell et de feuille de style XSLT</a>, puis un <a href="http://o.mengue.free.fr/xmltv/telerama.xmltv" type="application/xml" rel="noindex nofollow">proxy en PHP</a> il y a 6 mois, mais j'avais des problèmes de fiabilité en raison de l'hébergement chez Free.fr : un appel sur trois au service échouait. J'ai donc fait en une journée le portage en Python pour l'héberger sur Google AppEngine. Grâce à l'infrastructure de Google je ne devrait pas avoir de soucis du même type.</p>
<p>Pour l'instant, le flux récupéré ne correspond qu'à un seul appel au site Télérama et donc ne récupère que 3h de programmes des 6 chaînes analogiques nationales. Mais je compte bien poursuivre le portage pour arriver à l'équivalent de la version PHP puis éventuellement utiliser le stockage Google pour améliorer les performances grâce à un cache.</p>
<p>Pour vous faire patienter, voici un peu de doc sur l'interface du grabbber PHP :</p>
<ul>
<li><code>/xmltv/telerama.xmltv</code> : 3h de programme à partir de maintenant sur les 6 chaînes (c'est la seule chose qui fonctionne sur xmltv-fr.appspot.com pour l'instant).</li>
<li><code>/xmltv/telerama.xmltv?start=20080927220000</code> : 3h de programme à partir du samedi 27 à 22:00 (heure de Paris)</li>
<li><code>/xmltv/telerama.xmltv?channels=192,4,80,34,47,118,111,445,119,195,446,444,234,78,226,481,458,482</code> : 3h de programme de la TNT</li>
</ul>
<p>J'ai écrit cette semaine une feuille de style XSLT pour faire plusieurs appels au service et combiner les résultats en un seul fichier XMLTV :</p>
<pre class="terminal">
<samp>xsltproc -o tv.xml http://o.mengue.free.fr/xmltv/telerama-full.xslt http://o.mengue.free.fr/xmltv/TNT.xml</samp>
</pre>
<p>Dès que j'aurais implémenté les paramètres <code>start</code> et <code>channels</code> la même feuille de style pourra aussi fonctionner pour <code>xml-fr.appspot.com</code>.</p>
<p class="update"><strong>MàJ 2008-09-29 :</strong> le portage est complet, l'API complète (<code>start</code>, <code>channels</code>) est disponible, donc vous pouvez utiliser la même feuille de style simplement en changeant l'URL du service. Voici un exemple où je récupère le programme des 5 prochains jours (<a href="http://www.w3.org/TR/xmlschema-2/#duration">voir le format du paramètre <code>duration</code></a>) :</p>
<pre class="terminal">
<samp>xsltproc -o tv.xml -stringparam xmltv-url http://xmltv-fr.appspot.com/telerama.xmltv -stringparam duration P5D http://o.mengue.free.fr/xmltv/telerama-full.xslt http://o.mengue.free.fr/xmltv/TNT.xml</samp>
</pre>
<p>Malheureusement, je m'aperçois que je rencontre les mêmes problèmes d'accès au service : je ne peux qu'en déduire que cela vient en fait du site Télérama. À suivre…</p>Télérama → XMLTV : mise à joururn:md5:844f113c8a48ccb174097b15eb3dd1202008-03-02T01:44:00+00:002013-08-10T16:22:59+00:00Olivier MenguéXMLTVFrancegrabberTVtéléTéléramaXMLTV<p>J'ai mis en ligne une version corrigée des mes outils de transformation de la grille télé de Télérama en XMLTV (voir <a href="http://o.mengue.free.fr/blog/2008/02/11/51-les-programmes-tele-de-telerama-en-xmltv">mon billet précédent</a>). Maintenant l'<a href="http://doc.ubuntu-fr.org/ontv">applet OnTV</a> disponible pour le bureau Gnome fonctionne avec ces outils.</p>
<p style="text-align: center"><img src="http://o.mengue.free.fr/dolmen.blog/public/20080302-capture-ontv.png" alt="Capture de l'affichage des programmes avec OnTV" /></p> <p>J'ai corrigé les fichiers <a href="http://o.mengue.free.fr/xmltv/xmltv.xslt"><code>xmltv.xslt</code></a> et <a href="http://o.mengue.free.fr/xmltv/tv.sh"><code>tv.sh</code></a>.</p>
<p>Pour utiliser ce grabber avec OnTV il vous faut récupérer les fichiers suivants et les placer ensemble dans le répertoire que vous souhaitez :</p>
<ul>
<li><a href="http://o.mengue.free.fr/xmltv/leprogramme.xslt" type="text/xsl"><code>leprogramme.xslt</code></a></li>
<li><a href="http://o.mengue.free.fr/xmltv/chaines.xslt" type="text/xsl"><code>chaines.xslt</code></a></li>
<li><a href="http://o.mengue.free.fr/xmltv/xmltv.xslt" type="text/xsl"><code>xmltv.xslt</code></a></li>
<li><a href="http://o.mengue.free.fr/xmltv/tv.sh" type="application/x-shellscript"><code>tv.sh</code></a></li>
</ul>
<p>Éditez <code>tv.sh</code> pour sélectionner les chaînes qui vous intéressent. Puis donnez les droits d'exécution sur tv.sh et testez que tout fonctionne :</p>
<pre class="terminal"><samp class="prompt">$ </samp><kbd>chmod u+x tv.sh</kbd>
<samp class="prompt">$ </samp><kbd>./tv.sh</kbd>
<samp class="curl"> % Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 58925 0 58925 0 0 91714 0 --:--:-- --:--:-- --:--:-- 143k
</samp><samp class="prompt">$ </samp><kbd>gedit tv.xml</kbd>
</pre>
<p>Il suffit ensuite d'ajouter l'applet OnTV à votre tableau de bord et d'indiquer dans ses préférences les paramètres suivants sur l'onglet Général (OnTV 2.8.0) </p>
<ul>
<li><samp>Grabber command: </samp><var>le chemin complet vers tv.sh</var></li>
<li><samp>Output file: </samp><var>le chemin complet vers tv.xml</var></li>
</ul>
<p>Lancez la « mise à jour des programmes », puis retournez sur dans les préférences et, sur l'onglet « Chaînes », cochez dans l'ordre les chaînes qui vous intéressent.</p>
<p>Cliquez sur l'icône de OnTV et le programme devrait être là.</p>Les programmes télé de Télérama en XMLTVurn:md5:847ff4c10a314f8538e43d2889043dbe2008-02-11T00:19:00+00:002011-06-05T21:14:20+00:00Olivier MenguéXMLTVcurlEPGgrille téléHTMLJavaScriptPerlprogramme téléservice webTVtéléTéléramawebdevwebserviceXHTMLXMLXMLTVXSLTxsltproc<p><a href="http://xmltv.org/wiki/" hreflang="en">XMLTV</a> est un format informatique pour les programmes de télévision. Ce format est utilisable dans un nombre grandissant d'applications. Le magazine <a href="http://www.telerama.fr/">Télérama</a> propose sur son site une <a href="http://television.telerama.fr/tele/grille.php">grille des programmes télé</a>, mais juste consultable sur le web. Pas de XMLTV.</p>
<p>Je vous propose donc de combler ce manque avec un petit cours de reverse engineering sur le web et la démonstration de quelques outils pour arriver rapidement à vos fins. La grille de Télérama est une excellente cible pour ce genre d'exercice parce que, vous le verrez, la tâche n'est pas simple, mais possible. Elle donne l'ocassion de montrer l'usage de plusieurs outils (curl, XSLT, Perl) et c'est un exemple de ma démarche de prototypage rapide en utilisant le meilleur de chacun.</p>
<p><strong>MàJ 2008-02-15 :</strong> j'ai profondément remanié l'introduction et la conclusion suite à quelques commentaires de lecteurs.</p> <p style="text-align: center;"><a href="http://o.mengue.free.fr/xmltv/xsltv/tv.html"><img src="http://o.mengue.free.fr/dolmen.blog/public/20080214-grille-telerama-488.jpg" alt="La grille du site Télérama.fr" /></a></p>
<p>Cette grille fonctionne avec des <a href="http://fr.wikipedia.org/wiki/Service_web">services web</a>. Cela se voit en cliquant sur les flèches à gauche ou à droite du bandeau des heures : seule la grille est rechargée, et non pas la page entière. Un service web est par définition exploitable pour récupérer des données structurées, plus légères que la page entière affichée dans le navigateur.</p>
<p>La première étape : un survol rapide du source HTML de la page. On repère les éléments suivants :</p>
<ol>
<li>La page est très grosse : 208 381 octets. Toute la grille initiale est donc fournie en HTML. Ce sont les mises à jour qui sont fournies en service web.</li>
<li>La page est déclarée comme <a href="http://fr.wikipedia.org/wiki/XHTML">XHTML</a> d'après l'entête :
<pre class="code vim vimft-html"><span class="Comment"><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"</span>
<span class="Comment"> "<a href="http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd</a>"></span>
<span class="Identifier"><</span><span class="Statement">html</span><span class="Identifier"> xmlns=</span><span class="Constant">"<a href="http://www.w3.org/1999/xhtml">http://www.w3.org/1999/xhtml</a>"</span><span class="Identifier"> xml:</span><span class="Type">lang</span><span class="Identifier">=</span><span class="Constant">"fr"</span><span class="Type">lang</span><span class="Identifier">=</span><span class="Constant">"fr"</span><span class="Identifier">></span>
</pre></li>
<li>Plusieurs balises <SCRIPT> en majuscules. Or, en XHTML ces balises doivent être en minuscules. Ceci indique déjà que malgré la déclaration le XHTML n'est pas valide et donc ne sera pas utilisable directement dans un analyseur XML.</li>
<li>Beaucoup de références à des fichiers JavaScript additionnels. Les familiers d'<a href="http://www.ajaxian.com/">Ajaxian.com</a> détectent vite lesquels sont des librairies JavaScript bien connues. Pour les autres une petite recherche sur Google sur le nom du fichier donne rapidement la réponse.</li>
<li>Un bloc de JavaScript révélant l'adresse du service web et le framework utilisé pour l'appeler :
<pre class="code vim vimft-html"><span class="Identifier"><</span><span class="Statement">script</span><span class="Type">type</span><span class="Identifier">=</span><span class="Constant">"text/javascript"</span><span class="Identifier">></span>
<span class="Identifier">var</span><span class="Special"> xajaxRequestUri=</span><span class="Constant">"<a href="http://television.telerama.fr/tele/grille.php">http://television.telerama.fr/tele/grille.php</a>"</span><span class="Special">;</span>
<span class="Identifier">var</span><span class="Special"> xajaxDebug=</span><span class="Constant">false</span><span class="Special">;</span>
<span class="Identifier">var</span><span class="Special"> xajaxStatusMessages=</span><span class="Constant">true</span><span class="Special">;</span>
<span class="Identifier">var</span><span class="Special"> xajaxWaitCursor=</span><span class="Constant">true</span><span class="Special">;</span>
<span class="Identifier">var</span><span class="Special"> xajaxDefinedGet=</span>0<span class="Special">;</span>
<span class="Identifier">var</span><span class="Special"> xajaxDefinedPost=</span>1<span class="Special">;</span>
<span class="Identifier">function</span><span class="Special"> xajax_chargerProgramme</span>()<span class="Identifier">{</span><span class="Statement">return</span><span class="Special"> xajax.call</span>(<span class="Constant">"chargerProgramme"</span><span class="Special">, </span><span class="Identifier">arguments</span><span class="Special">, </span>1)<span class="Special">;</span><span class="Identifier">}</span>
<span class="Identifier"></</span><span class="Statement">script</span><span class="Identifier">></span>
</pre></li>
<li>Des champs de formulaire tel que celui-ci :
<pre class="code vim vimft-html"><span class="Identifier"><</span><span class="Statement">select</span><span class="Type">style</span><span class="Identifier">=</span><span class="Constant">"width: 120px;"</span><span class="Special">onchange="</span><span class="Special">ajouterChaine</span>(<span class="Identifier">this</span><span class="Special">.options</span><span class="Identifier">[</span><span class="Identifier">this</span><span class="Special">.options.selectedIndex</span><span class="Identifier">]</span><span class="Special">.value</span>)<span class="Special">;</span><span class="Special">"</span><span class="Identifier">></span>
<span class="Identifier"><</span><span class="Statement">option</span><span class="Type">value</span><span class="Identifier">=</span><span class="Constant">""</span><span class="Identifier">></span>Ajoutez une cha<span class="Special">&icirc;</span>ne<span class="Identifier"></</span><span class="Statement">option</span><span class="Identifier">></span>
<span class="Identifier"><</span><span class="Statement">OPTGROUP</span><span class="Type">label</span><span class="Identifier">=</span><span class="Constant">"Groupes de cha</span><span class="Special">&icirc;</span><span class="Constant">nes"</span><span class="Identifier">/></span>
<span class="Identifier"><</span><span class="Statement">option</span><span class="Type">value</span><span class="Identifier">=</span><span class="Constant">"192,4,80,34,47,111,118"</span><span class="Identifier">></span>Chaînes hertziennes<span class="Identifier"></</span><span class="Statement">option</span><span class="Identifier">></span>
<span class="Identifier"><</span><span class="Statement">option</span><span class="Type">value</span><span class="Identifier">=</span><span class="Constant">"192,4,80,34,47,111,118,445,119,195,446,444,78,234,481,226,458,482"</span><span class="Identifier">></span>Chaînes TNT<span class="Identifier"></</span><span class="Statement">option</span><span class="Identifier">></span>
</pre>
On voit qu'il s'agit d'une liste de codes pour les différentes chaînes de télé à afficher.
</li>
<li>Des appels de fonction JavaScript :
<pre class="code vim vimft-html"><span class="Identifier"><</span><span class="Statement">a</span><span class="Type">href</span><span class="Identifier">=</span><span class="Constant">"javascript:void(0);"</span><span class="Special">onclick="</span><span class="Statement">return</span><span class="Special"> changerJour</span>(0)<span class="Special">;</span><span class="Special">"</span><span class="Identifier">></span><span class="Underlined">Aujourd'hui</span><span class="Identifier"></</span><span class="Statement">a</span><span class="Identifier">></span>
<span class="Identifier"><</span><span class="Statement">a</span><span class="Type">href</span><span class="Identifier">=</span><span class="Constant">"javascript:void(0);"</span><span class="Special">onclick="</span><span class="Statement">return</span><span class="Special"> changerMaintenant</span>(0)<span class="Special">;</span><span class="Special">"</span><span class="Identifier">></span><span class="Underlined">Maintenant</span><span class="Identifier"></</span><span class="Statement">a</span><span class="Identifier">></span>
<span class="Identifier"><</span><span class="Statement">a</span><span class="Type">href</span><span class="Identifier">=</span><span class="Constant">"javascript:void(0);"</span><span class="Special">onclick="</span><span class="Statement">return</span><span class="Special"> changerCeSoir</span>(0)<span class="Special">;</span><span class="Special">"</span><span class="Identifier">></span><span class="Underlined">Ce soir</span><span class="Identifier"></</span><span class="Statement">a</span><span class="Identifier">></span>
</pre>
On note ainsi quelques noms de fonctions qu'on pourra chercher plus tard.</li>
<li>Le code HTML correspondant aux éléments de la grille. Par exemple :
<pre class="code vim vimft-html"><span class="Identifier"><</span><span class="Statement">div</span><span class="Type">class</span><span class="Identifier">=</span><span class="Constant">"emission magazine"</span><span class="Type">style</span><span class="Identifier">=</span><span class="Constant">"width:16px;left:677px;background-image: url('<a href="http://icon-telerama.sdv.fr/iconsv2/bg_grille_genre_vide.gif">http://icon-telerama.sdv.fr/iconsv2/bg_grille_genre_vide.gif</a>');height:51px; cursor: pointer; z-index: 10;"</span><span class="Type">id</span><span class="Identifier">=</span><span class="Constant">"emission_8069449"</span><span class="Special">onclick="</span><span class="Statement">return</span><span class="Special"> afficherEmission</span>(<span class="Constant">'8069449'</span><span class="Special">, </span><span class="Constant">'226'</span>)<span class="Special">;</span><span class="Special">"</span><span class="Type">alt</span><span class="Identifier">=</span><span class="Constant">"Journal de la nuit - Vendredi 08 février de 02h30 à 02h34"</span><span class="Type">title</span><span class="Identifier">=</span><span class="Constant">"Journal de la nuit - Vendredi 08 février de 02h30 à 02h34"</span><span class="Identifier">></span>
<span class="Identifier"><</span><span class="Statement">div</span><span class="Type">class</span><span class="Identifier">=</span><span class="Constant">"conteneur"</span><span class="Identifier">></span>
<span class="Identifier"><</span><span class="Statement">span</span><span class="Type">class</span><span class="Identifier">=</span><span class="Constant">"genre"</span><span class="Identifier">></span><span class="Identifier"></</span><span class="Statement">span</span><span class="Identifier">></span><span class="Identifier"><</span><span class="Statement">br</span><span class="Identifier"> /></span>
<span class="Identifier"><</span><span class="Statement">span</span><span class="Type">class</span><span class="Identifier">=</span><span class="Constant">"titre"</span><span class="Identifier">></span>...<span class="Identifier"></</span><span class="Statement">span</span><span class="Identifier">></span><span class="Identifier"><</span><span class="Statement">br</span><span class="Identifier"> /></span>
<span class="Identifier"><</span><span class="Statement">span</span><span class="Type">style</span><span class="Identifier">=</span><span class="Constant">"resume"</span><span class="Identifier">></span><span class="Identifier"></</span><span class="Statement">span</span><span class="Identifier">></span>
<span class="Identifier"><</span><span class="Statement">div</span><span class="Type">id</span><span class="Identifier">=</span><span class="Constant">"data_8069449"</span><span class="Type">style</span><span class="Identifier">=</span><span class="Constant">"display:none;"</span><span class="Identifier">></span>{"Id_Diffusion":"8069449","Id_Emission":"9648923","Id_Chaine":"226","Date_Debut":"2008-02-08 02:30:00","Date_Fin":"2008-02-08 02:34:00","Titre":"Journal de la nuit","Sous_Titre":"","ShowViewFr":"46271175","note_T":"0","Id_Rubrique":"8108","Rubrique_Libelle":"Journal","Rubrique_Niveau":"3","Type":"Magazine","Chaine_Nom":"i Télé","Logo":"226.gif","Id_Hierarchie":"040801","DureeEnSecondes":"240","resume_court":"","resume_long":"","dateheurechaine":"Vendredi 08 février de 02h30 à 02h34 sur i Télé","intervenant":""}<span class="Identifier"></</span><span class="Statement">div</span><span class="Identifier">></span>
<span class="Identifier"></</span><span class="Statement">div</span><span class="Identifier">></span>
</pre>
On remarque en particulier l'élement <code>data_8069449</code> qui n'est pas affiché et qui ressemble à des données au format <a href="http://fr.wikipedia.org/wiki/JSON">JSON</a>.
</li>
</ol>
<p>L'étape suivante consiste à récupérer une copie de la page et de tous les scripts additionnels, feuilles de style et images. Il suffit dans Firefox de choisir le menu Fichier → Enregistrer sous... → Page complète.</p>
<p>On obtient les fichiers suivants :</p>
<pre class="terminal"><samp class="prompt">$ </samp><kbd>ls</kbd>
<samp>grille.php.html grille.php_fichiers/</samp>
<samp class="prompt">$ </samp><kbd>ls grille.php_fichiers/</kbd>
<samp>1520033938Top1Bottom2x01x10.js mochikit_packed_tele_min.js
AC_RunActiveContent_min.js notes.js
ajax-loader.gif oas.js
alerte.js ong_montel_off.gif
builder.js ong_podcast_off.gif
carrousel_min.js ong_telerama_on.gif
controls.js ong_wiz_off.gif
couverture.gif pied.js
dragdrop.js prototype.js
effects.js rss.gif
empty.gif scriptaculous.js
favoris.js scriptaculous_packed_tele_min.js
fleche_droite_bottom1.gif scripts_2007.js
fleche_gauche_bottom1.gif slider.js
grille_croix.gif sound.js
grille_heures_fleche_dro.gif styles_2007.css
grille_heures_fleche_gau.gif T1_p.gif
heureFloatEntete.js T2_p.gif
hit.gif T3_p.gif
horsserie.js T5_p.gif
js_tra_authentification.html trans.gif
M5447.jpg tra_tele_v2.js
M5456.jpg urchin.js
M5495.jpg xajax.js
menu.js xtroi.js
milieu.js</samp>
<samp class="prompt">$ </samp><kbd>du -b -c grille.php.html grille.php_fichiers/</kbd>
<samp>210394 grille.php.html
546599 grille.php_fichiers/
756993 total</samp></pre>
<p>On peut alors les trier en trois catégories :</p>
<ol>
<li>les librairies : Scriptaculous, Prototype, Xajax, MochiKit. Repérer les librairies permet d'aller sur le web chercher la doc des fonctions et des objets et d'éviter de plonger le nez dans du JavaScript compressé.</li>
<li>les pubs et les pisteurs : on les reconnaît au faible nombre de lignes et à la piètre qualité du code écrit une fois il y a dix ans et jamais mis à jour en fonction des nouvelles normes (XHTML, DOM). Exemple : <a href="view-source:http://statique-telerama.sdv.fr/scripts/oas.js">oas.js</a></li>
<li>les scripts spécifiques au site : non compressé, avec un nom de fichier, des commentaires ou des noms de fonctions en français, ou contenant des noms de fonctions repérés dans des gestionnaires d'évènements attachés à un tag HTML (par exemple, <code>changerMaintenant()</code> vu plus haut). Chercher le nom du site (<code>grep telerama *.js</code>) permet aussi de les isoler. Ce sont bien sûr les plus importants puisque c'est là que l'on trouve les adresses des services web et la manière de les appeler.</li>
</ol>
<p>Ce premier aperçu permet de se donner une idée de la compétence du/des développeurs. En l'occurence :</p>
<ul>
<li>Malgré la déclaration de l'entête, <a href="http://validator.w3.org/check?verbose=1&uri=http%3A%2F%2Ftelevision.telerama.fr%2Ftele%2Fgrille.php">la page n'est pas du XHTML valide</a>. La validation avec <a href="http://validator.w3.org/">l'outil du W3C</a> révèle ainsi 384 erreurs !</li>
<li>Le fichier HTML est énorme (200 Ko), le nombre de fichiers également. Le poids total de la page est de plus de 800 Ko ! On a beau être à l'heure de l'ADSL en France, ce n'est pas une raison.</li>
<li>De nombreuses librairies JavaScript sont utilisées. Leurs fonctions se recouvrent et sont redondantes. Il existe au moins 3 façons différentes de faire un appel AJAX. Est-ce que plusieurs développeurs ont travaillé sur cette page successivement ? En tout cas le manque de coordination est flagrant.</li>
<li>Les tags XHTML sont détournés pour stocker des données JSON contenant elles-même du HTML (et non du XHTML). Pas étonnant que cela ne valide pas !</li>
<li>Beaucoup de code mort laissé en commentaires dans le JavaScript.</li>
</ul>
<p>En somme, pas brillant.</p>
<p>Nous avons repéré plus haut l'adresse d'un service web. Il est temps de le tester, en dehors du navigateur pour examiner les données retournées. Ce service est appellé avec <a href="http://xajaxproject.org/">Xajax</a>. En fouinant dans xajax.js, on trouve vite (cherchez "postData") la façon dont Xajax envoie les données au serveur. On peut alors reconstruire une requête avec <a href="http://curl.hacxx.se/">curl</a> :</p>
<pre class="terminal"><samp class="prompt">$ </samp><kbd>curl --data "xajax=chargerProgramme&xajaxr=$(date +%s)&xajaxargs[]=$(date '+%Y-%m-%d %H:00:00')&xajaxargs[]=192,4,80,34,47,111,118" http://television.telerama.fr/tele/grille.php</kbd>
</pre>
<p>On obtient cette fois du beau XML valide dont voici la structure :</p>
<pre class="code vim vimft-xml"><span class="Identifier"><</span><span class="Identifier">xjx</span><span class="Identifier">><</span><span class="Identifier">cmd</span><span class="Type">n</span>=<span class="Constant">"as"</span><span class="Type">t</span>=<span class="Constant">"leprogramme"</span><span class="Type">p</span>=<span class="Constant">"innerHTML"</span><span class="Identifier">></span><span class="Type"><![</span><span class="Statement">CDATA</span><span class="Type">[</span><var>...</var><span class="Type">]]></span><span class="Identifier"></cmd></span><var>...</var><span class="Identifier"></xjx></span>
</pre>
<p>Le contenu de <code>leprogramme</code> est le même que ce que l'on trouve dans la page HTML de base. On retrouve notamment la description des programmes à la fois en HTML et en JSON. Ce n'est pas vraiment efficace en terme de quantité de données transférées sur le réseau. Les données JSON aurait été suffisantes, et je l'avoue, cela m'aurait facilité la tâche.</p>
<p>Il suffit d'appliquer le filtre XSLT suivant (<a href="http://o.mengue.free.fr/xmltv/leprogramme.xslt" type="text/xsl">leprogramme.xslt</a>) pour extraire le contenu de <code>leprogramme</code> :</p>
<pre class="code vim vimft-xslt"><span class="Comment"><?</span><span class="Type">xml</span><span class="Type">version</span>=<span class="Constant">"1.0"</span><span class="Type">encoding</span>=<span class="Constant">"UTF-8"</span><span class="Comment">?></span>
<span class="Identifier"><</span><span class="Special">xsl</span><span class="Comment">:</span><span class="Statement">stylesheet</span><span class="Type">version</span>=<span class="Constant">"1.0"</span><span class="Type">xmlns</span><span class="Comment">:</span><span class="Type">xsl</span>=<span class="Constant">"<a href="http://www.w3.org/1999/XSL/Transform">http://www.w3.org/1999/XSL/Transform</a>"</span><span class="Identifier">></span>
<span class="Identifier"><</span><span class="Special">xsl</span><span class="Comment">:</span><span class="Statement">output</span><span class="Type">method</span>=<span class="Constant">"text"</span><span class="Type">encoding</span>=<span class="Constant">"UTF-8"</span><span class="Identifier"> /></span>
<span class="Identifier"><</span><span class="Special">xsl</span><span class="Comment">:</span><span class="Statement">strip-space</span><span class="Type">elements</span>=<span class="Constant">"*"</span><span class="Identifier">/></span>
<span class="Identifier"><</span><span class="Special">xsl</span><span class="Comment">:</span><span class="Statement">template</span><span class="Type">match</span>=<span class="Constant">"/xjx/cmd[@n='as']"</span><span class="Identifier">></span><span class="Type">&</span><span class="Statement">lt</span><span class="Type">;</span>!DOCTYPE html [
<span class="Type">&</span><span class="Statement">lt</span><span class="Type">;</span>!ENTITY nbsp "<span class="Type">&</span><span class="Statement">amp</span><span class="Type">;</span>#160;"<span class="Type">&</span><span class="Statement">gt</span><span class="Type">;</span>
]<span class="Type">&</span><span class="Statement">gt</span><span class="Type">;</span>
<span class="Type">&</span><span class="Statement">lt</span><span class="Type">;</span>html<span class="Type">&</span><span class="Statement">gt</span><span class="Type">;&</span><span class="Statement">lt</span><span class="Type">;</span>body<span class="Type">&</span><span class="Statement">gt</span><span class="Type">;</span><span class="Identifier"><</span><span class="Special">xsl</span><span class="Comment">:</span><span class="Statement">value-of</span><span class="Type">select</span>=<span class="Constant">"text()"</span><span class="Identifier">/></span><span class="Type">&</span><span class="Statement">lt</span><span class="Type">;</span>/body<span class="Type">&</span><span class="Statement">gt</span><span class="Type">;&</span><span class="Statement">lt</span><span class="Type">;</span>/html<span class="Type">&</span><span class="Statement">gt</span><span class="Type">;</span>
<span class="Identifier"></</span><span class="Special">xsl</span><span class="Comment">:</span><span class="Statement">template</span><span class="Identifier">></span>
<span class="Identifier"><</span><span class="Special">xsl</span><span class="Comment">:</span><span class="Statement">template</span><span class="Type">match</span>=<span class="Constant">"/xjx/cmd[@n!='as']"</span><span class="Identifier">/></span>
<span class="Identifier"></</span><span class="Special">xsl</span><span class="Comment">:</span><span class="Statement">stylesheet</span><span class="Identifier">></span>
</pre>
<p>Notez la génération d'un DOCTYPE définissant l'entité "nbsp", définie en HTML mais pas en XML.</p>
<p>Pour l'appliquer :</p>
<pre class="terminal"><samp class="prompt">$ </samp><kbd>xsltproc <a href="http://o.mengue.free.fr/xmltv/leprogramme.xslt" type="text/xsl">leprogramme.xslt</a> a.xml > b.xml</kbd>
</pre>
<p>On peut maintenant ouvrir ce fichier dans un navigateur pour vérifier que le document XML est valide. Ce n'est pas le cas :</p>
<ul>
<li>Il y a des entités mal formées (voir par exemple l'émission D&CO le dimanche soir sur M6)</li>
<li>Les blocs JSON contiennent contiennent des tags <code><br></code> non fermés.</li>
</ul>
<p>De plus, il serait bien utile d'extraire les données JSON sous forme de XML pour pouvoir continuer notre prototypage avec XSLT. Appellons Perl et le module JSON à la rescousse !</p>
<pre class="terminal"><samp class="prompt">$ </samp><kbd>xsltproc leprogramme.xslt a.xml | perl -M<a href="http://search.cpan.org/%7Emakamaka/JSON-2.06/lib/JSON.pm">JSON</a> -npe '
<span class="code vim vimft-perl"><span class="Statement">if</span> (m@^ *<div id=<span class="Constant">"</span><span class="Constant">(data_[^</span><span class="Constant">"</span>]*)<span class="Constant">"</span><span class="Constant"> style=</span><span class="Constant">"</span>display:none;<span class="Constant">"</span><span class="Constant">>([^}]*})</div>@) {</span>
<span class="Constant"> (</span><span class="Identifier">$id</span><span class="Constant">,</span><span class="Identifier">$data</span><span class="Constant">)=(</span><span class="Identifier">$1</span><span class="Constant">,jsonToObj(</span><span class="Identifier">$2</span><span class="Constant">));</span>
<span class="Identifier">$data</span><span class="Constant"> = join(</span><span class="Constant">"</span>\n<span class="Constant">"</span><span class="Constant">, map { qq|<div class=</span><span class="Constant">"</span><span class="Identifier">$_</span><span class="Constant">"</span><span class="Constant">></span><span class="Identifier">$data->{$_}</span><span class="Constant"></div>| } keys %</span><span class="Identifier">$data</span><span class="Constant">);</span>
<span class="Identifier">$_</span><span class="Constant"> = </span><span class="Constant">"</span><div id=\<span class="Constant">"</span><span class="Identifier">$id</span><span class="Special">\"</span><span class="Constant">></span><span class="Identifier">$data</span><span class="Constant"></div></span><span class="Constant">"</span>;
s@<span class="Identifier"><br></span>@<br/><span class="Identifier">@g</span>
}
<span class="Statement">s/</span><span class="Constant">&</span><span class="Special">([^;]{8})</span><span class="Statement">/</span><span class="Constant">&amp;</span><span class="Identifier">$1</span><span class="Statement">/g</span>;</span>' > c.xml</kbd>
</pre>
<p>Lançons un petit test d'extraction XSLT : nous allons lister les chaînes avec <a href="http://o.mengue.free.fr/xmltv/chaines.xslt" type="text/xsl"><code>chaines.xslt</code></a>.</p>
<pre class="code vim vimft-xslt"><span class="Comment"><?</span><span class="Type">xml</span><span class="Type">version</span>=<span class="Constant">"1.0"</span><span class="Type">encoding</span>=<span class="Constant">"UTF-8"</span><span class="Comment">?></span>
<span class="Identifier"><</span><span class="Special">xsl</span><span class="Comment">:</span><span class="Statement">stylesheet</span><span class="Type">version</span>=<span class="Constant">"1.0"</span><span class="Type">xmlns</span><span class="Comment">:</span><span class="Type">xsl</span>=<span class="Constant">"<a href="http://www.w3.org/1999/XSL/Transform">http://www.w3.org/1999/XSL/Transform</a>"</span><span class="Identifier">></span>
<span class="Identifier"><</span><span class="Special">xsl</span><span class="Comment">:</span><span class="Statement">output</span><span class="Type">method</span>=<span class="Constant">"text"</span><span class="Type">encoding</span>=<span class="Constant">"UTF-8"</span><span class="Identifier"> /></span>
<span class="Identifier"><</span><span class="Special">xsl</span><span class="Comment">:</span><span class="Statement">template</span><span class="Type">match</span>=<span class="Constant">"/html/body/div"</span><span class="Identifier">></span>
<span class="Identifier"><</span><span class="Special">xsl</span><span class="Comment">:</span><span class="Statement">value-of</span><span class="Type">select</span>=<span class="Constant">"substring(@id, 6)"</span><span class="Identifier">/></span>: <span class="Identifier"><</span><span class="Special">xsl</span><span class="Comment">:</span><span class="Statement">value-of</span><span class="Type">select</span>=<span class="Constant">"div[@class='chaine']/@title"</span><span class="Identifier">/></span>
<span class="Identifier"><</span><span class="Special">xsl</span><span class="Comment">:</span><span class="Statement">text</span><span class="Identifier">></span><span class="Type">&</span><span class="Statement">#10</span><span class="Type">;</span><span class="Identifier"></</span><span class="Special">xsl</span><span class="Comment">:</span><span class="Statement">text</span><span class="Identifier">></span>
<span class="Identifier"></</span><span class="Special">xsl</span><span class="Comment">:</span><span class="Statement">template</span><span class="Identifier">></span>
<span class="Identifier"></</span><span class="Special">xsl</span><span class="Comment">:</span><span class="Statement">stylesheet</span><span class="Identifier">></span>
</pre>
<p>Et voici le résultat :</p>
<pre class="terminal"><samp class="prompt">$ </samp><kbd>xsltproc <a href="http://o.mengue.free.fr/xmltv/chaines.xslt" type="text/xsl"><code>chaines.xslt</code></a> b.xml</kbd>
<samp>192: TF 1
4: France 2
80: France 3
34: Canal+
47: France 5
111: Arte
118: M6</samp></pre>
<p>OK. Nous avons le champ libre pour transformer notre document en XMLTV avec <a href="http://o.mengue.free.fr/xmltv/xmltv.xslt"><code>xmltv.xslt</code></a> :</p>
<pre class="code vim vimft-xslt"><span class="Comment"><?</span><span class="Type">xml</span><span class="Type">version</span>=<span class="Constant">"1.0"</span><span class="Type">encoding</span>=<span class="Constant">"UTF-8"</span><span class="Comment">?></span>
<span class="Identifier"><</span><span class="Special">xsl</span><span class="Comment">:</span><span class="Statement">stylesheet</span><span class="Type">version</span>=<span class="Constant">"1.0"</span><span class="Type">xmlns</span><span class="Comment">:</span><span class="Type">xsl</span>=<span class="Constant">"<a href="http://www.w3.org/1999/XSL/Transform">http://www.w3.org/1999/XSL/Transform</a>"</span><span class="Identifier">></span>
<span class="Identifier"><</span><span class="Special">xsl</span><span class="Comment">:</span><span class="Statement">output</span><span class="Type">method</span>=<span class="Constant">"xml"</span><span class="Type">indent</span>=<span class="Constant">"yes"</span><span class="Type">encoding</span>=<span class="Constant">"UTF-8"</span><span class="Identifier"> /></span>
<span class="Identifier"><</span><span class="Special">xsl</span><span class="Comment">:</span><span class="Statement">strip-space</span><span class="Type">elements</span>=<span class="Constant">"*"</span><span class="Identifier">/></span>
<span class="Identifier"><</span><span class="Special">xsl</span><span class="Comment">:</span><span class="Statement">template</span><span class="Type">match</span>=<span class="Constant">"/html"</span><span class="Identifier">></span>
<span class="Identifier"><</span><span class="Identifier">tv</span><span class="Type">generator-info-name</span>=<span class="Constant">"Télérama → XMLTV"</span>
<span class="Type">source-info-url</span>=<span class="Constant">"<a href="http://television.telerama.fr/tele/grille.php">http://television.telerama.fr/tele/grille.php</a>"</span>
<span class="Type">source-info-name</span>=<span class="Constant">"Télérama"</span><span class="Identifier">></span>
<span class="Identifier"><</span><span class="Special">xsl</span><span class="Comment">:</span><span class="Statement">apply-templates</span><span class="Type">mode</span>=<span class="Constant">"channel"</span><span class="Type">select</span>=<span class="Constant">"body/div/div[@class='chaine']"</span><span class="Identifier"> /></span>
<span class="Identifier"><</span><span class="Special">xsl</span><span class="Comment">:</span><span class="Statement">apply-templates</span><span class="Type">mode</span>=<span class="Constant">"programme"</span><span class="Type">select</span>=<span class="Constant">"body/div/div/div/div[contains(@class, 'emission')]/div/div[substring(@id, 0, 6)='data_']"</span><span class="Identifier"> /></span>
<span class="Identifier"></tv></span>
<span class="Identifier"></</span><span class="Special">xsl</span><span class="Comment">:</span><span class="Statement">template</span><span class="Identifier">></span>
<span class="Identifier"><</span><span class="Special">xsl</span><span class="Comment">:</span><span class="Statement">template</span><span class="Type">match</span>=<span class="Constant">"text()"</span><span class="Type">priority</span>=<span class="Constant">"-1"</span><span class="Identifier">/></span>
<span class="Identifier"><</span><span class="Special">xsl</span><span class="Comment">:</span><span class="Statement">template</span><span class="Type">mode</span>=<span class="Constant">"channel"</span><span class="Type">match</span>=<span class="Constant">"div"</span><span class="Identifier">></span>
<span class="Identifier"><</span><span class="Identifier">channel</span><span class="Identifier">></span>
<span class="Identifier"><</span><span class="Special">xsl</span><span class="Comment">:</span><span class="Statement">attribute</span><span class="Type">name</span>=<span class="Constant">"id"</span><span class="Identifier">></span>
<span class="Identifier"><</span><span class="Special">xsl</span><span class="Comment">:</span><span class="Statement">value-of</span><span class="Type">select</span>=<span class="Constant">"substring(../@id, 6)"</span><span class="Identifier">/></span>
<span class="Identifier"></</span><span class="Special">xsl</span><span class="Comment">:</span><span class="Statement">attribute</span><span class="Identifier">></span>
<span class="Identifier"><</span><span class="Identifier">display-name</span><span class="Type">lang</span>=<span class="Constant">"fr"</span><span class="Identifier">><</span><span class="Special">xsl</span><span class="Comment">:</span><span class="Statement">value-of</span><span class="Type">select</span>=<span class="Constant">"./@title"</span><span class="Identifier">/></span><span class="Identifier"></display-name></span>
<span class="Identifier"><</span><span class="Identifier">icon</span><span class="Type">width</span>=<span class="Constant">"40"</span><span class="Type">height</span>=<span class="Constant">"40"</span><span class="Identifier">></span>
<span class="Identifier"><</span><span class="Special">xsl</span><span class="Comment">:</span><span class="Statement">attribute</span><span class="Type">name</span>=<span class="Constant">"src"</span><span class="Identifier">></span><a href="http://icon-telerama.sdv.fr/tele/imedia/images_chaines_tra/Transparent/40x40/">http://icon-telerama.sdv.fr/tele/imedia/images_chaines_tra/Transparent/40x40/</a><span class="Identifier"><</span><span class="Special">xsl</span><span class="Comment">:</span><span class="Statement">value-of</span><span class="Type">select</span>=<span class="Constant">"substring(../@id, 6)"</span><span class="Identifier">/></span>.gif<span class="Identifier"></</span><span class="Special">xsl</span><span class="Comment">:</span><span class="Statement">attribute</span><span class="Identifier">></span>
<span class="Identifier"></icon></span>
<span class="Identifier"></channel></span>
<span class="Identifier"></</span><span class="Special">xsl</span><span class="Comment">:</span><span class="Statement">template</span><span class="Identifier">></span>
<span class="Identifier"><</span><span class="Special">xsl</span><span class="Comment">:</span><span class="Statement">template</span><span class="Type">mode</span>=<span class="Constant">"programme"</span><span class="Type">match</span>=<span class="Constant">"div"</span><span class="Identifier">></span>
<span class="Identifier"><</span><span class="Identifier">programme</span><span class="Identifier">></span>
<span class="Identifier"><</span><span class="Special">xsl</span><span class="Comment">:</span><span class="Statement">attribute</span><span class="Type">name</span>=<span class="Constant">"channel"</span><span class="Identifier">></span>
<span class="Identifier"><</span><span class="Special">xsl</span><span class="Comment">:</span><span class="Statement">value-of</span><span class="Type">select</span>=<span class="Constant">"div[@class='Id_Chaine']"</span><span class="Identifier">/></span>
<span class="Identifier"></</span><span class="Special">xsl</span><span class="Comment">:</span><span class="Statement">attribute</span><span class="Identifier">></span>
<span class="Identifier"><</span><span class="Special">xsl</span><span class="Comment">:</span><span class="Statement">attribute</span><span class="Type">name</span>=<span class="Constant">"start"</span><span class="Identifier">></span>
<span class="Identifier"><</span><span class="Special">xsl</span><span class="Comment">:</span><span class="Statement">apply-templates</span><span class="Type">mode</span>=<span class="Constant">"xmltv-time-from-iso-8601"</span><span class="Type">select</span>=<span class="Constant">"div[@class='Date_Debut']"</span><span class="Identifier">/></span>
<span class="Identifier"></</span><span class="Special">xsl</span><span class="Comment">:</span><span class="Statement">attribute</span><span class="Identifier">></span>
<span class="Identifier"><</span><span class="Special">xsl</span><span class="Comment">:</span><span class="Statement">attribute</span><span class="Type">name</span>=<span class="Constant">"stop"</span><span class="Identifier">></span>
<span class="Identifier"><</span><span class="Special">xsl</span><span class="Comment">:</span><span class="Statement">apply-templates</span><span class="Type">mode</span>=<span class="Constant">"xmltv-time-from-iso-8601"</span><span class="Type">select</span>=<span class="Constant">"div[@class='Date_Fin']"</span><span class="Identifier">/></span>
<span class="Identifier"></</span><span class="Special">xsl</span><span class="Comment">:</span><span class="Statement">attribute</span><span class="Identifier">></span>
<span class="Identifier"><</span><span class="Special">xsl</span><span class="Comment">:</span><span class="Statement">attribute</span><span class="Type">name</span>=<span class="Constant">"showview"</span><span class="Identifier">></span>
<span class="Identifier"><</span><span class="Special">xsl</span><span class="Comment">:</span><span class="Statement">value-of</span><span class="Type">select</span>=<span class="Constant">"div[@class='ShowViewFr']"</span><span class="Identifier">/></span>
<span class="Identifier"></</span><span class="Special">xsl</span><span class="Comment">:</span><span class="Statement">attribute</span><span class="Identifier">></span>
<span class="Identifier"><</span><span class="Identifier">title</span><span class="Type">lang</span>=<span class="Constant">"fr"</span><span class="Identifier">></span>
<span class="Identifier"><</span><span class="Special">xsl</span><span class="Comment">:</span><span class="Statement">value-of</span><span class="Type">select</span>=<span class="Constant">"div[@class='Titre']"</span><span class="Identifier">/></span>
<span class="Identifier"></title></span>
<span class="Identifier"><</span><span class="Identifier">sub-title</span><span class="Type">lang</span>=<span class="Constant">"fr"</span><span class="Identifier">></span>
<span class="Identifier"><</span><span class="Special">xsl</span><span class="Comment">:</span><span class="Statement">value-of</span><span class="Type">select</span>=<span class="Constant">"div[@class='Sous_Titre']"</span><span class="Identifier">/></span>
<span class="Identifier"></sub-title></span>
<span class="Identifier"><</span><span class="Identifier">desc</span><span class="Type">lang</span>=<span class="Constant">"fr"</span><span class="Identifier">></span>
<span class="Identifier"><</span><span class="Special">xsl</span><span class="Comment">:</span><span class="Statement">value-of</span><span class="Type">select</span>=<span class="Constant">"div[@class='resume_long']"</span><span class="Identifier">/></span>
<span class="Identifier"></desc></span>
<span class="Identifier"><</span><span class="Identifier">category</span><span class="Type">lang</span>=<span class="Constant">"fr"</span><span class="Identifier">></span>
<span class="Identifier"><</span><span class="Special">xsl</span><span class="Comment">:</span><span class="Statement">value-of</span><span class="Type">select</span>=<span class="Constant">"div[@class='Type']"</span><span class="Identifier">/></span>
<span class="Identifier"></category></span>
<span class="Identifier"><</span><span class="Identifier">length</span><span class="Type">units</span>=<span class="Constant">"seconds"</span><span class="Identifier">></span>
<span class="Identifier"><</span><span class="Special">xsl</span><span class="Comment">:</span><span class="Statement">value-of</span><span class="Type">select</span>=<span class="Constant">"div[@class='DureeEnSecondes']"</span><span class="Identifier">/></span>
<span class="Identifier"></length></span>
<span class="Identifier"></programme></span>
<span class="Identifier"></</span><span class="Special">xsl</span><span class="Comment">:</span><span class="Statement">template</span><span class="Identifier">></span>
<span class="Identifier"><</span><span class="Special">xsl</span><span class="Comment">:</span><span class="Statement">template</span><span class="Type">mode</span>=<span class="Constant">"xmltv-time-from-iso-8601"</span><span class="Type">match</span>=<span class="Constant">"*|@*"</span><span class="Identifier">></span>
<span class="Identifier"><</span><span class="Special">xsl</span><span class="Comment">:</span><span class="Statement">value-of</span><span class="Type">select</span>=<span class="Constant">"concat(substring(.,0,5),substring(.,6,2),substring(9,2),substring(.,12,2),substring(.,15,2))"</span><span class="Identifier">/></span>
<span class="Identifier"></</span><span class="Special">xsl</span><span class="Comment">:</span><span class="Statement">template</span><span class="Identifier">></span>
<span class="Identifier"></</span><span class="Special">xsl</span><span class="Comment">:</span><span class="Statement">stylesheet</span><span class="Identifier">></span>
</pre>
<p>Il n'y a plus qu'à enchaîner toutes les étapes dans un script shell (<a href="http://o.mengue.free.fr/xmltv/tv.sh"><code>tv.sh</code></a>) :</p>
<pre class="terminal unix"><samp class="prompt">$ </samp><kbd>./<a href="http://o.mengue.free.fr/xmltv/tv.sh">tv.sh</a> tv.2008-02-14T23:00:00.xml 2008-02-14T23:00:00</kbd>
</pre>
<p>Et voici quelques extraits du résultat :</p>
<pre class="code vim vimft-xml"><span class="Comment"><?</span><span class="Type">xml</span><span class="Type">version</span>=<span class="Constant">"1.0"</span><span class="Type">encoding</span>=<span class="Constant">"UTF-8"</span><span class="Comment">?></span>
<span class="Identifier"><</span><span class="Identifier">tv</span><span class="Type">generator-info-name</span>=<span class="Constant">"Télérama → XMLTV"</span><span class="Type">source-info-url</span>=<span class="Constant">"<a href="http://television.telerama.fr/tele/grille.php">http://television.telerama.fr/tele/grille.php</a>"</span><span class="Type">source-info-name</span>=<span class="Constant">"Télérama"</span><span class="Identifier">></span>
<span class="Comment"><!</span><span class="Comment">-- […] --</span><span class="Comment">></span>
<span class="Identifier"><</span><span class="Identifier">channel</span><span class="Type">id</span>=<span class="Constant">"111"</span><span class="Identifier">></span>
<span class="Identifier"><</span><span class="Identifier">display-name</span><span class="Type">lang</span>=<span class="Constant">"fr"</span><span class="Identifier">></span>Arte<span class="Identifier"></display-name></span>
<span class="Identifier"><</span><span class="Identifier">icon</span><span class="Type">width</span>=<span class="Constant">"40"</span><span class="Type">height</span>=<span class="Constant">"40"</span><span class="Type">src</span>=<span class="Constant">"<a href="http://icon-telerama.sdv.fr/tele/imedia/images_chaines_tra/Transparent/40x40/111.gif">http://icon-telerama.sdv.fr/tele/imedia/images_chaines_tra/Transparent/40x40/111.gif</a>"</span><span class="Identifier">/></span>
<span class="Identifier"></channel></span>
<span class="Comment"><!</span><span class="Comment">-- […] --</span><span class="Comment">></span>
<span class="Identifier"><</span><span class="Identifier">programme</span><span class="Type">channel</span>=<span class="Constant">"111"</span><span class="Type">start</span>=<span class="Constant">"2008020000"</span><span class="Type">stop</span>=<span class="Constant">"2008020220"</span><span class="Type">showview</span>=<span class="Constant">"2779370"</span><span class="Identifier">></span>
<span class="Identifier"><</span><span class="Identifier">title</span><span class="Type">lang</span>=<span class="Constant">"fr"</span><span class="Identifier">></span>Arizona Dream<span class="Identifier"></title></span>
<span class="Identifier"><</span><span class="Identifier">sub-title</span><span class="Type">lang</span>=<span class="Constant">"fr"</span><span class="Identifier">/></span>
<span class="Identifier"><</span><span class="Identifier">desc</span><span class="Type">lang</span>=<span class="Constant">"fr"</span><span class="Identifier">></span>Axel, un orphelin de 20 ans, vit davantage dans un monde rempli de rêves et de poissons volants qu'à New York, où il habite. Par l'esprit, il se «transporte» souvent sur la banquise lointaine et ...<span class="Identifier"></desc></span>
<span class="Identifier"><</span><span class="Identifier">category</span><span class="Type">lang</span>=<span class="Constant">"fr"</span><span class="Identifier">></span>Film<span class="Identifier"></category></span>
<span class="Identifier"><</span><span class="Identifier">length</span><span class="Type">units</span>=<span class="Constant">"seconds"</span><span class="Identifier">></span>8400<span class="Identifier"></length></span>
<span class="Identifier"></programme></span>
<span class="Comment"><!</span><span class="Comment">-- […] --</span><span class="Comment">></span>
<span class="Identifier"></tv></span>
</pre>
<p>Pour visualiser le résultat obtenu sous une forme plus lisible pour un humain, je vous recommande d'essayer <a href="http://www.ericandchar.com/xsltvgrid/" hreflang="en">XSLTv</a>. Vous enregistrez le fichier XMLTV sous <code>tv.xml</code> dans le répertoire de XSLTv et vous chargez <code>tv.html</code> dans votre navigateur. Vous obtenez <a href="http://o.mengue.free.fr/xmltv/xsltv/tv.html" rel="noindex nofollow">ceci</a> :</p>
<p style="text-align: center;"><a href="http://o.mengue.free.fr/xmltv/xsltv/tv.html" rel="noindex nofollow"><img src="http://o.mengue.free.fr/blog.dc/images/20080214-grille-telerama-xsltv-488.jpg" alt="Le fichier XMLTV visualisé avec XSLTv" /></a></p>
<p>Ce n'est pas visuellement aussi beau que le site Télérama, mais pensez que ce n'est que l'une des multiples utilisations du format XMLTV : ces données peuvent aussi être utilisées par exemple pour piloter un magnétoscope numérique.</p>
<p>L'étape suivante sera de programmer un proxy en PHP, mais je vous en parlerais plus tard.</p>
<hr>
<p>Fichiers joints :</p>
<ul>
<li><a href="http://o.mengue.free.fr/xmltv/leprogramme.xslt" type="text/xsl"><code>leprogramme.xslt</code></a></li>
<li><a href="http://o.mengue.free.fr/xmltv/chaines.xslt" type="text/xsl"><code>chaines.xslt</code></a></li>
<li><a href="http://o.mengue.free.fr/xmltv/xmltv.xslt" type="text/xsl"><code>xmltv.xslt</code></a></li>
<li><a href="http://o.mengue.free.fr/xmltv/tv.sh" type="application/x-shellscript"><code>tv.sh</code></a></li>
</ul>
<p><strong>MàJ 2008-03-02 :</strong> J'ai mis à jour tv.sh et xmltv.xslt. Voir <a href="http://o.mengue.free.fr/blog/2008/03/02/53-telerama-xmltv-mise-a-jour">ce billet</a>.</p>http://o.mengue.free.fr/blog/post/2008/02/11/51-les-programmes-tele-de-telerama-en-xmltv#comment-formhttp://o.mengue.free.fr/blog/feed/atom/comments/51