République
française
dsfr-data
Documentation — Web Components DSFR pour la dataviz
Composant intermediaire de normalisation et nettoyage des données.
Se place entre <dsfr-data-source> et <dsfr-data-query>
pour nettoyer les données avant traitement.
Invisible : Ce composant ne rend rien visuellement. Il normalise les données et les redistribue aux composants en aval via le systeme d'événements.
dsfr-data-source → dsfr-data-normalize → dsfr-data-query → dsfr-data-chart
Normaliser avant dsfr-data-query permet aux filtres et agrégations de travailler
sur des données propres (evite les comparaisons string vs number).
"1234" au lieu de 1234)"12,5" vs "12.5")N/A, n.d., - par des valeurs exploitables32073247.269999996 a 32073247| Attribut | Type | Défaut | Description |
|---|---|---|---|
id | String | - | Requis. Identifiant de la sortie. |
source | String | "" | ID de la source de données a ecouter |
numeric | String | "" | Champs a convertir en nombre (virgule-séparés). Ex: "population, surface" |
numeric-auto | Boolean | false | Detection automatique des champs numériques via looksLikeNumber() |
rename | String | "" | Renommage de clés. Format : "ancien:nouveau | ancien2:nouveau2". Un : ou | littéral dans un nom s'échappe en percent (%3A, %7C), comme dans where. |
trim | Boolean | false | Supprime les espaces en debut/fin de toutes les clés et valeurs string |
strip-html | Boolean | false | Supprime les balises HTML des valeurs string |
replace | String | "" | Remplacement de valeurs, sur tous les champs. Format : "pattern:remplacement | pattern2:remplacement2". Le pattern est comparé à la valeur entière (égalité stricte, pas de regex) ; un remplacement vide supprime la valeur. Un :, |, , ou % littéral dans le pattern ou le remplacement s'échappe en percent (%3A, %7C, %2C, %25), comme dans where (#676) : replace="10%3A00:10h" récrit « 10:00 » en « 10h ». La comparaison porte sur la forme chaîne de la valeur : une colonne numérique est concernée aussi (#730). Un champ TABLEAU (multivalué venu de la source) est remplacé élément par élément, longueur conservée et sans dédoublonnage (#774). Limite : le remplacement s'exécute AVANT split, il ne voit donc pas les tableaux fabriqués par split — il agit sur la chaîne entière avant la découpe. Pour un recodage plus riche (sous-chaîne, année d'une date ISO), utiliser compute avec replace() ou year(). |
replace-fields | String | "" | Remplacement ciblé par champ. Format : "CHAMP:pattern:remplacement | CHAMP2:p:r". Les deux premiers : sont des délimiteurs, le remplacement peut contenir des : bruts. Un : littéral dans le nom du champ ou dans le pattern s'échappe en %3A (%7C, %2C et %25 sont aussi décodés), comme dans where (#676) : replace-fields="h:10%3A00:10h". La comparaison porte sur la forme chaîne de la valeur : une colonne numérique est concernée aussi, replace-fields="annee:2024:2024-2025" fonctionne (#730). Sur un champ tableau venu de la source, élément par élément ; pas sur un tableau fabriqué par split, découpé après (#774, même limite que replace). Pas de regex : pour un recodage plus riche, voir compute (replace(), year()). |
flatten | String | "" | Clé du sous-objet a aplatir au premier niveau. Supporte la dot notation (ex: "data.attributes"). |
split | String | "" | Découpe des champs multivalués (chaîne avec séparateur) en vrais tableaux, comme une ChoiceList Grist. Format : "champ:sep, champ2:sep2" ; séparateur par défaut : la virgule ("champ" seul). Ex : "Axes:|, Cibles:;". Chaque élément est trimé, les éléments vides sont écartés, une chaîne vide donne un tableau vide. Les valeurs non-string (tableau déjà forme, null, nombre) sont laissées telles quelles. Les composants aval traitent ces tableaux comme des champs multi-valeurs (facettes : une valeur par élément). |
round | String | "" | Arrondit les champs numériques à l'entier (ou à N décimales). Format: "champ1, champ2" ou "champ1:2, champ2:0" |
lowercase-keys | Boolean | false | Met toutes les clés en minuscules |
compute | String | "" | Colonnes calculées, ligne à ligne, en dernier (sur les valeurs déjà typées par numeric / round / rename). Format : cible = expression; cible2 = expression2 (une assignation suivante peut relire une colonne calculée avant elle). Grammaire (ADR-105, #671) : - arithmétique + - * /, parenthèses, moins unaire ; + concatène dès qu'un côté n'est pas numérique ; littéraux texte 'entre quotes simples', nombres à point ; - littéraux null, true, false ; - fonctions en liste blanche, appel f(a, b) : dates year(d), month(d), day(d) (ISO ou Date, sinon null) ; nombres round(x, n), abs(x), floor(x), ceil(x) (non numérique → null) ; texte lower(s), upper(s), trim(s), len(s), concat(a, b, …), replace(s, 'de', 'vers') (littéral, toutes les occurrences, pas de regex) ; absence coalesce(a, b, …) (première valeur non nulle), is_null(x), is_empty(x) (null, '' ou tableau vide) ; tableaux join(arr, ', '), contains(arr_ou_texte, v) ; - conditions when COND then EXPR [when … then …]… else EXPR — le else est obligatoire (erreur de configuration sinon) ; comparaisons d'égalité = et != et d'ordre (inférieur, inférieur ou égal, supérieur, supérieur ou égal, avec les signes usuels — grammaire complète dans le guide « Colonnes calculées » de la skill), and, or, not. L'égalité est lâche comme celle de where (nombre ↔ chaîne numérique) : when cat = 'A' et where="cat:eq:A" gardent les mêmes lignes ; une cellule vide n'égale jamais un nombre (montant = 0 ne classe pas les montants non renseignés en zéro). Les comparaisons d'ordre se font en nombre quand les deux côtés sont numériques, en texte sinon (dates ISO comprises) ; null, undefined et '' ne matchent jamais. CHAMP TABLEAU (#953, ex-#842) : = regarde DANS le tableau — when tags = 'urgent' est VRAI pour ['urgent','social'], comme contains(tags, 'urgent'), et comme le portail sur une clause déléguée. != en est la négation, donc faux sur cette même ligne. contains() garde son utilité sur du TEXTE, où il cherche une sous-chaîne ; sur un tableau, les deux se rejoignent. Dériver ici un booléen puis filtrer where="a_urgent:eq:1" en aval reste valide — et utile, le filtre portant alors sur un scalaire regroupable et délégable — mais n'est plus NÉCESSAIRE pour filtrer un champ tableau : where="tags:eq:urgent" le fait directement. - arithmétique - * / et moins unaire : un opérande absent ou non numérique rend null (jamais un 0 plausible), une division par zéro rend null (jamais Infinity). Exemples : solde = actif - passif (null si l'un des deux manque), tranche = when montant = 0 then 'Nul' when is_empty(montant) then 'Inconnu' else 'Renseigné', type = coalesce(type_entreprise, 'Non renseigné'), annee = year(date_notification), pct = round(part * 100, 1), serie = Indicateurs + ' / ' + Sous_theme ; une tranche par seuils s'écrit avec les opérateurs d'ordre (voir le guide). Fonction hors liste, arité fausse, when sans else, expression trop longue ou trop imbriquée : erreur de configuration (console + data-dsfr-config-error), état d'erreur en aval — jamais une colonne silencieusement vide. Aucun eval : tokenizer, parseur, AST ; seuls les champs de la ligne sont accessibles. Hors périmètre : valeurs agrégées (query / kpi), ligne précédente, cumul. |
fold | String | "" | Repli de colonnes booléennes parallèles en un champ multi-valeurs (#677) — le motif open data « une colonne Oui/Non par modalité » (handicap_moteur, handicap_visuel…). Format : "motif:cible, motif2:cible2". Le joker * n'est accepté qu'en début ou en fin de motif (handicap_*, *_ok) ; un motif sans joker désigne une colonne exacte ; plusieurs motifs peuvent viser la même cible. Chaque ligne reçoit dans cible le tableau des colonnes dont la valeur est vraie au sens de toBoolean (Oui/Non, 1/0, true/false, X/vide…), étiquetées par la partie variable du motif (handicap_moteur donne « moteur ») ou par le nom complet de la colonne pour un motif sans joker. Les colonnes sources sont conservées (voir fold-drop). S'exécute après rename et lowercase-keys, avant compute : les motifs se lisent sur les noms renommés, qui servent donc d'étiquettes (rename="handicap_moteur:handicap_Moteur" donne « Moteur »). Le tableau obtenu se filtre avec dsfr-data-facets comme un champ split (une valeur par élément). Ex : fold="handicap_*:handicaps". |
fold-drop | Boolean | false | Avec fold : retire du résultat les colonnes sources repliées. |
Separateurs : rename et replace utilisent le pipe |
pour separer les paires, et : pour separer la clé de la valeur.
replace-fields utilise le format CHAMP:pattern:remplacement (les 2 premiers : sont des delimiteurs).
numeric utilise la virgule.
split utilise la virgule entre entrées et champ:séparateur pour chacune (le séparateur à découper est souvent |).
Les données brutes RappelConso contiennent des noms de colonnes longs et techniques. On renomme les colonnes pour la lisibilite et on nettoie les espaces superflus.
{
"modeles_ou_references": " Lot 2024-ABC ",
"categorie_produit": "Alimentation",
"marque_produit": "Ma Marque",
"date_publication": "2024-06-15",
"motif_rappel": "Presence de Listeria"
}
{
"Produit": "Lot 2024-ABC", // trim + rename
"Catégorie": "Alimentation", // rename
"Marque": "Ma Marque", // rename
"Date": "2024-06-15", // rename
"Motif": "Presence de Listeria" // rename
}
<dsfr-data-source id="raw" api-type="opendatasoft"
dataset-id="rappelconso-v2-gtin-trie"
base-url="https://data.economie.gouv.fr"
server-side page-size="50">
</dsfr-data-source>
<dsfr-data-normalize id="clean" source="raw"
trim
rename="modeles_ou_references:Produit | categorie_produit:Catégorie | marque_produit:Marque | date_publication:Date | motif_rappel:Motif">
</dsfr-data-normalize>
<!-- Les données normalisees sont pretes pour query/chart -->
<dsfr-data-list source="clean" pagination="5"></dsfr-data-list>
Source → Normalize → Query → Chart
<dsfr-data-source id="raw" url="..." transform="results"></dsfr-data-source>
<dsfr-data-normalize id="clean" source="raw"
numeric="population, budget"
rename="pop_tot:Population totale | lib_dep:Departement"
trim
replace="N/A: | n.d.:">
</dsfr-data-normalize>
<dsfr-data-query id="stats" source="clean"
group-by="Departement"
aggregate="population:sum"
order-by="population__sum:desc"
limit="10">
</dsfr-data-query>
<dsfr-data-chart source="stats" type="bar"
label-field="Departement"
value-field="population__sum">
</dsfr-data-chart>
L'API INSEE Melodi retourne des codes de dimension (AGE: "Y30T39", PCS: "3").
replace-fields permet de les decoder sans affecter les autres champs
qui pourraient contenir les mêmes valeurs.
<dsfr-data-source id="raw" api-type="insee"
base-url="https://api.insee.fr/melodi"
dataset-id="DS_POPULATIONS_REFERENCE"
where="POPREF_MEASURE:eq:PMUN, TIME_PERIOD:eq:2023">
</dsfr-data-source>
<dsfr-data-normalize id="decoded" source="raw"
replace-fields="AGE:Y30T39:30-39 ans | AGE:Y_LT30:Moins de 30 ans | PCS:3:Cadres | PCS:5:Employes"
replace="N/A:">
</dsfr-data-normalize>
<dsfr-data-chart source="decoded" type="bar"
label-field="AGE" value-field="OBS_VALUE">
</dsfr-data-chart>