source: spip-zone/_plugins_/isocode/trunk/services/nomenclature/iso/iso_api.php @ 125363

Last change on this file since 125363 was 125363, checked in by Eric Lupinacci, 6 months ago

S'assurer que le type de subdivision est toujours en minuscules

  • Property svn:eol-style set to native
File size: 19.8 KB
Line 
1<?php
2/**
3 * Ce fichier contient l'ensemble des constantes et fonctions implémentant le service ISO.
4 * Etant donné que la lecture des sources est réalisée par une fonction générique `lire_source` ce
5 * fichier ne contient que les fonctions spécifiques permettant de compléter les champs de base fournis
6 * par la source.
7 *
8 * @package SPIP\ISOCODE\SERVICES\ISO
9 */
10if (!defined('_ECRIRE_INC_VERSION')) {
11        return;
12}
13
14if (!defined('_ISOCODE_SIL_ISO639_3_ENDPOINT')) {
15        /**
16         * URL de base pour charger la page de documentation d'un code de langue alpha-3 sur le site
17         * sil.org. Complément à la table iso639families.
18         */
19        define('_ISOCODE_SIL_ISO639_3_ENDPOINT', 'http://www-01.sil.org/iso639-3/documentation.asp?id=');
20}
21if (!defined('_ISOCODE_LOC_ISO639_5_HIERARCHY')) {
22        /**
23         * URL de base pour charger la page du tableau de la hiérarchie ISO-639-5 sur le site
24         * de la Library of Congress. Complément à la table iso639families.
25         */
26        define('_ISOCODE_LOC_ISO639_5_HIERARCHY', 'https://www.loc.gov/standards/iso639-5/hier.php');
27}
28if (!defined('_ISOCODE_GEONAMES_INFORMATIONS_PAYS')) {
29        /**
30         * Chemin du fichier Geonames contenant des informations géographiques sur les pays.
31         * Complément à la table iso639countries.
32         */
33        define('_ISOCODE_GEONAMES_INFORMATIONS_PAYS', 'services/nomenclature/iso/iso3166countries-geonames-info.txt');
34}
35if (!defined('_ISOCODE_M49_REGION_PAYS')) {
36        /**
37         * Chemin du fichier des régions-pays M49 contenant la région de rattachement des pays.
38         * Complément à la table iso639countries.
39         */
40        define('_ISOCODE_M49_REGION_PAYS', 'services/nomenclature/m49/m49regions_countries.txt');
41}
42if (!defined('_ISOCODE_IOTA_ISO4217_SYMBOL')) {
43        /**
44         * URL de base pour charger la page du tableau des devises ISO-4217 sur le site
45         * de IOTA Finance qui permet de compléter les informations de base de l'ISO-4217.
46         * Complément à la table iso639currencies.
47         */
48        define('_ISOCODE_IOTA_ISO4217_SYMBOL', 'http://www.iotafinance.com/Codes-ISO-Devises.html');
49}
50
51$GLOBALS['isocode']['iso'] = array(
52        'iso639codes'       => array(
53                'groupe'       => 'langue',
54                'basic_fields' => array(
55                        'Id'            => 'code_639_3',
56                        'Part2B'        => 'code_639_2b',
57                        'Part2T'        => 'code_639_2t',
58                        'Part1'         => 'code_639_1',
59                        'Scope'         => 'scope',
60                        'Language_Type' => 'type',
61                        'Ref_Name'      => 'ref_name',
62                        'Comment'       => 'comment'
63                ),
64                'populating'   => 'file_csv',
65                'delimiter'    => "\t",
66                'extension'    => '.tab'
67        ),
68        'iso639names'       => array(
69                'groupe'       => 'langue',
70                'basic_fields' => array(
71                        'Id'            => 'code_639_3',
72                        'Print_Name'    => 'print_name',
73                        'Inverted_Name' => 'inverted_name'
74                ),
75                'populating'   => 'file_csv',
76                'delimiter'    => "\t",
77                'extension'    => '.tab'
78        ),
79        'iso639macros'      => array(
80                'groupe'       => 'langue',
81                'basic_fields' => array(
82                        'M_Id'     => 'macro_639_3',
83                        'I_Id'     => 'code_639_3',
84                        'I_Status' => 'status'
85                ),
86                'populating'   => 'file_csv',
87                'delimiter'    => "\t",
88                'extension'    => '.tab'
89        ),
90        'iso639retirements' => array(
91                'groupe'       => 'langue',
92                'basic_fields' => array(
93                        'Id'         => 'code_639_3',
94                        'Ref_Name'   => 'ref_name',
95                        'Ret_Reason' => 'ret_reason',
96                        'Change_To'  => 'change_to',
97                        'Ret_Remedy' => 'ret_remedy',
98                        'Effective'  => 'effective_date'
99                ),
100                'populating'   => 'file_csv',
101                'delimiter'    => "\t",
102                'extension'    => '.tab'
103        ),
104        'iso639families'    => array(
105                'groupe'       => 'langue',
106                'basic_fields' => array(
107                        'URI'             => 'uri',
108                        'code'            => 'code_639_5',
109                        'Label (English)' => 'label_en',
110                        'Label (French)'  => 'label_fr'
111                ),
112                'addon_fields' => array(
113                        'sil' => array(
114                                'Equivalent' => 'code_639_1',
115                                'Code set'   => 'code_set',
116                                'Code sets'  => 'code_set',
117                                'Scope'      => 'scope'
118                        ),
119                        'loc' => array(
120                                'Hierarchy' => 'hierarchy',
121                                'parent'    => 'parent'                 // Colonne est calculée à partir de la hiérarchie
122                        )
123                ),
124                'label_field'  => true,
125                'populating'   => 'file_csv',
126                'delimiter'    => "\t",
127                'extension'    => '.tab'
128        ),
129        'iso15924scripts'   => array(
130                'groupe'       => 'langue',
131                'basic_fields' => array(
132                        'Code'         => 'code_15924',
133                        'English Name' => 'label_en',
134                        'Nom français' => 'label_fr',
135                        'N°'           => 'code_num',
136                        'PVA'          => 'alias_en',
137                        'Date'         => 'date_ref',
138                ),
139                'label_field'  => true,
140                'populating'   => 'file_csv',
141                'delimiter'    => ';',
142                'extension'    => '.txt'
143        ),
144        'iso3166countries'  => array(
145                'groupe'       => 'geographie',
146                'basic_fields' => array(
147                        'English name' => 'label_en',
148                        'French name'  => 'label_fr',
149                        'Alpha-2'      => 'code_alpha2',
150                        'Alpha-3'      => 'code_alpha3',
151                        'Numeric'      => 'code_num',
152                        'category'     => 'category',
153                ),
154                'unused_fields' => array(
155                        'label_fr' => '',
156                        'label_en' => '',
157                ),
158                'addon_fields' => array(
159                        'geonames' => array(
160                                'Capital'        => 'capital',
161                                'Area(in sq km)' => 'area',
162                                'Population'     => 'population',
163                                'Continent'      => 'code_continent',
164                                'tld'            => 'tld',
165                                'CurrencyCode'   => 'code_4217_3',
166                                'CurrencyName'   => 'currency_en',
167                                'Phone'          => 'phone_id',
168                        ),
169                        'm49'      => array(
170                                'parent'         => 'code_num_region',
171                        ),
172                ),
173                'label_field'  => true,
174                'populating'   => 'file_csv',
175                'delimiter'    => ';',
176                'extension'    => '.txt'
177        ),
178        'iso3166subdivisions' => array(
179                'groupe'       => 'geographie',
180                'basic_fields' => array(
181                        '3166-2 code'          => 'code_3166_2',
182                        'Country'              => 'country',
183                        'Subdivision category' => 'type',
184                        'Parent subdivision'   => 'parent',
185                        'Language code'        => 'language',
186                        'Subdivision name'     => 'label',
187                ),
188                'unused_fields' => array(
189                        'language'        => '',
190                ),
191                'populating'   => 'file_csv',
192                'delimiter'    => "\t",
193                'extension'    => '.tsv',
194        ),
195        'iso4217currencies' => array(
196                'groupe'       => 'geographie',
197                'basic_fields' => array(
198                        'Ccy'        => 'code_4217_3',
199                        'CcyNbr'     => 'code_num',
200                        'CcyNm'      => 'label_en',
201                        'CcyMnrUnts' => 'minor_units',
202                ),
203                'addon_fields' => array(
204                        'iota' => array(
205                                'Symbol devise' => 'symbol',
206                                'Devise'        => 'label_fr',
207                        )
208                ),
209                'label_field'  => true,
210                'populating'   => 'file_xml',
211                'extension'    => '.xml',
212                'node'         => 'CcyTbl/CcyNtry',      // clé à laquelle débute la liste des éléments
213        ),
214);
215
216// ----------------------------------------------------------------------------
217// ----------------- API du service ISO - Actions spécifiques -----------------
218// ----------------------------------------------------------------------------
219
220function iso639families_completer_enregistrement($enregistrement, $config) {
221
222        // Initialisation
223        static $enregistrement_sil_defaut = array();
224
225        // Initialisation des champs additionnels dans l'enregistrement passé en argument
226        // (qui contient déjà les champs de base).
227        $config_champs_sil = $config['addon_fields']['sil'];
228        if (!$enregistrement_sil_defaut) {
229                include_spip('inc/isocode_utils');
230                $enregistrement_sil_defaut = initialiser_enregistrement('iso639families', $config_champs_sil);
231        }
232        $enregistrement = array_merge($enregistrement, $enregistrement_sil_defaut);
233
234        // On récupère la page de description de la famille sur le site SIL.
235        include_spip('inc/distant');
236        $url = _ISOCODE_SIL_ISO639_3_ENDPOINT . $enregistrement['code_639_5'];
237        $flux = recuperer_url($url, array('transcoder' => true));
238
239        // On décrypte la page et principalement le premier tableau pour en extraire les données
240        // additionnelles suivantes :
241        // - scope : C(ollective)
242        // - equivalent : éventuellement le code ISO-639-1
243        // - code set(s) : ISO-639-5 et/ou ISO-639-2
244        include_spip('inc/filtres');
245        $table = extraire_balise($flux['page'], 'table');
246        if ($table) {
247                // On extrait la première table de la page qui contient les données voulues
248                $lignes = extraire_balises($table, 'tr');
249                if ($lignes) {
250                        foreach ($lignes as $_ligne) {
251                                // Chaque ligne de la table est composée de deux colonnes, la première le libellé
252                                // et la deuxième la valeur.
253                                $colonnes = extraire_balises($_ligne, 'td');
254                                $colonnes = array_map('supprimer_tags', $colonnes);
255                                $colonnes = array_map('trim', $colonnes);
256                                if (count($colonnes) == 2) {
257                                        $titre = trim(substr($colonnes[0], 0, strpos($colonnes[0], ':')));
258                                        if (isset($config_champs_sil[$titre])) {
259                                                $valeur = str_replace(' ', '', $colonnes[1]);
260                                                switch ($titre) {
261                                                        case 'Equivalent':
262                                                                $equivalent = explode(':', $valeur);
263                                                                $enregistrement[$config_champs_sil[$titre]] = isset($equivalent[1]) ? trim($equivalent[1]) : '';
264                                                                break;
265                                                        case 'Code sets':
266                                                        case 'Code set':
267                                                                $enregistrement[$config_champs_sil[$titre]] = str_replace('and', ',', $valeur);
268                                                                break;
269                                                        case 'Scope':
270                                                                $enregistrement[$config_champs_sil[$titre]] = substr($valeur, 0, 1);
271                                                                break;
272                                                        default:
273                                                                break;
274                                                }
275                                        }
276                                }
277                        }
278                }
279        }
280
281        return $enregistrement;
282}
283
284function iso639families_completer_table($enregistrements, $config) {
285
286        // Initialisation des champs additionnels
287        $hierarchies = array();
288        $config_champs_loc = $config['addon_fields']['loc'];
289        include_spip('inc/isocode_utils');
290        $enregistrement_loc_defaut = initialiser_enregistrement('iso639families', $config_champs_loc);
291
292        // On récupère la page de description de la famille sur le site SIL.
293        include_spip('inc/distant');
294        $url = _ISOCODE_LOC_ISO639_5_HIERARCHY;
295        $flux = recuperer_url($url, array('transcoder' => true));
296
297        // On décrypte la page et principalement le tableau pour en extraire la colonne hiérarchie
298        // de chaque famille et créer la colonne parent dans la table iso639families.
299        include_spip('inc/filtres');
300        $table = extraire_balise($flux['page'], 'table');
301        if ($table) {
302                // On extrait la première table de la page qui contient les données voulues
303                $lignes = extraire_balises($table, 'tr');
304                if ($lignes) {
305                        // La première ligne du tableau est celle des titres de colonnes : on la supprime.
306                        array_shift($lignes);
307                        foreach ($lignes as $_ligne) {
308                                // Chaque ligne de la table est composée de deux colonnes, le première le libellé
309                                // et la deuxième la valeur.
310                                $colonnes = extraire_balises($_ligne, 'td');
311                                $colonnes = array_map('supprimer_tags', $colonnes);
312                                if (count($colonnes) >= 2) {
313                                        // La première colonne contient la hiérarchie et la seconde le code alpha-3 de la famille.
314                                        $code = trim($colonnes[1]);
315                                        $hierarchies[$code] = str_replace(array(' ', ':'), array('', ','), trim($colonnes[0]));
316                                }
317                        }
318                }
319        }
320
321        // On complète maintenant le tableau des enregistrements avec la colonne additionnelle hierarchy et la colonne
322        // dérivée parent qui ne contient que le code alpha-3 de la famille parente si elle existe.
323        foreach ($enregistrements as $_cle => $_enregistrement) {
324                $enregistrements[$_cle] = array_merge($enregistrements[$_cle], $enregistrement_loc_defaut);
325                $code = $_enregistrement['code_639_5'];
326                if (isset($hierarchies[$code])) {
327                        $enregistrements[$_cle][$config_champs_loc['Hierarchy']] = $hierarchies[$code];
328                        // Calcul du parent : si la hiérarchie ne contient qu'un code c'est qu'il n'y a pas de parent.
329                        // Sinon, le parent est le premier code qui précède le code du record.
330                        $parents = explode(',', $hierarchies[$code]);
331                        if (count($parents) > 1) {
332                                array_pop($parents);
333                                $enregistrements[$_cle][$config_champs_loc['parent']] = array_pop($parents);
334                        }
335                }
336        }
337
338        return $enregistrements;
339}
340
341function iso3166countries_completer_table($enregistrements, $config) {
342
343        // Inclusion de l'API.
344        include_spip('inc/isocode_utils');
345
346        // Lecture du fichier CSV geonames-countryInfo.txt pour récupérer les informations additionnelles.
347        // Le délimiteur est une tabulation.
348        // -- Initialisation des champs additionnels
349        $enregistrements_geo = array();
350        $config_champs_geo = $config['addon_fields']['geonames'];
351        $enregistrement_geo_defaut = initialiser_enregistrement('iso3166countries', $config_champs_geo);
352
353        // -- Lecture du fichier
354        $fichier = find_in_path(_ISOCODE_GEONAMES_INFORMATIONS_PAYS);
355        $separateur = "\t";
356        $lignes = file($fichier);
357        if ($lignes) {
358                $titres = array();
359                $index_code_pays = null;
360                foreach ($lignes as $_numero => $_ligne) {
361                        $valeurs = explode($separateur, trim($_ligne, "\r\n"));
362                        if ($_numero == 0) {
363                                // Stockage des noms de colonnes car la première ligne contient toujours le header et de
364                                // l'index correspondant au code ISO-3166 alpha2 du pays qui se nomme ISO dans le fichier CSV.
365                                $titres = $valeurs;
366                                $index_code_pays = array_search('ISO', $titres);
367                        } else {
368                                // On extrait de chaque ligne les informations additionnelles du pays ainsi que le code alpha2 du pays
369                                // qui servira d'index du tableau constitué.
370                                // On ne sélectionne que les colonnes correspondant à des champs additionnels.
371                                $enregistrement_geo = $enregistrement_geo_defaut;
372                                foreach ($titres as $_cle => $_titre) {
373                                        $titre = trim($_titre);
374                                        if (isset($config_champs_geo[$titre]) and !empty($valeurs[$_cle])) {
375                                                $enregistrement_geo[$config_champs_geo[$titre]] = trim($valeurs[$_cle]);
376                                        }
377                                }
378                                if (isset($valeurs[$index_code_pays])) {
379                                        $enregistrements_geo[$valeurs[$index_code_pays]] = $enregistrement_geo;
380                                }
381                        }
382                }
383        }
384
385        // Lecture du fichier CSV m49regions_countries.txt pour récupérer le lien entre les pays et leur région de
386        // rattachement (indicatif M49).
387        // Le délimiteur est un point-virgule.
388        // -- Initialisation des champs additionnels
389        $enregistrements_m49 = array();
390        $config_champs_m49 = $config['addon_fields']['m49'];
391        $enregistrement_m49_defaut = initialiser_enregistrement('iso3166countries', $config_champs_m49);
392
393        // -- Lecture du fichier
394        $fichier = find_in_path(_ISOCODE_M49_REGION_PAYS);
395        $separateur = ';';
396        $lignes = file($fichier);
397        if ($lignes) {
398                $titres = array();
399                $index_code_pays = null;
400                foreach ($lignes as $_numero => $_ligne) {
401                        $valeurs = explode($separateur, trim($_ligne, "\r\n"));
402                        if ($_numero == 0) {
403                                // Stockage des noms de colonnes car la première ligne contient toujours le header et de
404                                // l'index correspondant au code ISO-3166 numérique du pays qui se nomme 'code_num' dans le fichier CSV.
405                                $titres = $valeurs;
406                                $index_code_pays = array_search('code_num', $titres);
407                        } else {
408                                // On extrait de chaque ligne la région de rattachement du pays ainsi que le code numérique du pays
409                                // qui servira d'index du tableau constitué.
410                                // On ne sélectionne que les colonnes correspondant à des champs additionnels.
411                                $enregistrement_m49 = $enregistrement_m49_defaut;
412                                foreach ($titres as $_cle => $_titre) {
413                                        $titre = trim($_titre);
414                                        if (isset($config_champs_m49[$titre]) and !empty($valeurs[$_cle])) {
415                                                $enregistrement_m49[$config_champs_m49[$titre]] = trim($valeurs[$_cle]);
416                                        }
417                                }
418                                if (isset($valeurs[$index_code_pays])) {
419                                        $enregistrements_m49[$valeurs[$index_code_pays]] = $enregistrement_m49;
420                                }
421                        }
422                }
423        }
424
425        // On complète maintenant le tableau des enregistrements avec les informations glanées dans le fichier geonames
426        // et dans celui du M49.
427        foreach ($enregistrements as $_cle => $_enregistrement) {
428                // Les informations Geonames
429                $code = $_enregistrement['code_alpha2'];
430                if (isset($enregistrements_geo[$code])) {
431                        $enregistrements[$_cle] = array_merge($enregistrements[$_cle], $enregistrements_geo[$code]);
432                } else {
433                        $enregistrements[$_cle] = array_merge($enregistrements[$_cle], $enregistrement_geo_defaut);
434                }
435
436                // La région M49
437                $code = $_enregistrement['code_num'];
438                if (isset($enregistrements_m49[$code])) {
439                        $enregistrements[$_cle] = array_merge($enregistrements[$_cle], $enregistrements_m49[$code]);
440                } else {
441                        $enregistrements[$_cle] = array_merge($enregistrements[$_cle], $enregistrement_m49_defaut);
442                }
443        }
444
445        return $enregistrements;
446}
447
448function iso3166subdivisions_completer_enregistrement($enregistrement, $config) {
449
450        // La finalisation de l'enregistrement consiste à élaborer la version multilangue du champ label
451        // en considérant le champ language qui contient le codet alpha2 de la langue.
452        // Cette fonction est appelée pour le premier enregistrement ayant la clé primaire concernée, les autres
453        // enregistrements avec cette même clé sont traités dans la fonction fusionner_enregistrement().
454        // De fait, le champ label ne contient que le texte sans multi.
455        $enregistrement['label'] = "<multi>[{$enregistrement['language']}]"
456                . $enregistrement['label']
457                . '</multi>';
458
459        // S'assurer que la catégorie est en minuscule
460        $enregistrement['type'] = strtolower($enregistrement['type']);
461
462        return $enregistrement;
463}
464
465function iso3166subdivisions_fusionner_enregistrement($enregistrements, $index_enregistrement, $enregistrement, $config) {
466
467        // Cette fonction est appelée alors qu'il existe au moins un premier enregistrement ayant la clé primaire concernée.
468        // De fait, il suffit de compléter le champ label avec la traduction dans la langue de l'enregistrement coourant.
469        $label = $enregistrements[$index_enregistrement]['label'];
470        $enregistrements[$index_enregistrement]['label'] = '<multi>'
471                . str_replace(array('<multi>', '</multi>'), '', $label)
472                . "[{$enregistrement['language']}]"
473                . $enregistrement['label']
474                . '</multi>';
475
476        return $enregistrements;
477}
478
479function iso4217currencies_completer_table($enregistrements, $config) {
480
481        // Initialisation des champs additionnels
482        $enregistrements_iota = array();
483        $config_champs_iota = $config['addon_fields']['iota'];
484        include_spip('inc/isocode_utils');
485        $enregistrement_iota_defaut = initialiser_enregistrement('iso4217currencies', $config_champs_iota);
486
487        // On récupère la page de description de la famille sur le site SIL.
488        include_spip('inc/distant');
489        $url = _ISOCODE_IOTA_ISO4217_SYMBOL;
490        $flux = recuperer_url($url, array('transcoder' => true));
491
492        include_spip('inc/filtres');
493        $table = extraire_balise($flux['page'], 'table');
494        if ($table) {
495                // On extrait la première table de la page qui contient les données voulues
496                $lignes = extraire_balises($table, 'tr');
497                if ($lignes) {
498                        $cles_iota = array();
499                        $index_code_devise = null;
500                        foreach ($lignes as $_numero => $_ligne) {
501                                $balise_colonne = $_numero == 0 ? 'th' : 'td';
502                                $colonnes = extraire_balises($_ligne, $balise_colonne);
503                                $colonnes = array_map('supprimer_tags', $colonnes);
504                                $colonnes = array_map('trim', $colonnes);
505                                if ($_numero == 0) {
506                                        // La première ligne du tableau est celle des titres de colonnes.
507                                        // On détermine les index de colonnes correspondant aux champs additionnels configurés.
508                                        foreach ($colonnes as $_cle => $_titre) {
509                                                if (array_key_exists($_titre, $config_champs_iota)) {
510                                                        $cles_iota[$_titre] = $_cle;
511                                                }
512                                        }
513                                        // On détermine l'index de la colonne qui porte le code alpha3 ISO-4217 nommé
514                                        $index_code_devise = array_search('ISO devise', $colonnes);
515                                } else {
516                                        // Chaque ligne de la table est composée de plusieurs colonnes, la première étant le code alpha3
517                                        // de la devise selon l'ISO-4217
518                                        $enregistrement_iota = $enregistrement_iota_defaut;
519                                        foreach ($cles_iota as $_titre => $_cle) {
520                                                if ($colonnes[$_cle]) {
521                                                        $enregistrement_iota[$config_champs_iota[$_titre]] = $colonnes[$_cle];
522                                                }
523                                        }
524                                        $code = $colonnes[$index_code_devise];
525                                        $enregistrements_iota[$code] = $enregistrement_iota;
526                                }
527                        }
528                }
529        }
530
531        // On complète maintenant le tableau des enregistrements avec les colonne additionnelles symbole
532        // et devise en français.
533        // Etant donné qu'il faut que tous les enregistrements possèdent la même structure, si une devise ne
534        // possède pas d'informations complémentaires IOTA on lui adjoint des colonnes par défaut.
535        foreach ($enregistrements as $_cle => $_enregistrement) {
536                $code = $_enregistrement['code_4217_3'];
537                if (isset($enregistrements_iota[$code])) {
538                        $enregistrements[$_cle] = array_merge($enregistrements[$_cle], $enregistrements_iota[$code]);
539                } else {
540                        $enregistrements[$_cle] = array_merge($enregistrements[$_cle], $enregistrement_iota_defaut);
541                }
542        }
543
544        return $enregistrements;
545}
Note: See TracBrowser for help on using the repository browser.