Les petites cases

RDFaiser votre blog, 2ème partie : la pratique

Dans le précédent billet, j'ai expliqué en quoi RDFa permettait de décrire la structure du message contenu dans une page Web et comment on pourrait facilement générer du RDFa à partir des données structurées dans la base de données de votre CMS. Je vous propose maintenant de passer de la théorie à la pratique.

Ce tutoriel suppose que vous connaissez XHTML et le principe de base de RDF.

1ère étape : déclarer le bon doctype.

Dans la mesure où RDFa ajoute des attributs à XHTML, le W3C a mis au point une DTD spécifique issue de XHTML et intégrant les attributs RDFa. Par conséquent, si vous voulez que vos pages soient valides, le doctype à déclarer est le suivant :

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML+RDFa 1.0//EN" "http://www.w3.org/MarkUp/DTD/xhtml-rdfa-1.dtd">

2ème étape : choisir les vocabulaires RDF que vous aller utiliser

RDFa reposant sur RDF, il est possible et même conseillé d'utiliser des prédicats déclarés dans les vocabulaires existants. Il faut donc choisir les vocabulaires que vous allez utiliser. Dans notre cas, ce sont les suivants :

  • Le Dublin Core simple, vocabulaire RDF pour les prédicats de base : titre, auteur, date...
  • Le Dublin Core qualifié qui offre des prédicats plus précis : date de création, date de modification...
  • SIOC, Semantically-Interlinked Online Communities, vocabulaire permettant de décrire et de relier la production d'une communauté en ligne ;
  • SIOC type, vocabulaire RDF qui affine les types de contenu manipulé par SIOC ;
  • SKOS, vocabulaire RDF pour décrire des vocabulaires contrôlés ;
  • RDFS, vocabulaire RDF pour décrire une ontologie en RDF ;
  • XSD, qui n'est pas un vocabulaire RDF, mais le langage de description d'un XML schema et qui sert à spécifier les types de données : date, chaîne de caractères, arbre XML...

3ème étape : déclarez les espaces de noms des vocabulaires utilisés

RDFa utilise le principe des CURIEs, Compact URIs, syntaxe mis au point par le W3C pour simplifier l'écriture des URI dans le cadre de RDF suivant le principe des espaces de noms. Par exemple, ce code :

<h1 property="http://purl.org/dc/elements/1.1/title">Mon joli titre</h1>

Avec les CURIes, il donne :

<h1 xmlns:dc="http://purl.org/dc/elements/1.1/" property="dc:title">Mon joli titre</h1>

Vous remarquez qu'il est nécessaire de déclarer l'espace de nom correspondant au vocabulaire avant de l'utiliser dans la propriété.

Pour faciliter la réutilisation des vocabulaires sur l'ensemble de la page Web, il est préférable de déclarer tous les espaces de noms dans l'élément racine <html> ce qui, dans notre cas, donne :

<html
xmlns="http://www.w3.org/1999/xhtml"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:dcterms="http://purl.org/dc/terms/"
xmlns:sioc="http://rdfs.org/sioc/ns#"
xmlns:sioctype="http://rdfs.org/sioc/types#"
xmlns:skos="http://www.w3.org/2004/02/skos/core#"
xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
xmlns:xsd="http://www.w3.org/2001/XMLSchema#"
xml:lang="fr">

Étant donné qu'il s'agit d'une page Web encodé en XHTML, il ne faut pas oublier de déclarer l'espace de noms par défaut correspondant et la langue principale de la page Web.

4ème étape : Structurer le billet du blog

Nous y voilà, tout est prêt à présent pour ajouter le RDFa dans le code HTML de votre template/squelette/gabarits (choisissez votre cas) correspondant au billet de votre blog. Dans les exemples ci-dessous, le code HTML est donné à titre indicatif, je ne présage pas de la structure de votre page et je vous laisse adapter en conséquence. En revanche, le RDFa est le même :

[snip]
<body>
   <!-- je déclare que cette partie du code correspond à un billet de blog, en utilisant SIOC type et que l'URL du billet correspond au sujet des triples qui vont être déclarés ensuite grâce à l'attribut about -->
   <div class="monbillet" instanceof="sioctype:BlogPost" about="http://exemple.com/urldubillet">
        
         <!-- J'indique que le billet fait partie du blog dont l'URL est déclaré avec l'attribut href-->
        <span rel="sioc:has_container" href="http://exemple.com"/>
       
          <!-- Le titre du billet. Vous remarquerez que c'est l'attribut property qui est utilisé,
               car l'objet n'est pas une ressource, mais une chaîne de caractères-->
        <h1 id="titredemonbillet" property="dc:title">Le titre du billet</h1>
       
         <!-- Le contenu du billet-->
        <div class="textebillet" property="sioc:content">Le texte du billet</div>
       
         <p class="metadonnees">
              <!--
                     La date du billet. Dans ce cas, l'objet doit être sous une forme normalisée pour une exploitation automatique par les machines. L'attribut content est donc utilisé pour ne pas prendre en compte le contenu de l'élément et l'attribut datatype pour indiquer le type de données
               -->
              Billet écrit le <span property="dcterms:created" content="2008-02-24"  datatype="xsd:date">24 février 2008 – 15h15</span>
            
               <!-- l'auteur du billet Je me contente ici du strict minimum des informations. -->
              par <span rel="sioc:has_creator">
                       <span instanceof="sioc:User">
                         <span property="rdfs:label">le nom de l'auteur</span>
                       </span>
                     </span>
             
               <!-- les tags du billet. Premier cas : pas d'URI associé au tag -->
               <span rel="sioc:topic">
                      <span instanceof="skos:concept">
                            <!--L'utilisation de l'attribut content permet de faire ensuite de mettre du contenu dans la balise, comme un lien hypertexte vers la page qui contient tous les billets associés à votre tag-->
                           <span property="skos:prefLabel" content="tag">
                                 Tag
                           </span>
                      </span>
               </span>
             
               <!-- Second cas : une URI est associée au tag grâce à MOAT par exemple ;-) -->
               <span rel="sioc:topic" href="http://dbpedia.org/resource/Semantic_Web">
                      <span instanceof="skos:concept" about="http://dbpedia.org/resource/Semantic_Web">
                            <!--L'utilisation de l'attribut content permet de faire ensuite de mettre du contenu dans la balise, comme un lien hypertexte vers la page qui contient tous les billets associés à votre tag-->
                           <span property="skos:prefLabel" content="tag">
                                 Tag
                           </span>
                      </span>
               </span>
              <div class="commentaires">
                      cf. la 5ème étape
             </div>
        </p>
   </div>
</body>

5ème étape : Structurer les commentaires

La dernière étape consiste à structurer les commentaires. Ce code est à introduire à l'endroit où j'ai indiqué « cf. la 5ème étape » dans le code précédent.

<!-- Le commentaire est une réponse au billet d'où l'utilisation de la propriété SIOC « has_reply ».  Comme l'objet est une ressource, on indique son URL en valeur de l'attribut href-->
<div class="commentaire" rel="sioc:has_reply" href="http://example.com/uridubillet#idducommentaire">
   
     <!-- Indication du type de la portion d'information en utilisant SIOC types. L'attribut about indique que l'URL du    commentaire sera le sujet des triples suivants-->
    <div instanceof="sioctype:Comment" about="http://example.com/uridubillet#idducommentaire">
        <p class="metadonnees">
            Ecrit par
            <!-- Indication de l'auteur du commentaire-->
            <span rel="sioc:has_creator">
               <span instanceof="sioc:User">
                  <!-- Courriel de l'auteur du commentaire encodé en SHA1 pour éviter au robot spammeur de le récupérer -->
                  <span property="sioc:email_sha1" content="528b95cc44060ceea571d7498a9fd2c7e3ca8a4c"/>
                  <!--Nom de l'auteur du commentaire. Si vous voulez ajouter un lien vers le blog de l'auteur du commentaire, il faut utiliser l'attribut content avec comme valeur le nom du commentateur-->
                  <span property="rdfs:label">le nom de l'auteur du commentaire</span>
               </span>
            </span>
            <!-- Cf. plus haut pour la date-->
            le <span property="dcterms:created" content="2008-02-24"  datatype="xsd:date">24 février 2008 – 16h30</span>
       </p>
       <div class="textecommentaire" property="sioc:content">Texte du commentaire</div>
     </div>
</div>

Vous trouverez en fichier attaché à ce billet la page Web complète sans les commentaires.

6ème étape : Vérifier le RDF généré à partir de votre encodage en RDFa

Pour vérifier le code généré à partir de votre page Web encodé en RDFa, vous devez utiliser un extracteur. Il en existe plusieurs, mais le plus à jour et le plus simple d'utilisation est le RDFa distiller mis à disposition par le W3C. Il suffit d'indiquer l'URL de votre fichier et le système parse le code et génère le code dans la syntaxe RDF/XML. Vous pouvez comparer le résultat avec n'importe quel billet de ce blog, puisqu'il est entièrement « RDFaisé », par exemple : MOAT : donner du sens à vos tags.

Une dernière étape pourrait consister à mettre en place de la négociation de contenu pour proposer automatiquement un contenu adapté à l'agent qui requête la page : dans le cas d'un navigateur le code en XHTML+RDFa et dans le cas d'une application qui exploite le RDF le code en RDF/XML. Vous pouvez trouver un exemple sur le blog d'Ivan Herman.

Maintenant, c'est à vous de jouer. N'hésitez pas si vous avez des questions, des remarques ou des améliorations à proposer. J'essayerai d'y répondre dans la mesure de mes moyens.

Il ne reste plus qu'à exploiter ce code ce que j'aborderai dans le prochain billet, le dernier de cette série.



Structuration RDFa XHTML Geekeries — 

Commentaires

Bonjour et merci pour cette série d'articles,
Je viens de l'adapter à un squelette SPIP pour une page article.
A propos des "tags", je ne suis pas certain d'avoir bien saisi ce passage:
<!--L'utilisation de l'attribut content permet de faire ensuite de mettre du contenu dans la balise, comme un lien hypertexte vers la page qui contient tous les billets associés à votre tag-->
C'est bien comme ceci que cela s'applique:
<span rel="sioc:topic">
<span instanceof="skos:concept">
<span property="skos:prefLabel" content="Société et politique">
<a href="spip.php?mot27">Société et politique</a>
</span>
</span>
</span>
Vivement le prochain billet :-)




Oui, tu as parfaitement compris. Le principe est le suivant, lorsqu'on utilise l'attribut property, l'objet du triplet n'est pas une autre ressource, c'est une chaîne de caractères, une date... soit cet objet est le contenu de l'élément, soit c'est le contenu de l'attribut content. Dans la mesure où le contenu de l'élément contient des balises HTML qui n'ont pas de sens, il vaut mieux utiliser l'attribut content. Est-ce plus clair ?
Pour les spipistes qui passent par ici, vous pouvez voir le résultat du travail d'Igor à cette adresse, par exemple : http://www.igor-web.net/spip.php?article121 . Envisages-tu de mettre la maquette à disposition ?
Je m'aperçois que j'ai oublié quelque chose dans mon tutoriel, dans la balise head, il faut ajouter l'attribut profile :
profile="http://ns.inria.fr/grddl/rdfa/"
Cela permet de déclarer le profil de la page en vue de l'utilisation automatique de GRDDL, j'y reviendrai dans le prochain billet qui devrait arriver dans le week-end ;-)



"Oui, tu as parfaitement compris. Le principe est le suivant, lorsqu'on utilise l'attribut property, l'objet du triplet n'est pas une autre ressource, c'est une chaîne de caractères, une date... soit cet objet est le contenu de l'élément, soit c'est le contenu de l'attribut content. Dans la mesure où le contenu de l'élément contient des balises HTML qui n'ont pas de sens, il vaut mieux utiliser l'attribut content. Est-ce plus clair ?"
Donc si je souhaite indiquer la page de présentation de l'auteur avec un lien vers la page de cet auteur je devrais procéder de la même manière avec content:
<span rel="sioc:has_creator">
<span instanceof="sioc:User">
<span property="rdfs:label" content="#NOM"><a href="#URL_AUTEUR">#NOM</a></span>
</span>
</span>


"Envisages-tu de mettre la maquette à disposition ?"

Oui je ferais un "pas à pas" avec les balises SPIP pour une base de squelette article.html basique.

Voilà j'ai mis un truc en ligne, un peu confus peut-être: http://www.igor-web.net/spip.php?article122
C'est super et très clair. Merci Igor !

Tu préconises instanceof mais ça n'a pas l'air d'être valide du point de vue du validateur (et tu utilises d'ailleurs toi même typeof à la place), une raison particulière à cela ?

Par ailleurs, je me demandais si l'on pouvait grouper :

<div class="monbillet" instanceof="sioctype:BlogPost" about="http://exemple.com/urldubillet">
       
         <!-- J'indique que le billet fait partie du blog dont l'URL est déclaré avec l'attribut href-->
        <span rel="sioc:has_container" href="http://exemple.com"/>

Et c'est effectivement le cas :

<div class="monbillet" instanceof="sioctype:BlogPost" about="http://exemple.com/urldubillet" rel="sioc:has_container" href="http://exemple.com">

Merci pour le tuto :-)

RDFa n'ayant pas encore atteint le statut de recommandation au W3C, la spécification peut être amenée à changer. C'est typiquement ce qui s'est passé la semaine dernière pour cet attribut. Le groupe de travail a décidé de changer l'attribut @instanceof qui était trop proche de l'attribut @instance de Xforms en @typeof et la modification a été immédiatement répercutée sur la DTD rendant mon tutoriel invalide sur ce point. J'ai eu le temps de faire le changement dans mon code (j'en avais besoin pour tester des petits exemples...), mais, honte à moi, je n'ai pas pris le temps de le faire dans le corps du billet. Merci pour ta vigilance, David :-)

D'ailleurs, attention, il est tout à fait possible (et à mon avis souhaitable) que cet attribut change de nom avant le passage en recommandation de RDFa prévu au mois de juin. Pour ceux qui voudraient en savoir plus sur la question : l'editor's draft du 3 avril, et les threads concernés sur la liste de discussion du groupe de travail.

Merci, pour l'astuce sur le groupement, cela va effectivement simplifier le code source XHTML. Il faut que je fasse la modif...

Est ce que tu as en tête une idée d'UI pour pour RDFaiser les pages web générés avec Drupal et le module CCK ? Voir une façon d'automatiser complètement la RDFaisation ?
Désolé, je n'ai pas d'UI en tête pour RDFaiser automatiquement les pages Web, j'avoue ne pas y avoir réfléchi et cela n'existe pas à ma connaissance. Les projets RDF API (http://drupal.org/project/rdf) et SPARQL API (http://drupal.org/project/sparql) pour drupal 6 peuvent certainement servir de base à la construction d'une telle interface. Ils sont néanmoins encore en phase de développement et reste instable.
Bonjour Merci pour cet article pratique (et les autres de la même série...). Je l'ai appliqué à mon site sous Wordpress. A+
Bravo et merci à vous de le mettre en pratique, je vois que ce tuto n'était pas trop mal fait. Avez-vous mis à dispo votre thème Wordpress RDFaisé ?

Recette de nouveau appliquée, cette fois à un thème Dotclear. Le thème est téléchargeable (il s'agit du thème par défaut de Dotclear, modifié) : http://www.314r.fr/index.php?post/2010/03/21/Du-RDFa-dans-Dotclear.
Un article détaillant la méthode devrait suivre.
Encore merci !

Merci pour ce retour et bravo pour la réalisation. Les nouveautés de RDFa 1.1 devraient encore faciliter l'intégration de la structuration des données en RDF au sein d'une page d'une page HTML, il faudrait que j'en dresse les caractéristiques. A faire et à suivre....