@@ -15,6 +15,7 @@ suppressPackageStartupMessages({
15
15
library(jsonlite )
16
16
library(stringr )
17
17
library(dplyr )
18
+ library(purrr )
18
19
library(readr )
19
20
source(" qsf-utils.R" )
20
21
})
@@ -63,27 +64,68 @@ get_qsf_file <- function(path,
63
64
# # Questions
64
65
questions <- Filter(function (elem ) { elem [[" Element" ]] == " SQ" }, qsf $ SurveyElements )
65
66
67
+ qids <- questions %> %
68
+ map_chr(~ .x $ Payload $ QuestionID )
69
+
66
70
qid_item_map <- list ()
67
71
questions_out <- list ()
68
- for (question in questions ) {
69
- question <- question $ Payload
72
+ for (question_raw in questions ) {
73
+ question_raw <- question_raw $ Payload
70
74
71
75
# Skip items not shown to respondents.
72
- if ( ! (question $ QuestionID %in% shown_items ) ) {
76
+ if ( ! (question_raw $ QuestionID %in% shown_items ) ) {
73
77
next
74
78
}
75
79
76
- if (! identical(keep_items , c(" all" ))) {
77
- question <- question [names(question ) %in% c(" QuestionID" , keep_items )]
80
+ question <- question_raw [names(question_raw ) %in% c(" QuestionID" , keep_items )]
81
+
82
+ recode_values <- question_raw $ RecodeValues # If doesn't exist, will be NULL
83
+ carryforward_choices <- question_raw $ DynamicChoices $ Locator # If doesn't exist, will be NULL
84
+
85
+ if (! is.null(carryforward_choices )) {
86
+ # Get choices that are programmed specifically for this question
87
+ old_choices <- question $ Choices
88
+
89
+ # Get carried-forward choices
90
+ carryforward_choices_qid <- carryforward_choices %> %
91
+ str_split(. , " /" ) %> %
92
+ map(~ .x [3 ]) %> % unlist()
93
+ carryforward_question <- questions [qids == carryforward_choices_qid ][[1 ]]$ Payload
94
+ carryforward_choices <- carryforward_question $ Choices
95
+
96
+ # By default, carried forward choices are coded during the carry as
97
+ # "x<original code>". They are then recoded as pure numeric codes using
98
+ # the `RecodeValues` field. Some carried forward choices do not have
99
+ # `RecodeValues` defined and so in that case we don't want to prepend the
100
+ # codes with "x".
101
+ if (! is.null(recode_values )) {
102
+ names(carryforward_choices ) <- paste0(" x" , names(carryforward_choices ))
103
+ }
104
+ # Combine new choices and carried-forward choices
105
+ question $ Choices <- c(old_choices , carryforward_choices )
78
106
}
79
107
80
- # Rearrange Answers/Choices elements to be consistent between matrix and
81
- # other items.
82
108
if (" QuestionType" %in% names(question )) {
83
109
if (question $ QuestionType == " Matrix" ) {
110
+ # Rearrange Answers/Choices elements to be consistent between matrix and
111
+ # other items.
84
112
question $ Subquestions <- question $ Choices
85
113
question $ Choices <- question $ Answers
86
114
question $ Answers <- NULL
115
+
116
+ # Recode subquestion names to match exported data.
117
+ # FALSE if not set, otherwise a list
118
+ matrix_subquestion_field_names <- question_raw $ ChoiceDataExportTags
119
+ if (! inherits(matrix_subquestion_field_names , " list" )) {
120
+ # When subquestion field names are not set, generate incrementing names
121
+ names(question $ Subquestions ) <- paste(
122
+ question $ DataExportTag ,
123
+ 1 : length(question $ Subquestions ),
124
+ sep = " _"
125
+ )
126
+ } else {
127
+ names(question $ Subquestions ) <- matrix_subquestion_field_names [names(question $ Subquestions )] %> % unlist()
128
+ }
87
129
}
88
130
}
89
131
0 commit comments