guia completo · pt-BR

Construindo um questionário
do zero, célula por célula.

XLSForm é o padrão que transforma uma planilha comum em um formulário digital completo — com lógica de pulo, validação, GPS, fotos e vários idiomas — pronto para rodar em ODK Collect, KoboToolbox ou Enketo. Este guia constrói uma pesquisa domiciliar passo a passo e documenta todos os tipos de pergunta e configurações, com exemplos que você pode copiar e converter com rxform.

1 · Anatomia de um XLSForm

Um XLSForm é um arquivo .xlsx (ou .xls/.ods) com até três abas principais:

Regras de ouro para a coluna name (vale para perguntas, grupos e opções):

Nomes começam com letra ou _, contêm apenas letras, números, -, _ e . — sem espaços nem acentos. Eles viram os nomes das colunas no seu banco de dados, então prefira renda_mensal a Renda Mensal (R$). O label, por outro lado, é texto livre: acentos, emoji, o que precisar.

2 · O primeiro formulário

O menor formulário útil tem três linhas na aba survey:

survey
typenamelabel
2textentrevistadorNome de quem aplica a pesquisa
3integermoradoresQuantas pessoas moram no domicílio?
4select_one sim_naotem_aguaO domicílio tem água encanada?

A pergunta da linha 4 usa a lista sim_nao, definida na aba choices:

choices
list_namenamelabel
2sim_naosimSim
3sim_naonaoNão

E a aba settings dá identidade ao formulário:

settings
form_titleform_idversion
2Pesquisa Domiciliar 2026pesq_dom_20262026081101

Converta e pronto:

$ rxform pesquisa_domiciliar.xlsx
pesquisa_domiciliar.xml

3 · Todos os tipos de pergunta

Texto e números

survey
typenamelabelhint
2textobservacoesObservações geraisCampo livre
3integeridadeIdade (anos completos)Somente números inteiros
4decimalrendaRenda mensal (R$)Use ponto para centavos
5rangesatisfacaoSatisfação com o transporte0 = péssimo · 10 = ótimo

Datas e horas

survey
typenamelabelappearance
2datedata_visitaData da visita
3datemes_mudancaQuando se mudou?month-year
4timehora_inicioHora de início
5dateTimeagendamentoAgendar retorno para

Aparências úteis para date: month-year, year e no-calendar.

Escolhas e listas

survey
typenamelabelappearance
2select_one escolaridadeescolaridadeEscolaridade do responsávelminimal
3select_multiple servicosservicosQuais serviços chegam à rua?
4rank prioridadesprioridadesOrdene as prioridades do bairro

Colunas extras na aba choices são permitidas e viram dados da opção — a base dos filtros em cascata:

Seleções em cascata (choice_filter)

choices
list_namenamelabeluf
2ufspePernambuco
3ufsrsRio Grande do Sul
4municipiosrecifeRecifepe
5municipiosolindaOlindape
6municipiospoaPorto Alegrers
survey
typenamelabelchoice_filter
2select_one ufsufEstado
3select_one municipiosmunicipioMunicípiouf = ${uf}

No filtro, colunas da lista aparecem pelo nome (uf) e respostas anteriores como ${uf}. Para embaralhar opções: parameters = randomize=true (com seed=42 para ordem reproduzível).

Localização

survey
typenamelabelparameters
2geopointpontoLocalização do domicíliocapture-accuracy=5 warning-accuracy=10
3geotracetrajetoTrajeto até o ponto de ônibus
4geoshapeterrenoContorno do terreno

geopoint captura um ponto (com precisão-alvo em metros via parameters); geotrace, uma linha; geoshape, um polígono fechado.

Mídia e arquivos

survey
typenamelabelappearanceparameters
2imagefoto_fachadaFoto da fachadamax-pixels=1024
3imageassinaturaAssinatura do respondentesignature
4audiorelatoGrave o relatoquality=voice-only
5videovideo_viaVídeo da via
6filecomprovanteAnexe o comprovante (PDF)
7barcodecodigoCódigo de barras do hidrômetro

image com appearance = signature vira campo de assinatura; draw, desenho livre. max-pixels reduz o tamanho das fotos no aparelho.

Notas e confirmações

survey
typenamelabel
2noteaberturaBom dia! Esta pesquisa leva ~15 minutos. As respostas são confidenciais.
3acknowledgeconsentimentoO respondente concorda em participar

Campos invisíveis

survey
typenamecalculation
2calculaterenda_per_capita${renda} div ${moradores}
3hiddenversao_amostra

calculate computa um valor com XPath (funções como if(), concat(), selected(), count(), round()…); hidden guarda um valor preenchível por default ou por integrações.

Metadados — coletados sozinhos

survey
typenamelabel / trigger
2startinicio
3endfim
4todayhoje
5deviceidaparelho
6usernameusuario
7auditaudit
8start-geopointlocal_inicio
9background-audiogravacao
10background-geopointlocal_respostatrigger: ${tem_agua}

4 · Lógica do formulário

Toda a lógica usa ${nome} para referenciar respostas anteriores.

relevant — pular perguntas

survey
typenamelabelrelevant
2select_one sim_naotrabalhaVocê trabalha?
3textocupacaoQual a sua ocupação?${trabalha} = 'sim'
4noteobs_idadeMódulo aplicável a maiores de idade.${idade} >= 18

A pergunta só aparece quando a expressão é verdadeira. Combine condições com and/or; para múltipla escolha use selected(${servicos}, 'agua').

constraint — validar respostas

survey
typenamelabelconstraintconstraint_message
2integeridadeIdade. >= 0 and . <= 120Idade deve estar entre 0 e 120.
3datenascimentoData de nascimento. <= today()A data não pode ser futura.

O ponto . é a própria resposta. A mensagem aparece quando a regra falha.

required, default, read_only

survey
typenamelabelrequiredrequired_messagedefault
2select_one sim_naotem_aguaTem água encanada?yesEsta resposta é obrigatória.
3datedata_visitaData da visitatoday()
4integersetorSetor censitário42

trigger — recalcular quando algo muda

survey
typenamelabeltriggercalculation
2integermoradoresQuantos moradores?
3integercriancasQuantas crianças?${moradores}

Com trigger, o campo é (re)definido sempre que a pergunta referenciada mudar — aqui, limpando criancas quando moradores é alterado. Se houver calculation, ela roda nesse momento (em vez de continuamente).

5 · Grupos, repetições e loops

Grupos

survey
typenamelabelappearancerelevant
2begin_groupmodulo_aguaMódulo: Saneamentofield-list${tem_agua} = 'sim'
3select_one origem_aguaorigemOrigem da água
4integerdias_faltaDias sem água no mês
5end_group

Repetições

survey
typenamelabelrepeat_count
2begin_repeatmoradorDados do morador${moradores}
3textnomeNome
4integeridade_moradorIdade
5end_repeat

O bloco se repete uma vez por morador. Sem repeat_count, o entrevistador adiciona repetições manualmente; com uma expressão (ou número fixo), a quantidade é automática. Dentro da repetição, use position(..) para saber o índice atual e indexed-repeat() para ler valores de outra repetição.

Loops sobre uma lista

survey
typenamelabel
2begin loop over servicosaval_servicos
3select_one notasnotaComo avalia o serviço de %(label)s?
4end loop

Gera um bloco por opção da lista servicos, substituindo %(label)s e %(name)s pelo rótulo/nome de cada opção — uma pergunta “Como avalia o serviço de Água?”, outra “…de Esgoto?”, e assim por diante.

6 · Múltiplos idiomas

survey
typenamelabel::Português (pt)label::English (en)hint::Português (pt)
2integermoradoresQuantas pessoas moram aqui?How many people live here?Conte todos os residentes

Basta sufixar as colunas traduzíveis com ::Idioma (código): funciona para label, hint, guidance_hint, constraint_message, required_message, image, audio e video — nas abas survey e choices. Defina o idioma inicial em settingsdefault_language = Português (pt). O aplicativo ganha um menu para alternar idiomas.

Mídia por pergunta: as colunas image/audio/video associam arquivos (ex.: cartao_resposta.jpg) enviados junto com o formulário.

7 · Aparências (appearance)

referência
appearancevale paraefeito
minimalselect_one/multiplemenu suspenso compacto
quickselect_oneavança ao selecionar
likertselect_oneescala horizontal estilo Likert
columns / columns-nselectsopções em colunas
autocompleteselect_onebusca conforme digita
field-listgruposgrupo inteiro numa tela
table-listgruposmatriz de selects com a mesma lista
multilinetextcaixa de várias linhas
numbers / thousands-septextteclado numérico · separador de milhar
month-year · year · no-calendardateprecisão reduzida · sem calendário
signature · draw · annotateimageassinatura · desenho · anotar sobre foto
map · quick mapselect_one_from_file (geojson)escolha no mapa
ratingrangeestrelas
label · list-nolabelselectspeças para montar matrizes manuais

8 · Parâmetros (parameters)

A coluna parameters recebe pares chave=valor separados por espaço:

referência
tipoparâmetros
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 · A aba settings

referência
colunapara quê
form_titletítulo exibido no aplicativo
form_ididentificador único do formulário no servidor
versionversão (use data: 2026081101); o servidor gerencia atualizações por ela
instance_namenome de cada envio na listagem — ex.: concat(${municipio}, '-', ${data_visita})
default_languageidioma inicial, ex.: Português (pt)
stylepages (uma tela por grupo) · theme-grid
public_keychave RSA para criptografar envios de ponta a ponta
submission_url · auto_send · auto_deletedestino e política de envio
allow_choice_duplicatespermite name repetido numa lista
clean_text_valuesno preserva espaços múltiplos nas células (padrão colapsa)
name · namespaces · attribute::x · prefix · delimiter · flat · omit_instanceIDajustes avançados do XML gerado

10 · Dados externos e entities

Listas grandes em arquivo

survey
typenamelabelchoice_filter
2select_one_from_file municipios.csvmunicipioMunicípiouf = ${uf}
3select_one_from_file setores.geojsonsetorSetor (no mapa)

O CSV precisa de colunas name e label (ou indique outras com parameters = value=codigo label=descricao); GeoJSON usa id/title e habilita appearance = map. O arquivo é enviado ao servidor junto com o formulário.

Consultas com pulldata()

survey
typenamecalculation
2calculatemeta_setorpulldata('metas', 'meta', 'setor', ${setor})

Busca em metas.csv a coluna meta da linha em que setor = resposta. Há ainda ${last-saved#campo} (valor do último envio salvo) e a aba entities, que permite ao formulário criar e atualizar cadastros compartilhados entre formulários (ex.: cadastrar domicílios numa visita e reencontrá-los na seguinte) — com save_to nas perguntas e create_if/update_if/label na aba.

11 · Erros comuns — e como o rxform avisa

12 · Converter e publicar

# converter
$ rxform pesquisa_domiciliar.xlsx
pesquisa_domiciliar.xml

# conferir erros de autoria é só rodar — a mensagem aponta a célula
$ rxform pesquisa_domiciliar.xlsx --stdout > /dev/null
  1. KoboToolbox: você pode subir o próprio .xlsx (o Kobo converte no servidor com pyxform — o rxform gera exatamente o mesmo XML, então serve como validação local instantânea) ou implantar o XML via API.
  2. ODK Central: publique o .xlsx ou o .xml gerado; anexe os CSVs/GeoJSON de listas externas.
  3. Enketo: os formulários publicados ganham link web automaticamente.

Fluxo recomendado: mantenha o .xlsx no controle de versão, rode rxform no CI para validar cada mudança (a conversão falha com mensagem precisa se algo quebrar) e publique a partir da versão validada.

guia · rxform — voltar ao início · referência oficial xlsform.org