Module FSD — Formulaires Standards de Données

Présentation

Le module FSD automatise le moissonnage des données issues des Formulaires Standards de Données (FSD) des zonages naturels intersectant l’aire d’étude. Il traite deux référentiels complémentaires :

  • Natura 2000 : sites SIC (Sites d’Importance Communautaire) et ZPS (Zones de Protection Spéciale), dont les FSD sont publiés au format XML par l’INPN à l’adresse https://inpn.mnhn.fr/docs/natura2000/fsdxml/{zone_id}.xml.

  • ZNIEFF : inventaires de type I et II (Zones Naturelles d’Intérêt Écologique, Faunistique et Floristique), dont les fiches XML sont publiées à l’adresse https://inpn.mnhn.fr/docs/ZNIEFF/znieffxml/{zone_id}.xml.

Pour chaque référentiel, le module produit trois couches attributaires (sans géométrie) enregistrées dans un GeoPackage biblizou.gpkg, puis deux tableaux croisés dynamiques (pivots) facilitant la lecture bibliographique.

Note

Les étapes de téléchargement XML (NaturaDwlXml, ZnieffDwlXml) sont actuellement désactivées dans le workflow automatique. L’utilisateur doit déposer manuellement les fichiers XML dans le dossier de travail avant de lancer le traitement.

Flux de traitement

Le module FSD est orchestré par FsdProcessingThread (biblizou_worker.py), un QThread PyQt5 qui enchaîne les étapes suivantes dans cet ordre :

Étape

Description

Classe / Fonction appelée

1

Configuration des connexions WFS INPN

WfsManager.setup_wfs_connections()

2

Chargement des couches WFS dans le projet

WfsManager.load_wfs_layers()

3

Extraction des descriptions ZNIEFF

ZnieffXmlToLayerDesc

4

Extraction des espèces ZNIEFF

ZnieffXmlToLayerEsp

5

Extraction des habitats déterminants ZNIEFF

ZnieffXmlToLayerHab

6

Extraction des descriptions Natura 2000

NaturaXmlToLayerDesc

7

Extraction des espèces Natura 2000

NaturaXmlToLayerEsp

8

Extraction des habitats Natura 2000

NaturaXmlToLayerHab

9

Tableau croisé espèces déterminantes ZNIEFF

ZnieffPivotEspeces

10

Tableau croisé habitats déterminants ZNIEFF

ZnieffPivotHabitats

11

Tableau croisé espèces Natura 2000

NaturaPivotEspeces

12

Tableau croisé habitats Natura 2000

NaturaPivotHabitats

Note

Les étapes de pivot (9 à 12) ne sont exécutées que si les étapes d’extraction correspondantes ont produit des données (flags _has_znieff_esp, _has_znieff_hab, _has_natura_esp, _has_natura_hab positionnés par le thread).

Le thread émet trois signaux PyQt5 :

  • progress(int, int, str) — numéro d’étape, total, libellé

  • log(str) — messages textuels

  • finished(str) / error(str) — résultat final

Architecture des classes de base

Le module FSD repose sur deux classes abstraites mutualisées définies dans modules/base/.

DwlXml (base/DwlXml.py)

Classe abstraite gérant le téléchargement des fichiers XML depuis l’INPN. Elle s’appuie sur les couches WFS Patrinat déjà chargées dans le projet pour déterminer, par intersection spatiale avec l’aire d’étude, les identifiants de zones à télécharger.

Méthodes abstraites (à implémenter dans les classes enfants) :

Méthode

Rôle

get_patrinat_layer_names() tuple

Noms des deux couches WFS Patrinat à rechercher dans le projet QGIS

build_url(zone_id: str) str

Construction de l’URL de téléchargement pour un identifiant de zone

Méthodes concrètes mutualisées :

Méthode

Rôle

run_with_path(reference_layer, folder_path)

Point d’entrée : orchestre la recherche des couches, la sélection spatiale et le téléchargement

find_patrinat_layers()

Recherche les deux couches Patrinat par nom dans le projet QGIS

selectionner_et_stocker(couche_source, liste_stockage)

Sélection spatiale par intersection avec l’aire d’étude ; stockage des id_mnhn

download_file(url, save_path, retries=3)

Téléchargement HTTP avec retry exponentiel (1, 2, 4 secondes)

execute_download()

Lance la sélection spatiale sur les deux couches puis télécharge tous les XML

Sélection spatiale : la géométrie de la couche de référence (aire d’étude) est reprojetée dans le SCR de la couche WFS, puis une requête par boîte englobante filtre les candidats avant une vérification exacte d’intersection (intersects). Seuls les id_mnhn des entités intersectantes sont conservés.

XmlToLayer (base/XmlToLayer.py)

Classe abstraite gérant le parsing des fichiers XML et la création des couches QGIS. Elle suit le patron Template Method : le squelette du traitement est fixé dans les méthodes concrètes, les classes enfants n’implémentent que les quatre méthodes abstraites.

Méthodes abstraites :

Méthode

Rôle

get_layer_name() str

Nom de la couche QGIS et du layer dans le GeoPackage

get_xml_filter() callable

Fonction lambda filtrant les fichiers XML du dossier par nom

process_xml_file(xml_path) list

Parsing d’un fichier XML ; retourne une liste de dictionnaires

create_temp_layer(data) QgsVectorLayer

Création de la couche mémoire QGIS (sans géométrie) avec les champs appropriés

Méthodes concrètes mutualisées :

Méthode

Rôle

run_with_path(folder_path)

Point d’entrée : parcourt le dossier, crée la couche, sauvegarde et charge depuis le GPKG

process_folder(folder_path)

Liste les fichiers XML éligibles et appelle process_xml_file() sur chacun

save_to_geopackage(layer)

Délègue à LayerUtils.save_to_gpkg() ; met à jour le flag gpkg_saved

load_from_geopackage()

Charge la couche depuis le GPKG et la substitue dans le projet via LayerUtils.replace_layer()

Valeurs de retour de run_with_path() :

  • True — données trouvées, couche créée et chargée

  • None — aucune donnée dans le dossier (situation normale, sans erreur)

  • False — erreur technique

PivotLayer (base/PivotLayer.py)

Classe abstraite gérant la création des tableaux croisés dynamiques (format large) à partir des couches attributaires produites par XmlToLayer. Chaque colonne représente un site ; chaque ligne une espèce ou un habitat. La requête SQL est exécutée via une couche virtuelle QGIS (provider virtual).

Méthodes abstraites :

Méthode

Rôle

get_source_layer_name() str

Nom de la couche source à lire dans le projet QGIS

get_output_layer_name() str

Nom de la couche pivot à créer

get_site_keys() tuple

Paire (code_field, name_field) pour extraire les sites depuis la couche source

build_pivot_query() str

Requête SQL SELECT CASE WHEN GROUP BY complète

Méthodes concrètes mutualisées :

Méthode

Rôle

run(gpkg_path)

Orchestre le chargement de la source, la génération SQL, la création du pivot et l’export GPKG

get_sites() dict

Extrait les paires {code: nom} uniques depuis la couche source

create_virtual_layer(sql_query)

Crée et substitue la couche virtuelle dans le projet

export_to_geopackage(layer, gpkg_path)

Sauvegarde persistante via LayerUtils.save_to_gpkg()

col_alias(code, name) str

Génère l’alias de colonne au format [CODE] - NOM_SANS_ACCENTS

Nommage des colonnes : les accents sont supprimés (normalisation NFD) et le nom est mis en majuscules. Exemple : FR2500093 - BAIE DU MONT-SAINT-MICHEL.

LayerUtils (base/LayerUtils.py)

Classe utilitaire statique centralisant toutes les opérations sur les couches QGIS.

Méthode statique

Rôle

get_layer(name) QgsVectorLayer

Retourne la première couche du projet correspondant au nom exact

layer_is_ready(name) bool

Vérifie qu’une couche existe, est valide et contient des entités

replace_layer(layer) bool

Supprime atomiquement l’ancienne version d’une couche et ajoute la nouvelle

load_from_gpkg(gpkg_path, name) QgsVectorLayer

Charge un layer spécifique depuis un GeoPackage

create_empty_gpkg(gpkg_path) bool

Crée physiquement un GeoPackage vide s’il n’existe pas

save_to_gpkg(layer, gpkg_path) tuple[bool, str]

Exporte n’importe quelle couche (y compris virtuelle) dans un GeoPackage via QgsVectorFileWriter

Volet Natura 2000

Téléchargement — NaturaDwlXml

NaturaDwlXml hérite de DwlXml et spécialise le téléchargement pour les sites Natura 2000.

Méthode implémentée

Valeur retournée

get_patrinat_layer_names()

('Patrinat : SIC', 'Patrinat : ZPS')

build_url(zone_id)

https://inpn.mnhn.fr/docs/natura2000/fsdxml/{zone_id}.xml

Filtre des fichiers XML lors du parsing aval : fichiers dont le nom commence par FR, se termine par .xml et comporte exactement 13 caractères (ex : FR2500093.xml).

Extraction des descriptions — NaturaXmlToLayerDesc

Parse les balises SITECODE, SITE_NAME et COMMENTAIRE/COMMENTAIRE_ROW de chaque fichier XML Natura 2000.

Couche produite : Natura_2000_Descriptions

Champ

Type

Description

SITECODE

String

Code officiel du site Natura 2000 (ex : FR2500093)

SITE_NAME

String

Nom du site

QUALITY

String

Valeur écologique et intérêt du site (balise QUALITY)

VULNAR

String

Vulnérabilités et menaces identifiées (balise VULNAR)

HTML_POPUP

String

Popup HTML stylisée pour l’affichage QGIS (couleur #009999)

setDisplayExpression("SITE_NAME") est appliqué après chargement depuis le GeoPackage.

Extraction des habitats — NaturaXmlToLayerHab

Parse les balises HABIT1_ROW de chaque fichier XML Natura 2000.

Couche produite : Natura_2000_Habitats

Champ

Type

Description

SITECODE

String

Code du site Natura 2000

SITE_NAME

String

Nom du site

CD_UE

String

Code habitat directive Habitats (ex : 6210)

LB_HABDH_FR

String

Libellé français de l’habitat directive

Seules les lignes comportant au moins un code CD_UE ou un libellé LB_HABDH_FR sont retenues.

Extraction des espèces — NaturaXmlToLayerEsp

Parse les balises BIOTOP/SPECIES/SPECIES_ROW de chaque fichier XML. Cette classe fonctionne en mode hors-ligne (sans appel à l’API TaxRef).

Couche produite : Natura_2000_Especes

La couche comporte 43 champs correspondant à l’intégralité des balises SPECIES_ROW, dont les principaux :

Champ

Type

Description

SITECODE / SITE_NAME

String

Identifiants du site

CD_NOM

String

Code TaxRef de l’espèce

NOM

String

Nom scientifique

TAXGROUP

String

Groupe taxonomique (Oiseaux, Mammifères, etc.)

ANNEXE_II

String

Inscription à l’annexe II de la directive Habitats

POPULATION

String

Évaluation de la population sur le site

CONSERVE

String

État de conservation

TENDANCE

String

Tendance d’évolution de la population

UUID_SPECIES

String

Identifiant UUID de l’espèce dans la base INPN

Tableau croisé des habitats — NaturaPivotHabitats

Transforme Natura_2000_Habitats (format long) en tableau large avec un site par colonne.

Couche produite : Natura_2000_Habitats_Pivot

  • Colonnes fixes : CD_UE, LB_HABDH_FR

  • Colonnes dynamiques : une par site, nommée [SITECODE] - NOM_SITE

  • Valeur : 1 si l’habitat est présent sur le site, NULL sinon

  • Tri : par CD_UE croissant

Requête SQL générée (exemple simplifié) :

SELECT CD_UE, LB_HABDH_FR,
  MAX(CASE WHEN SITECODE = 'FR2500093' THEN 1 END) AS "FR2500093 - BAIE DU MONT-SAINT-MICHEL",
  MAX(CASE WHEN SITECODE = 'FR2500094' THEN 1 END) AS "FR2500094 - DUNES DE ..."
FROM "Natura_2000_Habitats"
GROUP BY CD_UE, LB_HABDH_FR
ORDER BY CD_UE

Tableau croisé des espèces — NaturaPivotEspeces

Transforme Natura_2000_Especes en tableau large.

Couche produite : Natura_2000_Especes_Pivot

  • Colonnes fixes : GROUPE (alias de TAXGROUP), CD_NOM, NOM

  • Colonnes dynamiques : une par site, nommée [SITECODE] - NOM_SITE

  • Valeur : 1 si l’espèce est présente, NULL sinon

  • Tri : par groupe puis par nom croissant

Note

La requête SQL référence la couche par son ID interne QGIS (layer.id()) plutôt que par son nom, afin d’éviter les conflits lorsque le nom contient des espaces ou des caractères spéciaux.

Volet ZNIEFF

Téléchargement — ZnieffDwlXml

ZnieffDwlXml hérite de DwlXml et spécialise le téléchargement pour les inventaires ZNIEFF.

Méthode implémentée

Valeur retournée

get_patrinat_layer_names()

('Patrinat : ZNIEFF1', 'Patrinat : ZNIEFF2')

build_url(zone_id)

https://inpn.mnhn.fr/docs/ZNIEFF/znieffxml/{zone_id}.xml

Filtre des fichiers XML lors du parsing aval : fichiers se terminant par .xml, de 13 caractères, ne commençant pas par FR (convention ZNIEFF).

Extraction des descriptions — ZnieffXmlToLayerDesc

Parse les balises de description de chaque fichier XML ZNIEFF. Les fichiers peuvent contenir des balises <p> imbriquées dans les champs texte longs (TX_GENE, TX_GEO, TX_ACTH…) ; la méthode _rich_text() gère cette ambivalence.

Couche produite : Znieff_Descriptions

La couche comporte 39 champs, dont les principaux :

Champ

Type

Description

NM_SFFZN

String

Numéro national ZNIEFF

LB_ZN

String

Nom de la ZNIEFF

TY_ZONE

String

Type de zone (1 ou 2)

SU_ZN

Double

Superficie en hectares

ALT_MINI / ALT_MAXI

Double

Altitudes minimale et maximale

DESCRIPTION

String

Texte général de description (balise TX_GENE)

TX_ACTH

String

Activités humaines

TX_MESPRO

String

Mesures de protection

TX_INTERET

String

Intérêt du site

DATE_CREA / DATE_MODIF

String

Dates de création et de dernière modification

ZNI_NM_SFFZN / ZNI_LB_ZN

String

Identifiants de la ZNIEFF parente (balise ZNI)

HTML_POPUP

String

Popup HTML stylisée pour l’affichage QGIS

setDisplayExpression appliqué : coalesce(LB_ZN, '') || ' (' || coalesce(NM_SFFZN, '') || ')'

Note

Les champs numériques (SU_ZN, ALT_MINI, ALT_MAXI, PROF_MINI, PROF_MAXI, X_L2E, Y_L2E) font l’objet d’une conversion explicite _to_double() lors de la création de la couche, avec nettoyage des virgules décimales et des caractères parasites.

Extraction des espèces — ZnieffXmlToLayerEsp

Parse les balises ESPECE_PROJET_ROW et ESPECE_ROW des fichiers XML ZNIEFF.

Couche produite : Znieff_Especes

Champ

Type

Description

nm_sffzn

String

Numéro ZNIEFF (issu de la ligne espèce ou de la racine XML)

lb_zn

String

Nom de la ZNIEFF

groupe

String

Groupe taxonomique

cd_nom

String

Code TaxRef

nom_complet

String

Nom scientifique complet

nom_vern

String

Nom vernaculaire

fg_esp

String

Flag espèce déterminante (D = déterminante)

fg_conf

String

Flag de confidentialité

origine

String

Origine de la donnée

Extraction des habitats — ZnieffXmlToLayerHab

Parse les balises TYPO_INFO_ROW des fichiers XML ZNIEFF. Seuls les habitats déterminants (FG_TYPO = 'D') sont retenus.

Couche produite : Znieff_Habitats

Champ

Type

Description

NM_SFFZN

String

Numéro ZNIEFF

LB_ZN

String

Nom de la ZNIEFF

LB_CODE

String

Code de l’habitat (référentiel CORINE Biotopes ou autre)

LB_HAB

String

Libellé de l’habitat

Tableau croisé des habitats — ZnieffPivotHabitats

Transforme Znieff_Habitats en tableau large.

Couche produite : Znieff_Hab_Pivot

  • Colonnes fixes : LB_CODE, LB_HAB

  • Colonnes dynamiques : une par ZNIEFF, nommée [NM_SFFZN] - NOM_ZNIEFF

  • Valeur : 1 si l’habitat est présent, NULL sinon

  • Tri : par LB_CODE croissant

Tableau croisé des espèces déterminantes — ZnieffPivotEspeces

Transforme Znieff_Especes en tableau large, filtré sur les espèces déterminantes (fg_esp = 'D').

Couche produite : Znieff_EspDet_Pivot

  • Colonnes fixes : GROUPE, cd_nom, nom_complet, nom_vern

  • Colonnes dynamiques : une par ZNIEFF avec des espèces déterminantes, nommée [NM_SFFZN] - NOM_ZNIEFF

  • Valeur : 1 si l’espèce est déterminante sur cette ZNIEFF, NULL sinon

  • Tri : par groupe puis par nom_complet croissant

Note

La méthode get_sites() est surchargée dans cette classe afin de ne collecter que les sites ayant au moins une espèce déterminante (fg_esp = 'D'), réduisant ainsi le nombre de colonnes dans le pivot.

Comme NaturaPivotEspeces, la requête SQL référence la couche source par son ID interne QGIS pour éviter les conflits de nommage.

Connexions WFS — WfsManager

WfsManager configure dans le registre QGIS (QSettings) la connexion au service WFS de l’IGN/INPN (data.geopf.fr) et charge dans le projet les quatre couches de zonage utilisées comme référence spatiale par DwlXml.

Nom de couche dans le projet

Typename WFS

Patrinat : ZPS

patrinat_zps:zps

Patrinat : SIC

patrinat_sic:sic

Patrinat : ZNIEFF1

patrinat_znieff1:znieff1

Patrinat : ZNIEFF2

patrinat_znieff2:znieff2

Toutes les couches sont chargées en EPSG:3857. Une couche déjà présente dans le projet n’est pas rechargée (vérification par mapLayersByName).

Couches et GeoPackage produits

Toutes les couches du module FSD sont des couches attributaires sans géométrie (provider "None" en mémoire, puis exportées en GPKG via QgsVectorFileWriter).

Nom de la couche / layer GPKG

Référentiel

Contenu

Natura_2000_Descriptions

Natura 2000

Descriptions qualité/vulnérabilité par site

Natura_2000_Habitats

Natura 2000

Habitats directive (format long)

Natura_2000_Especes

Natura 2000

Espèces directive (format long, 43 champs)

Natura_2000_Habitats_Pivot

Natura 2000

Tableau croisé habitats × sites

Natura_2000_Especes_Pivot

Natura 2000

Tableau croisé espèces × sites

Znieff_Descriptions

ZNIEFF

Descriptions des ZNIEFF (39 champs)

Znieff_Especes

ZNIEFF

Espèces (toutes, format long)

Znieff_Habitats

ZNIEFF

Habitats déterminants (format long)

Znieff_EspDet_Pivot

ZNIEFF

Tableau croisé espèces déterminantes × ZNIEFF

Znieff_Hab_Pivot

ZNIEFF

Tableau croisé habitats déterminants × ZNIEFF

Toutes ces couches sont enregistrées dans le fichier biblizou.gpkg situé dans le dossier de travail défini par l’utilisateur.

Référence des fichiers source

Fichier

Groupe

Rôle

modules/base/DwlXml.py

base

Classe abstraite téléchargement XML

modules/base/XmlToLayer.py

base

Classe abstraite parsing XML → couche QGIS

modules/base/PivotLayer.py

base

Classe abstraite tableau croisé dynamique

modules/base/LayerUtils.py

base

Utilitaires couches QGIS et GeoPackage

modules/WfsManager.py

FSD

Connexions et chargement WFS INPN

modules/NaturaDwlXml.py

FSD

Téléchargement XML Natura 2000

modules/NaturaXmlToLayerDesc.py

FSD

Extraction descriptions Natura 2000

modules/NaturaXmlToLayerHab.py

FSD

Extraction habitats Natura 2000

modules/NaturaXmlToLayerEsp.py

FSD

Extraction espèces Natura 2000

modules/NaturaPivotHabitats.py

FSD

Pivot habitats Natura 2000

modules/NaturaPivotEspeces.py

FSD

Pivot espèces Natura 2000

modules/ZnieffDwlXml.py

FSD

Téléchargement XML ZNIEFF

modules/ZnieffXmlToLayerDesc.py

FSD

Extraction descriptions ZNIEFF

modules/ZnieffXmlToLayerHab.py

FSD

Extraction habitats déterminants ZNIEFF

modules/ZnieffXmlToLayerEsp.py

FSD

Extraction espèces ZNIEFF

modules/ZnieffPivotHabitats.py

FSD

Pivot habitats déterminants ZNIEFF

modules/ZnieffPivotEspeces.py

FSD

Pivot espèces déterminantes ZNIEFF

biblizou_worker.py

Orchestration des threads de traitement