A1  ·  fx  =convert(survey)

Planilha entra.
XForm sai.

rxform converte planilhas XLSForm em XML ODK XForm — o formato que ODK Collect, Enketo e KoboToolbox entendem. Uma implementação do pyxform em Rust: um binário estático rápido, saída conferida formulário a formulário contra o original, e mensagens de erro que apontam a célula exata.

código-fonte ↗
survey.xlsx — sheet survey
type name label
2 select_one yes_no good_day Teve um bom dia?
3 begin repeat visit Cada visita
4 geopoint spot Onde você está?
form.xml — ODK XForm
<select1 ref="/data/good_day">
  <itemset nodeset="instance('yes_no')/root/item">
    <value ref="name"/>
  </itemset>
</select1>
<repeat nodeset="/data/visit">…</repeat>
<bind type="geopoint" nodeset="/data/visit/spot"/>

34/34

formulários de referência idênticos ao pyxform 4.5.0

100%

da especificação xlsform.org

65

testes fixando saída e diagnósticos

1

binário estático — sem Python

B7 · quando o formulário quebra

Erros que nomeiam
a célula, não a stack.

Um erro de digitação na linha 3 não deveria parecer um relatório de crash. Todo erro do rxform carrega a aba, linha e coluna onde aconteceu — mais a causa provável: o tipo de pergunta mais próximo, a lista que você provavelmente quis usar, a linha do begin que um end group perdido esqueceu.

  • tipos e ${referências} com typo → “você quis dizer …?”
  • grupos sem fechar apontam a linha do begin
  • nomes ambíguos pegos no ponto de uso
  • entities, triggers e listas verificados em cruzado
terminal
$ rxform household_survey.xlsx
error: [sheet 'survey', row 12, column 'type'] unknown question type 'selct_one districts'
  probable cause: did you mean 'select_one'?

$ rxform household_survey.xlsx
error: [sheet 'survey', row 48, column 'relevant'] '${distrct}' does not match
the name of any question or group
  probable cause: did you mean 'district'?

$ rxform household_survey.xlsx
household_survey.xml

C2 · aba “recursos”

A especificação inteira. Numa aba.

Tudo que está em xlsform.org converte — cada linha abaixo foi verificada contra a saída do próprio pyxform.

type name label
2 select_one spec question_types Todos os tipos: texto → traçados geo, ranges, mídia, códigos de barras, rank, calculate, audit, metadados
3 begin repeat structure Grupos, repetições (+ contagens), loops legados, table-list, formulários flat — aninhados à vontade
4 select_multiple langs multilanguage label::Idioma (código), hints traduzidos, mídia e mensagens via <itext>, guidance hints
5 select_one_from_file external_data Selects de CSV/XML/GeoJSON, pulldata(), search(), last-saved, select_one_external + itemsets.csv
6 text entities Criar e atualizar cadastros (entities): save_to, create_if/update_if, versionamento offline
7 calculate logic ${refs} → xpaths, choice_filter em cascata, defaults dinâmicos, ações de trigger, randomize
8 note settings Títulos, ids, versões, estilos, chaves de criptografia, namespaces, atributos custom, tags SMS

D4 · por dentro

Um pipeline que dá para apontar.

Planilha → células normalizadas → árvore de perguntas → validação com localização → XML XForm, impresso nas convenções do pyxform para o ferramental existente ver uma saída familiar.

rxform pipeline: xlsx workbook through parser, validation and generator to XForm XML
Mapping from XLSForm sheets to the parts of the generated XForm document

E9 · começo rápido

CLI ou crate. Você escolhe.

Binários prontos para toda plataforma acompanham cada release no GitHub — Linux (musl estático + .deb), macOS e Windows.

macOS · Homebrew

Debian · Ubuntu

$ sudo dpkg -i rxform_*.deb

baixar o .deb ↗

Windows · Scoop

Qualquer lugar · Cargo

linha de comando
# instalar uma vez
$ cargo install rxform

# converter — escreve survey.xml ao lado do arquivo
$ rxform survey.xlsx

# ou escolha o destino / imprima no stdout
$ rxform survey.xlsx -o out/form.xml
$ rxform survey.xlsx --stdout
biblioteca — docs.rs/rxform
// cargo add rxform
use std::path::Path;

let conversion = rxform::convert(Path::new("survey.xlsx"))?;
std::fs::write("form.xml", &conversion.xml)?;

if let Some(csv) = conversion.itemsets_csv {
    std::fs::write("itemsets.csv", csv)?; // selects externos
}