guide complet · FR

Construire un questionnaire
de zéro, cellule par cellule.

XLSForm est le standard qui transforme un simple tableur en formulaire numérique complet — avec logique de saut, validation, GPS, photos et plusieurs langues — prêt à tourner sur ODK Collect, KoboToolbox ou Enketo. Ce guide construit une enquête ménage pas à pas et documente tous les types de questions et réglages, avec des exemples à copier et convertir avec rxform.

1 · Anatomie d’un XLSForm

Un XLSForm est un fichier .xlsx (ou .xls/.ods) avec jusqu’à trois feuilles principales :

Règles d’or pour la colonne name (questions, groupes et options) :

Les noms commencent par une lettre ou _ et ne contiennent que lettres, chiffres, -, _ et . — sans espaces ni accents. Ils deviennent les noms de colonnes de votre base de données : préférez revenu_mensuel à Revenu Mensuel (€). Le label, lui, est du texte libre : accents, emoji, tout ce qu’il faut.

2 · Le premier formulaire

Le plus petit formulaire utile tient en trois lignes de la feuille survey :

survey
typenamelabel
2textenqueteurNom de la personne qui administre l’enquête
3integertaille_menageCombien de personnes vivent dans le ménage ?
4select_one sim_naoeau_couranteLe ménage a-t-il l’eau courante ?

La question de la ligne 4 utilise la liste oui_non, définie dans la feuille choices :

choices
list_namenamelabel
2oui_nonouiOui
3oui_nonnonNon

Et la feuille settings donne son identité au formulaire :

settings
form_titleform_idversion
2Enquête Ménage 2026enq_menage_20262026081101

Convertissez, et c’est prêt :

$ rxform enquete_menage.xlsx
enquete_menage.xml

3 · Tous les types de questions

Texte et nombres

survey
typenamelabelhint
2textobservationsObservations généralesTexte libre
3integerageÂge (années révolues)Nombres entiers uniquement
4decimalrevenuRevenu mensuelPoint pour les centimes
5rangesatisfactionSatisfaction transport0 = très mauvais · 10 = excellent

Dates et heures

survey
typenamelabelappearance
2datedate_visiteDate de la visite
3dateemmenagementQuand avez-vous emménagé ?month-year
4timeheure_debutHeure de début
5dateTimerendez_vousProgrammer le retour pour

Apparences utiles pour date : month-year, year et no-calendar.

Choix et listes

survey
typenamelabelappearance
2select_one scolaritescolariteNiveau d’études du chef de ménageminimal
3select_multiple servicesservicesQuels services desservent la rue ?
4rank prioritesprioritesClassez les priorités du quartier

Des colonnes supplémentaires dans choices sont permises et deviennent des données de l’option — la base des filtres en cascade :

Sélections en cascade (choice_filter)

choices
list_namenamelabeluf
2regionsdkDakar
3regionsthThiès
4communesplateauPlateaudk
5communesmedinaMédinadk
6communesthies_nThiès Nordth
survey
typenamelabelchoice_filter
2select_one regionsregionRégion
3select_one communescommuneCommuneregion = ${region}

Dans le filtre, les colonnes de la liste s’écrivent par leur nom (region) et les réponses précédentes en ${region}. Pour mélanger les options : parameters = randomize=true (avec seed=42 pour un ordre reproductible).

Localisation

survey
typenamelabelparameters
2geopointpointLocalisation du ménagecapture-accuracy=5 warning-accuracy=10
3geotracetrajetTrajet jusqu’à l’arrêt de bus
4geoshapeparcelleContour de la parcelle

geopoint capture un point (précision cible en mètres via parameters) ; geotrace, une ligne ; geoshape, un polygone fermé.

Médias et fichiers

survey
typenamelabelappearanceparameters
2imagephoto_facadePhoto de la façademax-pixels=1024
3imagesignatureSignature de l’enquêtésignature
4audiotemoignageEnregistrez le témoignagequality=voice-only
5videovideo_rueVidéo de la rue
6filejustificatifJoindre le justificatif (PDF)
7barcodecode_compteurCode-barres du compteur d’eau

image avec appearance = signature devient un champ de signature ; draw, dessin libre. max-pixels réduit la taille des photos sur l’appareil.

Notes et confirmations

survey
typenamelabel
2noteintroBonjour ! Cette enquête prend ~15 minutes. Les réponses sont confidentielles.
3acknowledgeconsentementL’enquêté accepte de participer

Champs invisibles

survey
typenamecalculation
2calculaterevenu_par_tete${revenu} div ${taille_menage}
3hiddenversion_echantillon

calculate calcule une valeur en XPath (fonctions if(), concat(), selected(), count(), round()…) ; hidden stocke une valeur remplie par default ou des intégrations.

Métadonnées — collectées toutes seules

survey
typenamelabel / trigger
2startdebut
3endfin
4todayaujourdhui
5deviceidappareil
6usernameutilisateur
7auditaudit
8start-geopointposition_debut
9background-audioenregistrement
10background-geopointposition_reponsetrigger : ${eau_courante}

4 · Logique du formulaire

Toute la logique utilise ${nom} pour référencer des réponses précédentes.

relevant — sauter des questions

survey
typenamelabelrelevant
2select_one sim_naotravailleTravaillez-vous ?
3textprofessionQuelle est votre profession ?${travaille} = 'oui'
4notenote_ageModule réservé aux majeurs.${age} >= 18

La question n’apparaît que si l’expression est vraie. Combinez avec and/or ; pour les choix multiples, selected(${services}, 'eau').

constraint — valider les réponses

survey
typenamelabelconstraintconstraint_message
2integerageÂge. >= 0 and . <= 120L’âge doit être entre 0 et 120.
3datenaissanceDate de naissance. <= today()La date ne peut pas être future.

Le point . est la réponse elle-même. Le message s’affiche quand la règle échoue.

required, default, read_only

survey
typenamelabelrequiredrequired_messagedefault
2select_one oui_noneau_couranteEau courante ?yesCette réponse est obligatoire.
3datedate_visiteDate de la visitetoday()
4integersecteurSecteur de recensement42

trigger — recalculer au changement

survey
typenamelabeltriggercalculation
2integertaille_menageCombien de résidents ?
3integerenfantsCombien d’enfants ?${taille_menage}

Avec trigger, le champ est (re)défini chaque fois que la question référencée change — ici, en vidant enfants quand taille_menage est modifié. S’il y a une calculation, elle s’exécute à ce moment-là (au lieu d’en continu).

5 · Groupes, répétitions et boucles

Groupes

survey
typenamelabelappearancerelevant
2begin_groupmodule_eauModule : Assainissementfield-list${eau_courante} = 'oui'
3select_one source_eausourceSource de l’eau
4integerjours_sansJours sans eau ce mois-ci
5end_group

Répétitions

survey
typenamelabelrepeat_count
2begin_repeatresidentDétails du résident${taille_menage}
3textnomNom
4integerage_residentÂge
5end_repeat

Le bloc se répète une fois par résident. Sans repeat_count, l’enquêteur ajoute les répétitions à la main ; avec une expression (ou un nombre), le compte est automatique. À l’intérieur, position(..) donne l’indice courant et indexed-repeat() lit les valeurs d’une autre répétition.

Boucles sur une liste

survey
typenamelabel
2begin loop over serviceseval_services
3select_one notesnoteComment évaluez-vous le service %(label)s ?
4end loop

Génère un bloc par option de la liste services, en substituant %(label)s et %(name)s — une question « Comment évaluez-vous le service Eau ? », une autre « …Assainissement ? », etc.

6 · Plusieurs langues

survey
typenamelabel::Français (fr)label::English (en)hint::Français (fr)
2integermoradoresCombien de personnes vivent ici ?How many people live here?Comptez tous les résidents

Il suffit de suffixer les colonnes traduisibles avec ::Langue (code) : label, hint, guidance_hint, constraint_message, required_message, image, audio et video — dans survey et choices. Fixez la langue initiale dans settingsdefault_language = Français (fr). L’application gagne un menu de langues.

Média par question : les colonnes image/audio/video associent des fichiers (ex. carte_reponse.jpg) envoyés avec le formulaire.

7 · Apparences (appearance)

référence
appearances’applique àeffet
minimalselect_one/multiplemenu déroulant compact
quickselect_oneavance à la sélection
likertselect_oneéchelle horizontale type Likert
columns / columns-nselectsoptions en colonnes
autocompleteselect_onerecherche à la frappe
field-listgroupestout le groupe sur un écran
table-listgroupesmatrice de selects partageant une liste
multilinetextzone multi-lignes
numbers / thousands-septextpavé numérique · séparateur de milliers
month-year · year · no-calendardateprécision réduite · sans calendrier
signature · draw · annotateimagesignature · dessin · annoter une photo
map · quick mapselect_one_from_file (geojson)choix sur carte
ratingrangeétoiles
label · list-nolabelselectsbriques pour matrices manuelles

8 · Paramètres (parameters)

La colonne parameters reçoit des paires clé=valeur séparées par des espaces :

référence
typeparamètres
rangestart=0 end=10 step=1
textrows=5
imagemax-pixels=1024
audio · background-audioquality=voice-only | low | normal
geopointcapture-accuracy=5 warning-accuracy=10
selectsrandomize=true seed=42
select_*_from_filevalue=coluna label=coluna
auditlocation-priority=balanced location-min-interval=60 location-max-age=120

9 · La feuille settings

référence
colonnerôle
form_titletitre affiché dans l’application
form_ididentifiant unique du formulaire sur le serveur
versionversion (utilisez une date : 2026081101) ; le serveur gère les mises à jour par elle
instance_namenom de chaque envoi dans les listes — ex. concat(${commune}, '-', ${date_visite})
default_languagelangue initiale, ex. Français (fr)
stylepages (un écran par groupe) · theme-grid
public_keyclé RSA pour chiffrer les envois de bout en bout
submission_url · auto_send · auto_deletedestination et politique d’envoi
allow_choice_duplicatesautorise des name répétés dans une liste
clean_text_valuesno préserve les espaces multiples dans les cellules (repliés par défaut)
name · namespaces · attribute::x · prefix · delimiter · flat · omit_instanceIDréglages avancés du XML généré

10 · Données externes et entités

Grandes listes en fichier

survey
typenamelabelchoice_filter
2select_one_from_file communes.csvcommuneCommuneregion = ${region}
3select_one_from_file secteurs.geojsonsecteurSecteur (sur la carte)

Le CSV requiert des colonnes name et label (ou indiquez-en d’autres avec parameters = value=code label=description) ; le GeoJSON utilise id/title et active appearance = map. Le fichier est téléversé avec le formulaire.

Recherches avec pulldata()

survey
typenamecalculation
2calculatecible_secteurpulldata('cibles', 'cible', 'secteur', ${secteur})

Cherche dans cibles.csv la colonne cible de la ligne où secteur = la réponse. Il y a aussi ${last-saved#champ} (valeur du dernier envoi) et la feuille entities, qui permet au formulaire de créer et mettre à jour des registres partagés entre formulaires (ex. enregistrer des ménages lors d’une visite et les retrouver à la suivante) — via save_to sur les questions et create_if/update_if/label sur la feuille.

11 · Erreurs courantes — et comment rxform prévient

12 · Convertir et publier

# convertir
$ rxform enquete_menage.xlsx
enquete_menage.xml

# vérifier les erreurs d’édition = simplement lancer — le message pointe la cellule
$ rxform enquete_menage.xlsx --stdout > /dev/null
  1. KoboToolbox : téléversez le .xlsx lui-même (Kobo convertit côté serveur avec pyxform — rxform produit exactement le même XML, donc il sert de validation locale instantanée) ou déployez le XML via l’API.
  2. ODK Central : publiez le .xlsx ou le .xml généré ; joignez les CSV/GeoJSON des listes externes.
  3. Enketo : les formulaires publiés reçoivent automatiquement un lien web.

Flux recommandé : gardez le .xlsx sous contrôle de version, lancez rxform en CI pour valider chaque changement (la conversion échoue avec un message précis si quelque chose casse) et publiez depuis la version validée.

guide · rxform — retour à l’accueil · référence officielle xlsform.org