Skip to content

Si c’est un lieu #hackathonBnF

20/11/2016

J’ai participé avec beaucoup de plaisir au premier hackathon organisé par la BnF ce week-end du 19-20 novembre. J’y étais pour apporter en cas de besoin une aide sur des questions de format, ce qui veut dire notamment que je n’ai eu aucune responsabilité à assurer sur les questions logistiques. J’étais donc concentré sur le fond, et ce fut une expérience vraiment sympa, sans stress (je le précise car d’autres ont dû être davantage happés par les aspects organisationnels, et ont dû en ressortir plus fatigués).

J’en profite pour saluer le travail des collègues de la BnF qui ont bossé dur pour que ça se déroule bien (il me semble que ce fut le cas), et féliciter l’équipe qui a été déclarée gagnante : @Gallicarte (site web / extension Chrome1).

Leur projet : proposer une navigation cartographique dans les résultats de Gallica, pour les documents qui possèdent une information de lieu. Question : comment, dans les données disponibles, un document est-il associé à un lieu dans Gallica.

Leur premier point d’entrée : voir si le document contient une indexation sujet de type Lieu.

(d’autres modalités ont été évoquées : lieux du déroulement de l’histoire que contient le document numérisés, si ces lieux sont listés dans Wikidata – exemple avec Le Comte de Monte Cristo, propriété Narrative location ; extraction de cette info dans les tables des matières)

Et donc c’est une occasion pour moi de parler un peu de data.bnf.fr. En effet quand vous avez une indexation Sujet, comment savoir (automatiquement) que ce sujet désigne un lieu ?

Le problème

Imaginions que vous tombiez sur ce document (parmi d’autres)

Fontaine du Pot de fer St Marcel (1671) - Rue Mouffetard : [photographie] / [Atget] -- Licence Etalab

Fontaine du Pot de fer St Marcel (1671) – Rue Mouffetard : [photographie] / [Atget] — Licence Etalab

Dans les métadonnées, accessibles à partir de l’identifiant ARK du document (et exposées via le protocole OAI, en Dublin Core) vous trouverez les infos suivantes :

Fontaines -- France -- Paris (France) -- 17e siècle
Paris (France) -- Rue Mouffetard
Paris (France) -- Rue du Pot-de-Fer
Paris (France) -- Fontaine du Pot-de-Fer

Comment distinguer ce qui est « sujet » de ce qui est « lieu » ?

La solution

Logiquement (il y a des exceptions, faut que je vois d’où ça vient) :

  1. les documents numérisés dans Gallica sont indexés en Rameau.
  2. Rameau est dans data.bnf.fr
  3. Rameau est découpé en 8 sous-ensembles
  4. Chaque concept est rattaché à l’un de ces sous-ensembles par la propriété dcterms:isPartOf
  5. La famille des Lieux a pour URI : http://data.bnf.fr/vocabulary/scheme/r167

On peut exporter la liste des familles de concepts à travers une requête comme celle-ci :
(à noter que pour certaines de ces familles, le label n’est pas fourni dans le Sparql Endpoint, mais c’est un bug destiné à disparaître)

PREFIX skos: <http://www.w3.org/2004/02/skos/core#>
PREFIX dcterms: <http://purl.org/dc/terms/>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
select distinct ?sousensembleRameau ?label where {
 ?ressource a skos:Concept.
 ?ressource dcterms:isPartOf ?sousensembleRameau.
 OPTIONAL {
    ?sousensembleRameau rdfs:label ?label.
  }
}
ORDER BY ?sousensembleRameau

Ce qui signifie que pour chaque indexation Sujet entrée dans un document de Gallica, on peut vérifier si dans data.bnf.fr elle est liée à la famille r167.

Donc si on dispose d’une indexation, il « suffit » de récupérer l’URI du concept à partir de son label, et de voir si cette URI est rattachée au groupe r167. Par exemple pour la première entrée , la requête suivante renvoie 0 résultat

PREFIX skos: <http://www.w3.org/2004/02/skos/core#>
PREFIX dcterms: <http://purl.org/dc/terms/>
select ?concept where {
  ?concept skos:prefLabel "Fontaines -- France -- Paris (France) -- 17e siècle"@fr.
  ?concept dcterms:isPartOf <http://data.bnf.fr/vocabulary/scheme/r167/>.
}

Alors que pour la seconde indexation « Paris (France) — Rue Mouffetard », la même requête renvoie bien l’URI

La récupération ou non de l’URI est une manière de faire test « lieu : oui/non ». Et donc ensuite de choisir d’afficher le document sur une carte.

Recherche Auteur = Atget sur Gallicarte

Recherche Auteur = Atget sur Gallicarte

—————————-
1. L’extension Chrome sert à ajouter dans les listes de résultats de Gallica une option « Affichage Carte » qui exploite les possibilités développées pour le site Gallicarte.

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 !