| Title: | 'LimeSurvey' '.lss' Questionnaires to and from Word Documents |
| Version: | 0.3.0 |
| Description: | Turn a 'LimeSurvey' '.lss' survey export into a publication-quality questionnaire document in Word ('.docx') or PDF, with up to four of the survey's own languages side by side. Every label the package adds around that content – column headers, type names, the audit section – is written in English, French, German, Spanish or Italian, whatever the survey languages are. A rule-based audit flags missing translations, forward filter references, duplicate codes, array-scale inconsistencies and orphan structural references. Questionnaires travel the other way too: describe one in R, or fill in a Word form, and write a '.lss' file ready to import. Meant for the people who work on questionnaires – researchers, methodologists, ethics committees, translators and reviewers – and fully local: the source file is the only input, and no questionnaire content is uploaded to a third-party service. |
| License: | MIT + file LICENSE |
| Encoding: | UTF-8 |
| Language: | en-US |
| Depends: | R (≥ 4.1) |
| Imports: | cli, lifecycle, rlang, xml2 |
| Suggests: | flextable, knitr, officer, rmarkdown, testthat (≥ 3.0.0), zip |
| VignetteBuilder: | knitr |
| Config/testthat/edition: | 3 |
| URL: | https://amaltawfik.github.io/lssdoc/, https://github.com/amaltawfik/lssdoc |
| BugReports: | https://github.com/amaltawfik/lssdoc/issues |
| Config/roxygen2/version: | 8.1.0 |
| NeedsCompilation: | no |
| Packaged: | 2026-09-16 07:00:19 UTC; at |
| Author: | Amal Tawfik |
| Maintainer: | Amal Tawfik <amal.tawfik@hesav.ch> |
| Repository: | CRAN |
| Date/Publication: | 2026-09-16 08:40:02 UTC |
lssdoc: 'LimeSurvey' '.lss' Questionnaires to and from Word Documents
Description
Turn a 'LimeSurvey' '.lss' survey export into a publication-quality questionnaire document in Word ('.docx') or PDF, with up to four of the survey's own languages side by side. Every label the package adds around that content – column headers, type names, the audit section – is written in English, French, German, Spanish or Italian, whatever the survey languages are. A rule-based audit flags missing translations, forward filter references, duplicate codes, array-scale inconsistencies and orphan structural references. Questionnaires travel the other way too: describe one in R, or fill in a Word form, and write a '.lss' file ready to import. Meant for the people who work on questionnaires – researchers, methodologists, ethics committees, translators and reviewers – and fully local: the source file is the only input, and no questionnaire content is uploaded to a third-party service.
Example surveys
Two example .lss files ship with the package and are reachable with
base::system.file(), so every reader can reproduce the examples and
the Get started vignette without supplying their own LimeSurvey
export:
-
demo_survey.lss– a clean, synthetic four-language survey (English, French, German, Spanish) with quotas and a consent block:system.file("extdata", "demo_survey.lss", package = "lssdoc"). -
audit_demo.lss– a deliberately flawed survey seeded with every anomalyaudit_lss()detects:system.file("extdata", "audit_demo.lss", package = "lssdoc").
Author(s)
Maintainer: Amal Tawfik amal.tawfik@hesav.ch (ORCID) (ROR) [copyright holder]
Authors:
Amal Tawfik amal.tawfik@hesav.ch (ORCID) (ROR) [copyright holder]
See Also
Useful links:
Report bugs at https://github.com/amaltawfik/lssdoc/issues
Turn a parsed LimeSurvey survey into an authoring specification
Description
Usage
as_lss_spec(lss, strict = TRUE)
Arguments
lss |
An |
strict |
Logical. |
Details
Experimental. Convert an lss object – a real LimeSurvey export
read by read_lss() – into the lss_spec() object the authoring side of
the package works with. It is the entry point for modifying an existing
questionnaire: read the .lss a colleague sends, render it as the Word
authoring form with write_form_docx(), let the author edit the form, and
hand the result back to read_form_docx() and write_lss().
The conversion is deliberately narrower than the file it reads. An lss
object is whatever LimeSurvey exported; an lss_spec is what lssdoc can
author and re-emit. Everything in between is reported: refused outright
(strict = TRUE) or dropped with a warning (strict = FALSE). Nothing is
ever lost in silence.
Value
An lss_spec() object.
What is converted
-
Kinds: the LimeSurvey type letter maps to the authoring kind through the kind table (
lss_kindsin the sources). A question theme other than the authorable one is replaced by it and reported. -
Texts: survey title, welcome and end text, group titles and descriptions, question wordings and help, option, row and column labels, the "other" label and the quota name and message, each taken per language from the
*_l10nstables. HTML is flattened to plain text – paragraphs and<br>become line breaks, inline marks are dropped – and every field that really carried markup is named in the lossy warning. -
Languages: all the survey's languages, the base language (
surveys.language) first, aslss_spec()requires. A text missing in a language is filled from the base language and reported: real exports do have missing translations – that is whataudit_lss()flags – and the author fixes them in the form. A text missing in the BASE language but present in another is filled the other way round, and the report names the direction ("help of question Q1 [fr, from en]"), so the translations a survey drafted in another language already has are never thrown away. -
Structure: options, rows and columns from
answersandsubquestions; the native "other" option fromother = "Y"andother_replace_text; exclusive options fromexclude_all_others; the cap frommax_answers; the "other" position fromother_positionandother_position_code. Every other question attribute passes through unchanged into the question'sattributes. -
Filters: the three equations
write_lss()emits –Q.NAOK == "1",(Q.NAOK == "1" or Q.NAOK == "-oth-")andcount(Q_1.NAOK, ...) >= n– are translated back intoQ = 1,Q in [1, autre]andcount(Q) >= n, with or without.NAOK. -
Quotas: a single-member quota with the terminate action becomes a
code = valuecondition on its question – on any kind holding a single coded answer, the implicit scales included, so a quota on the gender question (M/F) converts like a quota on a declared option code.
What is refused
Each of the following is one row of the unconvertible report (question code, item, reason), and all of them are listed at once:
a question whose type is not authorable – the eight deferred LimeSurvey types (
P,H,1,;,:,*,|,I) and any unknown one;a question code that is not a spec code, or a duplicate of an earlier one;
a question or option with no wording in the base language, or a shape the
lss_spec()validator refuses (too few options, an array without rows or columns, a cap larger than the option list);a display condition in any other form than the three above – a hand-written equation is never guessed at;
a quota combining several questions, built on a question the spec cannot target, or carrying an action other than "terminate";
a group with no title in the base language (its questions go with it), and a question belonging to no group at all;
a question storing rows on a second answer scale, or in a section its type does not carry: the shape on file is not the shape lssdoc emits, and half an option list is not a smaller option list;
a structural column carrying something a specification has no field for and
write_lss()would silently replace by its own constant, where that changes what the respondent meets: a group display equation (groups.grelevance) or randomization, a per-subquestion relevance (an array filter), a validation regex (preg), per-question JavaScript (question_l10ns.script), encrypted storage (encrypted). The columns that change nothing a respondent sees – assessment values,same_default,modulename,same_script, a quota URL description – are noted in the lossy warning instead;a multilingual survey that does not declare its base language: a specification's first language IS its base language, and
<languages>lists the base one last.
See Also
read_lss(), lss_spec(), write_form_docx(), write_lss().
Examples
# The bundled flawed survey uses LimeSurvey question types lssdoc does
# not author yet, and a filter it cannot express, so it converts only in
# the permissive mode -- which names everything it had to drop.
flawed <- system.file("extdata", "audit_demo.lss", package = "lssdoc")
spec <- suppressWarnings(as_lss_spec(read_lss(flawed), strict = FALSE))
spec
Audit a LimeSurvey survey for reviewable anomalies
Description
Inspect a LimeSurvey survey and flag anomalies that can be detected without any AI. The audit guides a human reviewer; it does not silently correct anything. Every finding names a precise location and a severity.
Usage
audit_lss(input)
Arguments
input |
Either a path to a |
Details
Checks performed:
-
Missing translations – a question, help, answer, or subquestion text present in at least one language but empty in another.
-
Empty in all languages – a translatable text empty in every language.
-
Duplicate codes – a question variable code repeated in the survey, or an answer/subquestion code repeated within one question.
-
Whitespace in codes – a question, subquestion or answer code containing leading, trailing or interior whitespace (likely a typo; causes subtle bugs in the data export).
-
Missing options for the type – a question whose type requires answer options or subquestions but has none (per the type taxonomy).
-
Forward filter references – a relevance expression that names a variable appearing at or after the filtered question (the value is not yet collected when the filter is evaluated).
-
Array-scale inconsistencies – an array (single or dual) whose subquestions reference a
scale_idthat has no answer options, or vice versa. -
Orphan references – a subquestion or answer pointing to a question that does not exist.
Value
An object of class lss_audit: a list with file,
languages, summary counts, and a findings data frame
(severity, check, location, language, message). It has
a print() method and an as.data.frame() method.
See Also
render_audit() to write the same findings to a Word or
PDF document.
Examples
# A deliberately flawed demo survey ships with the package, seeded
# with every anomaly the audit detects.
demo <- system.file("extdata", "audit_demo.lss", package = "lssdoc")
audit_lss(demo)
Report every problem of a Word authoring form at once
Description
Usage
check_form_docx(path)
## S3 method for class 'lss_form_check'
print(x, ..., n = 20L)
Arguments
path |
Character. Path of the |
x |
An |
... |
Ignored. |
n |
Maximum number of problems to print; |
Details
Experimental. Run read_form_docx()'s parser in dry-run mode: an
author iterates on a form until it is clean, and fixing one problem per
round trip is not a workflow. The same rules, the same messages; the first
error simply does not stop the read.
A problem in one block does not hide the problems of the next: parsing resumes at the following block. Three problems are still fatal, because nothing can be read past them: an unreadable file, a missing or unsupported contract version, and a document-wide structural refusal (tracked changes, content controls). When one of those fires it is the only row reported.
Value
An object of class lss_form_check: a data frame with one row per
problem and the columns severity ("error" or "warning"), class
(the condition class), block, code, field and message. Zero rows
means the document reads: read_form_docx() will return a specification.
A print() method summarizes it.
See Also
read_form_docx(), write_form_docx(), lss_template_docx().
Examples
if (requireNamespace("officer", quietly = TRUE) &&
requireNamespace("flextable", quietly = TRUE)) {
form <- tempfile(fileext = ".docx")
lss_template_docx(form, lang = "fr", kinds = c("single", "text"))
check_form_docx(form)
}
Build and validate a survey specification
Description
Usage
lss_spec(
title,
groups,
languages = NULL,
language = NULL,
welcome = NULL,
end_text = NULL,
quotas = NULL
)
Arguments
title |
Character. Survey title shown to respondents. |
groups |
List of groups. Each group is a list with |
languages |
Character vector of language codes, the primary
language first (e.g. |
language |
Character. Backward-compatible alias for a
single-language survey: |
welcome |
Character vector of welcome-text paragraphs, or a single
string starting with |
end_text |
Character vector of end-page paragraphs, or a single
string starting with |
quotas |
List of end-of-survey quotas. Each element is a list with
|
Details
Experimental. Assemble a survey specification – the
authoring-side counterpart of the lss object – that write_lss()
can turn into an importable LimeSurvey .lss file. The specification
is validated in depth at construction time, because LimeSurvey itself
imports silently: a mistyped attribute, a filter referencing a missing
answer code, or a cap larger than the option list are all accepted on
import and only surface once respondents hit them.
Each question is a list with fields:
-
code– stable technical code (letters then letters/digits, at most 20 characters), unique across the survey. Codes become variable names in the data and are pinned once fieldwork starts. -
kind– the question type. Choice kinds:"single"(radio list),"dropdown","singlecomment"(list with comment),"multiple","ranking". Array kinds:"array"(rows and columns),"array5","array10","arrayyesno","arraytrend"(rows only, the scale is implicit). Item batteries:"multitext","multinumeric"(one field per option). Scalar kinds:"text","shorttext","hugetext","numeric","date","yesno"(implicit Y/N),"gender"(implicit M/F),"fivepoint"(implicit 1-5). Plus"display"(text shown without input). Every kind maps to a LimeSurvey type attested by real exports; eight further LimeSurvey types are deferred, each with its own reason, inlss_kinds_deferredin the sources. -
text– the question wording.mandatory– logical, defaultFALSE.help– optional help text shown under the wording. -
options– for every kind that takes an option list (single,dropdown,singlecomment,multiple,ranking,multitext,multinumeric): list of options, each a list withtextand optionallycode,other = TRUE(native LimeSurvey "other" with a free-text field;single,dropdownandmultipleonly) andexclusive = TRUE(multipleonly; unchecks every other box). Options without acodeare numbered1..nin order, skipping theotheroption, which LimeSurvey codes natively. An explicit code is letters and digits, and its length follows the table LimeSurvey stores the list in: 5 characters for a list emitted as answers (single,dropdown,singlecomment,rankingoptions, andarraycolumns –answers.codeis avarchar(5)), 20 characters for a list emitted as subquestions (multiple,multitext,multinumericoptions, andarrayand implicit-scale array rows –questions.titleis avarchar(20), the same column as a question code). -
rows/columns– forarray: the subquestions and the answer scale, same shape asoptions. -
relevance– display condition in a minimal syntax:code = 1,code in [1, 2, autre],count(code) >= 2(at least n boxes ticked in a multiple-choice question). The keywordautredesignates the native "other" option. Conditions may only reference questions defined earlier in the survey. -
max_answers– cap formultiple(strictly below the number of options) andranking(at most the number of items). -
other_position– where the "other" option is displayed:"end"(LimeSurvey default),"beginning", or"specific"together withother_position_code, the code of the option AFTER which "other" appears. In practice "other" usually belongs before the "none of the above"-type exclusive options, which the default position puts it after. -
attributes– optional named list of extra question attributes passed through verbatim (e.g.display_columns). A name LimeSurvey stores per language (prefix,suffix,choice_title,printable_help, ...) is emitted once per declared language bywrite_lss(), and may be given either as one string for every language or keyed by language code.
Value
An object of class lss_spec: the validated specification with
normalized questions (auto-numbered option codes filled in).
Languages
languages declares the survey languages, the primary one first;
languages[1] is the base language write_lss() emits, and every other
declared language is written alongside it. Every localizable
text – survey title, welcome and end texts, group titles, question
texts and help, option, row and column labels, the "other" label, quota
names and messages – accepts either a plain string (read as the
primary language) or a named character vector or list keyed by language
code:
lss_spec(
title = c(fr = "Enquete", en = "Survey"),
languages = c("fr", "en"),
groups = list(list(
title = c(fr = "Profil", en = "Profile"),
questions = list(list(
code = "q1", kind = "yesno",
text = c(fr = "Etes-vous d'accord ?", en = "Do you agree?")))))
)
The spec keeps one canonical form (a named list over the declared
languages) and is strict: as soon as several languages are declared,
every text must supply every one of them. A missing translation is
precisely what audit_lss() flags when reading a .lss, so the spec
refuses to author one. write_lss() writes every declared language:
languages[1] becomes the survey's base language and the others its
additional languages, each localized section carrying one row per
language.
See Also
write_lss() to emit the .lss file, read_lss() and
audit_lss() to read it back and check it.
Examples
spec <- lss_spec(
title = "Demo",
languages = "fr",
groups = list(list(
title = "Profil",
questions = list(
list(code = "consent", kind = "single", text = "Participez-vous ?",
mandatory = TRUE,
options = list(list(text = "Oui"), list(text = "Non"))),
list(code = "raisons", kind = "multiple", text = "Pourquoi ?",
relevance = "consent = 1", max_answers = 2,
options = list(
list(text = "Une raison"), list(text = "Une autre"),
list(text = "Encore une"),
list(text = "Aucune raison", exclusive = TRUE),
list(text = "Autre raison", other = TRUE)))
)
))
)
spec$groups[[1]]$questions[[2]]$options[[4]]$code
Write a blank Word template for authoring a questionnaire
Description
Usage
lss_template_docx(path, lang = "fr", kinds = lss_kinds$kind, languages = lang)
Arguments
path |
Character. Path of the |
lang |
Language of the template's labels and example wording, one of
|
kinds |
Character vector of kinds to illustrate, |
languages |
Content languages of the questionnaire to be written,
the first one being the primary language. Defaults to |
Details
Experimental. Generate the blank authoring form: one example
question per requested kind, every default pre-filled, and a muted hint
under each key telling the author the syntax the field expects. The
template is always generated from the kind table – the package ships
no static .docx – so it cannot describe a field lss_spec() would
refuse.
Delete the example questions you do not need, edit the others, then hand
the file to the reader (0.3.0) to obtain an lss_spec() and, through
write_lss(), a .lss file LimeSurvey imports.
The template is the render of a generated example specification, so the
same object feeds the template, the tests and the vignette. The value of a
Type row is always the spec kind (single, array5, ...); the localized
type label is shown as the hint under the key, because it is many-to-one
and could not be read back. Reserved words
are localized: an option line reading Autre in a French template creates
the native other option, and an ordinary option that happens to read
"Autre" is written with an explicit code (9 = Autre) – which the hint
under the Options key spells out.
Requires the suggested packages officer and flextable.
Value
Invisibly, the path to the written file.
See Also
write_form_docx() to render an existing specification,
lss_spec(), write_lss().
Examples
if (requireNamespace("officer", quietly = TRUE) &&
requireNamespace("flextable", quietly = TRUE)) {
out <- tempfile(fileext = ".docx")
lss_template_docx(out, lang = "fr", kinds = c("single", "multiple"))
file.exists(out)
# A bilingual questionnaire, with French labels on the form itself.
both <- tempfile(fileext = ".docx")
lss_template_docx(both, lang = "fr", languages = c("fr", "en"),
kinds = "single")
file.exists(both)
}
Print an lss_audit object
Description
Pretty-printed audit summary on the console, capped at the first
n findings. Severity-based bullet symbols (errors, warnings,
notes) mirror what is shown in the audit table inside the
rendered .docx.
Usage
## S3 method for class 'lss_audit'
print(x, ..., n = 20L)
Arguments
x |
An |
... |
Currently ignored. |
n |
Maximum number of findings to print. Defaults to |
Value
The audit object, invisibly.
Read a Word authoring form back into a survey specification
Description
Usage
read_form_docx(path)
Arguments
path |
Character. Path of the |
Details
Experimental. Parse a .docx authoring form – the document
write_form_docx() and lss_template_docx() produce, filled in by an
author in Word – back into an lss_spec(), ready for write_lss() and a
LimeSurvey import. The round trip is exact: a specification written as a
form and read back describes the same survey.
Reading needs no suggested package: only xml2 and utils::unzip(),
so an author's file can be turned into a .lss on a bare installation.
officer and flextable are needed to WRITE a form, never to read
one.
The contract the document must honor – all of it written by
write_form_docx(), and spelled out in the blank template's hints:
one top-level two-column table per block (Survey, Group, Question, Quota), the key on the left and the value on the right; the first row of a block names it, and a title row starts a new block even in the middle of a table (pasting a block makes Word merge two tables).
keys are matched by their TEXT, ignoring case, accents, quotes and a trailing colon, against the labels of all five chrome languages, so a French author can fill an English template. Only the first line of a key cell is read: the muted hints under the key are ignored.
a value cell holds one value per line, where a line is a paragraph or a soft return (Enter or Shift+Enter). Options, rows and columns are read as
code = label, or as a bare label that gets auto-numbered; the reserved word (Other,Autre,Sonstiges,Otro,Altro) alone or on the left of=is the native other option.the Type cell carries the kind code (
single,array5, ...); a localized type label is accepted only when it names exactly one kind.-
Mandatorytakes the yes/no words of any language (andy/n,true/false,1/0); blank means no. TheFiltercell takes the mini-language oflss_spec()(Q1 = 1,Q2 in [1, autre],count(Q3) >= 2); its keywords are matched whatever Word capitalized, and the case of a question or answer code is never changed. when the survey declares several languages, every localizable key is suffixed with a language code –
Wording [fr],Wording [en]– and every declared language must supply every text.the file must carry the custom document property
lssdoc-template-version: it is the reader's proof that the document agreed to this contract. Tracked changes, content controls, merged cells, a third column, a nested table and Word's automatic list numbering are each refused with a classed error naming the block and the field.
Errors carry the class lssdoc_bad_form plus one leaf class
(lssdoc_bad_form_file, _marker, _layout, _block, _key, _value,
_spec), and every message names the block, the question code and the
field. Use check_form_docx() to list every problem of a document at once
instead of stopping at the first.
Value
An lss_spec() object.
See Also
write_form_docx() and lss_template_docx() to write the form,
check_form_docx() for a dry run, lss_spec(), write_lss().
Examples
if (requireNamespace("officer", quietly = TRUE) &&
requireNamespace("flextable", quietly = TRUE)) {
form <- tempfile(fileext = ".docx")
lss_template_docx(form, lang = "fr", kinds = c("single", "text"))
spec <- read_form_docx(form)
spec
}
Read a LimeSurvey .lss file
Description
Read a LimeSurvey survey structure export (.lss, an XML file) and turn
it into a structured lss object that the rest of the package can
audit (audit_lss()) and render (render_questionnaire(),
render_audit()). Parsing is fully local: the file is never uploaded
anywhere.
Usage
read_lss(file)
Arguments
file |
Character. Path to a |
Details
The .lss format is a LimeSurvey XML export. Since DBVersion 4xx/7xx
the translatable text lives in dedicated localization sections
(*_l10ns), keyed by language, while the structural sections hold
identifiers and settings. read_lss() reads every section into a tidy
data frame without mutating any user-facing identifier or text. A
field that is present but empty (e.g. <help/>) is read as ""; a
field that is absent from a row is read as NA.
Failure is graceful by construction: a malformed, truncated, or
non-UTF-8 file is refused in R with a classed lssdoc_invalid_xml
error before or instead of any libxml2 diagnostic, and the parser is
never allowed to fetch an external DTD or entity over the network.
Value
An object of class lss: a list with the survey languages,
metadata, and one data frame per .lss section. Structural sections
(surveys, groups, questions, subquestions, answers,
question_attributes, conditions) stay separate from the
localized text sections (survey_language_settings, group_l10ns,
question_l10ns, answer_l10ns), which carry the per-language
titles, labels, and help texts. All values are read verbatim as
character.
Examples
# A synthetic four-language demo survey ships with the package.
demo <- system.file("extdata", "demo_survey.lss", package = "lssdoc")
lss <- read_lss(demo)
lss$languages
Render the audit as a focused Word or PDF document
Description
Build a short, action-oriented document containing only the audit findings: the same cover page as the full questionnaire document, summary counts, then one table per severity (errors, warnings, notes) listing every finding with its location and message. Use it for QA follow-up or to share issues with a colleague without distributing the full questionnaire.
Usage
render_audit(
input,
output,
languages = NULL,
logo = NULL,
logo_width = 1.5,
logo_height = 0.75,
font = NULL,
font_code = NULL,
colors = NULL,
authors = NULL,
description = NULL,
chrome_lang = NULL
)
Arguments
input |
Either a path to a |
output |
Character. Path to the file to create. The extension
determines the output format: |
languages |
Character vector of language codes used on the
cover page. |
logo |
Optional path (character) to a PNG or JPEG image
displayed at the top of the cover page. |
logo_width, logo_height |
Image dimensions in inches. Defaults
|
font |
Optional body font name (character). |
font_code |
Optional monospace font (character) used for
code-like content (variable codes, raw expressions). |
colors |
Optional named list of hex color overrides for the
editorial petrol-blue palette. |
authors, description |
Optional cover-page credit block
( |
chrome_lang |
Language used for the document chrome (column
headers, row labels, audit section). One of |
Value
The output path, invisibly.
See Also
audit_lss() to inspect the same findings in the console;
render_questionnaire() for the full questionnaire document.
Examples
## Not run:
# One-shot (path -> .docx)
render_audit(
system.file("extdata", "demo_survey.lss",
package = "lssdoc"),
tempfile(fileext = ".docx")
)
# PDF output -- same call, just pass a .pdf path
render_audit("survey.lss", "qa.pdf")
## End(Not run)
Render a LimeSurvey questionnaire to a Word or PDF document
Description
Build a professional questionnaire document from a LimeSurvey survey,
displaying up to four languages side by side. Each question becomes a
compact flextable with a meta header (variable code, type, mandatory,
filter) shown once, language column headers, the question text per
language, and the subquestion or answer-option rows underneath – codes
on the left, labels per language on the right. Headings, a metadata
cover page, an optional table of contents, and an optional audit summary
tie the document together. Rendering uses the suggested packages
officer and flextable; both must be installed.
Usage
render_questionnaire(
input,
output,
languages = NULL,
template = c("cards", "table"),
layout = c("auto", "side-by-side", "stacked"),
show_audit = TRUE,
show_help = TRUE,
show_attrs = c("prefix", "suffix", "other_replace_text", "validation"),
show_technical_attrs = FALSE,
page_format = c("auto", "A4-portrait", "A4-landscape", "A3"),
show_toc = TRUE,
show_index = TRUE,
show_quotas = TRUE,
show_header_title = TRUE,
show_source = TRUE,
show_item_heading = FALSE,
show_raw_filter = FALSE,
show_groups = TRUE,
show_welcome = TRUE,
show_endtext = TRUE,
show_description = TRUE,
show_consent = TRUE,
show_privacy_settings = FALSE,
show_admin_settings = FALSE,
title = NULL,
logo = NULL,
logo_width = 1.5,
logo_height = 0.75,
font = NULL,
font_code = NULL,
colors = NULL,
authors = NULL,
description = NULL,
chrome_lang = NULL,
variable_names = c("brackets", "underscore"),
base_size = 10L
)
Arguments
input |
Either a path to a |
output |
Character. Path to the file to create. The extension
determines the output format: |
languages |
Character vector of language codes to display,
in the order they will appear as columns. |
template |
Output style. One of
|
layout |
Reserved for future use. Currently |
show_audit |
Logical. If |
show_help |
Logical. If |
show_attrs |
Character vector of question attributes to surface
under the question text when present. Default keeps the attributes
that change how respondents see the item: |
show_technical_attrs |
Logical. If |
page_format |
Page format. One of |
show_toc |
Logical. If |
show_index |
Logical. If |
show_quotas |
Logical. If |
show_header_title |
Logical. If |
show_source |
Logical. If |
show_item_heading |
Logical. If |
show_raw_filter |
Logical. If |
show_groups |
Logical. If |
show_welcome |
Logical. If |
show_endtext |
Logical. If |
show_description |
Logical. If |
show_consent |
Logical. If |
show_privacy_settings |
Logical. If |
show_admin_settings |
Logical. If |
title |
Optional override of the survey title shown on the
cover and the top-right header. |
logo |
Optional path (character) to a PNG or JPEG image
displayed at the top of the cover page. |
logo_width, logo_height |
Image dimensions in inches.
Defaults |
font |
Optional body font name (character). |
font_code |
Optional monospace font name (character) used
for code-like content: the variable column in each meta table,
the raw relevance expression under each filter cell, and the
variable index entries. |
colors |
Optional named list of hex color overrides for the
editorial petrol-blue palette. |
authors |
Optional credit block for the questionnaire's
designers, displayed on the cover page below the subtitle.
Each author is shown centered on its own line as
|
description |
Optional free-form text (single string) shown
on the cover page below the authors block. |
chrome_lang |
Language used for the chrome of the document
(column headers, row labels, navigation titles, type labels,
Value descriptors, audit section). One of |
variable_names |
How response-variable names are written, so the document matches the data file the reader holds. One of:
|
base_size |
Body type size in points (default |
Value
The output path, invisibly.
"LimeSurvey last save" date on the cover
The cover metadata table carries a row labelled
"LimeSurvey last save" (or its localized equivalent). It is read
verbatim from the surveys.lastmodified column of the .lss,
which is the only timestamp LimeSurvey writes into the export –
no other table (questions, question_l10ns, answer_l10ns,
groups, etc.) carries a per-row modification date. The row is
named "last save" rather than "last modified" because LimeSurvey
only bumps that field reliably when the user clicks Save on a
survey-level form (Settings tab); editing a question text, an
answer label, or a translation through the Question Editor does
not consistently update it across LimeSurvey versions. If the
date looks stale relative to your most recent edits, the
workaround is to open Survey settings in LimeSurvey, click
Save (no other change needed), then re-export the .lss. The
next render will show the bumped timestamp.
Field-update prompt in Word
Opening the rendered .docx in Microsoft Word may surface a
security-style prompt: "This document contains fields that may
refer to other files. Do you want to update the fields in this
document?". This is expected: the package marks the page-number
and bookmark-reference fields as needing a refresh so the footer
shows the correct page count and the table of contents links
resolve to the right pages on first open (this is also what makes
headless PDF conversion via LibreOffice produce correctly
paginated output without a manual F9). Clicking Yes is safe –
the document has no INCLUDETEXT, INCLUDEPICTURE-linked, or DDE
fields; the only external links are the ORCID and DOI URLs in the
cover credits, which are static HYPERLINK targets and not fetched
on update.
PDF output
When output ends in .pdf, the function first renders a .docx
to a temporary location and then converts it locally via
LibreOffice headless (or Word on Windows). LibreOffice
(soffice executable) must be installed and on PATH; otherwise
a classed error explains how to install it. Conversion stays on
the user's machine: no upload, no network call. LibreOffice
headless does not refresh Word field values (TOC, page counts)
during conversion, so the table of contents may appear empty in
the converted PDF. To obtain a PDF with a populated TOC, render to
.docx instead, open it in Word (the TOC refreshes automatically)
and use File > Save As > PDF.
See Also
render_audit() for the audit-only document;
audit_lss() to inspect findings in the console without
rendering; read_lss() to pre-parse a .lss file once and
render multiple variants.
Examples
## Not run:
file <- system.file("extdata", "demo_survey.lss", package = "lssdoc")
# One-shot: parse + render Word document
render_questionnaire(file, tempfile(fileext = ".docx"))
# Same call, PDF output (format inferred from extension)
render_questionnaire(file, tempfile(fileext = ".pdf"))
# Parse once, render several variants without re-parsing
lss <- read_lss(file)
render_questionnaire(lss, tempfile(fileext = ".docx"),
languages = "en")
render_questionnaire(lss, tempfile(fileext = ".docx"),
template = "table",
languages = c("en", "fr"))
# Branded cover with authors block and palette override
render_questionnaire(
lss,
tempfile(fileext = ".docx"),
template = "table",
chrome_lang = "en",
colors = list(primary = "#5C9F1A", accent = "#7FA82E"),
authors = list(
list(name = "Jane Doe", affiliation = "HESAV",
orcid = "0009-0001-2345-6789"),
list(name = "John Doe", affiliation = "HESAV",
orcid = "0009-0002-3456-7890")
)
)
## End(Not run)
Render a survey specification as a Word authoring form
Description
Usage
write_form_docx(spec, path, lang = NULL, hints = FALSE, strict = TRUE)
Arguments
spec |
An |
path |
Character. Path of the |
lang |
Language of the form's own labels (its "chrome"), one of
|
hints |
Logical. Add the muted syntax hint under each key
( |
strict |
Logical, used only when |
Details
Experimental. Write an lss_spec() as a .docx form: one
two-column table per block (Survey, Group, Question, Quota), keys on the
left, values on the right. Unlike the review documents produced by
render_questionnaire(), this document is meant to be edited: an author
fills or changes the value cells in Word and the companion reader
(0.3.0) turns the file back into a specification.
The rows a Question block carries are decided by the question's kind, so
the form shows exactly the fields that kind accepts and never a field the
validator would refuse. Defaults are written as real values (Mandatory
No, an empty Filter, the other option at the End) rather than as
placeholders, because anything sitting in a value cell is content.
Conventions the document obeys, and the companion reader relies on:
Each block is a top-level two-column table whose first row is its title row; two empty paragraphs separate two blocks. No cell is merged.
Multi-valued fields (Options, Rows, Columns, Exclusive) hold one value per line. A line break inside a single-line field (an option label, a title, a quota name) is refused with a classed error naming the question, the field and the offending lines.
The Type row carries the spec kind (
single,array5, ...) as its value; the localized type label ("Single choice") is deliberately many-to-one, so it appears only as the key's hint in a blank template, never as content.Options are always written with an explicit code,
1 = Label; the native other option is written with the reserved word of the form language (Other,Autre,Sonstiges,Otro,Altro), alone when the option has no label and asOther = Labelas soon as it has one.When the spec declares several languages, every localizable key is written once per language and suffixed with the language code –
Question [fr],Question [en]– primary language first, the primary one suffixed as well.The file carries the custom document property
lssdoc-template-version, the version of this contract.
Requires the suggested packages officer and flextable.
Value
Invisibly, the path to the written file.
See Also
lss_template_docx() for a blank template, lss_spec(),
write_lss(), render_questionnaire().
Examples
if (requireNamespace("officer", quietly = TRUE) &&
requireNamespace("flextable", quietly = TRUE)) {
spec <- lss_spec(
title = "Demo",
groups = list(list(title = "G", questions = list(
list(code = "q1", kind = "single", text = "Oui ou non ?",
options = list(list(text = "Oui"), list(text = "Non")))
)))
)
out <- tempfile(fileext = ".docx")
write_form_docx(spec, out, lang = "fr")
file.exists(out)
}
Write a survey specification to an importable .lss file
Description
Usage
write_lss(spec, file, sid = 100001L, settings = list())
Arguments
spec |
An |
file |
Character. Path of the |
sid |
Integer. Survey id embedded in the file. LimeSurvey assigns a fresh id on import when this one is taken, so the value rarely matters. |
settings |
Named list of survey fields overriding the built-in
defaults (e.g. |
Details
Experimental. Turn an lss_spec() specification into a
LimeSurvey structure file (.lss) that imports directly through
Create survey -> Import. The output targets LimeSurvey 6
(DBVersion 700). The emitted file can be
read back with read_lss(), checked with audit_lss() and rendered
with render_questionnaire() – so the document reviewers read is
produced from the very file LimeSurvey receives.
Mapping choices, each validated against real LimeSurvey 6 imports:
Each kind maps to a LimeSurvey type and theme attested by a corpus of real exports (see
lss_kindsin the sources). Options of single-choice lists, rankings and array columns are emitted asanswers; options of multiple-choice questions, item batteries and array rows assubquestions; scalar kinds and implicit scales (yes/no, gender, five-point, 5/10-point arrays) emit none.The native
otheroption is emitted asother = "Y"plus the localized attributeother_replace_text. Localized attributes MUST carry the language code: emitted without one, LimeSurvey silently ignores them and shows its default wording. Global attributes (exclude_all_others,max_answers, ...) stay language-less.-
other_position/other_position_codecontrol where the other option is displayed;exclude_all_othersaccepts several codes separated by;. Relevance equations are translated from the minimal syntax of
lss_spec()into ExpressionScript (code.NAOK == "1").Quotas are emitted with the terminate action and the quota's
limit(zero unless the spec gives one).A group's optional
descriptionis emitted intogroup_l10ns.description(empty when the spec gives none).A mandatory or capped ranking also receives
min_answers = 1, overridable through the question'sattributes.
Value
Invisibly, the path to the written file.
Languages
Every language the spec declares is written. The surveys row carries
the base language – languages[1] – as language and the others,
space-separated, as additional_languages. Every localized section
(surveys_languagesettings, group_l10ns, question_l10ns for
questions and subquestions alike, answer_l10ns,
quota_languagesettings) receives one row per language, grouped by
entity as a real LimeSurvey export groups them. lss_spec() already
requires every declared language for every text, so no translation can
go missing at emission.
The <languages> element lists the additional languages first and the
base language last, the order LimeSurvey itself writes. It is only a
membership set: read the base language from read_lss()$base_language,
never from read_lss()$languages[1].
Localized question attributes – other_replace_text, prefix,
suffix, choice_title, rank_title, printable_help, ... – are
emitted once per language, each row carrying its language code; without
it LimeSurvey silently ignores the attribute and shows its own default
wording. An attribute passed through question$attributes under one of
those names is treated the same way: a plain string is repeated in every
language, a value keyed by language code is resolved language by
language (attributes = list(prefix = "CHF") or
list(choice_title = c(fr = "Choix", en = "Choice"))). Every other
attribute stays language-less, as LimeSurvey stores it.
Per-language survey settings work the same way: settings accepts a
single value repeated in every surveys_languagesettings row, or a list
keyed by language code for the fields LimeSurvey genuinely varies –
list(surveyls_dateformat = c(fr = "5", en = "2")) gives the French
respondent a dd.mm.yyyy date picker and the English one mm/dd/yyyy.
A declared language missing from such a value is an error, not a silent
fallback.
A quota is localized through quotals_name and quotals_message, one
row per language. The administration-side label quota.name has a
single column in LimeSurvey and therefore keeps the primary-language
wording.
See Also
lss_spec(), read_lss(), audit_lss(),
render_questionnaire().
Examples
spec <- lss_spec(
title = "Demo",
groups = list(list(title = "G", questions = list(
list(code = "q1", kind = "single", text = "Oui ou non ?",
options = list(list(text = "Oui"), list(text = "Non")))
)))
)
out <- tempfile(fileext = ".lss")
write_lss(spec, out)
audit_lss(out)