Skip to content

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).

 

Enrichir ses tableurs Excel ou LibreOffice Calc grâce à des API (1/4) : Présentation

20/07/2016

J’avoue que je n’arrive pas à comprendre pourquoi je trouve aussi peu sur Internet de documentation et de cas d’utilisations des fonctions couplées SERVICEWEB + FILTREXML (ou FILTRE.XML sous Excel).

Sans doute parce que pour Excel, c’est dans les versions postérieures à 2010 (Excel 2010 non compris), et qu’il faut se rabattre sur LibreOffice Calc (sans aucun scrupule, d’ailleurs !) pour les établissements qui n’auraient pas les versions les plus récentes de la suite Office.

Pour faire simple : ces fonctions permettent d’interroger facilement des API fournissant du XML, pour récupérer une information précise, à partir de données présentes dans un tableau, sans utiliser ni XSL ni aucun autre langage de programmation.

La seule compétence à avoir, c’est XPath, c’est-à-dire connaître la manière de naviguer dans un fichier XML (voir notamment dans la série « XSL » les billets sur XPath, dont celui-ci donne les principes et celui-là  récapitule toutes les options).

Un exemple simple pour commencer : récupérer les PPN Sudoc d’une série d’ISBN

vous disposez d’un fichier contenant des métadonnées bibliographiques de base à 5 colonnes : ISBN, Titre, Auteur, Editeur, Date – et vous voulez savoir si ces notices sont déjà présentes dans le Sudoc.

tableau livres

En gros, ce qui vous intéresse est de faire jouer l’API isbn2ppn, pour convertir l’ISBN en PPN et ajouter une colonne PPN sur la droite.

Pour commencer, on va découper le processus en plusieurs fois, mais ça peut ensuite se faire en une seule étape.

  1. Construire l’URL de requête de l’API, sur le modèle http://www.sudoc.fr/services/isbn2ppn/{isbn}
    Comme {isbn} doit prendre la valeur de l’ISBN (imaginons que ce soit en colonne A), je vais créer une 6e colonne (F) contenant :
    ="http://www.sudoc.fr/services/isbn2ppn/"&A2
    Ce qui va concaténer la chaîne de caractère correspondant à l’URL racine, et la valeur de la cellule A2. Je reporte ensuite cette formule dans l’ensemble des lignes de la colonne F
    première formule - URL

  2. Récupérer le résultat (XML) correspondant à l’URL
    Je vais faire ça en colonne G :
    Le contenu de la cellule G2 sera :
    =SERVICEWEB(F2)
    Tout simplement, Calc ou Excel va suivre l’URL de la cellule D2 et rapatrier le contenu
    deuxieme formule - resultat XML

  3. Dans le résultat XML, récupérer seulement une information en exprimant en XPath le chemin vers cette information.
    Je vais faire ça en colonne H (cellule H2) :
    =FILTREXML(G2;"//result/ppn")
    troisième formule - PPN
    ou =FILTRE.XML(G2;"//result/ppn") sous Excel

Une fois que ces 3 colonnes ont été renseignées, vous avez donc une table de correspondance ISBN → PPN

Ajouter des métadonnées descriptives

Notez que dès lors que vous avez le PPN, vous pouvez de la même manière construire l’URL http://www.sudoc.fr/{ppn}.rdf pour récupérer dans ce fichier d’autres informations (comme le PPN de l’auteur, la zone de description, etc.

Pour cela j’utilise la colonne I pour reconstruire l’URL : j’indique en I2 :
="http://www.sudoc.fr/"&H2&".rdf"

Puis la colonne J pour récupérer le contenu de la notice RDF
=SERVICEWEB(I2)

Puis la colonne K pour récupérer le contenu de la balise <dc:description/> :
=FILTREXML(J2;"//dc:description")

Ou, plutôt que de découper ça en 3 étapes, j’aurais pu directement écrire en cellule I2 (à côté de la colonne H contenant les PPN) :

=FILTREXML(SERVICEWEB("http://www.sudoc.fr/"&H2&".rdf");"//dc:description")

en imbriquant les fonctions les unes dans les autres.

Ca tient en une ligne, et c’est particulièrement rapide pour récupérer une valeur simple (dc:description) correspondant à une variable en entrée (ici, le PPN).

J’évoquerai plus tard 2 problèmes rencontrés régulièrement :

  • les valeurs répétables
    Car la formule FILTREXML() ne va récupérer que la première occurrence du XPath que vous avez indiqué (donc si un ISBN renvoie plusieurs PPN, il va vous renvoyer seulement le premier, sans préciser qu’il y en a d’autres)

  • les espaces de nom, y compris les espaces de nom sans nom [sic]

Au préalable, je vous donnerai dans un prochain billet un autre exemple d’enrichissement avec ces fonctions, mais en utilisant le SPARQL Endpoint de DataBnF (SPARQL servant alors d’API universelle, permettant d’interroger n’importe quel critère d’une base de triplets afin de retourner n’importe quel résultat associé à ce critère).

 

Journée Afnor/BnF sur l’open data du 24 juin 2016 (6/5) : et en plus, ça bouge

13/07/2016

Mes 5 précédents billets étaient plutôt longs, textuels, pas beaucoup d’images, tout ça tout ça.

Du coup j’en rajoute un sixième, juste pour vous indiquer que les vidéos sont en ligne, ainsi que les supports de présentation des intervenants.

Vous pourrez y constater que j’ai oublié de mentionner pleins de trucs, ou que j’ai tout compris de travers, et que j’ai raté le plus important. N’hésitez pas à venir me le re-signaler !

Accéder aux vidéos

160626_afnor_visuel

 

 

Journée Afnor/BnF sur l’open data du 24 juin 2016 (5/5) : partager son EAD

11/07/2016

Dernier billet sur cette journée. Si vous ne l’avez pas lu, prenez le temps de lire l’intro du premier billet où j’explique que je ne fais pas un compte-rendu).

Je reviens à présent sur quelques propos de Gaël Chenard (très stimulant, comme toujours) au cours de la table ronde.

Il a présenté

  • la politique d’open data (et open content) de son service depuis 2014,
  • la constitution d’une base d’1,5 million d’images numérisées,
  • la numérisation de documents à la demande,
  • et sa frustration sur deux points.

En effet tout le monde dans son département des Hautes-Alpes est d’accord pour partager au maximum les métadonnées (IR, ou instruments de recherche, c’est-à-dire inventaires d’archives) et les données (documents numérisés).

Le problème est qu’il bute sur deux problèmes strictement techniques pour partager données et métadonnées :

  • Le protocole OAI, classiquement utilisé pour exposer ses données au moissonnage, n’est pas adapté aux inventaires en EAD :
    • en OAI, les notices sont toutes sur le même plan ;
    • en EAD toutes les infos sont imbriquées les unes dans les autres.
      Si bien que les métadonnées sont juridiquement ouvertes mais ne le sont pas techniquement, faute de format pivot pour leur exposition.
  • Proposer le téléchargement massif de la base d’images ferait tomber leur serveur s’il avait trop de demandes simultanées.

Je reviens sur chacun de ses deux points, dont je découvre en rédigeant ce billet qu’ils sont finalement assez liés.

EAD et OAI

J’ai déjà eu l’occasion d’exprimer mon opinion là-dessus (sans vraiment de réaction, accord ou désaccord, de la part des services producteurs d’instruments de recherche) : les instruments de recherche sont construits à tort, pour des raisons historiques, comme des livres composés de chapitres, sous-chapitres, rubriques et sous-rubriques.

En gros, quand internet est apparu, on a voulu remplacer les inventaires imprimés par des inventaires en ligne. La TEI (DTD massivement utilisée dans le monde de l’édition, notamment scientifique) ne permettant pas d’indiquer le sens des différents paragraphe, une DTD spécifique a été rédigée permettant de préciser que tel paragraphe n’était pas un paragraphe, mais de l’information sur les conditions d’accès aux boîtes (balise <accessrestrict/>) ou sur le support (matériau, format).

En réalité il faut concevoir un inventaire non pas comme un document à encoder d’une manière sémantisée (çàd avec des balises plus significatives que <p/> ou <div/>), mais comme l’imbrication de composants avec un système d’héritage de certaines propriétés.

Donc si on veut modéliser la description d’un fonds d’archives (si on veut chercher l’équivalent du FRBR pour les fonds d’archives), la question à résoudre n’est pas : quels éléments structure un fonds d’archives ? Quelles sont les propriétés d’un fonds d’archives ?

mais : quelles sont les propriétés d’un composant ? Qu’est-ce qui caractérise le composant d’un fonds d’archives ?

J’insiste : Le concept central pour décrire un fonds d’archives, c’est le composant, pas le fonds lui-même.

Si cela peut vous aider à comprendre ce que je veux dire, voyez l’ontologie Org permettant de décrire une organisation.

Schéma de l’ontologie Org – source https://www.w3.org/TR/vocab-org/

Une org:Organisation est composée d’org:Organisations (cf. les propriétés org:hasSubOrganization et org:subOrganizationOf).

Si on essaie d’imaginer un ead:Composant à la place du org:Organization, quelles sont les propriétés indispensables ?

Pour restituer la structure d’un fonds d’archives à partir de ses composants, chaque composant a besoin de 3 éléments essentiels :

  • l’identifiant du composant parent
  • l’ordre d’apparition au sein de cet élément parent
  • le type de composant qu’on est en train de décrire (lettre, registre d’état-civil, sous-série, fonds)

Avec ces 3 informations, il est possible d’exposer à plat ses métadonnées, permettant ainsi aux moissonneurs de reconstruire, et de réindexer correctement, les composants.

Je signale que concernant l’héritage de l’indexation, l’EAD en fait pas forcément mieux et tout dépend du moteur de recherche. Ainsi, la base Archives et Manuscrits de la BnF, qui tourne actuellement sous Pleade, ne permet pas de retrouver un composant à partir d’un mot se trouvant au sein d’un composant supérieur. Ce sera résolu avec la nouvelle plateforme en cours de production, sans que les données en entrée soient modifiées : toujours de l’EAD. Donc c’est bien le paramétrage du moteur de recherche qui permet de faire hériter l’indexation à des sous-composants, et non la structure du fichier lui-même.
Au moment de l’exposition des données en OAI, il faudrait évidemment documenter la manière dont on a affecté ces 3 propriétés (id du <c/> parent, ordre, type de <c/>), c’est-à-dire quelles sont les balises (DC ou autres) utilisées pour les fournir.

  • La notion de « sous-composant de » n’est pas spécifique aux archives, il existe déjà certainemrent plein d’ontologies qui le prévoient
    dcterms:isPartOf pourrait déjà faire l’affaire dans un premier temps
  • Pour le type, dcterms:type, évidemment
  • Pour le rang, je ne sais pas s’il peut être induit de la cote, par exemple. Mais je sais qu’en EAD on peut se retrouver avec des composants qui ont un <unititle/> et pas de cote spécifique. Donc il faudrait trouver ou créer un xxx:rank pour résoudre ce problème.

Cela dit, pour l’exposition de ses données, un point particulier doit être retravaillé : l’identifiant du composant (du <c/> parent, mais aussi du <c/> exposé). En effet cela implique :

  1. que chaque composant ait un identifiant, ce qui n’est pas forcément le cas dans les inventaires actuels
  2. que cet identifiant soit pérenne (et ne soit pas juste le numéro d’ordre au sein de l’inventaire)
  3. que cet identifiant soit exprimé sous forme d’URI : en effet une fois décontextualisé, si un <c/> renvoie vers son <c/> parent dont celui-ci est « AD05-23.362 », on se demande ce qu’on peut bien en faire : pas seulement dans le cadre du web de données (je n’ai même pas évoqué la RDFisation des inventaires, là), mais au sein d’un moteur de recherche qui aurait moissonné (et reconstitué) plusieurs centaines d’inventaires récupérés dans plusieurs dizaines de serveurs OAI : il faut bien que chaque ID soit unique. Et pour cela, rien de mieux qu’une URI.

Mettre à plat ses métadonnées EAD au sein d’un serveur OAI permettrait aussi de les percevoir un peu plus comme une base de données (liées entre elles) et moins comme un texte linéaire et arborescent.

Exposer ses images à tout venant

Le second problème technique est très intéressant aussi : comment exposer son 1,5 million d’images sans exploser son serveur au bout de la 2e requête.

Une solution serait d’autoriser à 1 téléchargement du dump par jour. Après tout, WorldCat limite le nombre de requêtes sur son API à 50.000 par jour ; l’IGN autorise 100 téléchargements par jour de cartes Minecraft ; et les utilisateurs intéressés par 1,5 millions d’images ne doivent pas être si nombreux !

D’ailleurs, qui sont-ils, ces utilisateurs qui aimeraient pouvoir télécharger 1,5 millions d’images ? En quoi les avoir sur leur (gros) PC ou sur leur serveur leur semblerait plus avantageux que d’en disposer en ligne ?

Je manque peut-être d’imagination, mais je vois seulement deux raisons pour opérer un tel téléchargement :

  • quelqu’un qui veut mettre en place une plateforme en agrégeant des contenus de toutes parts (l’histoire des Hautes-Alpes, l’état-civil français, etc.).
    Ces personnes là (sociétés, administrations, associations) doivent être suffisamment peu nombreuses pour qu’on puisse passer convention (même orale) avec elles et leur fournir un dump complet à la demande.
  • Quelqu’un qui voudrait récupérer un corpus d’images, pour lequel les critères disponibles sur l’interface de recherche ne permettent pas :
    • soit de récupérer d’un clic les quelques centaines ou milliers de résultats obtenus
    • soit d’interroger correctement la base, parce que le formulaire de recherche n’est pas adapté

En gros, la vraie question devient alors : quel service je rends à l’internaute qui souhaite constituer un corpus d’images ?

  • Comment peut-il constituer son lot ?
  • Comment peut-il le récupérer ?
  • Comment peut-il récupérer les métadonnées qui vont avec ?

Oui, parce que récupérer 1,5 millions ou 6000 images, si c’est juste autant de fichiers déposés tels quels dans un répertoire de ma machine, je ne vois pas ce que je peux en faire ?

Bref, il me faut impérativement les métadonnées associées (ou un minimum de métadonnées associées).

Et donc il me semble que, plutôt que de chercher à fournir un dump des 1,5 millions d’images, le vrai service consiste à fournir la liste des URL des 1,5 millions d’images, et quelques métadonnées + API ou RDF pour en récupérer davantage si besoin.

En gros, une sitemap listant les « ressources » (qui sont les URI des <c/> de tout à l’heure) avec un lien (propriété rdarelationships:electronicReproduction par exemple) vers l’image.

En bonus : l’URI de la ressource renvoie à l’inventaire EAD en ligne, lequel expose pour chaque composant quelques métadonnées en RDFa (dont les 3 propriétés évoquées tout à l’heure).

Et comme on n’a généralement pas une seule image par <c/> (puisqu’un registre d’état-civil, c’est un composant mais des dizaines d’images) : rien n’empêche qu’un même <c/> ait plusieurs propriétés « reproduction électronique ».

Toutes ces réflexions n’ont que quelques jours, voire quelques heures. Je ne prétends donc pas que j’ai la solution à tous ces problèmes, loin s’en faut.

Et vous identifierez très certainement plein de problèmes conceptuels, structurels, logistiques, qui font que ma proposition ne marche pas. Je serai ravi que vous me démontriez mes erreurs : ça éviterait qu’elles restent en ligne et que d’autres s’en inspirent et se plantent à cause de moi (et donc à cause de vous, qui n’aurez rien fait).

Suivre

Recevez les nouvelles publications par mail.

Rejoignez 144 autres abonnés