Automatisation d’une cartographie à partir d’un flux RSS (Partie 1)

Construire une cartographie puis la mettre à jour régulièrement tout en buvant un café, ou plutôt sans s’en occuper est possible. Si le projet de géomatique le permet, les stockages, les traitements et les diffusions automatiques de données spatiales sont même indispensables lors de la manipulation d’une quantité importante d’informations géographiques. Et on peut dire que les chaînes de traitements de données spatiales les plus gourmandes en ressources informatiques concernent les disciplines de la météorologie et de la climatologie. D’après la définition du Larousse, l’automatisation est l’exécution totale ou partielle de tâches techniques par des machines fonctionnant sans intervention humaine. En clair, on configure le serveur ou le PC pour répéter une opération ou un ensemble d’opérations à un instant donné. En géomatique, plusieurs questions se posent pour mettre en œuvre un système de cartographies automatisées :

  • D’où proviennent les données géographiques (site internet externe, machine connectée, production interne, etc) ?
  • Est-il possible de les importer et de les traiter automatiquement sans l’intervention d’un géomaticien ?
  • Quelles sont les informations diffusées ?
  • Et sur quels supports les diffuser (document pdf, shape, protocoles WMS, WFS, flux GeoRSS, interface cartographique, etc) ?

Dès lors que l’on a répondu à ces questions, on peut mettre en place le processus d’automatisation d’une cartographie. Pour illustrer cette démarche, l’objectif de cet article est de cartographier les sites de l’UNESCO (United Nations Educational, Scientific and Cultural Organization) à partir d’un flux RSS. Dans un premier temps, on cible les informations attributaires et géométriques du fournisseur de données. Ces éléments sont stockés dans un Système de Gestion de Base de Données (SGBD) grâce à l’exécution automatique d’un script. Les tables du SGBD sont ensuite relayées par un serveur cartographique puis les sites de l’UNESCO sont enfin présentés sur une interface de webmapping via le protocole WFSle résultat final est visible sur l’espace dédié aux exemples -. On terminera par montrer comment diffuser des données géographiques en GeoRSS.

Pour suivre ce tutoriel, il est nécessaire d’avoir installer un serveur web, PHP, le SGBD PotgreSQL / PostGIS et le serveur cartographique GeoServer. La figure 1 schématise les interactions entre les outils Open Sources mis en place dans l’architecture du Système d’Informations Géographiques (SIG).

Figure 1 : Schéma de l’architecture SIG mise en oeuvre pour le traitement automatique de données géographiques.

1. Stockage des données géographiques des sites de l’UNESCO dans le SGBD PostgreSQL / PostGIS

On utilise les langages PHP et SQL afin de bancariser les informations des sites de l’UNESCO dans PostgreSQL / PostGIS.

1.1. Lecture des données attributaires et géométriques du flux RSS

L’UNESCO met à disposition un flux RSS (Rich Site Summary ou  Really Simple Syndication) qui répertorie les différents sites retenus par l’organisation. A ce jour, 1073 sites sont référencés à l’échelle mondiale. Le fichier de format XML est mis à jour automatiquement à chaque évolution du contenu du site. Quelles sont les informations présentes dans ce fichier XML? 

<row>
	<category></category>
	<criteria_txt></criteria_txt>
	<danger/>
	<date_inscribed></date_inscribed>
	<extension></extension>
	<historical_description></historical_description>
	<http_url></http_url>
	<id_number></id_number>
	<image_url></image_url>
	<iso_code></iso_code>
	<justification/>
	<latitude></latitude>
	<location></location>
	<longitude></longitude>
	<long_description></long_description>
	<region></region>
	<revision></revision>
	<secondary_dates/>
	<short_description></short_description>
	<site></site>
	<states></states>
	<transboundary></transboundary>
	<unique_number></unique_number>
</row>

Chaque site de l’UNESCO est décrit à l’intérieur des balises <row> dans lesquelles on retrouve une vingtaine d’informations tels le nom du site, la catégorie (Cultural, Natural et Mixed), la date d’inscription, les descriptions historiques, des présentations courtes et longues, des éléments spécifiques au website de l’UNESCO (l’identifiant, l’URL et une photo) et des éléments géographiques (le code ou les codes ISO des pays, le ou les pays concernés, la localisation, la longitude et latitude). La situation géographique avec les latitudes et longitudes n’est pas toujours enregistrée puisque certains sites sont étendus sur des régions entières. Toutefois, on se sert de ces informations ponctuelles pour construire la géométrie spatiale de la table PostgreSQL dans laquelle on retient : le nom du site, la catégorie, la date d’inscription, la localisation, les pays concernés, la description courte, la photo, l’URL et l’identifiant unique du website de l’UNESCO. Les latitudes et longitudes de l’UNESCO sont transformées en géométrie spatiale. La table appelée “sites_unesco” est donc créé dans PostgreSQL via PgAdmin :

-- Table: public.sites_unesco

-- DROP TABLE public.sites_unesco;

CREATE TABLE public.sites_unesco
(
  gid integer NOT NULL, -- Identifiant unique du site
  nom character varying(255), -- Nom du site de l"UNESCO
  date_inscription integer DEFAULT NULL, -- Date d"inscription du site de l"UNESCO
  categorie character varying(150), -- Catégorie du site 
  localisation character varying(1000) DEFAULT NULL, -- Localisation du site
  pays character varying(500) DEFAULT NULL, -- Pays concernés
  description character varying(3000) DEFAULT NULL, -- Description courte du site
  photo character varying(100) DEFAULT NULL, -- Photo du site
  url_unesco character varying(250) DEFAULT NULL, -- URL du site sur le website de l"UNESCO
  id_unesco integer DEFAULT NULL, -- Identifiant unique du site sur le website de l"UNESCO
  geom geometry(Point,4326) DEFAULT NULL, -- Géométrie du point en EPSG 4326
  CONSTRAINT sites_unesco_pkey PRIMARY KEY (gid)
)
WITH (
  OIDS=FALSE
);
ALTER TABLE public.sites_unesco OWNER TO postgres;

CREATE SEQUENCE sites_unesco_gid_seq
    START WITH 1
    INCREMENT BY 1
    NO MAXVALUE
    NO MINVALUE
    CACHE 1;


ALTER TABLE sites_unesco ALTER COLUMN gid SET DEFAULT nextval('sites_unesco_gid_seq'::regclass);

Quelques remarques sur la création de la table spatiale. On note que plusieurs valeurs des champs sont par défaut “NULL” puisque certains nœuds du flux RSS des sites de l’UNESCO sont vides.  Ici, le propriétaire de la table “OWNER” reste sous les droits de “POSTGRES”, propriétaire par défaut et le schéma choisi est “Public”. On créé une séquence afin d’incrémenter la clé primaire désignée par l’identifiant unique de la table gid. Enfin, comme évoqué précédemment, la géométrie utilisée pour chaque entité est un POINT qui est projeté en WGS 84 (EPSG:4326).

1.2. Construction du script de stockage en PHP et SQL

Une fois la table créée, on construit un script en PHP et SQL qui charge les informations du flux RSS décrites précédemment et alimente la table “sites_unesco”. Pour exécuter le fichier PHP, placé dans le répertoire du serveur web, on visualise le résultat dans un navigateur web.

Comment lire un fichier XML en PHP? La classe  simplexml_load_file convertit le fichier XML en objet contenant les éléments de chaque nœud. Si le fichier XML est lisible alors on liste chaque information de chaque site correspondant au nœud row et on les place dans des arrays. Dans le fichier PHP, on écrit :

$urlUnesco='http://whc.unesco.org/fr/list/xml/index.xml ';
$xmlUnesco=simpleXML_load_file($urlUnesco,"SimpleXMLElement",LIBXML_COMPACT); 
if($xmlUnesco===FALSE){ 
	echo "Erreur de lecture du fichier XML.";
}else{ 
	foreach($xmlUnesco->row as $itemUnesco){
		$nom[]=$itemUnesco->site;
		$date_inscription[]=$itemUnesco->date_inscribed;
		$categorie[]=$itemUnesco->category;
		$localisation[]=$itemUnesco->location;
		$pays[]=$itemUnesco->states;
		$description[]=$itemUnesco->short_description;
		$photo[]=$itemUnesco->image_url;
		$url_unesco[]=$itemUnesco->http_url;
		$id_unesco[]=$itemUnesco->unique_number;
		$latitude[]=$itemUnesco->latitude; 
		$longitude[]=$itemUnesco->longitude;
	}
	$nb_site=count($nom);
}

Dans la boucle foreach, on peut écrire quelques informations comme le nom des sites par exemple.

Ensuite, pour l’ensemble des sites, les éléments des tableaux sont liés (bind en anglais) aux colonnes correspondantes de la table PostgreSQL. Les latitudes et les longitudes sont transformées en géométrie spatiale ponctuelle grâce à l’extension PostGIS et la classe ST_MakePoint. ST_SetSRID garantit la projection WGS 84 (EPSG:4326) des géométries spatiales. Attention, ces classes ne gèrent pas les valeurs vides et comme quelques sites de l’UNESCO n’ont pas de longitude et de latitude spécifiée, on leur attribue la valeur NULL. On a :

ini_set('error_reporting', E_ALL);
ini_set('display_errors', true);
$message='';
try{
	$dbconn=new PDO("pgsql:host=*;dbname=*","utilisateur","mot de passe") or die('Connexion impossible');
	$dbconn->exec("SET CHARACTER SET utf8");
	$dbconn->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
	$req_ajout=$dbconn->prepare("INSERT INTO public.sites_unesco(gid,nom,date_inscription,categorie,localisation,pays,description,photo,url_unesco,id_unesco,geom) 
		VALUES(DEFAULT,:nom,:date_inscription,:categorie,:localisation,:pays,:description,:photo,:url_unesco,:id_unesco,ST_SetSRID(ST_MakePoint(:longitude,:latitude),4326))"); 
	$urlUnesco='http://whc.unesco.org/fr/list/xml/index.xml ';
	$xmlUnesco=simpleXML_load_file($urlUnesco,"SimpleXMLElement",LIBXML_COMPACT); 
	if($xmlUnesco===FALSE){ 
		$message .= "Erreur de lecture du fichier XML. \r\n";
	}else{ 
		foreach($xmlUnesco->row as $itemUnesco){
			$nom[]=$itemUnesco->site;
			$date_inscription[]=$itemUnesco->date_inscribed;
			$categorie[]=$itemUnesco->category;
			$localisation[]=$itemUnesco->location;
			$pays[]=$itemUnesco->states;
			$description[]=$itemUnesco->short_description;
			$photo[]=$itemUnesco->image_url;
			$url_unesco[]=$itemUnesco->http_url;
			$id_unesco[]=$itemUnesco->unique_number;
			if($itemUnesco->latitude ==''){ $latitude[]=NULL; }else{ $latitude[]=$itemUnesco->latitude; }
			if($itemUnesco->longitude ==''){ $longitude[]=NULL; }else{ $longitude[]=$itemUnesco->longitude; }
		}
		$nb_site=count($nom);
		if($nb_site > 0){
			for($i=0;$i<$nb_site;$i++){
				$req_ajout->bindValue(':nom', $nom[$i], PDO::PARAM_STR); 
				$req_ajout->bindValue(':date_inscription', $date_inscription[$i], PDO::PARAM_STR); 
				$req_ajout->bindValue(':categorie', $categorie[$i], PDO::PARAM_STR); 
				$req_ajout->bindValue(':localisation', $localisation[$i], PDO::PARAM_STR); 
				$req_ajout->bindValue(':pays', $pays[$i], PDO::PARAM_STR); 
				$req_ajout->bindValue(':description', $description[$i], PDO::PARAM_STR); 
				$req_ajout->bindValue(':photo', $photo[$i], PDO::PARAM_STR); 
				$req_ajout->bindValue(':url_unesco', $url_unesco[$i], PDO::PARAM_STR); 
				$req_ajout->bindValue(':id_unesco', $id_unesco[$i], PDO::PARAM_INT); 
				$req_ajout->bindValue(':longitude', $longitude[$i], PDO::PARAM_INT); 
				$req_ajout->bindValue(':latitude', $latitude[$i], PDO::PARAM_INT);
				if($req_ajout->execute()){ 
					$message .= $nom[$i]." a été ajouté dans la base de données. \r\n";
				}else{ 
					$message .= "Un problème d\'enregistrement dans la base de données a eu lieu pour le site : ".$nom[$i].". \r\n";
				}
			}
		}
	}
}catch(PDOException $e) {
	$e->getMessage();
	$message .= "Erreur de connexion à la base : ".$e.". \r\n";
}

On exécute le fichier PHP et logiquement l’ensemble des informations des sites sont stockées dans le SGBD. Si des erreurs apparaissent lors du développement, il est possible de les visualiser en saisissant au début du fichier PHP :

ini_set('error_reporting', E_ALL);
ini_set('display_errors', true);

Bien entendu en production, on retire ces lignes.

A ce stade, il est possible de visualiser les données géographiques dans PgAdmin et/ou dans QGIS. Le problème est qu’une nouvelle exécution du script entraîne le chargement de tous les éléments précédemment stockés en base. Alors, comment mettre à jour la table PostgreSQL en prenant seulement en compte les modifications du fichier XML? Dans cet exemple, cela concerne la mise à jour de sites de l’UNESCO existant et l’ajout de nouveaux sites. Pour des données mises à jour infra-journalières  ou journalières, une date de mise à jour des données du flux XML est souvent associée, ce qui facilite la sélection des données à modifier ou à ajouter dans la table. Ici, étant données les informations retenues, je choisis seulement de mettre en place une vérification entre les noms des sites, ce qui est discutable. On ajoute le “checking” avec la requête SQL préparée :

$req_check=$dbconn->prepare("SELECT nom FROM sites_unesco WHERE nom=:nom");

Puis, un fichier log est créé afin de visualiser les différents résultats du script. Voici le script final du fichier PHP :

Veuillez vous connecter pour consulter ce contenu.

En remarque, on aurait pu séparer la connexion à la base de données et créer un objet lié à la table mais comme le script est exécuté en local et ne fait pas appel à beaucoup d’actions, cela résout les problématiques de sécurité et de classes.

1.3. Mise à jour automatique des données géographiques

Enfin, comme on n’a pas le temps d’exécuter le script tous les jours, un événement est planifié dans le planificateur de tâches de Windows. Il a pour mission de lancer un batch  (.bat) très simple qui déclenche PHP :

@ECHO OFF
:: "chemin de l'exécutable PHP" chemin du fichier PHP
:: Par exemple : 
"C:\php\php.exe" C:\unesco\fichier.php

Sur Linux, l’équivalent est d’éditer un crontab en spécifiant le chemin du programme PHP et du fichier à exécuter. On saisit par exemple :

00 11 * * * /usr/bin/php /chemin/fichier.php

Le fichier PHP peut être déplacé dans un répertoire inaccessible par le serveur web pour des raisons de sécurité et d’organisation.

La mise à jour automatique des données géographiques est établie, il nous reste à les cartographier et à les diffuser dans la deuxième partie de l’article.

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *