source: spip-zone/_plugins_/taxonomie/trunk/services/itis/itis_api.php @ 92799

Last change on this file since 92799 was 92799, checked in by eric@…, 4 years ago

Ajout d'une démo.
Mise au point de l'action get_record sans gestion du cache pour l'instant.

  • Property svn:eol-style set to native
File size: 16.4 KB
Line 
1<?php
2/**
3 * Ce fichier contient l'ensemble des constantes et functions implémentant le service de taxonomie ITIS.
4 *
5 * @package SPIP\TAXONOMIE\ITIS
6 */
7
8if (!defined("_ECRIRE_INC_VERSION")) return;
9
10if (!defined('_TAXONOMIE_ITIS_URL_BASE_REQUETE'))
11        /**
12         * Préfixe des URL du service web de ITIS.
13         * Le service fournit des données au format XML ou JSON
14         */
15        define('_TAXONOMIE_ITIS_URL_BASE_REQUETE', 'http://www.itis.gov/ITISWebService/');
16if (!defined('_TAXONOMIE_ITIS_URL_CITATION'))
17        /**
18         * URL à fournir dans la citation du service ITIS.
19         */
20        define('_TAXONOMIE_ITIS_URL_BASE_CITATION', 'http://www.itis.gov/servlet/SingleRpt/SingleRpt?search_topic=TSN&search_value=%tsn%');
21if (!defined('_TAXONOMIE_ITIS_LANGUE_DEFAUT'))
22        /**
23         * Langue par défaut pour les api utilisant des noms communs
24         */
25        define('_TAXONOMIE_ITIS_LANGUE_DEFAUT', 'en');
26
27if (!defined('_TAXONOMIE_ITIS_REGEXP_RANKNAME'))
28        /**
29         * Ligne d'un fichier ITIS hiérachie généré.
30         * Il est indispensable de respecter les majuscules des noms de groupe pour éviter de matcher
31         * les suborder, infrakingdom...
32         */
33        define('_TAXONOMIE_ITIS_REGEXP_RANKNAME', '#(%groups_list%):\s*(\w+)\s*\[([^\]]*)\]\s*\[(\d+)\]#');
34
35
36/**
37 * Configuration de l'api du service web ITIS
38 */
39$GLOBALS['itis_language'] = array(
40        'fr' => 'french',
41        'en' => 'english',
42);
43$GLOBALS['itis_webservice'] = array(
44        'search' => array(
45                'commonname' => array(
46                        'function' => 'searchByCommonName',
47                        'argument' => 'srchKey',
48                        'list' => 'commonNames',
49                        'index' => 'commonName'
50                ),
51                'scientificname' => array(
52                        'function' => 'searchByScientificName',
53                        'argument' => 'srchKey',
54                        'list' => 'scientificNames',
55                        'index' => 'combinedName'
56                )
57        ),
58        'vernacular' => array(
59                'vernacularlanguage' => array(
60                        'function' => 'getTsnByVernacularLanguage',
61                        'argument' => 'language',
62                        'list' => 'ax23:vernacularTsns',
63                        'index' => 'commonName'
64                )
65        ),
66        'getfull' => array(
67                'record' => array(
68                        'function' => 'getFullRecordFromTSN',
69                        'argument' => 'tsn',
70                        'list' => 'ns:return',
71                        'index' => 'scientificName,taxRank,kingdom,commonNameList,taxonAuthor,parentTSN'
72                )
73        ),
74        'get' => array(
75                'scientificname' => array(
76                        'multiple' => false,
77                        'function' => 'getScientificNameFromTSN',
78                        'argument' => 'tsn',
79                        'index' => 'combinedName',
80                ),
81                'kingdomname' => array(
82                        'multiple' => false,
83                        'function' => 'getKingdomNameFromTSN',
84                        'argument' => 'tsn',
85                        'index' => 'kingdomName',
86                ),
87                'parent' => array(
88                        'multiple' => false,
89                        'function' => 'getHierarchyUpFromTSN',
90                        'argument' => 'tsn',
91                        'index' => 'parentTsn',
92                ),
93                'rankname' => array(
94                        'multiple' => false,
95                        'function' => 'getTaxonomicRankNameFromTSN',
96                        'argument' => 'tsn',
97                        'index' => 'rankName',
98                ),
99                'author' => array(
100                        'multiple' => false,
101                        'function' => 'getTaxonAuthorshipFromTSN',
102                        'argument' => 'tsn',
103                        'index' => 'authorship',
104                ),
105                'coremetadata' => array(
106                        'multiple' => false,
107                        'function' => 'getCoreMetadataFromTSN',
108                        'argument' => 'tsn',
109                        'index' => 'rankId',
110                ),
111                'experts' => array(
112                        'multiple' => true,
113                        'function' => 'getExpertsFromTSN',
114                        'argument' => 'tsn',
115                        'list' => 'experts',
116                ),
117                'commonnames' => array(
118                        'multiple' => true,
119                        'function' => 'getCommonNamesFromTSN',
120                        'argument' => 'tsn',
121                        'list' => 'commonNames',
122                ),
123                'othersources' => array(
124                        'multiple' => true,
125                        'function' => 'getOtherSourcesFromTSN',
126                        'argument' => 'tsn',
127                        'list' => 'otherSources',
128                ),
129                'hierarchyfull' => array(
130                        'multiple' => true,
131                        'function' => 'getFullHierarchyFromTSN',
132                        'argument' => 'tsn',
133                        'list' => 'hierarchyList',
134                ),
135                'hierarchydown' => array(
136                        'multiple' => true,
137                        'function' => 'getHierarchyDownFromTSN',
138                        'argument' => 'tsn',
139                        'list' => 'hierarchyList',
140                ),
141        ),
142);
143
144
145/**
146 * Recherche un taxon dans la base ITIS par son nom commun ou scientifique
147 * et retourne son identifiant unique nommé tsn.
148 *
149 * @param string        $api
150 *              Recherche par nom commun ou par nom scientifique. Prend les valeurs 'commonname' ou 'scientificname'
151 * @param string        $recherche
152 *              Nom à rechercher précisément. Seul le taxon dont le nom coincidera exactement sera retourné.
153 *
154 * @return int
155 *              Identifiant unique (tsn) dans la base ITIS ou 0 si la recherche échoue
156 */
157function itis_search_tsn($api, $recherche) {
158        global $itis_webservice;
159        $tsn = 0;
160
161        // Normaliser la recherche: trim et mise en lettres minuscules
162        $recherche = strtolower(trim($recherche));
163
164        // Construire l'URL de la fonction de recherche
165        $url = itis_api2url('json', 'search', $api, rawurlencode($recherche));
166
167        // Acquisition des données spécifiées par l'url
168        include_spip('inc/taxonomer');
169        $data = url2json_data($url);
170
171        // Récupération du TSN du taxon recherché
172        $api = $itis_webservice['search'][$api];
173        if (isset($data[$api['list']])
174        AND $data[$api['list']]) {
175                // La recherche peut renvoyer plusieurs taxons. On considère que le "bon" taxon
176                // correspond à celui dont le nom est exactement celui recherché.
177                foreach ($data[$api['list']] as $_data) {
178                        if ($_data
179                        AND (strcasecmp($_data[$api['index']], $recherche) == 0)) {
180                                // On est sur le bon taxon, on renvoie le TSN
181                                $tsn = intval($_data['tsn']);
182                                break;
183                        }
184                }
185        }
186
187        return $tsn;
188}
189
190
191/**
192 * Renvoie l'ensemble des informations sur un taxon désigné par son identifiant unique (tsn).
193 *
194 * @param int   $tsn
195 *              Identifiant unique du taxon dans la base ITIS (tsn)
196 *
197 * @return array
198 */
199function itis_get_record($tsn) {
200        global $itis_webservice;
201        $output =array();
202
203        // Construire l'URL de l'api sollicitée
204        $url = itis_api2url('xml', 'getfull', 'record', strval($tsn));
205
206        // Acquisition des données spécifiées par l'url
207        $api = $itis_webservice['getfull']['record'];
208        include_spip('inc/distant');
209        $flux = recuperer_page($url);
210
211        if ($flux) {
212                // Suppression du préfixe ax21: des balises afin de récupérer des index associatifs non préfixés
213                $flux = str_replace('ax21:parentTsn', 'ax21:TsnParent', $flux );
214                $flux = str_replace('ax21:', '', $flux);
215                // Suppression des suffixes xsi:type="xxx" ou xsi:nil="xxx" pour avoir des index de tableau simples
216                $flux = preg_replace(';\sxsi:(type|nil)="\w*";i', '', $flux);
217
218                // Phrasage de la chaine XML obtenue
219                include_spip('inc/xml');
220                $arbre = spip_xml_parse($flux);
221                if (spip_xml_match_nodes(",^{$api['list']},", $arbre, $matches) > 0) {
222                        $record = reset($matches);
223                        // Il est compliqué de créer une configuration du service qui permette un traitement générique de chaque
224                        // information. Le code est donc spécifique à chaque information.
225                        // Le résultat est stocké dans un tableau dont chaque index est le nom du champ correspondant de spip_taxon.
226                        if (isset($record[0])) {
227                                $record = $record[0];
228                                // Nom scientifique, rang taxonomique, règne et TSN parent
229                                $output['nom_scientifique'] = (empty($record['scientificName'][0]['combinedName'][0])
230                                        ? ''
231                                        : strtolower($record['scientificName'][0]['combinedName'][0]));
232                                $output['rang'] = (empty($record['taxRank'][0]['rankName'][0])
233                                        ? ''
234                                        : strtolower($record['taxRank'][0]['rankName'][0]));
235                                $output['regne'] = (empty($record['kingdom'][0]['kingdomName'][0])
236                                        ? ''
237                                        : strtolower($record['kingdom'][0]['kingdomName'][0]));
238                                $output['tsn_parent'] = (empty($record['parentTSN'][0]['TsnParent'][0])
239                                        ? 0
240                                        : intval($record['parentTSN'][0]['TsnParent'][0]));
241                                // Auteur
242                                $output['auteur'] = '';
243                                if (!empty($record['taxonAuthor'])) {
244                                        foreach ($record['taxonAuthor'] as $_author) {
245                                                if (isset($_author['authorship'][0])) {
246                                                        $output['auteur'] = $output['auteur'] ? ', ' . $_author['authorship'][0] : $_author['authorship'][0];
247                                                }
248                                        }
249                                }
250                                // Noms communs
251                                $output['nom_commun'] = '';
252                                if (!empty($record['commonNameList'][0]['commonNames'])) {
253                                        foreach ($record['commonNameList'][0]['commonNames'] as $_nom) {
254                                                if (isset($_nom['commonName'][0]) AND isset($_nom['language'][0])) {
255                                                        $output['nom_commun'][$_nom['language'][0]] = $_nom['commonName'][0];
256                                                }
257                                        }
258                                }
259                        }
260                }
261        }
262
263        return $output;
264}
265
266
267/**
268 * Renvoie les informations demandées sur un taxon désigné par son identifiant unique (tsn).
269 *
270 * @param string        $api
271 *              Type d'information demandé. Prend les valeurs
272 *      - 'scientificname' : le nom scientifique du taxon
273 *      - 'kingdomname' : le règne du taxon
274 *      - 'parent' : le taxon parent dont son tsn
275 *      - 'rankname' : le rang taxonomique du taxon
276 *      - 'author' : le ou les auteurs du taxon
277 *              - 'coremetadata' : les métadonnées (???)
278 *              - 'experts' : les experts du taxon
279 *              - 'commonnames' : le ou les noms communs
280 *              - 'othersources' : les sources d'information sur le taxon
281 *              - 'hierarchyfull' : la hiérarchie complète jusqu'au taxon
282 *              - 'hierarchydown' : la hiérarchie ???
283 * @param int           $tsn
284 *              Identifiant unique du taxon dans la base ITIS (tsn)
285 *
286 * @return array
287 *              Le tableau renvoyé est caractéristique du type d'information demandé.
288 */
289function itis_get_information($api, $tsn) {
290        global $itis_webservice;
291        $output =array();
292
293        // Construire l'URL de l'api sollicitée
294        $url = itis_api2url('json', 'get', $api, strval($tsn));
295
296        // Acquisition des données spécifiées par l'url
297        include_spip('inc/taxonomer');
298        $data = url2json_data($url);
299
300        // On vérifie que le tableau est complet sinon on retourne un tableau vide
301        $api = $itis_webservice['get'][$api];
302        if ($api['multiple']) {
303                if (isset($data[$api['list']][0])
304                AND $data[$api['list']][0]) {
305                        $output = $data[$api['list']];
306                }
307        }
308        else {
309                if (isset($data[$api['index']])
310                AND $data[$api['index']]) {
311                        $output = $data;
312                }
313        }
314
315        return $output;
316}
317
318
319/**
320 * @param $language_code
321 *
322 * @return array
323 */
324function itis_list_vernaculars($language_code) {
325        global $itis_webservice;
326        $vernaculars =array();
327
328        // Construire l'URL de l'api sollicitée
329        $url = itis_api2url('xml', 'vernacular', 'vernacularlanguage', itis_code2language($language_code));
330
331        // Acquisition des données spécifiées par l'url
332        $api = $itis_webservice['vernacular']['vernacularlanguage'];
333        include_spip('inc/distant');
334        $flux = recuperer_page($url);
335
336        // Suppression du préfixe ax21: des balises afin de récupérer des index associatif non préfixés
337        $flux = str_replace('ax21:', '', $flux);
338
339        // Phrasage de la chaine XML obtenue
340        include_spip('inc/xml');
341        $arbre = spip_xml_parse($flux);
342        if (spip_xml_match_nodes(",^{$api['list']},", $arbre, $matches) > 0) {
343                $names = reset($matches);
344                $tag_language = '[' . $language_code . ']';
345                foreach ($names as $_name) {
346                        $vernaculars[$_name['tsn'][0]] .= $tag_language . $_name[$api['index']][0];
347                }
348        }
349
350        return $vernaculars;
351}
352
353
354/**
355 * Lecture du fichier hiérarchique ITIS des taxons d'un règne.
356 *
357 * @param string        $kingdom
358 *              Nom scientifique du règne en lettres minuscules (animalia, plantae, fungi)
359 * @param string        $upto
360 *              Rang taxonomique minimal jusqu'où charger le règne. Ce rang est fourni en anglais et
361 *              correspond à : phylum (pour le règne animalia) ou division (pour les règnes fungi et plantae),
362 *              class, order, family, genus.
363 * @param int           $sha_file
364 *              Sha calculé à partir du fichier de taxons correspondant au règne choisi. Le sha est retourné
365 *              par la fonction afin d'être stocké par le plugin.
366 *
367 * @return array
368 */
369function itis_read_hierarchy($kingdom, $upto, &$sha_file) {
370        $hierarchy = array();
371        $sha_file = false;
372
373        include_spip('inc/taxonomer');
374        static $group_ids = array(
375                'kingdom' => 1,
376                'class' => 3,
377                'order' => 4,
378                'family' => 5,
379                'genus' => 6,
380                'specie' => 7);
381        $rang_phylum = $kingdom==_TAXONOMIE_REGNE_ANIMAL ? 'phylum': 'division';
382        $group_ids[$rang_phylum] = 2;
383        asort($group_ids);
384
385        if (array_key_exists($upto, $group_ids)) {
386                // Construire la regexp qui permet de limiter la hiérarchie comme demandée
387                $groups_list = implode('|', array_map('ucfirst', array_slice(array_flip($group_ids), 0, $group_ids[$upto])));
388                $regexp = str_replace('%groups_list%', $groups_list, _TAXONOMIE_ITIS_REGEXP_RANKNAME);
389
390                $file = find_in_path('services/itis/' . ucfirst($kingdom) . '_Genus.txt');
391                if (file_exists($file)
392                AND ($sha_file = sha1_file($file))) {
393                        $lines = file($file);
394                        if ($lines) {
395                                $tsn = 0;
396                                $groups = array();
397                                for ($i=1;$i<=array_search($upto, $group_ids);$i++) {
398                                        $groups[$i] = 0;
399                                }
400                                // Scan du fichier ligne par ligne
401                                foreach ($lines as $_line) {
402                                        $taxon = array(
403                                                'regne' => $kingdom,
404                                                'nom_commun' => '',
405                                                'descriptif' => '',
406                                                'edite' => 'non');
407                                        if (preg_match($regexp, $_line, $match)) {
408                                                // Initialisation du taxon
409                                                $taxon['rang'] = strtolower($match[1]);
410                                                $taxon['nom_scientifique'] = strtolower($match[2]);
411                                                $taxon['auteur'] = mb_convert_encoding(trim($match[3]), 'ISO-8859-1');
412                                                $tsn = intval($match[4]);
413                                                $taxon['tsn'] = $tsn;
414
415                                                // Recherche du parent
416                                                $taxon_group_id = $group_ids[$taxon['rang']];
417                                                if ($taxon_group_id == 1) {
418                                                        // On traite à part le cas du règne qui ne se rencontre qu'une fois en début de fichier
419                                                        $taxon['tsn_parent'] = 0;
420                                                }
421                                                else {
422                                                        for($i=$taxon_group_id-1;$i>=1;$i--) {
423                                                                if ($groups[$i]) {
424                                                                        $taxon['tsn_parent'] = $groups[$i];
425                                                                        break;
426                                                                }
427                                                        }
428                                                }
429
430                                                // Insertion du taxon dans la hiérarchie
431                                                $hierarchy[$tsn] = $taxon;
432
433                                                // Stockage du groupe venant d'être inséré
434                                                $groups[$taxon_group_id] = $tsn;
435                                                // On vide les groupes d'après
436                                                for($i=$taxon_group_id+1;$i<=5;$i++) {
437                                                        $groups[$i] = 0;
438                                                }
439                                        }
440                                }
441                        }
442                }
443        }
444
445        return $hierarchy;
446}
447
448
449/**
450 * Lit le fichier des noms communs (tout règne confondu) d'une langue donnée et renvoie un tableau
451 * de tous ces noms indexés par leur TSN.
452 *
453 * @param string        $language_code
454 * @param int           $sha_file
455 *
456 * @return array
457 */
458function itis_read_vernaculars($language_code, &$sha_file) {
459        $vernaculars =array();
460        $sha_file = false;
461
462        // Ouvrir le fichier de nom communs correspondant au code de langue spécifié
463        $file = find_in_path("services/itis/vernaculars_${language_code}.csv");
464        if (file_exists($file)
465        AND ($sha_file = sha1_file($file))) {
466                // Lecture du fichier csv comme un fichier texte sachant que :
467                // - le délimiteur de colonne est une virgule
468                // - le caractère d'encadrement d'un texte est le double-quotes
469                $lines = file($file);
470                if ($lines) {
471                        // Créer le tableau de sortie à partir du tableau issu du csv (tsn, nom commun)
472                        $tag_language = '[' . $language_code . ']';
473                        foreach ($lines as $_line) {
474                                $name = explode(',', trim($_line));
475                                $vernaculars[intval($name[0])] = $tag_language . trim($name[1], '"');
476                        }
477                }
478        }
479
480        return $vernaculars;
481}
482
483/**
484 * @param $id_taxon
485 * @return string
486 */
487function itis_citation($id_taxon) {
488        // On recherche le tsn du taxon afin de construire l'url vers sa page sur ITIS
489        $taxon = sql_fetsel('tsn, nom_scientifique', 'spip_taxons', 'id_taxon='. sql_quote($id_taxon));
490
491        // On crée l'url du taxon sur le site ITIS
492        $url = str_replace('%tsn%', $taxon['tsn'], _TAXONOMIE_ITIS_URL_BASE_CITATION);
493        $link = '<a href="' . $url . '"><em>' . ucfirst($taxon['nom_scientifique']) . '</em></a>';
494
495        // On établit la citation
496        $citation = _T('taxonomie:citation_itis', array('url' => $link));
497
498        return $citation;
499}
500
501/**
502 * @param $format
503 * @param $area
504 * @param $api
505 * @param $key
506 *
507 * @return string
508 */
509function itis_api2url($format, $area, $api, $key) {
510        global $itis_webservice;
511
512        // Construire l'URL de l'api sollicitée
513        $url = _TAXONOMIE_ITIS_URL_BASE_REQUETE
514                 . ($format=='json' ? 'jsonservice/' : 'services/ITISService/')
515                 . $itis_webservice[$area][$api]['function'] . '?'
516                 . $itis_webservice[$area][$api]['argument'] . '=' . $key;
517
518        return $url;
519}
520
521/**
522 * @param $language_code
523 *
524 * @return string
525 */
526function itis_code2language($language_code) {
527        global $itis_language;
528
529        $language = $itis_language[_TAXONOMIE_ITIS_LANGUE_DEFAUT];
530        if (array_key_exists($language_code,  $itis_language)) {
531                $language = $itis_language[$language_code];
532        }
533
534        return $language;
535}
536
537
538/**
539 * @return array
540 */
541function itis_list_sha() {
542        global $itis_language;
543        $shas = array();
544
545        include_spip('inc/taxonomer');
546        $kingdoms = lister_regnes();
547
548        foreach ($kingdoms as $_kingdom) {
549                $file = find_in_path('services/itis/' . ucfirst($_kingdom) . '_Genus.txt');
550                if (file_exists($file)
551                AND ($sha_file = sha1_file($file))) {
552                        $shas['taxons'][$_kingdom] = $sha_file;
553                }
554        }
555
556        foreach (array_keys($itis_language) as $_language_code) {
557                $file = find_in_path("services/itis/vernaculars_${_language_code}.csv");
558                if (file_exists($file)
559                AND ($sha_file = sha1_file($file))) {
560                        $shas['traductions'][$_language_code] = $sha_file;
561                }
562        }
563
564        return $shas;
565}
566?>
Note: See TracBrowser for help on using the repository browser.