Vous êtes sur la page 1sur 61

Contents

Sorting Categorical Response Lists.................................................................................. 3


Shared Lists.................................................................................................................. 3
Creating Shared Lists................................................................................................... 3
Using a Shared List as a Response List for a Question..................................................4
Using One List in Another List...................................................................................... 5
When the Same Response Appears in More Than One List.................................................6
Subheadings in a Shared List.......................................................................................... 7
Subheadings using "sublist"........................................................................................ 8
Response Indentation with Subheadings.........................................................................10
Sorting Responses with Subheadings............................................................................. 10
Responses Based on Answers to Previous Questions.......................................................11
Displaying Answers in Question and Banner Texts............................................................12
Displaying the Values of Temporary Variables in Question and Banner Texts........................12
Displaying loop control values in repeated questions.........................................................12
Three-dimensional grids............................................................................................... 14
Splitting large grids over several pages...........................................................................15
Categorical loops based on answers to previous questions................................................17
Loops inside loops....................................................................................................... 17
Controlling how case data is written................................................................................ 18
Displaying a list of questions on the same page..........................................................19
Question blocks......................................................................................................... 19
Replacing the standard message texts............................................................................20
For all questions....................................................................................................... 20
For individual questions............................................................................................. 22
Wrapping Text in Cells............................................................................................... 23
Nested grid with radio buttons in each cell....................................................................24
Images as Buttons (Clickable Images)............................................................................ 25
Checking Categorical Responses............................................................................... 27
Number of Responses Chosen...................................................................................... 27
All specified responses and no others..........................................................................27
At least one specified response and no others..............................................................28
A Given Number of Specified Responses Chosen............................................................28

Checking Text Responses.......................................................................................... 29


Checking date/time responses....................................................................................... 29
Combining expressions................................................................................................ 29
At least one expression true....................................................................................... 29
Only one expression true........................................................................................... 30
Combining more than two expressions........................................................................30
Conditional Actions...................................................................................................... 31
Select Case................................................................................................................ 31
If...Then...Else............................................................................................................. 32
Repetitive Actions in the Routing Section........................................................................34
While an expression is tru.......................................................................................... 34
Until an expression becomes true...............................................................................35
Repeat While a Condition is True................................................................................... 36
A set number of repetitions........................................................................................ 37
Repeat for each element of an array or collection.............................................................39
Executing a Series of Statements on a Single Question.....................................................39
Other Flow Control Statements...................................................................................... 40
Terminating the Interview.............................................................................................. 41
Filtering Questions and Response Lists..........................................................................42
Asking a Subset of Questions from a Block, Compound, or Page........................................42
Filtering categorical response lists.................................................................................. 43
Response Lists of Answers Chosen at a Previous Question...............................................44
Answers Chosen in Response to At Least One Question...................................................45
Answers Chosen at Both (All) Questions.........................................................................46
Answers Chosen at Only One Question..........................................................................48
Responses that Should Not be Filtered...........................................................................49
Filtering the questions in a loop (ask some questions, but not others)..................................50
Filtering the Repetitions of Loops with Categorical Control Lists..........................................51
Filtering the Repetitions of Loops with Numeric Control List...............................................52
Filtering a Grid using Answers from a Previous Grid..........................................................53
Repeat a loop once for a randomly selected value.........................................................54
Using random answers from those chosen at a previous question...................................54
Jagged Grids.............................................................................................................. 55
1

Cancelling Filters......................................................................................................... 57

Sorting Categorical Response Lists

Keyword

Description

asc

Sort in ascending alphabetical order

desc

Sort in descending alphabetical order

fix

Keep response in its current position

ran

Sort in a random order

rev

Reverse the order for each alternate interview

rot

Sort in rotated order

Shared Lists

Keyword

Description

define

Create a shared list

namespace

Make 'duplicate' responses unique when using two lists with some responses in common

use

Include one list in another list, or use a shared list as a question's response list

Creating Shared Lists


To create a shared list, place the following statement in the metadata section of the questionnaire:

Name define
{
ResponseName1 [ResponseText1],
ResponseName2 [ResponseText2],
...
ResponseNamen [ResponseTextn]
};
where:

Name is the name of the list. Try to make the list name reflect its contents as this will make the rest of
the questionnaire script easier to understand.

ResponseName1 to ResponseNamen are the response names. These must consist of a letter followed
by letters and numbers only. It is a good idea to make the response name the same as the response
text if you can so that you can omit the response text.

ResponseText1 to ResponseTextn are the response texts. If a response text does not contain spaces,
punctuation, or other non-alphanumeric characters you may omit it and the interviewing program will
use the response name as the response text.

Here is a shared list naming different brands of a product:

BrandList define
{
Alpine,
Finborough,
Alsace,
DairyFresh "Dairy Fresh"
};

Using a Shared List as a Response List for a Question


To use a shared list as the response list for a question, place the following statement in the metadata section of
the questionnaire:

Name "Question text" categorical [NumResps]


{
use ListName
};
where:

NumResps defines the number of responses that may be chosen, as for a standard categorical
question.

ListName is the name of the list you want to use as the response list for the question.

For example:

BrandList define
{
Alpine,
Finborough,
Alsace,
DairyFresh "Dairy Fresh"
};
IceCreamKnow "Which brands of ice cream can you name?"
categorical [1..]
{
use BrandList
};
IceCreamBuy "Which brand of ice cream do you usually buy?"
categorical [1..1]

use BrandList

};

You can build a question's response list using more than one shared list, or by combining a shared list with
other categorical responses. To do this, enter one use statement for each shared list and separate these
statements with commas. The following example defines separate lists for organic and nonorganic brands, but
uses the two lists to generate the brand list for the unaided awareness question.

BrandList define
{
Alpine,
Finborough,
Alsace,
DairyFresh "Dairy Fresh"
};
OrganicBrands define
{
HelenBradley "Helen Bradley's",
KentishFarm "Kentish Farm",
NaturesWay "Nature's Way Organic"
};
DessertKnow "Which brands of frozen desserts can you name?"
categorical [1..]
{
use BrandList,
use OrganicBrands
};

Using One List in Another List


You can create a shared list by using the contents of other shared lists, in much the same way that you use two
or more shared lists to generate the complete response list for a question. In the metadata section, type:

Name define
{
use ListName1,
...
use ListNamen
};
where:

Name is the name of the main list.

ListName1 to ListNamen are the names of the shared lists you want to include in the main list.

For example:

AllBrands define
{
use BrandList,
use OrganicBrands
};
BrandList define
{
Alpine,
Finborough,
Alsace,
DairyFresh "Dairy Fresh"
};
OrganicBrands define
{
HelenBradley "Helen Bradley's",
KentishFarm "Kentish Farm",
NaturesWay "Nature's Way Organic"
};
Unaided "When I mention the word yogurt, which brand names do
you think of?" categorical [1..]
{
use AllBrands
};

When the Same Response Appears in More Than One List


Let's start by assuming that you have the following lists:

AlpineList define
{
Raspberry, Strawberry, BlackCherry "Black cherry"
};
DairyFreshList define
{
Strawberry, Apricot, Peach
};
Both lists contain a strawberry response. As long as you do not use the two lists with the same question, there
is no need to use namespacing because these responses will always be unique within the response list for a
single question. For example:

AlpLike "Which flavors of Alpine yogurt do you like?"


categorical [1..]
{
use AlpineList
};
DFLike "Which flavors of Dairy Fresh yogurt do you like?"
categorical [1..]
{
use DairyFreshList
};

Here you have one question for Alpine brand and another for Dairy Fresh brand so there is no overlap between
the responses within each question.
If you rewrite this example so that there is one question for all brands, the response list for that question will
contain two occurrences of strawberry. In order for this to be accepted you must follow each list name in the
question definition with thenamespace keyword as shown below.

Like "Which flavors of yogurt do you like?" categorical [1..]


{
Alpine
{
use AlpineList namespace
},
DairyFresh "Dairy Fresh"
{
use DairyFreshList namespace
}
};
The same rule applies if you create a shared list that uses lists that have common responses. In this case you
place the namespacekeyword inside the main list as follows:

OrganicFlavors define
{
use HelenBradleyList namespace,
use KentishList namespace
};
HelenBradleyList define
{
Raspberry, Pineapple, Apricot, Blackcurrant
};
KentishList define
{
Blackcurrant, Mango, Peach, Apricot
};
Prefer "Which of the following ice cream flavors do you
like best?" categorical [1..1]
{
use OrganicFlavors
};

Subheadings in a Shared List


The rules for defining subheadings inside a shared list are similar to those for placing subheadings in response
lists. To add subheadings to a shared list, place the following statement in the metadata section of the
questionnaire:

name define

SubheadName1 ["Text1"]
{
response definitions
},
SubheadName2 ["Text2"]
{
response definitions
}
...

}
where:

SubheadName1 and SubheadName2 are the names of the subheadings.

Text1 and Text2 are the texts for the subheadings. If the texts are the same as the names and do not
contain spaces or other non-alphanumeric characters you may omit them and the interviewing
program will display the subheading names instead.

response definitions are either a list of response names and texts, or one or more use statements
naming shared lists to be included in this list.

For example:

Like "Which flavors of yogurt do you like?" categorical [1..]


{
Alpine
{
use AlpineList namespace
},
DairyFresh "Dairy Fresh"
{
use DairyFreshList namespace
}
};

Subheadings using "sublist"


If you have shared lists that you load into questions with use, you can use the sublist keyword to mark lists
whose responses are to be treated as a single group or sublist within the response list as a whole:

Name "Question text" categorical [NumResps]


{
use ListName1 sublist ["Subheading1"],
...
use ListNamen sublist ["Subheadingn"]
};
where:

Name is the question name.

ListName1 to ListNamen are the names of the shared lists you want to include in the question's
response list.

Subheading1 to Subheadingn are optional subheadings to be displayed above the shared lists.

For example:

BrandList define
{
Alpine,
Finborough,
Alsace,
DairyFresh "Dairy Fresh"
};
OrganicBrands define
{
HelenBradley "Helen Bradley's",
KentishFarm "Kentish Farm",
NaturesWay "Nature's Way Organic"
};
TVAds "Which brands of yogurt have you see advertised
on TV?" categorical [1..]
{
use BrandList sublist "Non-organic brands",
use OrganicBrands sublist "Organic brands"
};

If you use a shared list as a sublist for a number of questions and you always want to use the same
subheading text, you can include the subheading text as part of the list's definition and omit it from the
individual uses. The list's definition becomes:

Name "
SubheadingText
" define
{
ResponseName1 [ResponseText1],
ResponseName2 [ResponseText2],
...
ResponseNamen [ResponseTextn]
};
You can rewrite the previous example as follows and still achieve the same page layout as in the illustration.

NonOrgYogs "Non-organic brands" define


{
Alpine,
Finborough,
Alsace,
DairyFresh "Dairy Fresh"
};
OrgYogs "Organic brands" define

HelenBradley "Helen Bradley's",


KentishFarm "Kentish Farm",
NaturesWay "Nature's Way Organic"

};
PrintedAds "Which brands of yogurt have you seen
advertised in magazines or newspapers?" categorical [1..]
{
use NonOrgYogs sublist,
use OrgYogs sublist
};

Response Indentation with Subheadings


When a shared list has subheadings, the interviewing program indents the responses below their respective
subheadings, making it clear that the subheadings are texts rather than selectable responses. The interviewing
program applies this indentation automatically until either it reaches the end of the subsection (a closing curly
brace or another sublist keyword) or it reads a response that has a different indent specified. Indentation is
one of a response's many style properties, along with size, color, and font effect. To reset a response back to
the default indentation, type:

style(indent=0)
in the response line after the response text. You may want to do this with response lists that use a combination
of shared lists and special responses such as No answer or Don't know. Here's an example:

FruitKnow "Which brands of fruit yogurt can you name?"


categorical [1..]
{
use BrandList sublist "Non-organic brands",
use OrganicBrands sublist "Organic brands",
OtherBrands "Other (specify)" style(indent=0) other,
NoBrands "None" style(indent=0) na
};

Sorting Responses with Subheadings


Subheadings affect the way that responses in a list are sorted or reordered. If you place an ordering keyword at
the end of the question definition, the interviewing program applies it to the subsections only. The responses
within a subsection (that is, under a subheading) remain in their subsections in the order they were defined. For
example, if the question is defined as:

PlainKnow "Which brands of natural yogurt can you name?"


categorical [1..]
{
use BrandList sublist "Non-organic brands",
use OrganicBrands sublist "Organic brands"

10

} rot;
the interviewing program will display nonorganic brands followed by organic brands for one interview, and then
organic followed by nonorganic for the next. The individual brand names will simply move with their
subheadings.
If you want to reorder the responses under a subheading, do one of the following:

Place the ordering keyword at the end of the use statement, after the sublist clause.

Place the ordering keyword after the curly brace that terminates the subsection in
the define statement.

Responses Based on Answers to Previous Questions


The metadata section contains the following text:

Spont "Which brands of fresh cream puddings do you know?"


categorical [1..]
{
use BrandList
};
BrandsUsed "And of those brands, which ones do you buy?"
categorical [1..]
{
use BrandList
};
AidedQ "Do you recognize any of the following brand names?"
categorical [1..]
{
use BrandList,
AidedNA "Do not recognize any of these names" na
} ran;
KnownQ "The brands that you named are as follows." categorical [1..]
{
use BrandList
};

The routing section contains the following statements:

Spont.Ask()
' Set response list for BrandsUsed to be those brands mentioned
' at Spont.
BrandsUsed.Categories.Filter = Spont
BrandsUsed.Ask()
' Set response list for AidedQ to be all brands not mentioned
' at Spont.

11

AidedQ.Categories.Filter = AidedQ.Categories - Spont


AidedQ.Ask()
' Merge unaided and aided mentions into a single variable
KnownQ = Spont + AidedQ
KnownQ.Show()

Displaying Answers in Question and Banner Texts


o display the answer to a question in the text of another question or in a banner, type:

{#QuestionName}
in the question or banner text at the point at which you want the substituted text to appear. QuestionName is
the name of the question whose answer you want to display. For example:

Name "What is your full name?" text [5..50];


Thanks "Thank you, {#Name:u}, for taking part in our survey."
info;
The :u in the Thanks example is a formatting specification that forces the name to be displayed with the first
letter in upper case, regardless of how the respondent typed his or her name

Displaying the Values of Temporary Variables in Question and


Banner Texts
Temporary variables are those that you define in the routing section using the Dim keyword. To display the
value of a temporary variable in a question or banner text, type:

{#VariableName}

12

Displaying loop control values in repeated questions

o display the current value of the loop control item in a question or banner text, type:

{@LoopName}
in the question text at the point at which you want the substituted text to appear. LoopName is the name of the
loop. For example, if the loop is defined in the metadata section as:

RateLoop loop {
Knowledge "Subject knowledge",
Presentation "Presentation skills",
Interest "Ability to hold my interest",
Friendly "Friendliness/approachability",
Problems "Ability to deal with problems"
} fields "How would you rate the trainer for ...<p/>" (
Rating "{@RateLoop}" categorical [1..1]
{
Excellent, VGood "Very Good", Good,
Poor, VPoor "Very Poor"
};
) expand;
each question page will start with the general question text defined after fields, then a blank line, and then the
item to be rated:

{@OuterLoopName.InnerLoopName}
The metadata section that defines the loop and the text substitutions is:

CoursePart loop
{
Architecture "Overview of system architecture",
Installation "Server installation",
Performance "Performance monitoring",
Troubleshooting, Security,
Access "Implementing access plans"
} fields (
RateFor loop
{
Relevance "Relevant to my job",
Content "Information provided",
Materials "Training materials",
Exercises "Exercises"
} fields
(
Rating "Please rate the <I>{@CoursePart}</I> section
of the course for <I>{@CoursePart.RateFor}</I>."
categorical [1..1]
{
Excellent, VGood "Very Good", Good, Poor,
VPoor "Very Poor"

13

};
) expand;
) expand;
Dim training_section, attribute, question
For Each training_section In CoursePart
For Each attribute In training_section
For Each question in attribute
question.Ask()
Next
Next
Next

Three-dimensional grids
he general structure of a three-dimensional grid in the metadata section is as follows:

LoopName "
Question text
" loop
{
Repetition texts
} fields
(
Qname "" loop
{
Grid categories
} fields
(
SubQname categorical [1..1]
{
Responses
};
) expand;
) [column|row] expand;
where:

14

LoopName is the name of the loop.

Question text is the question text.

Repetition texts are the texts to use for each repetition of the question. You can use a shared list here
is you wish.

Qname is the name of the question that forms the second dimension of the grid (either rows or
columns depending on the position of the repetition texts). You can use a shared list here if you wish.

Grid categories are the category texts for the second dimension of the grid (either rows or columns
depending on the position of the sub-question texts).

SubQname is the name of the sub-question that the respondent answers in each cell of the grid.

Responses is a list of categorical responses from which respondents can choose an answer in each
cell of the grid. You can use a shared list here if you wish.

Here is the definition for the carrier by service by rating grid:

WebSite "How would you rate each company's web site for the following?"
loop
{
use InsuranceCompanies
} fields (
Aspect "" loop
{
Usability "Ease of use",
Information "Provision of information",
Visual "Visual layout/appearance",
Speed "Speed of loading"
} fields (
Rating "Rating" style(control(type="droplist"))
categorical [1..1]
{
NoSelect "Please select"
{
Excellent, VeryGood "Very Good",
Good, Fair, Poor
}
};
) expand;
) expand;
The fact that the list should be displayed as a drop-down list is defined in the routing section, which is as
follows:

WebSite[..].Aspect[..].Rating.Style.Control = ControlTypes.ctDropList
WebSite.Ask()
WebSite[..].Aspect[..].Rating is a reference to every cell of the grid: WebSite[..] refers to each
carrier, Aspect[..] refers to each service, and Rating refers to the ratings, so this part of the statement
translates to "For every combination of carrier, service and rating".

15

Style refers to the display characteristics of each cell, and Control is the keyword for the way the cell is to
be displayed. In this example, a drop-down list is required so the display control for each cell is set
to ControlTypes.ctDropList. Don't worry about having to remember all these words. The routing section
has a ScriptAssist facility that displays selection lists of appropriate keywords that change as you type.

Splitting large grids over several pages

Large grids can be difficult to display effectively on a single page without resorting to small fonts and cramped
row and column spacing. A better approach is to split the grid over a number of pages. This immediately makes
it easier for respondents to use and allows you to retain the styles and page layout set in your standard
templates.
Start by defining the grid in the metadata section in the usual way. Then place the following statements in the
routing section at the point you want to display the grid.

Dim start_pos_variable
Dim numrows_variable
start_pos_variable = 0
numrows_variable = rows_per_page
' QuestionFilter assignment is split across two lines for printing purposes
only
While (start_pos_variable < loopname.Categories.Count)
loopname.QuestionFilter =
loopname.Categories.Mid(start_pos_variable, numrows_variable)
loopname.Ask()
start_pos_variable = start_pos_variable + numrows_variable
loopname.QuestionFilter = NULL
End While
where:

start_pos_variable is a variable that is used to mark the start position in the loop control list for the
current page.

numrows_variable is a variable that stores the number of rows to display on each page.

rows_per_page is the number of rows to display on each page. You must specify this value in the
routing section (as in the example below) or ask a question whose value can be used as the value for
this parameter.

Here's an example that will make understanding this general syntax much easier. The grid is defined in the
metadata section as follows:

LargeGrid "For which of the following insurance companies have


you seen or heard advertising during the three months?" loop
{
RedWhiteBlue "Red, White, Blue Insurance",
InsuranceToGo "Insurance To Go",
WhistleHope "Whistle and Hope",
BestDeals "Best Deals",
CloverBenCo "Clover Ben and Co",

16

Rothwood,
Woodhurst "Woodhurst Ltd",
TusonNoakes "Tuson, Noakes and Partners",
GoFaster "Go Faster",
BestDealsFaster "Best Deals Faster"
} fields (
SeeHearAds "SeeHearAds" categorical [0..]
{
Seen "Saw advertising",
Heard "Heard advertising"
};
) expand;
The routing statements that split this grid so that only five rows are displayed on each page is:

Dim startpos
Dim numrows
startpos = 0
numrows = 5
While (startpos < LargeGrid.Categories.Count)
LargeGrid.QuestionFilter = _
LargeGrid.Categories.Mid(startpos, numrows)
LargeGrid.Ask()
startpos = startpos + numrows
LargeGrid.QuestionFilter = NULL
End While
The While loop in this code is repeated all the time that the current start position in the loop control list
(startpos) is less than the total number of items in the loop control list (LargeGrid.Categories.Count). It filters
the loop control list by selecting five items starting at the current start position, and then displays a grid
containing the repeated questions and those five items. When the respondent clicks Next, the new start
position is calculated by adding five (numrows) to its current setting.

Categorical loops based on answers to previous questions


Often you'll want to ask a question for each response given to an earlier question; for example, in a brand
awareness test you may ask respondents to name brands they have seen advertised and then, for each of
those brands, ask what type of advertising was seen or heard and where.
The way to do this is to define the repeated question in the metadata section as if you were going to ask the
question for all brands, not just those mentioned by the respondent. Then, in the routing section, you define a
filter that restricts the brand list to those mentioned, and then ask the question in the normal way.
Note: You can also create Numeric loops.

17

Here is the metadata section for some insurance advertising awareness questions:

InsuranceCompanies define
{
RedWhiteBlue "Red, White, Blue Insurance",
InsuranceToGo "Insurance To Go",
WhistleHope "Whistle and Hope",
BestDeals "Best Deals",
CloverBenCo "Clover Ben and Co"
};
Adverts "Which insurance Companies have you seen or heard
advertised during the last month?" categorical [1..]
{
use InsuranceCompanies
};
Company "Company loop" loop
{
use InsuranceCompanies
} fields (
AdvertType "What type of advertising did you see/hear for
{@Company}?" categorical [1..]
{
TV, Radio, Newspaper, Magazine, Billboard
};
WhereAdvert "Please specify exactly where you saw/heard the
advertising (e.g., which TV channel, which magazine)" text;
) expand;
The Company loop is set up to ask the questions for each item in InsuranceCompanies, but you want to restrict
this to only the companies mentioned at Adverts. You do this by defining a filter in the routing section as
follows:

Adverts.Ask()
Company.Categories.Filter = Adverts
Company[..].Ask()
The filter statement tells the interviewing program to filter the categories held in Company so that they are the
same as the answers given to Adverts. See the topic Filtering categorical response lists for more information.

Loops inside loops


Loops can contain other loops. This is called nesting. When loops are nested, the interviewing program
generates a separate page for each repetition of the outer loop and then displays on that page all the questions
in the inner and outer loops in the order they are defined. If the inner loop contains more than one question,
those questions are displayed side by side across the page, with categorical questions being displayed as grids
unless the routing section specifies a non-grid layout.
As an example, suppose that the metadata section contains the following code. The indentation helps show the
hierarchy of the loop, and the keywords and punctuation that mark the start and end of each loop have been
highlighted to make this clearer.

Newspapers loop

18

Bugle "The Daily Bugle",


Herald "The Morning Herald",
Informer "The Informer"
} fields
(
RatePaper "On a scale of 1 (Excellent) to 5 (Very poor), how would you
rate {@Newspapers}?" long [1..5];
NewsSections "" loop
{
Property, Arts, Sports, Financial
} fields
(
ReadSection "How often do you read the following sections of this
newspaper?" categorical [1]
{
Always, Usually, Sometimes, Never
};
RateSection "Rating: 1=Excellent, 5=Very bad" long [1..5];
) expand;
Like "Is there anything that you particularly like about
{@Newspapers}?" text;
) expand;
The outer loop consists of the RatePaper and Like questions, while the inner loop consists
of ReadSection and RateSection. The routing section contains just Newspapers[..].Ask()

Controlling how case data is written


Case (respondent) data for questions in grids and loop can be stored in a flat format or in a hierarchical format.
By default, repeated questions are defined as levels, which means that the case data is stored in a hierarchical
format. If you want to store it in a flat format, place the expand keyword at the end of the loop specification in
the metadata section of the interview script, as follows:

LoopName "Question text" loop


{
Loop control list
} fields
(
Questions
) expand;

Displaying a list of questions on the same page


When you want to display a set of questions all on the same page, place the following statement in the
metadata section of the interview script:

PageName ["Text"] page(Qname1, ..., Qnamen);


where:

19

PageName is the page name. This is the equivalent of a question name and you use it in the routing
section when you want to display the page.

Text is a text to display at the top of the page.

Qname1 to Qnamen are the names of the questions you want to display on the page.

For example:

CommState "Over the last year, would you say that communication
in the company has" categorical [1..1]
{
Improved,
Same "Stayed the same",
Worse "Got worse"
};
CommStateWhy "Why do you think this is?" text;
Communication page (CommState, CommStateWhy);
To display the page during the interview, type:

PageName.Ask()
in the routing section, where

PageName is the name of the page.

Question blocks
Use a question block to define a set of related questions that you want to keep together as a group. During
interviews, all questions in the block are displayed on the same page in the order they appear in the block.
Demographic questions are typically defined as blocks.
To define a question block, place the following statements in the metadata section of the interview script:

BlockName ["Text"] block fields


(
Questions
);
where:

BlockName is the name of the question block.

Text is the text to display at the top of the block.

Questions are questions defined in the usual way.

For example:

AboutYou "" block fields


(

20

);

Age "How old are you?" long [18..99];


WorkStatus "Do you work ...?" categorical [1]
{
Fulltime "Full time",
Parttime "Part time"
};
Dept "Which department do you work for?" categorical [..1]
{
CustomerService "Customer Services",
Facilities "Facilities",
Finance "Finance",
HumanResources "Human Resources",
IT "IT",
Sales "Sales/Marketing"
};

To display the question block, type:

BlockName.Ask()
in the routing section, where:

BlockName is the name of the question block.

Replacing the standard message texts


You can define your own error messages to replace the standard texts for all questions or for individual
questions. Defining message texts is very similar to defining questions and responses.

For all questions


To define replacement texts for the whole script, include the following in the metadata section:

StandardTexts block fields


(
Errors block fields
(
MessageName1 "
Text 1" info;
MessageName2 "
Text 2" info;
...
);
);
where:

MessageName is the name of the standard message you are replacing.

Text is the replacement message text.

21

You can define any number of replacement messages just by listing them one after the other inside the Errors
block.
Replacement message texts can contain substitution markers for things such as question names or category
texts, in the same way that markers are used in the standard texts. Substitution markers are always enclosed in
curly braces to differentiate them from the message text, and are as follows:

ANSWER
RANGE
QUESTION
QUESTION_NUMBER
LENGTH
MINLENGTH
MAXLENGTH
MINANSWERS
MAXANSWERS
CATEGORY
ERROR

For example:

StandardTexts "StandardTexts" block fields


(
Errors "Errors" block fields
(
MissingAnswer "You have forgotten to answer the question."
info;
InvalidText "Your response is not in the right format."
info;
TooFewAnswers "You have not chosen enough answers. At least {MINANSWERS}
are required."
info;

22

);

);

The substitution markers in the table apply to specific standard error messages only and replacements that you
define for those messages. A replacement text can include some or all of the substitution markers that are used
in the corresponding standard error message, but should not contain substitution markers that are used in other
error texts. For example, the TooLittleText error is "The answer does not have enough text, current length is
'{LENGTH}', minimum is '{MINLENGTH}'." Your replacement text may use both markers or neither of them. The
replacement message "Incorrect text length. Must be between {MINLENGTH} and {MAXLENGTH} characters."
will not work because {MAXLENGTH} is not valid with TooLittleText. The interviewing program will treat the
marker as ordinary text.
The same rule applies to other substitution markers (also known as inserts) that you might use elsewhere in the
questionnaire script. These markers are not valid in error messages and will be treated as ordinary text.

For individual questions


If you want to use a different message for just one question in a script, you define it in the metadata section as
a helper text related to that question. Write the question's definition as normal and then insert
the helperfields block at the end of the definition:

Qname "
Text
" Definition
helperfields
(
StandardTexts block fields
(
Errors block fields
(
MessageName "
MessageText
" info;
);
);
where:

Qname is the question name.

Text is the question text.

Definition is the remainder of the usual question definition, including the question type, length, and
so on.

MessageName is the name of the standard message you are replacing.

MessageText is the replacement message text.

For example, the following message will be displayed only if the respondents enters an invalid response at the
MembershipNumber question:

23

MembershipNumber "Please enter your membership number."


text [9..9]
helperfields (
StandardTexts "StandardTexts" block fields
(
Errors "Errors" block fields
(
InvalidText "Invalid number. Membership number format is UUnnnnnnU;
for example, AA123456Z." info;
);
);
) validation("\u{2}\d{6}\u{1}");

Wrapping Text in Cells


When a row text or column heading is wider than the space available to display it, the interviewing program
automatically wraps the text onto a new line by splitting it at a convenient space character in the text. If the text
does not contain spaces then it cannot be wrapped, but you can get round this by inserting <br/> tags in the
text anywhere that you want to force a break.
You can set text wrapping for row and column texts independently. To allow or disallow wrapping of row texts,
type:

Gridname.Categories[..].Label.Style.Cell.Wrap = Value
and for column texts, type:

Gridname[..].Qname.Categories[..].Label.Style.Cell.Wrap = Value
where:

Gridname is the name of the grid.

Qname is the name of the repeated question.

Value is True to allow text wrapping (the default) or False to disallow it.

The general rules for text wrapping are these:


When text wrapping is on (the default)

Longer texts are allocated wider columns that shorter texts.

Text wraps at the ends of words only. Long words are never wrapped.

No column is set narrower than the length of the longest word it contains. If this makes the grid wider
than the width of the browser window, the browser extends the width of the grid past the end of the
window and displays a horizontal scroll bar.

24

If no column widths are specified, the browser tries to make each column wide enough to contain the
full column heading all on one line, while still ensuring that the overall width of the grid does not
exceed that of the browser window. If the text is too long for this, the column widths are reduced and
text wrapping occurs where necessary.

If column widths are specified, the browser tries to make the columns those widths but, due to the
constraints noted earlier, this may not always be possible. In these cases, the columns may be wider
or narrower than specified.

When text wrapping is off

The browser makes each column as wide as is necessary to display the column heading all on one
line, even if this makes the grid wider than the width of the browser window.

The next example has all columns, including the row text column, set to 1.5cm. Now Lapsang Souchong wraps
as well.
The statements that created this grid were:

TeaLoop[..].Countries.Categories[..].Label.Style.Cell.Wrap = True
TeaLoop.Categories[..].Label.Style.Cell.Width = "1.5cm"
TeaLoop[..].Countries.Categories[..].Style.Cell.Width = "1.5cm"
TeaLoop.Ask()
The final example uses the same code as the previous one, but with the following change which switches off
text wrapping for the repeated question:

TeaLoop[..].Countries.Categories[..].Label.Style.Cell.Wrap = False

Nested grid with radio buttons in each cell


he metadata that creates it is:

Treatments "Treatment Options for Back Pain" compound


{
AntiInflam "Anti-inflamatory medication",
PainRelief "Pain relief",
PhysioHydro "Physiotherapy/Hydrotherapy"
} fields
(
ConfLoopFeatures "" loop {} fields (
ConfLoop "" loop
{
ConfLevel "Level of confidence in treatment" labelstyle(Width =
"200px")
} fields (
Confidence "Level of confidence in treatment"
style(Align="left",Cell(BorderStyle = "Solid", BorderWidth="1"))
categorical [1..1]
{
NotConfident "Not at all confident",

25

LittleConfident "A little confident",


SomeConfident "Somewhat confident",
Confident "Confident",
VeryConfident "Very confident"

);

};
) expand ;
)expand;
FreqLoopFeatures "" loop {} fields (
FreqLoop "" loop
{
FreqLevel "Frequency of recommendation" labelstyle(Width = "200px")
} fields (
Frequency "Frequency of recommendation"
style(Align="left",Cell(BorderStyle = "Solid", BorderWidth="1"))
categorical [1..1]
{
Never "Never", Seldom "Seldom", Occasionally "Occasionally",
Frequently "Frequently", Always "Always"
};
) expand;
)expand;

The important points about this script are as follows:

The page consists of two three-dimensional grids side by side. This signals a compound item as the
overall structure for the question. The thing that is common to both grids is the rows, so these become
the control items for the compound item that is, the items about which the questions are asked.

In a three-dimensional grid, the outer loop defines the repetition texts, while the inner loop defines the
grid categories. In this example, the repetition texts for
the ConfLoopFeatures and FreqLoopFeatures outer loop have already been defined as part of the
compound item so their loop control lists are blank.

The responses to the question inside each inner loop become the contents of each grid cell so we
define these questions in the normal way.

The repetition texts for the inner loops match the question texts of the questions in the loops. The
interviewing program uses the texts in the loop control lists as the column headings, but since you may
need individual question texts for each cell for analysis purposes, the script defines the same text as
part of the questions themselves.

The width of each grid is specified using labelstyle on the items in the inner loop control lists. This
ensures an even column width across both grids.

The boxes around the grid cells are specified using the style keyword in the questions.

The radio buttons in each cell are indented because this is what the default layout template does.
Add indent=-1 to each question's style settings to omit the indent. This will also reduce the overall
width of the boxed grid cells so you may want to reduce the label widths for the column headings by a
corresponding amount.

Images as Buttons (Clickable Images)


26

To make the images clickable, define the images in the metadata or routing section. Then specify that
responses should be displayed as buttons. You can do this in the metadata section by placing:

style(control(type = "button"))
after each response text, or in the routing section using:

Qname.Style.Control.Type = ControlTypes.ctButton
For example:

BestLogo "Which logo looks best?" categorical [1..1]


{
PinkLogo "" style(image = "logo_fuchsia.gif", control(type = "button")),
BlueLogo "" style(image = "logo_blue.gif", control(type = "button")),
GreenLogo "" style(image = "logo_green.gif", control(type = "button")),
YellowLogo "" style(image = "logo_yellow.gif", control(type = "button"))
};

Metadata and Routing


A very simple Metadata section with one categorical question looks like this:

Metadata(en-us, Question, label)


LikesBest "Which tea do you like best?" categorical [1..1]
{
Assam,
Darjeeling,
China,
Ceylon,
Other
};
End Metadata
A very simple Routing section that specifies a template to use and asks two questions in sequence looks like
this:

Routing(Web)
IOM.LayoutTemplate = "Card_Blue.htm"
TeaDrink.Ask()
LikesBest.Ask()
End Routing

Events define actions that are to be carried out at specific points such as at the start or end of the interview.
You define them in the Routing section using a Substatement:

Sub OnBeforeQuestionAsk(Question, IOM)


' Do something here
End Sub

27

You can use the following operators for testing numeric responses:

Logical expressions
Operator

Description

Equal to

<>

Unequal to

<

Less than

<=

Less than or equal to

>

Greater than

>=

Greater than or equal to

Checking Categorical Responses


You can use any suitable operator or function in the IBM SPSS Data Collection Scripting language for
testing responses to categorical questions. However, the majority of tests can be carried out using just the
operators and functions listed in the following table. For information about the full range of functions available
for categorical responses, refer to Categorical Functions and Text, Categorical, or Array Functions.

Operator

Description

Tests whether the response exactly matches a specified answer

<>

Tests whether the response does not exactly match a specified answer

<

Tests whether the response contains a subset of specified answers but not all of
them

<=

Tests whether the response contains one or more specified answers

>

Tests whether the response contains all the specified answers and at least one
other answer

>=

Tests whether the response contains all specified answers, with or without
additional answers

AnswerCount Returns the number of responses chosen


ContainsAll

Tests whether the response contains all the specified answers

28

Operator
ContainsAny

Description
Tests whether the response contains at least one of the specified answers

ContainsSom Tests whether the response contains a given number of the specified answers
e

Number of Responses Chosen


Some questions may require the respondent to choose a certain number of responses from a list.
The AnswerCount function counts the number of responses chosen, and the following example shows one
way in which it can be used:

DaysVisit.Ask()
If DaysVisit.AnswerCount() < 2 Then
WhyNoMore.Ask()
End If

All specified responses and no others


To test whether the respondent chose all the specified responses and no others, type either:

Qname = {Resp1, Resp2, ... Respn}


or:

Qname.ContainsAll({Resp1, Resp2, ... Respn}, true)


where:

Qname is the name of the question whose response you want to check.

Resp1 to Respn are the names of the responses you want to check for. If you are
using ContainsAll, you must name at least two responses.

At least one specified response and no others


To test whether the respondent chose at least one of the specified responses and no others, type either:

Qname <= {Resp1, Resp2, ... Respn}


or:

Qname.ContainsAny({Resp1, Resp2, ... Respn}, true)

29

where:

Qname is the name of the question whose response you want to check.

Resp1 to Respn are the names of the responses you want to check for.

Example

aysVisit "On which days do you normally visit the gym?"


categorical [1..7]
{
Monday, Tuesday, Wednesday, Thursday,
Friday, Saturday, Sunday
};
the expressions:

DaysVisit <= {Saturday, Sunday}


DaysVisit.ContainsAny({Saturday, Sunday}, true)
are True for all respondents who go to the gym at the weekend only; that is, on Saturday only, on Sunday only,
or on both Saturday and Sunday. The expressions are False for people who go to the gym on any weekday
even if they also go at the weekend.

A Given Number of Specified Responses Chosen


To test whether the respondent chose a given number of answers from a set of responses, as in, did the
respondent choose three track and field sports from a selection of sports, use the ContainsSome function as
follows:

ContainsSome({Resp1, Resp2, ... Respn}[, Minimum][, Maximum][, No_Others])

Checking Text Responses


With text questions you can test whether the response matches, or is like, a pattern. The expression format is:

Qname Like "pattern"


where:

pattern is the text with which the response is to be compared. An underscore in the text matches any
single character, and a percent sign matches any number of characters, including zero.

30

TelephoneNumber like "01342%"


This expression returns True for all respondents who typed telephone numbers starting with 01342.

Checking date/time responses

Day(performance) < 20
Month(performance) > 6
Year(performance) = 2005
Minute(performance) <> 30

Combining expressions

Expression
And
Or
Xor

At least one expression true


To test whether one expression or the other, or both expressions are True, use the Or operator:

Expression1 Or Expression2

Only one expression true


The Xor operator combines expressions such that only one of the expressions must be True. If both
expressions are True then the expression as a whole is False:

Expression1 Xor Expression2

31

Combining more than two expressions


When an expression contains more than one operator, the expression is evaluated using the following order of
precedence:
1.

Not

2.

*, /, Mod

3.

+, , Like

4.

=, <>, <, >, <=, >=

5.

And, Or, Xor

unaid >= {BrandA} Or aided >= {BrandB} And advert >= {BrandB}

Conditional Actions
32

Statement

Description

If...Then...Else

Execute statements based on the value of a logical expression

Select Case

Execute statements based on the value of a variable or question

Select Case

Select Case is a quick and easy way of defining conditional actions when the conditions are based on a
question that can have only one value; that is a single-response categorical question, a numeric question, or a
boolean question. To use it, type:

Select Case Qname.Response.Value


Case Response1
Actions1
Case Response2
Actions2
...
[Case Else
ActionsN]
End Select
where:

Qname is the name of the question whose response controls the conditional actions.

Response1 and Response2 are responses to the question or, for numeric responses, expressions
such as <value that group responses to the question.

Actions1 and Actions2 are one or more statements to be executed if the question's response matches
the response for the current Case statement.

ActionsN is one or more statements to be executed for respondents who fail all the
previous Case tests.

EXAMPLE
For example, suppose your interview script contains the following questions:

BestColor "Which color scheme do you think suited


the product best?" categorical [1..1]
{
BluePink "Blue and pink" ,
RedYellow "Red and yellow" ,
YellowGreen "Yellow and green" ,
None "None were suitable"
};

33

Red "Why do you think red and yellow is effective?" text [1..];
Blue "Why do you think blue and pink is effective?" text [1..];
Green "Why do you think yellow and green is effective?" text [1..];

BestColor.Ask()
Select Case BestColor.Response.Value
Case {RedYellow}
Red.Ask()
Case{BluePink}
Blue.Ask()
Case {YellowGreen}
Green.Ask()
End Select

If...Then...Else

If Expression Then
Actions
End If
where:

Expression is a logical expression whose result determines whether the rest of the If statement will
be executed.

Actions are one or more statements specifying actions to be carried out if Expression is True.

EXAMPLE
For example, suppose the metadata section defines the following questions:

METADATA
AllColors "You had three packets of the test product each with
a different color scheme. Which color schemes do you think suited
the product?" categorical [1..]
{
BluePink "Blue and pink" ,
RedYellow "Red and yellow" ,
YellowGreen "Yellow and green" ,
None "None were suitable" exclusive
};
Red "Why do you think red and yellow is effective?" text [1..];
Blue "Why do you think blue and pink is effective?" text [1..];
Green "Why do you think yellow and green is effective?" text [1..];

34

AllColors.Ask()
' Respondents mentioning red and yellow packaging with any others
If AllColors.ContainsAny({RedYellow}) Then
Red.Ask()
End If
' Respondents mentioning blue and pink packaging with any others
If AllColors >= {BluePink} Then
Blue.Ask()
End If
' Respondents mentioning yellow and green packaging with any other
If AllColors <= {YellowGreen} Then
Green.Ask()
End If

If BestColor={RedYellow} Then
Red.Ask()
ElseIf BestColor = {BluePink} Then
Blue.Ask()
ElseIf BestColor = {YellowGreen} Then
Green.Ask()
End If

35

Repetitive Actions in the Routing Section

Keyword

Description

Do...Until

Repeat statements until a condition becomes True

Do...While

Repeat statements all the time a condition is True

For...Next

Repeat statements a specified number of times

For Each...Next

Repeat statements for each element in an array or collection

While...End While

Repeat statements all the time a condition is True

With

Execute a series of statements on a single object

Object[.. In Object2]
A typical example is when you want to ask questions in a loop only for responses mentioned at a previous
question. To ask respondents to rate each product that they tried, you could type:

36

ProductsTried.Ask()
RatingLoop.Categories.Filter = ProductsTried
RatingLoop[.. In ProductsTried].Ask()

While an expression is tru


Do While Expression
Statements
Loop

Do

Statements
Loop While Expression

n both cases:

Expression is a logical expression that controls whether the statements in the loop will be repeated.

Statements are the statements to be executed

Here is an example that illustrates how you can use Do...Loop to ask a question and repeat it if the answer is
not correct. The questions in the metadata section are:

HoursTV "How many hours, to the nearest quarter hour, did you spend
watching TV last week?" double [0 .. 168];
Programs "How much of that time was spent watching ..." loop
{
Films,
News "News programs",
Documentaries,
Sitcoms "Situation comedies",
Otherprogs "Other programs"
} fields
(
ProgTime "" double [0..168];
) expand grid;
NoMatch "The sum of the times you have just entered is {Total} but the
total time you gave earlier is {HoursTV}. Please check those figures."
info;

The routing section needs to do three things:

37

1.

Ask the question.

2.

Check that the sum of program times matches the total time.

3.

If the sum of times does not match the total time, issue an error message and repeat the question.

The loop that you write is as follows:

HoursTV.Ask()
Dim Total, Prog
Do
Total=0.0
Programs.Ask()
' Add up the individual program times
For Each Prog in Programs
Total = Total + Prog.Item["ProgTime"]
Next
' Compare sum of program times with original total time
If Total <> HoursTV Then
NoMatch.Label.Inserts["Total"] = Total
NoMatch.Label.Inserts["HoursTV"] = HoursTV
NoMatch.Show()
End If
Loop While (Total <> HoursTV)

Until an expression becomes true


Do Until Expression
Statements
Loop
Do
Statements
[Exit Do]
More statements
Loop Until Expression
In both cases:

Expression is a logical expression that controls whether the statements in the loop will be repeated.

Statements are the statements to be executed.

If you want to execute the statements in the loop at least once, place the expression at the end of the loop.
Here is the earlier example rewritten to use Until. Notice that it identical apart from the last line,
where Until replaces While and the operator in the expression changes from <> to =.

HoursTV.Ask()
Dim Total1, Prog1
Do

38

Total1=0.0
Programs.Ask()
' Add up the individual program times
For Each Prog1 in Programs
Total1 = Total1 + Prog1.Item["ProgTime"]
Next
' Compare sum of program times with original total time
If Total1 <> HoursTV Then
NoMatch.Label.Inserts["Total"] = Total1
NoMatch.Label.Inserts["HoursTV"] = HoursTV
NoMatch.Show()
End If
Loop Until (Total1 = HoursTV)

Repeat While a Condition is True

While Expression
Statements
End While
where:

Expression is a logical expression that controls whether the statements in the loop will be repeated.

Statements are the statements to be executed.

Here is an example that illustrates how you can use While to ask a question and repeat it if the answer is not
correct. The questions in the metadata section are:

HoursTV "How many hours, to the nearest quarter hour, did you spend
watching TV last week?" double [0 .. 168];
Programs "How much of that time was spent watching ..." loop
{
Films,
News "News programs",
Documentaries,
Sitcoms "Situation comedies",
Otherprogs "Other programs"
} fields
(
ProgTime "" double [0..168];
) expand grid;
NoMatch "The sum of the times you have just entered is {Total} but the

39

total time you gave earlier is {HoursTV}. Please check those figures."
info;
The routing section needs to do three things:
1.

Ask the question.

2.

Check that the sum of program times matches the total time.

3.

If the sum of times does not match the total time, issue an error message and repeat the question.

The loop that you write is as follows:

HoursTV.Ask()
Dim Total2, Prog2
Total2=0.0
While (Total2 <> HoursTV)
Total2=0.0
Programs.Ask()
' Add up the individual program times
For Each Prog2 in Programs
Total2 = Total2 + Prog2.Item["ProgTime"]
Next
' Compare sum of program times with original total time
If Total2 <> HoursTV Then
NoMatch.Label.Inserts["Total"] = Total2
NoMatch.Label.Inserts["HoursTV"] = HoursTV
NoMatch.Show()
End If
End While

A set number of repetitions


If you want to repeat a set of statements a fixed number of times you can place them inside
a For...Next loop:

Dim Variable
For Variable = Start To Finish
Statements
Next
where:

Variable is a temporary variable that counts the number of repetitions, and points to each value in the
range Start to Finishin turn.

Start and Finish define a range that determines the number of times the statements are to be
repeated.

Statements are the statements to be repeated.

A simple example of a For...Next loop is one that repeats a question a set number of times if the respondent
has not answered the question correctly. Here is an example. The questions in the metadata section are:

40

HoursTV "How many hours, to the nearest quarter hour, did you spend
watching TV last week?" double [0 .. 168];
Programs "How much of that time was spent watching ..." loop
{
Films,
News "News programs",
Documentaries,
Sitcoms "Situation comedies",
Otherprogs "Other programs"
} fields
(
ProgTime "" double [0..168];
) expand grid;
NoMatch "The sum of the times you have just entered is {Total} but the
total time you gave earlier is {HoursTV}. Please check those figures."
info;

HoursTV.Ask()
Dim Total3, Prog3, i
For i = 1 to 3
Total3=0.0
Programs.Ask()
' Add up the individual program times
For Each Prog3 in Programs
Total3 = Total3 + Prog3.Item["ProgTime"]
Next
' Compare sum of program times with original total time
If Total3 = HoursTV Then
Exit For
End If
If Total3 <> HoursTV And i < 3 Then
NoMatch.Label.Inserts["Total"] = Total3
NoMatch.Label.Inserts["HoursTV"] = HoursTV
NoMatch.Show()
Else
HoursTV = Total3
End If
Next

Repeat for each element of an array or collection

Dim Variable
For Each Variable In Collection
Statements
Next

41

where:

Variable is a temporary variable that will point to each element in the collection in turn.

Collection is the name of the element collection to which the statements in the loop should be applied.

Statements are the statements to be applied to each element in the collection.

WhichSections.Ask()
Dim Chosen
For Each Chosen In WhichSections
Select Case Chosen
Case {Health}
...
Case {Leisure}
...
Case {Business}
...
Case ...
...
End Select
Next
DemographicsPage.Ask()

Executing a Series of Statements on a Single Question


If you have a series of statements that all apply to one question, you may find that using a With...End
With block helps you reduce the amount of repetition in the code and makes the code easier to read

HoursTV.Label.Style.Color = "Blue"
HoursTV.Style.Font.Effects = FontEffects.feBold + FontEffects.feItalic
HoursTV.Style.Font.Family = "Arial"
HoursTV.Style.Orientation = Orientations.orRow
HoursTV.Style.Rows = 3
HoursTV.Ask()

The syntax for an With...End With block is:

With Qname
Statements
End With
where:

Qname is the question (or other interview scripting object) that the statements in the block apply to.

Statements are the statements that are to executed for the named question or object

42

So, to specify the requirements for the Unaided question, you could type:

With HoursTV
.Label.Style.Color = "Blue"
.Style.Font.Effects = FontEffects.feBold + FontEffects.feItalic
.Style.Font.Family = "Arial"
.Style.Orientation = Orientations.orRow
.Style.Rows = 3
.Ask()
End With

With HoursTV.Style
.Font.Effects = FontEffects.feBold + FontEffects.feItalic
.Font.Family = "Arial"
.Orientation = Orientations.orRow
.Rows = 3
End With
HoursTV.Label.Style.Color = "Blue"
HoursTV.Ask()

Other Flow Control Statements

Keyword

Description

exit

Terminate the interview immediately

goto

Jump to a named location

o name a section in the routing section, type the name on a line by itself and follow the name with a colon:

SectionName:

Terminate:
IOM.Banners.Remove("IntroBanner")
TerminateText.Show()
Exit

If (RailwayWorker = {Yes}) Then GoTo Terminate


sends people who are railway workers straight to the end of the script because they are not eligible to be
interviewed.

43

Terminating the Interview

Intro "Hello, I'm calling from The Train Company. I wonder if you
can spare some time to answer a few questions about train travel." info;
TerminateText "Thank you for your help, but your household does not meet
the requirements for this survey." info;
Callback "INTERVIEWER: Arrange an appointment to call back and speak to
this person." info;
RailwayWorker "Do you work on the railways?
Is anyone in your immediate family associated with this field?"
categorical [1..1]
{
Yes, No
} NoCaseData;
UsesTrain "Do you travel regularly by train / may I speak with someone
who regularly travels by train?" categorical [1..1]
{
RegularTraveler "Respondent travels regularly by train",
NoTrainTraveler "No one travels regularly by train",
TrainUserNA "Regular train traveler not available"
} NoCaseData;
LastTwoWeeks " Have you traveled by train during the last two weeks?"
categorical [1..1]
{
Yes, No
} NoCaseData;
JourneyReason "What was the main reason for your journey?"
categorical [1..1]
{Business, Pleasure};

Notice how the screening questions have been flagged with NoCaseData because the data is of no use to the
survey.
The routing section that filters out unsuitable respondents is as follows:

IOM.Banners.Add("IntroBanner",Intro.Label)
RailwayWorker.Ask()
If (RailwayWorker = {Yes}) Then GoTo Terminate
UsesTrain.Ask()
If (UsesTrain = {TrainUserNA}) Then GoTo Callback
If (UsesTrain = {NoTrainTraveler}) Then GoTo Terminate
LastTwoWeeks.Ask()
If (LastTwoWeeks = {No}) Then GoTo Terminate
' Questions for train travellers
IOM.Banners.Remove("IntroBanner")
JourneyReason.Ask()

44

Exit
Callback:
IOM.Banners.Remove("IntroBanner")
Callback.Show()
Exit
Terminate:
IOM.Banners.Remove("IntroBanner")
TerminateText.Show()
Exit
This script deals with three types of respondent.

Those who work for the railway or who have close relatives that work for the railway are ineligible for
the survey so their interview is terminated straight away.

Having established that the household is suitable, the script then guides the interviewer to finding a
suitable respondent within the household. Although the script does not specifically do this, the
implication is that if the first respondent is not a regular train traveler, the interviewer will automatically
ask to speak to someone who is. Once all possibilities have been exhausted, the interviewer enters an
answer to UsesTrain.
If there is no one at all who travels by train, the interview is terminated. If there is a regular train
traveler but this person is not available, the interviewer is asked to make an appointment. The
interviewer does this by selecting the appropriate option from the call results menu. There is no need
for the script to terminate the interview because this happens automatically when the interviewer
makes the appointment.

If the respondent travels regularly by train but has not done so within the last two weeks, the interview
is also terminated. After this, only people who travel regularly by train and who have done so in the two
weeks are left to start the main part of the interview.

Filtering Questions and Response Lists

Asking a Subset of Questions from a Block, Compound, or Page

Name.QuestionFilter = "SubQname1, ..., SubQnameN"


where:

Name is the name of the block, compound, or page.

SubQname1 to SubQnameN are the names of the subquestions you want to display.

45

Here's how to use it to set up the example. The block is defined in the metadata section as:

Demographics "Demographic Questions" block fields


(
Gender "Are you ...?" categorical [1..1]
{
Male,
Female,
NoAnswer "No answer" na
};
Age "How old are you?" long [18..99];
MaritalStatus "What is your marital status?" categorical [1..1]
{
Single,
Couple "Married/Living with partner",
Separated,
Divorced,
Widowed,
NoAnswer "No answer" na
};
NumberChildren "How many children are there in your household?"
long [0..9];
ChildAge "How old are those children?" categorical [1..]
{
Baby "Under 18 months",
Preschool "19 months to 5 years",
Child "5-12 years",
Teen "12-18 years",
Adult "18 years or older"
};
);
An earlier question called HasChildren (not shown here) tells you whether the respondent has children. To
suppress the questions in the block about children, you place the following statements in the routing section:

If (HasChildren <> {Yes}) Then


Demographics.QuestionFilter = "Gender, Age, MaritalStatus"
End If
Demographics.Ask()

Filtering categorical response lists

Name.Categories.Filter = Category_Spec

46

in the routing section, where:

Name is the name of the question whose response list is being filtered.

Category_Spec names the categories to be displayed. This may be the name of a single category or
a comma-separated list of category names, both enclosed in curly braces. Alternatively, you can
specify a range of categories using the standard range syntax, with the category specification
enclosed in double quotation marks.

For example, suppose the metadata contains:

IceCream "Which brands of ice cream can you name?"


categorical [1..]
{
Alpine, Finborough, Alsace,
DairyFresh "Dairy Fresh",
CountryFayre "Country Fayre",
KentishFarm "Kentish Farm"
};
You can reduce the response list so that it contains only Alpine, Alsace, Dairy Fresh, and Kentish Farm brands
by placing the following statement in the routing section before you ask the question:

IceCream.Categories.Filter = {Alpine, Alsace, DairyFresh, KentishFarm}

If the categories to be used as filters are defined consecutively, you can save yourself work by using the
double-dot range operator. For example:

IceCream.Categories.Filter = "Alpine..CountryFayre"
to include all brands between Alpine and Country Fayre inclusive (that is, all except Kentish Farm). An
alternative way of writing this particular example is to use the Not (^) operator as follows:

IceCream.Categories.Filter = "^KentishFarm"

Response Lists of Answers Chosen at a Previous Question

Name.Categories.Filter = PrevQname

Here's an example. The metadata section is:

BrandList define
{
Alpine, Finborough, Alsace,

47

DairyFresh "Dairy Fresh",


CountryFayre "Country Fayre"
};
OrganicBrandList define
{
HelenBradley "Helen Bradley's",
KentishFarm "Kentish Farm",
NaturesWay "Nature's Way Organic",
SimpleOrganix "Simple Organix"
};
Unaided "Which brands of yogurt can you name?" categorical [1..]
{
use BrandList,
use OrganicBrandList,
OtherUnaided "Other" Other fix,
NoneUnaided "None" excl fix
} asc;
Buy "And of those brands, which ones do you buy?" categorical [1..]
{
use BrandList,
use OrganicBrandList,
BuyNone "None of them" excl fix
} asc;

The routing section is:

Unaided.Ask()
Buy.Categories.Filter = Unaided.Response.Value
Buy.Ask()

Answers Chosen in Response to At Least One Question

This topic shows how to create a response list that displays only answers that were chosen in response to at
least one of two earlier questions. The metadata section is as follows:

BrandList define
{
Alpine, Finborough, Alsace,
DairyFresh "Dairy Fresh",
CountryFayre "Country Fayre"
};
OrganicBrandList define
{
HelenBradley "Helen Bradley's",
KentishFarm "Kentish Farm",
NaturesWay "Nature's Way Organic",
SimpleOrganix "Simple Organix"
};
SawAdvert "Which of the following brands have you seen advertised

48

during the last four weeks?" categorical [1..]

use BrandList,
use OrganicBrandList,
SawNone "Did not see any brands advertised" excl fix
} asc;
HeardAdvert "Which of the following brands have you heard advertised
during the last four weeks?" categorical [1..]
{
use BrandList,
use OrganicBrandList,
HeardNone "Did not hear any brands advertised" excl fix
} asc;
MostEffective "Of those advertisements, which brand do you think
had the most effective advertising overall?" categorical [1..1]
{
use BrandList,
use OrganicBrandList
} asc;
You want the response list for MostEffective to contain only the brands that were mentioned
at SawAdvert or HeardAdvert or both, so place the following statements in the routing section:

SawAdvert.Ask()
HeardAdvert.Ask()
MostEffective.Categories.Filter = SawAdvert.Response.Value +
HeardAdvert.Response.Value
MostEffective.Ask()

Answers Chosen at Both (All) Questions

This topic shows how to generate a response list that displays only responses chosen at both the previous
questions. The questions in the metadata section are:

BrandList define
{
Alpine, Finborough, Alsace,
DairyFresh "Dairy Fresh",
CountryFayre "Country Fayre"
};
OrganicBrandList define
{
HelenBradley "Helen Bradley's",
KentishFarm "Kentish Farm",
NaturesWay "Nature's Way Organic",
SimpleOrganix "Simple Organix"
};
SawAdvert "Which of the following brands have you seen advertised
during the last four weeks?" categorical [1..]
{
use BrandList,

49

use OrganicBrandList,
SawNone "Did not see any brands advertised" excl fix
} asc;
HeardAdvert "Which of the following brands have you heard advertised
during the last four weeks?" categorical [1..]
{
use BrandList,
use OrganicBrandList,
HeardNone "Did not hear any brands advertised" excl fix
} asc;
CompareAds "For the brands for which you both saw and heard
advertising, which brand had better visual than audio
advertising?" categorical [1..]
{
use BrandList,
use OrganicBrandList
} asc;
The routing statements that produce a list of answers that were given at both SawAdvert and HeardAdvert are
as follows:

CompareAds.Categories.Filter = SawAdvert.Response.Value *
HeardAdvert.Response.Value
CompareAds.Ask()
This script uses the intersection (*) operator to collect answers that were chosen at both questions. Answers
chosen at only one question or not chosen at all are ignored. If the filter for CompareAds generates a blank list,
the question is not asked.
Here's a prompted and unprompted awareness example that results in a final rating question about a brand
selected at random from those that the respondent knows. The metadata section defines all the questions that
are used (they are not all asked):

BrandList define
{
Alpine, Finborough, Alsace,
DairyFresh "Dairy Fresh",
CountryFayre "Country Fayre"
};
OrganicBrandList define
{
HelenBradley "Helen Bradley's",
KentishFarm "Kentish Farm",
NaturesWay "Nature's Way Organic",
SimpleOrganix "Simple Organix"
};
FirstKnown "When you think of frozen desserts, which is the first
brand that comes to mind?" categorical [1..1]
{
use BrandList,
use OrganicBrandList
} asc;
OtherKnown "Which other brands can you think of?" categorical [0..]
{
use BrandList,
use OrganicBrandList

50

} asc;
Prompted "Which of the following brands do you recognize?" categorical [0..]
{
use BrandList,
use OrganicBrandList
} asc;
RateThis "Randomly selected brand for rating" categorical [1..1]
{
use BrandList,
use OrganicBrandList
} asc;
Rating "How would you rate {#RateThis} overall?" categorical [1..1]
{Excellent, VGood "Very Good", Good, Poor, VPoor "Very poor"};
The routing section is as follows. Notice the use of the temporary AllKnown variable that keeps track of which
brands have been mentioned.

Dim AllKnown
FirstKnown.Ask()
AllKnown = FirstKnown.Response.Value
' Use all except first known brand
OtherKnown.Categories.Filter = OtherKnown.DefinedCategories() FirstKnown.Response.Value
OtherKnown.Ask()
AllKnown = AllKnown + OtherKnown.Response.Value
' Use all not known
Prompted.Categories.Filter = Prompted.DefinedCategories() - AllKnown
Prompted.Ask()
AllKnown = AllKnown + Prompted.Response.Value
' Select one answer at random from all brands known
' An alternative is Ran(AllKnown,1)
RateThis = AllKnown.Ran(1)
Rating.Ask()

Answers Chosen at Only One Question

You can filter a response list so that it contains answers that were chosen at only one of a set of questions. As
an example, suppose that the metadata section defines the following questions:

BrandList define
{
Alpine, Finborough, Alsace,
DairyFresh "Dairy Fresh",
CountryFayre "Country Fayre"
};
OrganicBrandList define
{
HelenBradley "Helen Bradley's",
KentishFarm "Kentish Farm",
NaturesWay "Nature's Way Organic",
SimpleOrganix "Simple Organix"

51

};
SawAdvert "Which of the following brands have you seen advertised
during the last four weeks?" categorical [1..]
{
use BrandList,
use OrganicBrandList,
SawNone "Did not see any brands advertised" excl fix
} asc;
HeardAdvert "Which of the following brands have you heard advertised
during the last four weeks?" categorical [1..]
{
use BrandList,
use OrganicBrandList,
HeardNone "Did not hear any brands advertised" excl fix
} asc;
OnlyOne "For the brands for which you either saw or heard advertising,
but not both, which brand had the best advertising?" categorical [1..1]
{
use BrandList,
use OrganicBrandList
} asc;
To create a response list that contains brands for which advertising was either seen or heard but not both, the
routing is as follows.

OnlyOne.Categories.Filter = SawAdvert.Response.Value /
HeardAdvert.Response.Value
OnlyOne.Ask()

Responses that Should Not be Filtered

InsProducts define
{
Life,
CriticalIllness "Critical illness",
Buildings,
Contents,
Mortgage "Mortgage protection",
Income "Income protection",
Travel,
OtherInsProducts "Other insurance products" other nofilter,
NoInsProducts "None" na,
DkInsProducts "Can't remember / Don't know" dk
};
HasInsurance "Which types of insurance do you currently have?"
categorical [1..]
{
use InsProducts
};
EnquiredThisYear "And are there any other types of insurance
that you have considered buying in the past year or that you

52

are considering buying now?" categorical [1..]

use InsProducts
};
GotQuote "And of those products that you considered or are
considering buying, for which ones did you request a
quotation?" categorical [1..]
{
use InsProducts
};
The routing is quite straightforward:

HasInsurance.Ask()
EnquiredThisYear.Categories.Filter = _
EnquiredThisYear.DefinedCategories() - HasInsurance.Response.Value
EnquiredThisYear.Ask()
GotQuote.Categories.Filter = EnquiredThisYear.Response.Value
GotQuote.Ask()

Filtering the questions in a loop (ask some questions, but not


others)

To filter the questions in a loop so that only some are presented to the respondent, place the following
statement in the routing section:

LoopName[..].QuestionFilter = "Questions"
where:

LoopName is the name of the loop.

Questions are the questions to be displayed. This can be either a comma-separated list of questions
names or, if the questions are consecutive, a range of names defined as Qname1..QnameN.

For example:

FoodList define
{
Fruit, Vegetables, Salads, Fish, Meat, Bread,
Dairy "Dairy produce",
Pulses "Pulses/Nuts/Cereals",
PastaRice "Pasta/Rice"
};
TimesEaten "On the following days last week, how many times did you
eat ... ?" loop
{use FoodList}
fields
(

53

Monday long [0..10];


Tuesday long [0..10];
Wednesday long [0..10];
Thursday long [0..10];
Friday long [0..10];
Saturday long [0..10];
Sunday long [0..10];
) grid expand;
In this loop, the types of food are the answers (rows) and the days are the questions (columns). To restrict the
grid to displaying weekend days only, place the following statement in the routing section:

TimesEaten[..].QuestionFilter = "Saturday, Sunday"


For a grid that displays weekdays only, type:

TimesEaten[..].QuestionFilter = "Monday..Friday"

Filtering the Repetitions of Loops with Categorical Control Lists

Name.Categories.Filter = {Category_Spec}
where:

Name is the name of the loop.

Category_Spec names the categories to be displayed. This may be the name of a single category or
a comma-separated list of category names, both enclosed in curly braces. Alternatively, you can
specify a range of categories using the standard range syntax, with the category specification
enclosed in double quotation marks.

Here is an example based on a loop that is defined in the metadata section as follows:

FoodList define
{
Fruit, Vegetables, Salads, Fish, Meat, Bread,
Dairy "Dairy produce",
Pulses "Pulses/Nuts/Cereals",
PastaRice "Pasta/Rice"
};
TimesEaten "On the following days last week, how many times did you
eat ... ?" loop
{use FoodList}
fields
(

54

Monday long [0..10];


Tuesday long [0..10];
Wednesday long [0..10];
Thursday long [0..10];
Friday long [0..10];
Saturday long [0..10];
Sunday long [0..10];
) grid expand;
We want to ask about pulses/nuts/cereals, pasta/rice and bread only. We do this by placing the following
statement in the routing section before we ask the loop:

TimesEaten.Categories.Filter = {Pulses, PastaRice, Bread}


TimesEaten.Ask()
If the categories to be used as filters are defined consecutively, you can save yourself work by using the
double-dot range operator. For example:

TimesEaten.Categories.Filter = "Fruit..Bread"
Another way of filtering loop repetitions is to use the QuestionFilter object with a simple reference to the
loop name:

TimesEaten.QuestionFilter = {Fruit, Salads}

Filtering the Repetitions of Loops with Numeric Control List

PeopleInHousehold "How many people are there in your household?"


long[1..9];
PersonLoop loop [1..9]
fields
(
PersonAge "How old is person {@PersonLoop}?" long [0..99];
PersonGender "Is this person ...?" categorical [1..1]
{Male, Female}
) expand;
the routing statements to repeat the loop for just the number of people in each household will be:

PeopleInHousehold.Ask()
PersonLoop.QuestionFilter = PeopleInHousehold
PersonLoop[..].Ask()

The [..] notation in the last statement causes each iteration of the loop to be presented as a separate page
rather than as a grid all on one page. If there are three people in the household, the respondent will see three
pages only even though the loop is defined to execute a maximum of nine times. A typical page looks like this:
If you would prefer to use a grid, define the loop as:

55

PersonLoop1 "For each person in the household ..." loop [1..9]


fields
(
PersonAge1 "Age" long [0..99];
PersonGender1 "Gender" categorical [1..1]
{Male, Female}
) grid expand;
and write the .Ask statement as:

PersonLoop1.QuestionFilter = PeopleInHousehold
PersonLoop1.Ask()

Filtering a Grid using Answers from a Previous Grid

The metadata for the example is as follows:

FoodList define
{
Fruit, Vegetables, Salads, Fish, Meat, Bread,
Dairy "Dairy produce",
Pulses "Pulses/Nuts/Cereals",
PastaRice "Pasta/Rice"
};
FoodLoop "Which of the following do you eat as part of
your normal diet?" loop
{use FoodList}
fields (
NormalDiet "" categorical [1..1]
{
Yes, No
}
) expand;
LastWeekLoop "And roughly how many portions of these foods
do you eat each week?" loop
{use FoodList}
fields (

56

Portions "" long [1..100]


) expand;
The routing section contains the following code. Notice how the filtering for the second grid has been placed in
a function, making it reusable elsewhere in the survey.

FoodLoop.Ask()
LastWeekLoop.QuestionFilter = GridIterationsContainsAny(FoodLoop, {Yes})
LastWeekLoop.Ask()
Function GridIterationsContainsAny(Grid, Answers)
Dim Iteration
For Each Iteration In Grid
' Iteration[0] is the first categorical question in the grid
If Iteration[0].Response.ContainsAny(Answers) Then
GridIterationsContainsAny = GridIterationsContainsAny +
CCategorical(Iteration.QuestionName)
End If
Next
End Function

Repeat a loop once for a randomly selected value


The same questions are asked for each project, so they are defined in a loop whose control list contains the
project descriptions:

Projects loop
{Project1, Project2, Project3, Project4} ran
fields
(
Position "What was your position in the {@Projects} project team?"
categorical [1..1]
{
Designer, Developer, Writer, QA, Manager
};
HowLong "How long (in months) did you work on this project?"
long [1..12];
Likes "What did you particularly enjoy about this project?"
text;
Dislikes "And was there anything you disliked about the project?"
text;
) expand;
The routing section needs to select one project from the list and ask just that iteration of the loop. There are a
number of ways you can do this, but the most efficient is as follows:

57

Projects[Projects.DefinedCategories().Ran(1)].Ask()

Using random answers from those chosen at a previous


question
ProjectList define
{Project11, Project12, Project13, Project14};
YourProjects "Which projects did you work on last year?" categorical [1..]
{use ProjectList};
ProjectsLoop loop
{use ProjectList}
fields (
Position1 "What was your position in the {@ProjectsLoop} project team?"
categorical [1..1]
{
Designer, Developer, Writer, QA, Manager
};
HowLong1 "How long (in months) did you work on this project?"
long [1..12];
Likes1 "What did you particularly enjoy about this project?"
text;
Dislikes1 "And was there anything you disliked about the project?"
text;
) expand;
The routing statements to ask the questions in the loop about one project chosen at random from those worked
on are as follows:

YourProjects.Ask()
Projects.Categories.Filter = YourProjects.Response.Ran(1)
ProjectsLoop[..].Ask()
Another option, and one that does not use filtering at all, is to write:

YourProjects.Ask()
ProjectsLoop[YourProjects.Response.Ran(1)].Ask()

Jagged Grids

Name.Style.Hidden = True
in the routing section, where:

Name is the question name

58

DailyNewspapersList define
{
Telegraph, Independent "The Independent",
Times "The Times", Express "The Express", Mail,
Sun "The Sun", DailyMirror "Daily Mirror"
};
WeekdayNewspapersList define
{
Guardian "The Guardian", Star "The Star",
FinancialTimes "The Financial Times"
};
SundayNewspapersList define
{
Observer "The Observer",
NewsoftheWorld "The News of the World"
};
DayList define
{
Sunday, Monday, Tuesday, Wednesday, Thursday,
Friday, Saturday
};
JaggedGrid "Please select the newspapers that you read on each day." loop
{
use SundayNewspapersList sublist,
use WeekdayNewspapersList sublist,
use DailyNewspapersList sublist
} fields
(
DayQ "" categorical [0..]
{DayList use \\.DayList sublist};
) expand grid;
Hiding cells is all done in the routing section, as shown below.

Dim sunday, weekday, newspaper


' Create some category lists to be used for comparison
sunday = JaggedGrid.DefinedListElements({SundayNewspapersList})
weekday = JaggedGrid.DefinedListElements({WeekdayNewspapersList})
' Hide newspapers as appropriate
For Each newspaper in JaggedGrid.DefinedCategories()
With JaggedGrid[CCategorical(newspaper)].DayQ.Categories.DayList
' If the newspaper is a Sunday newspaper, hide the Monday through
' Saturday categories
If sunday >= newspaper Then
.Monday.Style.Hidden = True
.Tuesday.Style.Hidden = True
.Wednesday.Style.Hidden = True
.Thursday.Style.Hidden = True
.Friday.Style.Hidden = True
.Saturday.Style.Hidden = True
End If

59

' If the newspaper is a weekday newspaper, hide the Sunday category


If weekday >= newspaper Then
.Sunday.Style.Hidden = True
End If
End With
Next
JaggedGrid.Ask()
The code that hides unavailable responses steps through each newspaper in the control list for
the JaggedGrid loop. TheWith...End With statement is simply a more efficient way of writing:

If sunday >= newspaper Then


JaggedGrid[CCategorical(newspaper)].DayQ.Categories.DayList.Monday.Style.Hidde
n=True
JaggedGrid[CCategorical(newspaper)].DayQ.Categories.DayList.Tuesday.Style.Hidd
en=True
...
End If
and hides the cell if the current newspaper is a Sunday one

Cancelling Filters
To cancel a question filter, type:

Name.QuestionFilter = Null
For category filters, type:

Name.Categories.Filter = Null
In all cases, Name is the name of a filtered question or loop.

60

Vous aimerez peut-être aussi