A1  ·  fx  =convert(survey)

Entra una planilla.
Sale un XForm.

rxform convierte los libros XLSForm de cálculo en XML ODK XForm — el formato que hablan ODK Collect, Enketo y KoboToolbox. Una implementación de pyxform en Rust: un binario estático veloz, salida cotejada formulario por formulario contra el original, y errores que señalan la celda exacta.

código fuente ↗
survey.xlsx — sheet survey
type name label
2 select_one yes_no good_day ¿Tuvo un buen día?
3 begin repeat visit Cada visita
4 geopoint spot ¿Dónde está usted?
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

formularios de referencia idénticos a pyxform 4.5.0

100%

de la especificación xlsform.org

65

pruebas que fijan salida y diagnósticos

1

binario estático — sin Python

B7 · cuando el formulario falla

Errores que nombran
la celda, no el stack.

Un error de tipeo en la fila 3 no debería leerse como un informe de crash. Cada error de rxform lleva la hoja, fila y columna donde ocurrió — más una causa probable: el tipo de pregunta más cercano, la lista que seguramente quiso usar, la fila del begin que un end group extraviado olvidó.

  • tipos y ${referencias} mal escritos → “¿quiso decir …?”
  • los grupos sin cerrar señalan su fila begin
  • nombres ambiguos detectados en el punto de uso
  • entities, triggers y listas verificados en 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 · hoja “funciones”

Toda la spec. En una hoja.

Todo lo que figura en xlsform.org se convierte — cada fila fue verificada contra la salida del propio pyxform.

type name label
2 select_one spec question_types Todos los tipos: texto → trazos geo, ranges, medios, códigos de barras, rank, calculate, audit, metadatos
3 begin repeat structure Grupos, repeticiones (+ conteos), loops heredados, table-list, formularios flat — anidados libremente
4 select_multiple langs multilanguage label::Idioma (código), pistas traducidas, medios y mensajes vía <itext>, guidance hints
5 select_one_from_file external_data Selects CSV/XML/GeoJSON, pulldata(), search(), last-saved, select_one_external + itemsets.csv
6 text entities Crear y actualizar entidades: save_to, create_if/update_if, versionado offline
7 calculate logic ${refs} → xpaths, choice_filter en cascada, valores por defecto dinámicos, acciones trigger, randomize
8 note settings Títulos, ids, versiones, estilos, claves de cifrado, namespaces, atributos custom, tags SMS

D4 · bajo el capó

Un pipeline que se puede señalar.

Libro → celdas normalizadas → árbol de preguntas → validación localizada → XML XForm, impreso con las convenciones de pyxform para que las herramientas existentes vean una salida 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 · inicio rápido

CLI o crate. Usted decide.

Binarios precompilados para cada plataforma acompañan cada release de GitHub — Linux (musl estático + .deb), macOS y Windows.

macOS · Homebrew

Debian · Ubuntu

$ sudo dpkg -i rxform_*.deb

descargar el .deb ↗

Windows · Scoop

Donde sea · Cargo

línea de comandos
# instalar una vez
$ cargo install rxform

# convertir — escribe survey.xml junto al archivo
$ rxform survey.xlsx

# o elija el destino / imprima a 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
}