Aller au contenu principal

Une URI, deux URI, tralalalalère

13/11/2016

Cherchez pas à comprendre le titre, je l’ai pris comme une évidence sous le coup de l’inspiration

Interpellé de bon matin par Gautier Poupeau sur Twitter, un week-end de pont (faut-y être sadique ! ou obsessionnel !) sur nos URI et nos alignements dans data.bnf.fr, je trouve que l’occasion est excellent pour faire un petit récapitulatif de la situation.

Bien sûr, pour ceux qui ont déjà été confrontés à de la modélisation RDF, je n’apprendrai rien. Mais je suppose qu’il en reste quelques-uns qui ne sont pas encore passés par là : donc voici le problème.

Au commencement était le Verbe

Cas d’école : vous voulez exposer en RDF un lot de notices de personnes (que ce soient les auteurs dans votre catalogue, ou les chercheurs dans votre annuaire universitaire). Vous allez attribuer à chacun d’entre eux une URI (généralement construite à partir de l’identifiant interne dans votre base de données) et affecter un certain nombre de propriétés à cette ressource.

Par exemple si votre base de données contient l’info :

vian_boris

Vous allez pouvoir exposer les triplets suivants, adossés aux ontologies FOAF + BIO qui vous fournissent les propriétés nécessaires :

<http://mon.univ.fr/123456> rdf:type foaf:Person
<http://mon.univ.fr/123456> foaf:familyName"Vian"
<http://mon.univ.fr/123456> foaf:givenName "Boris"
<http://mon.univ.fr/123456> bio:birth "1920-03-10"

La première ligne est essentielle : pour toute ressource exposée, on prend la peine de préciser de quoi on parle (ce qui est logique dans une base de données interne, n’a rien d’évident une fois exposé sur le web, récupéré, décontextualisé, etc.)

Maintenant, vous avez aussi une table des pseudonymes, et vous voulez exposer la liste des pseudonymes de Boris Vian.

sullivan

Pour lister des « formes alternatives » (ou « autres dénominations ») l’ontologie SKOS est très pratique : elle vous permet de définir des skos:altLabel en plus du (non répétable) skos:prefLabel.

Le plus simple et tentant serait donc d’écrire :

<http://mon.univ.fr/123456> skos:altLabel "Sullivan, Vernon"

Ben oui mais non : la propriété skos:altLabel ne peut avoir pour sujet qu’un skos:Concept. Or la ressource identifiée par l’URI <http://mon.univ.fr/123456&gt; n’est pas de type skos:Concept mais de type foaf:Person.

Une personne a une date de naissance. Un concept a, au mieux, une date de création (c’est-à-dire généralement la date de création de la notice). Ce sont donc deux choses bien distinctes.

Bref, si vous voulez utiliser à la fois les propriétés de FOAF et celles de SKOS, il va vous falloir deux ressources distinctes (le concept et la personne), donc deux URI distinctes, chacune avec ses propriétés, et un lien entre les deux.

Ce lien s’exprimera sous la forme : http://uri_du_concept foaf:focus http://uri_de_la_personne1

Dans data.bnf.fr, c’est propre…

Il y a plein de choses à revoir dans le modèle de data.bnf.fr, très certainement. Mais pour cette question-là, la distinction est bien faite : Boris Vian a

Et on a bien les triplets

<http://data.bnf.fr/ark:/12148/cb13091689x> rdf:type skos:Concept
<http://data.bnf.fr/ark:/12148/cb13091689x#foaf:Person> rdf:type foaf:Person

Chacune de ses URI a les propriétés adaptées qui lui sont associées : la date de naissance est attribuée à la personne, les formes alternatives (pseudonymes) sont attribuées au concept.

… ou presque

Les 5 étoiles du linked data

Les 5 étoiles du linked data

Mais on a un effet de bord, dû à la philosophie même de ce qu’est le web de données liées.

On s’efforce de lier autant que possible des ressources BnF à d’autres référentiels, de construire les équivalences.

Cela permet au réutilisateur des données de les enrichir facilement, en allant récupérer par exemple ailleurs la photo de Boris Vian si data.bnf.fr.

Par exemple, DBpedia (qui reste au centre du graphique Linked open data cloud dans sa version la plus récente — août 2014, avant la montée en puissance de Wikidata) fournit une propriété foaf:depiction avec photo.

Les données de data.bnf.fr sont donc alignées avec DBpedia. En soi, c’est une bonne idée. C’est même un minimum.

Malheureusement DBpedia n’a pas fait le même effort de modélisation. Et au lieu de distinguer 2 URI pour chaque ressource (faut reconnaître que ça peut compliquer la modélisation pour les modélisateurs, et la réutilisation pour les réutilisateurs), chaque ressource est tout simplement déclarée comme étant à la fois le concept et la personne.

personne_et_concept

Donc dans data.bnf.fr, devons-nous lier à DBpedia notre URI concept ou notre URI personne ?

Devons-nous exposer le triplet

<http://data.bnf.fr/ark:/12148/cb13091689x#foaf:Person&gt; owl:sameAs <http://fr.dbpedia.org/resource/Boris_Vian&gt;

ou le triplet

<http://data.bnf.fr/ark:/12148/cb13091689x&gt; skos:Concept <http://fr.dbpedia.org/resource/Boris_Vian&gt;

En fait, les deux alignements ont été déclarés dans data.bnf.fr. Cela nous conduit à une erreur dans notre propres données, puisque par déduction (on dit inférence) ça signifie que nos deux ressources, le concept et la personne, sont une seule et même chose.

Comment faire ?

On aurait pu imaginer de ne conserver qu’un de ces deux triplets. Par exemple, retenir que l’URI de DBpedia désigne la personne Boris Vian (avec date de naissance, etc.) et ne garder que l’équivalence :

<http://data.bnf.fr/ark:/12148/cb13091689x#foaf:Person&gt; owl:sameAs <http://fr.dbpedia.org/resource/Boris_Vian&gt;

Mais le résultat n’est pas tellement plus heureux : en effet l’URI DBpedia a comme propriété (entre autres)  rdf:type skos:Concept

Par inférence, cela revient à dire que notre foaf:Person est donc de type skos:Concept

Le problème est identique si l’on décide de lier notre URI concept à l’URI DBpedia : par inférence, notre concept serait donc aussi une personne.

Enfin bref, dès lors qu’on se lie à une ressource DBpedia de ce type-là (il y a beaucoup de types de ressources dans DBpedia, bien plus que dans data.bnf.fr, donc j’ignore si le problème se pose systématiquement), on créer une incohérence sur notre propres données.

En voulant enrichir nos données, sans même importer d’information de DBpedia, on en vient à les polluer. La seule conclusion logique serait donc de s’interdire de se lier à DBpedia.

En tout cas c’est la seule que j’envisage. Et je ne la trouve pas plus satisfaisante.

——————————————–
1. Je trouve d’ailleurs curieux que ce soit l’ontologie FOAF, et non l’ontologie SKOS, qui fournisse une propriété permettant de relier la chose (ici la personne) à son concept. En effet dans plein de cas on aura autre chose que des personnes (des objets, des événements, des documents), toutes sortes de choses du monde réel (même si skos:Concept est lui aussi une sous-classe de owl:Thing, puisque tout est chose et que les concepts, comme Internet, font partie du « vrai » monde) pour lesquelles on aura besoin de les associé à leur fiche SKOS — sans pouvoir utiliser foaf:focus, dont le sous-domaine (l’objet) est nécessairement un foaf:Agent (personne ou organisation).

SemWeb.Pro 2016 : c’est dans moins de 15 jours !

09/11/2016

SemWeb.Pro, c’est une journée de conférences et de rencontres autour de réalisations dans le web de données.

L’événement essaie de regrouper plusieurs domaines d’activités qui ne se rencontrent pas nécessairement dans la vraie vie : culture, industrie, services, etc.

Cette année, ce sera le lundi 21 novembre, dans le 14e arrondissement de Paris.

Et le programme vaut le coup de venir y faire un tour ! [Conflict of interest disclosure : j’ai participé à son élaboration]

Côté culture, il y aura notamment Isidore & Nakala, Persée, ISTEX, Biblissima. C’est donc l’occasion de se mettre à jour sur lces acteurs nationaux

Mais il me semble que, quand on vient des bibliothèques, un des enjeux de ce genre de journées est plutôt de se confronter à d’autres univers que nous connaissons moins, et dont les objets ne sont pas bibliothéconomiques : parce que c’est justement en découvrant les démarches issues d’autres milieux qu’on peut apprendre d’autres façons de penser, repartir avec des idées différentes.

Bref, une occasion à ne pas manquer.

Dernier intérêt de cette journée : sa date. SemWeb.Pro arrive juste au bon moment s’il vous reste quelques dizaines d’euros dans votre budget annuel, que vous ne savez pas trop comment dépenser. En l’occurrence, ce sera d’ailleurs plus un investissement qu’une dépense.

 

Un livre blanc sur la blockchain

07/11/2016

3 mois d’inactivité, c’est lamentable. Je ne désespère pas de trouver un rythme quotidien qui me permette d’insérer du temps de rédaction de billets de blog. J’aimerais bien vous raconter un peu ce que je fais à la BnF (si, c’est intéressant !) et pour parler de data.bnf.fr. Mais pour arriver à reprendre, je reprends en version light pour le moment.

Je continue une veille ciblée sur la blockchain (en plus de quelques autres thématiques) dont je soupçonne qu’elle peut faire bouger pas mal de choses dans la société, et dans le monde des bibliothèques entre autres.

Chaîne de blocs Bitcoin. Source : Wikimedia. CC-BY-SA-3.0

Chaîne de blocs Bitcoin. Source : Wikimedia. CC-BY-SA-3.0

Ceci étant posé, il est probable que les dispositifs qui seront mis en place pour se substituer aux mécanismes actuels, et permettront des services sans intermédiaires, ne bouleverseront que peu l’expérience utilisateur, en dehors du choix de confiance qu’il accordera à ces dispositifs. Je veux dire par là que pour l’établissement de contrats, le vote électronique, ou la gestion d’un compte bancaire, on en est aujourd’hui encore au stade où, pour utiliser un système utilisant la technologie blockchain, il faut un minimum s’intéresser aux mécanismes sous-jacents, à la paire clé publique/clé privée, au système des chaînes de blocs, etc. A court ou moyen terme, les concepteurs de ces dispositifs se préoccuperont de plus en plus de l’expérience utilisateur. Donc avec des outils dont les mécanismes seront plus ou moins invisibles, ou ressemblant fort à ce qui est (re)connu par ailleurs.

Bref.

Parmi ce que j’ai pu lire, je vous recommande de prendre le temps de lire le livre blanc « Comprendre la blockchain » (PDF – 56 pages) : il reprend l’historique, les principes du systèmes, des exemples d’utilisations, des enjeux et certains problèmes (comme celui de la consommation énergétique).

La dimension technique m’a paru un peu pauvre et trop peu détaillée, mais c’est selon mon goût à moi. Je rencontre peu de gens qui soient aussi exigeants au sujet des descriptions techniques…

Donc pour ceux qui ont juste vu passer quelques infos, mais sans avoir eu le temps d’approfondir vraiment, c’est un document tout à fait adapté pour se mettre au niveau.

comprendre_la_blockchain

L’enjeu à ce stade est ensuite d’imaginer (de fantasmer, même) sur des pistes d’utilisations possibles. Pour reconstruire des services existants et en envisager de nouveaux.

Enrichir ses tableurs Excel ou LibreOffice Calc grâce à des API (4/4) : résultats multiples

28/07/2016

Dernier billet de cette petite série (cf. les billets 1 : présentation, 2 : SPARQL, et 3 : espaces de noms). L’essentiel est dans le premier billet. Les autres ne seront utiles que lorsque vous serez confrontés aux problèmes que chacun d’entre eux évoque.

Donc, celui-ci : quand une requête (sur une API ou un SPARQL Endpoint, peu importe) renvoie plusieurs résultats. J’ai pris l’exemple d’un ISBN qui renvoie plusieurs PPN ou ARK, mais voici un autre besoin : pour un PPN donné, je veux récupérer les indexations sujet.

Je repars sur l’hypothèse d’un tableau à 6 colonnes : ISBN, Titre, Auteur, Editeur, Date, PPN (trouvé grâce à l’ISBN).

billet 4 - tableau init

Exemple : récupération de l’indexation sujet et problème

Les notices RDF sont accessibles via une URL du type http://www.sudoc.fr/009294937.rdf. Dans le RDF, on a 2 types de sujets :

  • les balises <dc:subject> qui contiennent les libellés des mots-clés
  • les balises <dcterms:subject> qui contiennent les URI de ces mots-clés dans IdRef
    (notez au passage que l’ordre d’affichage est indifférent puisque c’est un graphe : la notion d’ordre n’est pas pertinente)
    billet 4 - exemple de subject

Dans mon fichier, le PPN est en colonne F. Et comme je travaille sous Calc je vais devoir supprimer l’espace de nom dc: avant de pouvoir récupérer l’indexation (oui, parce que là, c’est le libellé qui m’intéresse et pas l’URI, c’est comme ça). En G2, je vais donc écrire :

=FILTREXML(SUBSTITUE(SERVICEWEB("http://www.sudoc.fr/"&F2&".rdf");"dc:";"");"//subject")

Je déploie la formule sur l’ensemble des lignes du tableau (double-clic gauche sur l’angle inférieur droit de ma cellule G2) et j’obtiens ceci :

billet 4 - résultats sujets

Et je constate rapidement que seule la première occurrence du subject a été récupérée. Comment récupérer les autres ?

Réponse

Ce n’est pas possible. Aucune option d’Excel ou Calc ne permet de récupérer l’ensemble des occurrences d’un XPath (à la différence d’OpenRefine, par exemple, qui récupère une liste quand on utilise la fonction ParseHtml, équivalent de FILTREXML + SERVICEWEB).

Proposition

La manière dont j’essaie de résoudre ce problème, est d’ajouter une colonne pour compter le nombre d’occurrences. Donc en colonne G, je remplace la formule indiquée ci-dessus par :

=FILTREXML(SUBSTITUE(SERVICEWEB("http://www.sudoc.fr/"&F2&".rdf");"dc:";"");"count(//subject)")

Ce qui me donne :
billet 4 - décompte des sujets

Si dans ma démarche je souhaite récupérer l’ensemble des valeurs, je suis alors contraint de retenir le nombre maximal d’occurrence constaté (ici : 12) , et de prendre les 12 colonnes suivantes pour y affecter à chaque fois une occurrence de //subject, en fonction de sa position. Donc dans les cellules H2 à S2, je pourrais écrire :

  • =FILTREXML(SUBSTITUE(SERVICEWEB("http://www.sudoc.fr/"&F2&".rdf");"dc:";"");"//subject[1]")
  • =FILTREXML(SUBSTITUE(SERVICEWEB("http://www.sudoc.fr/"&F2&".rdf");"dc:";"");"//subject[2]")
  • =FILTREXML(SUBSTITUE(SERVICEWEB("http://www.sudoc.fr/"&F2&".rdf");"dc:";"");"//subject[3]")
  • =FILTREXML(SUBSTITUE(SERVICEWEB("http://www.sudoc.fr/"&F2&".rdf");"dc:";"");"//subject[4]")
  • =FILTREXML(SUBSTITUE(SERVICEWEB("http://www.sudoc.fr/"&F2&".rdf");"dc:";"");"//subject[5]")
  • =FILTREXML(SUBSTITUE(SERVICEWEB("http://www.sudoc.fr/"&F2&".rdf");"dc:";"");"//subject[6]")
  • =FILTREXML(SUBSTITUE(SERVICEWEB("http://www.sudoc.fr/"&F2&".rdf");"dc:";"");"//subject[7]")
  • =FILTREXML(SUBSTITUE(SERVICEWEB("http://www.sudoc.fr/"&F2&".rdf");"dc:";"");"//subject[8]")
  • =FILTREXML(SUBSTITUE(SERVICEWEB("http://www.sudoc.fr/"&F2&".rdf");"dc:";"");"//subject[9]")
  • =FILTREXML(SUBSTITUE(SERVICEWEB("http://www.sudoc.fr/"&F2&".rdf");"dc:";"");"//subject[10]")
  • =FILTREXML(SUBSTITUE(SERVICEWEB("http://www.sudoc.fr/"&F2&".rdf");"dc:";"");"//subject[11]")
  • =FILTREXML(SUBSTITUE(SERVICEWEB("http://www.sudoc.fr/"&F2&".rdf");"dc:";"");"//subject[12]")

En fait c’est une très mauvaise idée : ça veut dire que je vais ouvrir 12 fois la même notice (très peu performant).

Il vaut donc mieux rapatrier une seule fois le contenu du fichier XML et le stocker dans une cellule, et appeler le contenu (avec FILTREXML()) depuis les cellule d’à côté

Et je me retrouve avec plein de #VALEUR très laids. Pour les supprimer : je sélectionne l’ensemble des colonnes, que je copie, puis je fais un collage spécial > texte pour que les formules soient écrasées par les valeurs récupérées. Enfin, j’effectue un chercher-remplacer : chercher « #VALEUR ! », remplacer par «  »

Et enfin :

billet 4 - indexation sujet

Notez au passage la colonne I, intitulée « Notice RDF », dans laquelle vont chercher les colonnes J à U.

C’est le dernier billet de la série, et le dernier billet de l’été : j’entre en hibernation pour quelques semaines.

Bonnes vacances à ceux qui n’en sont pas encore revenus !

Enrichir ses tableurs Excel ou LibreOffice Calc grâce à des API (3/4) : les espaces de noms et XPath

26/07/2016

On est est resté, à la fin de l’épisode précédent, à un fichier XML tout simple que l’expression XPath envisagée n’arrivait pas à retrouver.

Voici un des fichiers XML récupérés grâce l’ISBN :

<sparql xmlns="http://www.w3.org/2005/sparql-results#" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.w3.org/2001/sw/DataAccess/rf1/result2.xsd">
<head>
<variable name="ark"/>
</head>
<results distinct="false" ordered="true">
<result>
<binding name="ark"><literal>ark:/12148/cb34657300h</literal></binding>
</result>
</results>
</sparql>

Tel est le résultat renvoyé par un Sparql Endpoint quand on lui demande une réponse en XML

Un espace de nom, c’est quoi ?

C’est simple : dans les fichiers XML qu’on peut rencontrer, c’est ce qui précède le « : » dans le nom de la balise.

Ainsi, si dans un fichier XML vous rencontrez <dc:title>Education européenne  [Texte imprimé]  / Romain Gary</dc:title>, la balise title a comme espace de nom dc : cela signifie que la propriété title appartient à un vocabulaire spécifique, et que ce vocabulaire est précisé dans le fichier XML.

Je ne sais pas pourquoi, les navigateurs n’affichent pas les déclarations d’espaces de nom, et si vous ouvrez cette notice RDF l’espace de nom « dc » ne semblera pas déclaré.

espace de nom dctitle

Pour le voir, il vous faut afficher le code source de cette page (Clic droit > Code source de la page ou Ctrl+U). Il n’y a pas d’indentation dans le code source, c’est pas de bol, ça ne facilite pas la lecture. En tout cas voilà ce que ça donne :

RDF - liste des namespace

J’ai surligné en jaune un ensemble d’attributs affectés à la balise racine du fichier <rdf:RDF>. Tous ces attributs s’appellent xmlns:quelquechose="uri"

« ns » signifie namespace (espace de nom). xmlns:quelquechose="uri" signifie donc : espace de nom XML QuelqueChose est la manière abrégée de raccrocher un ensemble de balise au même vocabulaire qu’on désigne par un uri commun

Et donc si vous regardez bien, vous verrez que s’y trouve la déclaration de l’espace de nom « dc » sous la forme :

 xmlns:dc="http://purl.org/dc/elements/1.1/"

Et si vous suivez l’URL http://purl.org/dc/elements/1.1/, vous tombez (évidemment) sur la description du vocabulaire Dublin Core (non étendu)

Avec XPath, il faut donc désigner un élément en précisant son espace de nom. Pour accéder à la balise dc:title dans le fichier ci-dessus, il faudrait donc préciser « //dc:title » et non pas « //title »

« Oui, mais dans le résultat Sparql, la balise en question n’a pas de préfixe… »

C’est vrai, le résultat est dans la ligne :

<binding name="ark"><literal>ark:/12148/cb34657300h</literal></binding>

Mais dans la balise racine, on trouve l’attribut suivant :

xmlns="http://www.w3.org/2005/sparql-results#"

Ce qui signifie que toutes les balises sans préfixe-espace de nom se rattachent par défaut au vocabulaire http://www.w3.org/2005/sparql-results#

Je précise que cette situation est très fréquente dans les API : les résultats Marc21 de WorldCat par exemple on un espace de nom vide (c’est-à-dire sans préfixe).

Comportement différencié dans Excel et dans Calc

Dans Excel, on constate la chose suivante :

  • quand la balise a un préfixe déclaré (comme dc:), on peut l’ajouter dans le XPath.
    Par exemple, on peut récupérer le dc:title en écrivant
    =FILTRE.XML(SERVICEWEB("http://www.sudoc.fr/082268789.rdf");"//dc:title")
  • quand la balise se rattache à un espace de nom sans préfixe (comme c’est le cas dans les résultats XML de Sparql), le XPath ne trouve rien.

Dans Calc, c’est pire

Qu’il y ait un préfixe ou non, Calc n’arrive pas à accéder aux balises dès lors qu’elles sont associées à un espace de nom.

Comment faire ?

On entre alors dans le bidouillage / bricolage. Comme je l’ai déjà dit, la documentation est indigente concernant cette fonction, que ce soit pour Excel ou pour Calc. Il existe peut-être une manière propre de déclarer dans la fonction FILTRE.XML (Excel) ou FILTREXML (Calc) un espace de nom, mais je n’ai pas trouvé comment. Si vous avez la réponse « académique », elle m’intéresse.

En attendant, voilà comment je me débrouille :

Pour faire simple, j’introduis entre FILTREXML et SERVICEWEBune étape de transformation-modification du résultat XML afin d’escamoter l’espace de nom.

Deux cas de figure

  • les balises ont un espace de nom avec préfixe (« dc: », « rdf: », etc.) :
    [manipulation inutile sous Excel, comme je le dis plus haut]
    J’utilise la fonction SUBSTITUE() (SUBSTITUTE() en anglais) qui va chercher toutes les occurrences de ce préfixe et les remplacer par rien.
    Exemple : =SUBSTITUE("<dc:title>Education européenne  [Texte imprimé]  / Romain Gary</dc:title>";"dc:";"") récupère les toutes les occurrences de « dc: » dans la chaîne de caractères indiquée, et le remplace par rien.
    Application : =FILTREXML(SUBSTITUE(SERVICEWEB("http://www.sudoc.fr/082268789.rdf");"dc:";"");"//title")

    • SERVICEWEB() récupère le contenu « natif » de la notice RDF
    • la fonction SUBSTITUE() récupère le contenu de SERVICEWEB() et y enlève tous les « dc: »
    • la fonction FILTREXML() exploite ce fichier XML retraité pour en récupérer la balise <title> qui a remplacé <dc:title>
  • les balises ont un espace de nom sans nom (comme dans le résultat XML de Sparql)
    J’utilise alors la fonction SUBSTITUE() pour supprimer la déclaration de l’espace de nom « vide » :
    Exemple : =SUBSTITUE("<sparql xmlns=""http://www.w3.org/2005/sparql-results#"" xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xsi:schemaLocation=""http://www.w3.org/2001/sw/DataAccess/rf1/result2.xsd">";" xmlns=""http://www.w3.org/2005/sparql-results#"";"")
    Attention : dans Excel comme dans Calc, on peut mettre des guillemets à l’intérieur de valeurs de formule en les répétant : "" au lieu de ".
    Application : =FILTREXML(SUBSTITUE(SERVICEWEB("http://data.bnf.fr/sparql?default-graph-uri=&query=PREFIX+bnf-onto%3A+%3Chttp%3A%2F%2Fdata.bnf.fr%2Fontology%2Fbnf-onto%2F%3Eselect+%28substr%28str%28%3Furi%29%2C20%2C22%29+as+%3Fark%29+where+%7B++%3Furi+bnf-onto%3Aisbn+%222-901040-29-2%22%0D%0A%7D&format=application%2Fsparql-results%2Bxml&timeout=0&should-sponge=&debug=on");" xmlns=""http://www.w3.org/2005/sparql-results#""";"");"//binding[@name='ark']")

Au bout d’un moment, je reconnais qu’il peut être plus prudent de découper le processus en plusieurs colonnes successives…

Sur un Sparql Endpoint, le HTML pourra être plus pertinent, sauf si par exemple vous voulez récupérer plusieurs valeurs (plusieurs colonnes) en une seule requête :

  • en HTML, il faudra dans le XPath tenir compte du numéro de la colonne : "//td[1]", "//td[2]", etc
    Et on risque de perdre pied
  • En XML, on précise dans le XPath le nom de la variable mis dans la requête : "//binding[@name='ark']", "//binding[@name='isbn']", "//binding[@name='DateDeNaissance']", etc.

Il me reste un dernier billet à rédiger : comme faire quand une requête renvoie plusieurs réponses (par exemple : un ISBN renvoie plusieurs ARK, ou plusieurs PPN).

Car la méthode FILTREXML ne renvoie que la première réponse…

Astuce 14 : ouvrir un onglet en cliquant sur la molette de la souris

25/07/2016

Un micro-post pour signaler une fonctionnalité apparemment mal connue : devant une liste de résultats, je vois beaucoup de gens faire un clic droit > Ouvrir dans un nouvel onglet, et continuer à balayer la liste à la recherche d’autres réponses pertinentes à explorer.

clic molette

En réalité vous obtenez la même chose si vous cliquez directement sur la molette en passant la souris sur le lien.

C’est vachement plus rapide !

 

Enrichir ses tableurs Excel ou LibreOffice Calc grâce à des API (2/4) : résultats SPARQL

22/07/2016

J’ai donné dans le billet précédent les principes de la fonctionnalité

=FILTREXML(SERVICEWEB(url);"xpath")

Voyons comment ça fonctionne si au lieu d’une API « classique » on veut exploiter un SPARQL Endpoint.

Je reste sur mon exemple de tableau ISBN-Titre-Auteur-Editeur-Date auquel on a rajouté la fois précédente une colonne PPN

fichier 6 colonnes

Si en plus du PPN, je veux ajouter l’ARK BNF (c’est-à-dire son identifiant pérenne exprimé sous la forme d’un ARK). La BnF ne propose pas d’API de conversion isbn2ark, à l’image de ce que fait l’Abes. En revanche le Sparql Endpoint de DataBnF (qui ne contient pas encore tout le catalogue pour l’instant) peut fonctionner de la même manière qu’une API : on construit une requête, ça génère une URL, on récupère le résultat.

La requête pour convertir l’ISBN en ARK

La propriété bnf-onto:isbn sert à déclarer l’ISBN d’une manifestation (notice bibliographique). La requête sera donc, pour un ISBN donné :

PREFIX bnf-onto: <http://data.bnf.fr/ontology/bnf-onto/&gt;
select ?uri where {
?uri bnf-onto:isbn "2-11-072340-8"
}

Si je l’exécute dans le Sparql Endpoint de DataBnF, le résultat ressemble à ça : une page blanche, avec un tout petit tableau en haut à gauche

isbn2ark

Si je veux uniquement l’ARK, non préfixé « http://data.bnf.fr/ &raquo;, je peux raffiner un peu : considérer l’URI de la ressource comme une chaîne de caractères (la fonction str(?uri) sert à ça) puis en supprimer les 20 premiers caractères pour ne garder que l’ARK :

PREFIX bnf-onto: <http://data.bnf.fr/ontology/bnf-onto/&gt;
select (substr(str(?uri),20,22) as ?ark) where {
?uri bnf-onto:isbn "2-11-072340-8"
}

Une fois qu’on a trouvé la bonne requête, on en récupère l’URL correspondante pour la donner à Excel/Calc.

Format en sortie HTML ?

SPARQL permet de sélectionner le format en sortie voulue.

Spontanément, il serait logique de choisir le XML puisqu’on utilise une fonction FILTREXML. On va voir tout à l’heure que c’est possible (et sans doute parfois souhaitable) mais dans les faits c’est plus compliqué.

En réalité, pour des utilisations simples comme celle ci-dessus, le HTML convient très bien, vu que c’est du XHTML (non déclaré comme tel) au sens où toutes les balises HTML sont correctement fermées.

Voici le code source de la page de résultats pour la requête ci-dessus :

<table class="sparql" border="1">
  <tr>
    <th>ark</th>
  </tr>
  <tr>
    <td>"ark:/12148/cb34311898n"</td>
  </tr>
</table>

Ca ressemble beaucoup à un résultat de l’API isbn2ppn, à la seule différence que le navigateur préfère l’afficher non sous forme d’arbre XML mais de tableau.

Le chemin XPath pour accéder à l’information est facile à définir : "//td"
(sur XPath, c’est par là)

Donc si je reprends les 3 étapes décrites dans le billet précédent, mais imbriquées dans une seule cellule, je vais mettre en cellule G2 la formule suivante :

=FILTREXML(SERVICEWEB("http://data.bnf.fr/sparql?default-graph-uri=&query=PREFIX+bnf-onto%3A+%3Chttp%3A%2F%2Fdata.bnf.fr%2Fontology%2Fbnf-onto%2F%3Eselect+substr%28str%28%3Furi%29%2C20%2C22%29+where+%7B++%3Furi+bnf-onto%3Aisbn+%22"&A2&"%22%0D%0A%7D&format=text%2Fhtml&timeout=0&should-sponge=&debug=on");"//td")

Pour construire l’URL, j’ai simplement repris l’URL d’une page de résultats, et j’ai modifié 2-11-072340-8 l’ISBN par "&A2&"

ajout ARK

A noter qu’une fois obtenu ce résultat, on a intérêt à écraser la colonne G par un copier-coller de ses valeurs (Sélectionner la colonne > Copier > Collage spécial > Texte) pour éviter que chaque cellule ne s’actualise à chaque réouverture du fichier (avec un temps d’attente plus ou moins long pour interroger le Sparql Endpoint pour chaque ISBN).

Format en sortie XML ?

Bien sûr, Excel et Calc sont capables de récupérer des infos du flux XML plutôt que HTML.

L’URL du XML

Première difficulté pratique : récupérer l’URL du flux XML renvoyé par le Sparql Endpoint. En effet quand au lieu de HTML on sélectionner le format XML en sortie, le navigateur n’affiche pas le résultat (cf. ce billet, mais surtout les commentaires qui sont dessous vu que je me suis complètement planté et que j’ai été heureusement corrigé) mais propose systématiquement d’ouvrir le fichier dans un autre logiciel (bloc-notes, éditeur XML, etc.) ou de le télécharger.

fichier XML à télécharger

Il faut donc récupérer l’URL d’un résultat HTML et y remplacer la valeur du paramètre format=text%2Fhtml en format=application%2Fsparql-results%2Bxml

http://data.bnf.fr/sparql?default-graph-uri=&query=PREFIX+bnf-onto%3A+%3Chttp%3A%2F%2Fdata.bnf.fr%2Fontology%2Fbnf-onto%2F%3Eselect+%28substr%28str%28%3Furi%29%2C20%2C22%29+as+%3Fark%29+where+%7B++%3Furi+bnf-onto%3Aisbn+%222-11-072340-8%22%7D&amp;format=application%2Fsparql-results%2Bxml&timeout=0&should-sponge=&debug=on

A côté de mes ARK déjà récupérés, je vais ajouter une colonne SERVICEWEB pour récupérer le contenu de ce fichier XML. La formule sera donc :

=SERVICEWEB("http://data.bnf.fr/sparql?default-graph-uri=&query=PREFIX+bnf-onto%3A+%3Chttp%3A%2F%2Fdata.bnf.fr%2Fontology%2Fbnf-onto%2F%3Eselect+%28substr%28str%28%3Furi%29%2C20%2C22%29+as+%3Fark%29+where+%7B++%3Furi+bnf-onto%3Aisbn+%22"&A2&"%22%0D%0A%7D&format=application%2Fsparql-results%2Bxml&timeout=0&should-sponge=&debug=on")

Et voilà le résultat (pour les 3 premières lignes)

resultat XML

Je remets ici le contenu d’une des cellules pour pouvoir commenter :

<sparql xmlns="http://www.w3.org/2005/sparql-results#" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.w3.org/2001/sw/DataAccess/rf1/result2.xsd">
<head>
<variable name="ark"/>
</head>
<results distinct="false" ordered="true">
<result>
<binding name="ark"><literal>ark:/12148/cb34657300h</literal></binding>
</result>
</results>
</sparql>

 

Le chemin XPath dans ce fichier XML

C’est un fichier XML assez simple. Et on voit que le résultat est dans une balise <binding> dont l’attribut name contient le nom de ma variable ark. La balise <literal/> précise le type de données qu’on traite.

Donc mon XPath sera simple aussi : "//binding[@name='ark']"

Et si je rajoute une colonne I à côté de ma colonne H (qui contient les résultats XML), la cellule I2 contiendra :

=FILTREXML(H2;"//binding[@name='ark']")

Et là vous avez une belle colonne
Ah tiens, non…

Flux XML - résultat Erreur

Et ça, c’est la faute aux espaces de nom.

D’où mon prochain billet.

En attendant :

  1. pour interroger des Sparql Endpoint, utilisez les sorties HTML
  2. pour les autres API, espérez qu’il n’y a pas d’espace de nom caché quelque part (c’est de plus en plus fréquent)

Ce prochain billet prendra le temps d’expliquer ce que sont les espaces de nom (mais à la limite, vous pouvez trouver ça dans plein d’endroits sur Internet, voire même le savoir déjà), et surtout comment vous en débarrasser sous Calc et Excel. Et là, je n’ai pas encore trouvé de documentation qui l’explique (si vous en avez, ça m’intéresse et ça m’économisera un billet).