Dimensions
Dimensions
Dimensions
Cancelling Filters......................................................................................................... 57
Keyword
Description
asc
desc
fix
ran
rev
rot
Shared Lists
Keyword
Description
define
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
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.
BrandList define
{
Alpine,
Finborough,
Alsace,
DairyFresh "Dairy Fresh"
};
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
};
Name define
{
use ListName1,
...
use ListNamen
};
where:
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
};
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:
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.
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
};
name define
SubheadName1 ["Text1"]
{
response definitions
},
SubheadName2 ["Text2"]
{
response definitions
}
...
}
where:
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:
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.
};
PrintedAds "Which brands of yogurt have you seen
advertised in magazines or newspapers?" categorical [1..]
{
use NonOrgYogs sublist,
use OrgYogs sublist
};
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:
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.
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
{#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:
{#VariableName}
12
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
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.
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.
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:
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.
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.
Newspapers loop
18
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.
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
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:
For example:
20
);
BlockName.Ask()
in the routing section, where:
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:
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.
Qname "
Text
" Definition
helperfields
(
StandardTexts block fields
(
Errors block fields
(
MessageName "
MessageText
" info;
);
);
where:
Definition is the remainder of the usual question definition, including the question type, length, and
so on.
For example, the following message will be displayed only if the respondents enters an invalid response at the
MembershipNumber question:
23
Gridname.Categories[..].Label.Style.Cell.Wrap = Value
and for column texts, type:
Gridname[..].Qname.Categories[..].Label.Style.Cell.Wrap = Value
where:
Value is True to allow text wrapping (the default) or False to disallow it.
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.
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
25
);
};
) 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 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.
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:
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:
27
You can use the following operators for testing numeric responses:
Logical expressions
Operator
Description
Equal to
<>
Unequal to
<
Less than
<=
>
Greater than
>=
Operator
Description
<>
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 all the specified answers and at least one
other answer
>=
Tests whether the response contains all specified answers, with or without
additional 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
DaysVisit.Ask()
If DaysVisit.AnswerCount() < 2 Then
WhyNoMore.Ask()
End If
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.
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
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
Day(performance) < 20
Month(performance) > 6
Year(performance) = 2005
Minute(performance) <> 30
Combining expressions
Expression
And
Or
Xor
Expression1 Or Expression2
31
Not
2.
*, /, Mod
3.
+, , Like
4.
5.
unaid >= {BrandA} Or aided >= {BrandB} And advert >= {BrandB}
Conditional Actions
32
Statement
Description
If...Then...Else
Select Case
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:
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:
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
Keyword
Description
Do...Until
Do...While
For...Next
For Each...Next
While...End While
With
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()
Do
Statements
Loop While Expression
n both cases:
Expression is a logical expression that controls whether the statements in the loop will be repeated.
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;
37
1.
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.
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)
Expression is a logical expression that controls whether the statements in the loop will be repeated.
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)
While Expression
Statements
End While
where:
Expression is a logical expression that controls whether the statements in the loop will be repeated.
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.
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.
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
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.
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
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.
WhichSections.Ask()
Dim Chosen
For Each Chosen In WhichSections
Select Case Chosen
Case {Health}
...
Case {Leisure}
...
Case {Business}
...
Case ...
...
End Select
Next
DemographicsPage.Ask()
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()
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()
Keyword
Description
exit
goto
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
43
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.
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:
Name.Categories.Filter = Category_Spec
46
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.
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"
Name.Categories.Filter = PrevQname
BrandList define
{
Alpine, Finborough, Alsace,
47
Unaided.Ask()
Buy.Categories.Filter = Unaided.Response.Value
Buy.Ask()
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
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()
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()
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()
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
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()
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:
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
TimesEaten[..].QuestionFilter = "Monday..Friday"
Name.Categories.Filter = {Category_Spec}
where:
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
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:
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.QuestionFilter = PeopleInHousehold
PersonLoop1.Ask()
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
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
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()
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:
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.
59
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