Logical Expressions Overview
Logical expressions
Logical expressions are used in filter="..." attributes of the <subq>, <section>, <r>, <other>, <info> , <say> and <do> tags, in the if attribute of the <goto> tag and in dependent range lists.
Logical expressions always evaluate to either "TRUE" or "FALSE".
In general they refer to previous responses/answers in the questionnaire.
E.g. if the questionnaire contains a question about "Gender" that looks like this:
an expression like:
\Q1=1
will evaluate to "TRUE" for "Male" respondents and "FALSE" for "Female" respondents.
A logical expression always contains an "=" (equal) sign. On the left handside you refer to an address of a previously asked question (ques-item). An address always starts with "\" (backslash). In QML you refer to a question by its id (label) and not the actual question number. This means that all questions we want to refer to, must have an "id".
On the right hand side of "=" we have a value or value list. If the referred quest-item has an answer equal to this value or list of values, the expression is "TRUE".
The MI Pro system automatically keeps track of which ques-items have been asked and/or answered through the QR-bits.
As surveys are conducted over time, there might also be questions and answers that have not existed for the whole duration. We might therefore also have "not-existed" represented for ques-items and for answers. "Not-existed" is represented internally as the “illegal” combination of the "QR-bits" being not-asked but answered.
This means that the "QR-bits" have the following meaning:
Q | R | Meaning |
0 | 0 | Not asked, not answered |
1 | 0 | Asked, not answered |
1 | 1 | Asked and answered |
0 | 1 |
No existence |
Value/value lists
The value or value list can be expressed as follows:
Value | Explanation |
5 | Single value |
1;5;8 | Discrete list (1 or 5 or 8) |
2:5 | Interval (from 2 through 5) |
1;4;7:10 | Combination of discrete list and interval |
In addition special codes: | |
¤ | Exists (all QR-bit combinations except "01") |
? | Asked (QR-bit combination "10" or "11") |
* | Answered (QR-bit combination "11") |
- | Not answered (QR-bit combination "10") |
% | The "%" sign is used when we refer to a subq-type N or M question from a subq-type with ques-items in each row (subq-types f/h/rn/rm/a). The significance here is that for each row we exchange the "%" with the corresponding code from the n/m subq in this row. This means that the expression is evaluated once for each row. |
# | The "#" sign means count the number of responses. E.g. \10=#3 is "TRUE" if question 10 has exactly 3 responses. \10=#2:6 is "TRUE" if question 10 has between 2 and 6 responses. \10=1:12#3:12 is "TRUE" if question 10 codes 1 through 12 has between 3 and 12 responses. Basic logical expressions can be combined with logical operators "|" (or), "&" (and) and "!" (not) and using parentheses. |
E.g. a comlex example:
((\Q10=3)&(\Q11=2:5))|((\Q14=#2:5)&(\Q17=-))
This translates to
Q10=3 AND Q11= 2 or 3 or 5
OR
Q14 has between 2 and 5 answers AND Q17 is not answered
Address
An address to a ques-item consists of up to 3 parts:
- Question number (always expressed through its ID)
- Sub question letter (A-Z)
- Row number (for sub questions with ques-items in each row rn/rm/f/h/a)
An address is always introduced through the "\" (backslash) character. Each component is separated with "." (punctuation mark). When referring within a question, one might skip the question number like this: \.a=2.
One might also combine questions, subqs or rows using ";" or ":" like:
\Q10.a:c=#1:3
Meaning 1 to 3 answers total, in question 10 both subq A, B and C.
When combining questions or subqs (using “;” or “:”the following rules apply:
The questions/subqs must be of the same type.
Only subqtype n/m
Only subqtype rn/rm
Only subqtype f/h
Same number of rows
Same number of codes (rn/rm)
The "%" (percent sign) might be used in place of a row number. In this case the expression is evaluated for each row, and "%" is replaced with the current row number.
The referred question must have at least the same number of rows.
Special addresses
The following special addresses might be used:
\script:NAME(P1,P2...)
This calls an external routine NAME. The parameters provided may be any valid address or a constant. Addresses will be replaced by actual answers, before the routine is called. In this way intricate logic may be implemented. Such scripts must be implemented by MI Pro.
System variables
These variables are described in the section: System Variables
Sample variables
Variables from the sample file, or passed as parameters in the link can also be used directly. These should be preceeded by “\@sms_” .
E.g. If an imported sample has a column labelled “gender”, “\@sms_gender” will refer to this value.
Backward referencing
All expressions in filters etc. have to be backward in the questionnaire. Reference within a block of rotated questions is not allowed (only to other questions guaranteed to come before).
Range expressions (valid answers)
The "range" attribute specifies absolute rules. This means that responses outside of valid ranges are not permitted at all. An example might be a range="15:99" to limit the responses for an age question to ages 15 through 99 years old. Any other value is not possible.
Syntax
Range expressions can be simple or quite complex. The basic part is what we call a "list-part". This consists of a response-value or a list of allowed responses.
List-part | Description |
4 | only 4 is allowed |
1:5 | responses 1, 2, 3, 4 and 5 are allowed |
1;3;8 | responses 1, 3 and 8 are allowed |
1:3;5;7:9 | responses 1, 2, 3, 5, 7, 8 and 9 are allowed |
* | we must have an answer/response required |
- | we allow no answer/response |
\4 | any response from question 4 is allowed |
! | negates the list |
!\4 | any response not given to question 4 is allowed |
!3:6 | 3, 4, 5 and 6 are not allowed |
rank N | The number of type F rows to be ranked |
script:NAME(P1, P2..) | Call an external routine (NAME). Supply any number of parameters which can be addresses of previous ques-items or constants. The external routine should return the allowable answers. MI Pro must implement such routines. |
% | Code at current row. Can be used in n/m subqs. Use together with a % for the row part of a conditional construct, meaning evaluate for each row and allow code if condition is "TRUE" Eg. % when \car.%=1:3 The referred question must have at least the same number of rows. |
#N or #N:M | Number of answers for subq-types m and rm. Sum for subq-type f. N gives number of answers or exact sum. N:M gives an interval. For subq-types m/rm further limitations on which codes to count by prefixing E.g. 1:7#3 meaning 3 answers of codes 1 through 7. For subq-type m, number of asnwers should be checked before moving to next subq. For subq-type rm, check each row. For subq-type f, check the sum of all rows before moving to next subq. |
These "range" lists can be combined with logical operators.
E.g.
(1:5)&(\Q3) must be 1, 2, 3, 4, or 5 but also given as response to question 3
(!\Q3.a)|(!\Q5.b) all responses not given to question 3.a or any response given to question 5.b
If a range expression has at least one logical operator then parentheses must be used to group the basic list expressions.
The range list can again be valid under certain circumstances. E.g. One list for “men” and another for “women”.
Conditional Constructs in the Range
There are two conditional constructs:
1. the "when" construct
2. the "try" construct
The "when" construct
This consists of an optional default list followed by one or more "when" lists followed by an optional "else" list (“when” constructs are typically used on single choice questions).
E.g.
(1:5)&(\Q3) must be 1, 2, 3, 4, or 5 but also given as response to question 3
(!\Q3.a)|(!\Q5.b) all responses not given to question 3.a or any response given to question 5.b
If a range expression has at least one logical operator then parentheses must be used to group the basic list expressions.
The range list can again be valid under certain circumstances. E.g. One list for “men” and another for “women”.
The "try" construct
This consists of an optional default list followed by one or more "try" lists (“try” constructs are typically used on multiple choice questions).
E.g.
(1;2) (3) try \3.A=1 (3;5;7) try \3.A=2:4
Default list (1;2) means 1 and 2 are always ok.
3 is ok if response to question 3.A is 1.
3, 5 or 7 is ok if response to question 3.A is 2, 3 or 4.
The "try" construct first inspects the default list if present. Then it will inspect one after the other of the "try" expressions. If the "try" expression evaluates to "TRUE" the list is inspected. If the response is found, everything is ok. If not check the next "try" expression. If a valid response is not found an error message informing the user of an invalid response, should be issued.
System variables
A list of the most relevant system variables is shown below:
Name | Description |
sys_altid | The altid of the interview |
sys_computer | The computer name (server name) |
sys_date | The date yyymmdd |
sys_dayofweek | Day of week 1:Monday |
sys_elapsedtime | Time in seconds from start |
sys_lang | Current language |
sys_method | Method (not relevant anymore, 2 = cawi) |
sys_quespos | Current question |
sys_respguid | GUID of interview |
sys_random | The sys_random variable |
sys_rotseed | The seed used to generate the random variable |
sys_timenowf | Current time (servertime) hhmmss |
sys_timenowh | Current time (servertime) hh/mm |
sys_timestartf | Start time of interview hhmmss |
sys_timestarth | Start time of interview hh/mm |
sys_week | Week number 1-52 |
fasta cawi-variable:
Name | Description |
cawi_browser | Users browser |
cawi_cookies | Cookies set in session |
cawi_ipaddress | IP address of respondent |
cawi_language | Language of browser |
cawi_os | OS of respondent |
cawi_referer | Page refered from |
cawi_rspguid | |
cawi_pagenumcurrent | Current page number |
cawi_localtimeoffset | Time offset respondent vs server |
cawi_firstaccesstime | Time of first access format YYYY-MM-DD HH:MM:SSZ |
cawi_lastaccesstime | Time of last access |
Scripts:
The following table describes some of the scripts that you can use to create quantitative variables in Research Studio:
VB Script | Description |
autocode1(filename,text,lookupc,returnc,othercode) …. autocode4(filename,text1,text2,text3,text4,lookupc,returnc,othercode) |
Used to autocode open text based on lookups in an Excel file: Supply the followiung parameters filname - the XLSX file to search, there must be a sheet called Sheet1 rtext (1..4) - reference to an open question containing one or more rows of text to be coded lookupc -vname of column header where to search for text return - name of column containing code to be returned othercode - code to be assigned category 'other' or '-' to ignore lookups that are not found |
codeless1(code) | Returns 1:code-1 (typically used in answer control to limit answers to 1 less than the supplied parameter) |
codeupton(code) | Returns 0:code |
codexor(vara, varb) | vara and varb is a list of codes. Function returns an XOR between the codes (e.g. returning only the ones that are present in one of the variables. |
concat2(a,b) …. concat8(a,b,c,d,e,f,g,h) |
Concatenates the two or more parameters |
concat2x(a,b) …. concat8x(a,b,c,d,e,f,g,h) |
Concatenates the two or more parameters, however allows the following character placeholders to be automatically replaced by the proper value: _AND_SIGN_ "&" _QUES_SIGN_ "?" _EQUAL_SIGN_ "=” _SEMI_SIGN_ ";" |
curr_age(born,sysdate) | Return current age in years base by subtracting born and sysdate. “born” should be 4 digit year. Systdate should be 8 didgit yyyymmdd format. Typically use \@sys_date as parameter to get todays date. |
datetimediff(format,date1,time1,date2,time2) | Computs difference in date/time. Formats can be: "yyyy", "q", "m", "y", "d", "w", "ww", "h", "n" or "s" |
Diff(x1,x2,x3) | Calculates the difference between two values, x1 and x2. If x1 or x2 is non-numeric, the script alters the value with x3. |
Diff0(x1,x2,x3) | Calculates the difference between two values, x1 and x2. If x1 or x2 is non-numeric, the script alters the value with x3. If difference is negative, the script returns 0. |
Diffneg(x1,x2,x3) | Calculates the difference between two values, x1 and x2. If x1 or x2 is non-numeric, the script alters the value with x3. If difference is negative, the script returns the ABSOLUTE VALUE, e.g. positive. |
Div2(x1,x2) | Divide x1 by x2 |
echo1(arg1) echo2(arg1,arg2) |
Just returns the value input (used for e.g. testing) |
email2(a,b) | Concatenate two email addresses with “;” between |
EvenOdd(N) | Returns 1 if even, 2 if odd number |
fromto(fromx,tox) | Returns fromx:tox (typically to be used in an answer control to limit min/max value |
Hashsum(number) | Returns #number (typically to be used in answercontrol to limit number of responses |
invitation_qif_altid(qif, altid) | Constructs the url: "http://dc.miprocloud.net/dcwebengine/panelsurvey.aspx?qif=" & qif & "&altid=" & altid |
invitation_qif_altid_anchor(qif, altid, anchor) | Constructs the url above, wrapped in an <a> element with the text set to the “anchor” parameter. |
lindex(needle,haystack) | Returns the 1 based index of needle found in haystack. Haystack should be a # separated list. “– “returned if not found. |
isequal(arg1, arg2) | Returns 1 if equal, else 0 |
lengthOf(istr) | Returns length of string |
lteq4(p1,p2,p3,p4) | Returns 1 if p1<p2<p3<p4 else returns 0 |
Sum2(x1,x2) …… Sum12(x1,x2,x3,x4,x5,x6,x7,x8,x9,x10,x11,x12) |
Calculates the sum of two numbers. If any number is non-numeric, it is set to zero. |
multiAnswerCount(iStrListe) | Returns the number of answers |
Mult2(x1,x2) Mult3(x1,x2,x3) |
Multiples the input parameters |
Max2(x1,x2) Max3(x1,x2,x3) |
Finds the maximum of two /treenumbers. If any number is non-numeric, it is set to zero. |
MaxIndex20 (N1,N2,N3,N4,N5,N6,N7,N8,N9,N10, N11,N12,N13,N14,N15,N16,N17,N18,N19,N20) | Finds the index of the maximum number(s) up to 20 parameters. If any number is non-numeric it is set to 0 |
mktimerandom(xtime,xrandom) | Concatenates xtime and xrandom, making sure xrandom is 4 digits (prepends leading 0’s) |
Mult2(x1,x2) | Multiplies two numbers. If any number is non-numeric, it is set to zero. |
quarter(date) | Date should be minimum format YYYYMM (typically YYYYMMDD) returns quarter number 1,2,3 or 4. |
RandomMulti(lngRangeStart,lngRangeEnd,lngReturnCnt, iSeed) | Creates a list of randomly generated codes. Supply start code vale, end code value, number of codes to generate and seed. |
redirect_p1(pre,p1n,p1v) …. redirect_p8(pre,p1n,p1v,p2n,p2v,p3n,p3v,p4n,p4v,p5n,p5v,p6n,p6v,p7n,p7v,p8n,p8v) |
Construct redirect links with from 1 to 8 parameters. The redirect links is constructed as follows: pre&p1n=p1v&p2v=p2n……p8n=p8v E.g. redirect_p2(‘http://xyz.com/return’,’stat’,’1’,’id’,\id.a.1) will give http://xyz.com/return?stat=1id=1234 (if the id questions contains 1234. |
rspidredirect(rspid) | Redirects to: http://dc.miprocloud.net/dcwebengine/collect.aspx?rspid=" & rspid |
SelectRandomN(x1,x2,x3) | Select RANDOM codes from a list: x1 – Codes to pick from x2 – Numbers to pick x3 – A number to initiate the random generator, usually \@sys_random is used to ensure the same sequence the next time around. |
selectN(iStrListe,iIntNumberToPick) | Select the the n'th codes from a list |
SelectFirstN(x1,x2) | Select FIRST codes from a list. x1 – Codes to pick from x2 – Numbers to pick |
select1of5(ind,a,b,c,d,e) | Select the element pointed to by “ind” |
selectTopXFrom20 (r1,r2,r3,r4,r5,r6,r7,r8,r9,r10, r11,r12,r13,r14,r15,r16,r17,r18,r19,r20 ,topx,maxvalue,random) | Find the top X rows from a selection of 20 rows, max value of codes is maxvalue |
singleautocode(needle_in, list_in,list_out,not_found) | Will look for needle_in, in the # delimted list list_in. If found it will return the correspondning element from the list_out, else the not_found value is returned |
substr(inp, startp, lenp) | Return a substring of “inp” |
tomax(fromx, maxx) | Returns fromx+1:maxx (typically to be used in an answer control to limit min/max value |
tomin(tox, minx) | Returns minx:tox-1 (typically to be used in an answer control to limit min/max value |
TimeDiffSeconds(x1,x2) | The TimeDiffSeconds calculates the difference between ANY two timers, e.g. start and end time. Returns time used (in seconds) x1 = TimeStart |
timedifh(fromtimeh, totimeh) | Parameters should be in format hhmm, returns difference and accounts for midnight shift (assumes less than 24 hours) |