Les petites cases

Le code de la knowledge box

Plusieurs d'entre vous m'ont demandé le code de la knowledge box. C'est avec plaisir que je vous en fais part, mais autant vous prévenir tout de suite je suis un très mauvais codeur quand il s'agit d'utiliser un langage de programmation. Merci d'avance pour votre indulgence à ce niveau ;-).

Six parties composent la knowledge box :

  • la classe PHP, RAP, RDF API for PHP mis au point par Chris Bizer, qui permet d'interroger le SPARQL end point de Dbpedia ;
  • Un script PHP qui utilise cette classe et qui rapatrie les données ;
  • Un script javascript très très simple pour l'AJAX ;
  • Un bout de code PHP à introduire dans un bloc de Drupal ;
  • les triples RDFa dans votre contenu ;

Pour RAP, il suffit de le télécharger et de le poser dans votre arborescence. Attention au chemin, il nous sera utile pour y faire référence dans le script PHP.

Le script PHP permet d'interroger le serveur SPARQL de Dbpedia, de construire la requête et de formater la réponse qui revient en HTML zarbi... (j'ai l'impression qu'il y a un bug à ce niveau chez Dbpedia).

<!--Le chemin vers RAP -->
define("RDFAPI_INCLUDE_DIR", "./api/");
include(RDFAPI_INCLUDE_DIR . "RdfAPI.php");
<!--Ici on récupère l'argument URI dans l'URL qui correspond à l'objet du triple RDF, par exemple, http:/dbpedia.org/resource/Tim_Berners-Lee-->
$uri=$_GET['uri'];
<!--J'instancie un appel au serveur SPARQL de Dbpedia-->
$client = ModelFactory::getSparqlClient("http://dbpedia.org/sparql");
<!--Je demande les résultats au format XML, mais pour l'instant il semble qu'il y a un bug et c'est du HTML zarbi qui est renvoyé-->
$client->setOutputFormat("xml");
<!--La requête en SPARQL : concrètement, je récupère le résumé en français et le lien vers la page de la wikipedia francophone-->
$querystring = "
PREFIX owl: >http://www.w3.org/2002/07/owl#>
PREFIX xsd: >http://www.w3.org/2001/XMLSchema#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
PREFIX dc: <http://purl.org/dc/elements/1.1/>
PREFIX : <http://dbpedia.org/resource/>
PREFIX dbpedia2: <http://dbpedia.org/property/>
PREFIX dbpedia: <http://dbpedia.org/>
PREFIX skos: <http://www.w3.org/2004/02/skos/core#>
SELECT ?hasValue ?wikifr
WHERE {
{ <".$uri."> <http://dbpedia.org/abstract> ?hasValue.
  <".$uri."> <http://dbpedia.org/property/wikipage-fr> ?wikifr
}
FILTER ( lang(?hasValue) = \"fr\" )
}
";
$query = new ClientQuery();
$query->query($querystring);
$result = $client->query($query);
$result="<div>".$result."</div>";
<!--Mise en forme du résultat avec un peu de XPath et simpleXML de PHP5-->
$xml = new SimpleXMLElement($result);
if ($xml->xpath('/div/table/tr[2]')) {
foreach($xml->xpath('/div/table/tr[2]') as $line) {
echo "<span>".$line->td[0]."</span><br/><a href=".$line->td[1].">En savoir plus</a>";
}
}
else {
echo "pas d'informations";
}

Le script Javascript pour l'AJAX est ultra simple (j'ai repris le script AJAX pour débutants ;-) ). Il se contente de ramener la page Web query.php à laquelle je fais passer l'argument URI :

function objAjax(){
var xhr = null;
if(window.XMLHttpRequest) // Firefox et autres
xhr = new XMLHttpRequest();
else if(window.ActiveXObject){ // Internet Explorer
try {
xhr = new ActiveXObject("Msxml2.XMLHTTP");
} catch (e) {
xhr = new ActiveXObject("Microsoft.XMLHTTP");
}
}
else { // XMLHttpRequest non supporté par le navigateur
alert("Votre navigateur ne supporte pas les objets XMLHTTPRequest...");
xhr = false;
}
return xhr
}
/*** Méthode qui sera appelée sur le click du bouton*/
function go(arg1){
var xhr = objAjax()
// On défini ce qu'on va faire quand on aura la réponse
xhr.onreadystatechange = function(){
if(xhr.readyState == 1) {
document.getElementById('reponse').innerHTML="<img src='http://www.lespetitescases.net/images/spinner.gif'/>"
}
// On ne fait quelque chose que si on a tout reçu et que le serveur est ok
if(xhr.readyState == 4 && xhr.status == 200){
var reponse=xhr.responseText.replace( /\\u0*([0-9A-F]*)/g, '&#x$1;' );
var reponse=reponse.replace(/\\n/g, '<br/>');
document.getElementById('reponse').innerHTML=reponse;
}
}
var url="http://lespetitescases.net/essai/rapi/query.php?uri="+arg1
xhr.open("GET",url,true);
xhr.send(null);
}

Dans Drupal (je vous laisse adapter en fonction de votre CMS), il faut créer un nouveau bloc que j'ai limité à un billet, pour l'instant, avec ce code dont l'idée est d'analyser le contenu pour trouver les attributs RDFa (dans cet exemple, je me suis contenté de l'attribut rel et de la valeur owl:sameAs) :

if (arg(0) == 'node' && is_numeric(arg(1)) && is_null(arg(2))) {
  //Je récupère l'ID du node
  $nid = (int)arg(1);
  //Je vais récupérer le corps de ce node dans la base de données MYsql
  $sql = "SELECT title,body FROM node_revisions WHERE nid={$nid}";
  $result = db_query(db_rewrite_sql($sql));
  while ($anode = db_fetch_object($result)) {
    $content=$anode->body;
    $content="<div>".$content."</div>";
    $xml = new SimpleXMLElement($content);
    //Je fais une requête XPath pour trouver tous les noeuds qui comportent l'attribut rel avec la valeur owl:sameAs
    if ($xml->xpath('//node()[@rel="owl:sameAs"]')) {
      echo "<ul>";
//Pour chacun de ces noeuds, je le mets en forme
      foreach($xml->xpath('//node()[@rel="owl:sameAs"]') as $triple) {
$url=$triple['href'];
$string=$triple;
        //Je fais l'appel au javascript en passant en argument l'URI objet.
echo "<li><a href='#' onclick='go(\"".$url."\")'>".$triple."</a></li>";
      }
      echo "</ul><span id='reponse'></span><br/>";
    }
    else {
      echo "<p>Pas de triplets RDFa dans ce billet</p>";
    }
  }
}

Et pour finir, il faut introduire les triplets en RDFa dans votre contenu :

<span id="php" about="#php" rel="owl:sameAs" href="http://dbpedia.org/resource/PHP">PHP</span>

Pour retrouver l'URI, vous pouvez utiliser l'interrogation plein texte de Dbpedia avec bif:contains.

Comment améliorer cette knowledge box ? Je vois plusieurs pistes :

  • Amélioration du code ;-)
  • Permettre à l'utilisateur de rapatrier d'autres propriétés, c'est à dire paramétrer la requête SPARQL
  • Ne pas se limiter à Dbpedia, mais rapatrier des informations contenues dans un fichier FOAF, par exemple, ou dans un autre RDF triple Store
  • Afficher une carte de Yahoo Maps ou de Google Maps quand le sujet est un lieu
  • Et toutes vos idées...

Il n'y a pas de licences, vu la bidouille de ce code, mais vous pouvez le récupérer, l'adapter, le triturer, l'améliorer...

Bon amusement !!

PS: j'allais oublier que si quelqu'un veut traduire en anglais ce billet et le précédent, ce sera aussi avec plaisir...

RDF Sparql Outils OWL RDFa Geekeries —