# XLSForm Mapping {#xlsform-mapping}


MQUAD is XLSForm-compatible. Every logic feature described in this section
maps to a standard XLSForm column, and importing/exporting an XLSForm file
preserves them. This page documents the mapping and clearly separates
**standard XLSForm behaviour** from **MQUAD-specific extensions**.

---


## Column mapping {#column-mapping}


| MQUAD feature | XLSForm column | Sheet | Example |
|---|---|---|---|
| Validation | `constraint` | survey | `. >= 18` |
| Validation message | `constraint_message` | survey | `Age must be at least 18` |
| Skip logic | `relevant` | survey | `${age} >= 18` |
| Default value | `default` | survey | `#country#res_num` |
| Calculation | `calculation` | survey | `${q1} + ${q2}` |
| Required | `required` | survey | `yes` / `true` |
| Choice filtering | `choice_filter` | survey | see below |
| Extra accepted choices | `additional_values` | survey | `98, 9997` |


### Example survey sheet {#example-survey-sheet}


| type | name | label | required | relevant | constraint | constraint_message | calculation | default |
|---|---|---|---|---|---|---|---|---|
| `date` | `dob` | Date of birth | yes | | | | | |
| `calculate` | `age` | Age | | | | | `age(${dob}, ${interview_date})` | |
| `integer` | `adult_income` | Monthly income | | `${age} >= 18` | `. >= 0` | Income cannot be negative | | |
| `text` | `psu_id` | PSU Identifier | | | | | | `#country#res_num` |
| `select_one` | `satisfaction` | Satisfaction | yes | | | | | |


### Import behaviour {#import-behaviour}


When importing an XLSForm file, MQUAD automatically:

1. **Expands regex shortcuts** — `regex=email` becomes the full
   `regex(., '^...$')` expression.
2. **Corrects common syntax** — bare `&` becomes `and`, bare `|` becomes `or`,
   bare comparisons like `>=10` gain the `.` prefix.
3. **Validates field references** — every `${name}` is checked against existing
   questions.
4. **Detects circular dependencies** — chains like `Q1 → Q3 → Q4 → Q1` are
   flagged and blocked.
5. **Preserves extra columns** — non-standard columns are kept through the
   round-trip.

---


## Standard XLSForm behaviour {#standard-xlsform-behaviour}


The following are standard XLSForm/ODK columns and behave as defined by the
XLSForm specification:

- **`relevant`** — XPath expression controlling visibility (skip logic).
- **`constraint`** — XPath expression that must evaluate true for the answer
  to be accepted.
- **`constraint_message`** — the message shown when the constraint fails.
- **`calculation`** — XPath expression producing a value for `calculate`-type
  questions.
- **`default`** — initial value expression.
- **`required`** — whether an answer is mandatory.
- **`choice_filter`** — filters the choices of a select question based on
  another question's value.

These columns use standard XPath/ODK expression syntax: `and`/`or`/`not()`,
comparison operators, `.` for the current value, and standard ODK functions
like `selected()`, `count-selected()`, `concat()`, `today()`, `now()`,
`if()`, `regex()`, `int()`, `number()`, and so on.

---


## MQUAD-specific extensions {#mquad-specific-extensions}


The following are **MQUAD extensions** — they work inside MQUAD but are not
guaranteed to work in other ODK tools:


### `additional_values` {#additional_values}


An MQUAD extension column on the survey sheet for `select_one` /
`select_multiple` questions. Lists comma-separated extra accepted values beyond
the defined choices (e.g. `98, 9997` for "Don't know" / "Refused"). Values are
deduplicated against the choice list at render time.


### Regex shortcuts {#regex-shortcuts}


Designer-only shortcuts (`Email Format`, `10-Digit Mobile`, `Numbers Only`,
`Money (1 decimal)`, `Letters Only`, `Letters & Numbers`) that expand to full
`regex(., '...')` expressions. On import, a `regex=email` style shortcut
expands automatically.


### MQUAD calculation functions {#mquad-calculation-functions}


The frozen calculation functions are MQUAD extensions. They are not part of
the standard ODK function set:

| Function | Standard ODK? |
|---|---|
| `date-diff`, `date-add`, `date-subtract` | **MQUAD extension** |
| `day`, `month`, `year`, `day-of-week` | **MQUAD extension** |
| `time-diff` | **MQUAD extension** |
| `age`, `age-months`, `age-days` | **MQUAD extension** |
| `gestational-weeks`, `gestational-days`, `gestational-total-days` | **MQUAD extension** |
| `bmi` | **MQUAD extension** |

Standard ODK functions (`selected`, `count-selected`, `concat`, `if`, `today`,
`now`, `days-between`, `duration`, `regex`, `int`, `number`, and the numeric
`sum`/`min`/`max`/`round`/`abs`/`pow`, string `string-length`/`contains`/
`starts-with`/`ends-with`/`replace`/`join`/`string`, `coalesce`, `uuid`,
`random`, `once`, `selected-at`, `count`) map to their standard counterparts.

> A form that uses only standard columns and functions can round-trip through
> other XLSForm tools. A form that uses MQUAD extension functions will still
> work in MQUAD but the extension functions may not be recognized elsewhere —
> plan accordingly if you need to share the form.


### `format-date` format strings {#format-date-format-strings}


MQUAD accepts `%Y %y %m %d %b %B %H %M %S` placeholders (e.g.
`'%d/%m/%Y'`). This is an ODK-style format; other tools may differ in the
details.

---


## Choice constraints (per-choice) {#choice-constraints-per-choice}


Beyond `choice_filter`, MQUAD supports a per-choice `constraint` column in the
**choices** sheet. Each choice whose constraint evaluates false is hidden:

| list_name | name | label | constraint |
|---|---|---|---|
| `score_level` | high | High | `score >= 26` |

The two mechanisms compose: `choice_filter` filters by extra-column values
first, then each choice's constraint is evaluated. A choice is shown only when
both pass. See the [Survey Designer](/user-manual/survey-designer.md) page for the full
details.

---


## Notes on round-tripping {#notes-on-round-tripping}


- MQUAD stores skip logic in the internal format `${age} >= 18 and ${married}
  = 'yes'`. When you export to XLSForm, `relevant` is written in standard
  XPath form, so the file works in other tools.
- The `default` column uses MQUAD's `#reference` grammar on the survey sheet.
  This is MQUAD's own default-value syntax (the standard ODK default grammar
  differs); MQUAD preserves the `#` references it understands.
- `calculate` type rows export with their calculation in the `calculation`
  column.
- `calendar_grid` questions are stored with their configuration in the
  `calculation` column using a `__calendar__:` JSON prefix — an MQUAD-specific
  encoding preserved through round-trips.
