At the end of this session participants will be able to:
- Use the commands skip and ask if to skip fields
- Use if then else statements to implement skip patterns
- End rosters from logic using endgroup
- Automatically fill in fields using logic
In question F04 (other housing units), we need to skip over question F05 (numbers of housing units) if they answer "no".
To skip to a field, we need to use logic. To add logic to a CSPro application click on the logic button

on the toolbar to switch to the logic view. Here we can type in CSPro logic to control the program. Logic is added to a PROC (procedure) usually associated with a field on the form. To go to the PROC for a field in the logic view, just click on the field in the form tree on the left while in logic view. We will add our skip to the PROC of field
OTHER_HOUSING_UNITS so click on
OTHER_HOUSING_UNITS in the form tree.
To skip to a field, we use the command
skip. In order to skip only when the answer is no, we need to combine the skip with an
if statement as follows:
The
if statement only executes the code between the
then and the
endif if the condition (
OTHER_HOUSING_UNITS = 2) is true, otherwise it goes straight to the first command after the
endif.
This will skip directly to TENURE for individuals who answer "no" to OTHER_HOUSING_UNITS, skipping over the HOUSING_UNITS roster.
In addition to "=" to check if two values are equal, you can use the following operators:
Operation | Symbol |
Equal to | = |
Not equal to | <> |
Less than | < |
Less than or equal to | <= |
Greater than | > |
Greater than or equal to | >= |
For example, to skip over B08, residence one year ago, for those less than one year of age we could add the following logic to the PROC of the preceding question:
Note that once we have skipped the field RESIDENCE_ONE_YEAR_AGO, we can't get to it by clicking on it or going back from the following field. CSEntry keeps track of the fact that this field was skipped and won't let us back in until we change the value of AGE. This is an important difference between system controlled and operator controlled data entry mode.
We should add a comment to other readers of our logic so that they will understand what we are trying to do. This will not only help others understand our logic but it will help us when come back to it after a few months.
PROC PLACE_OF_BIRTH
// Do not ask residence one year ago for those less than one year old
if AGE < 1 then
skip to MOTHER_ALIVE;
endif
Everything on a line after // is considered a comment and is ignored by CSPro. You can also use /* */ for multiline comments. It is good practice to use plenty of comments to document your logic.
A note on coding style
When writing if statements, your code will be more readable and easier for others to understand if you indent the statements between the then and the endif. It is also helpful to use consistent capitalization. We recommend all uppercase for dictionary variables like
NUMBER_OF_HOUSEHOLD_MEMBERS and all lowercase for CSPro keywords like
if,
then and
endif. Finally, you should use comments as much as possible to help others, and your future self, better understand your code.
An alternative to the skip is the statement
ask if. It skips the current question if the condition is NOT met. For example, to use
ask if in order to only ask the question
RESIDENCE_ONE_YEAR_AGO (
B08) for those aged 1 and over we can use the following logic:
The
ask if statement skips over the question unless the condition
AGE >= 1 is true. In other words, if the age is less than 1, the question will be skipped. Note that when changing from
skip to
ask if, the condition was negated by switching from "<" to ">=".
The line
preproc tells CSPro to execute this logic
before asking the question. Our previous examples did not specify
preproc, so by default the logic was executed in the
postproc. Postproc logic is executed
after the data are entered. Preproc logic is executed before the data are entered. For each variable, you can specify a preproc, a postproc or both. The
ask if statement will always be used in the
preproc of the field being skipped while
skip can either be in the preproc of the field being skipped or in the postproc of the preceding field.
Group exercise
Implement the skip pattern for questions
F10 (has a toilet) and
F11 (type of toilet). If the answer to question F10, have toilet, is "no", skip question
F11, type of toilet. You can use either
skip or
ask if. Make sure to add a comment to your code and to format your code using correct indentation and capitalization.
As another example, we will implement the skip pattern for question
C01. We need to skip over
C02, highest level of education, if school attendance is "never attended" (1) or "don't know" (9). We can implement this with two if statements:
PROC ATTENDED_SCHOOL
// Skip over highest level education for those who never attended school
if ATTENDED_SCHOOL = 1 then
skip to LITERATE;
endif;
// Skip over highest level education for those whose attendance is "don't know"
if ATTENDED_SCHOOL = 9 then
skip to LITERATE;
endif;
Note that in CSPro, logic statements must be separated by semicolons (;). This tells CSPro when one command ends and the next begins. Forgetting to put the semicolon at the end of a statement is a very common error that new users make. If you forget the semicolon, usually CSPro will tell you that that a semicolon was expected, although sometimes it gets confused and gives you a less informative error message.
We can simplify this code by combining the two if statements using the "or" operator to create a compound condition.
PROC ATTENDED_SCHOOL
// Skip over highest level education for those whose attendance is "never attended"
// or "don't know"
if ATTENDED_SCHOOL = 1 or ATTENDED_SCHOOL = 9 then
skip to LITERATE;
endif;
In addition to the "or" operator you can also make compound conditions using the "and" operator. A compound statement linked by "or" is true if either one of the conditions are true but a compound statement using "and" is only true if both conditions are true.
In addition to "or", CSPro supports the following logical operators:
Operation | Keyword |
Negate an expression | not |
True if both expressions are true | and |
True if either expression is true | or |
You can also use compound conditions with
ask if. For example we only want to ask question
B14, age at first marriage, for those who responded "married" or "widowed" or "divorced" for marital status.
PROC AGE_AT_FIRST_MARRIAGE
preproc
// Only ask age at first marriage for those whose marital status indicates
// they are/were married
ask if MARITAL_STATUS = 2 or MARITAL_STATUS = 3 or MARITAL_STATUS = 4;
An "or" expression is true when either the left or right expressions are true so the question will only be asked if the MARITAL_STATUS is either 2, 3 or 4.
We can make our expression even simpler using the "in" operator which checks if a value is in a range:
PROC AGE_AT_FIRST_MARRIAGE
preproc
// Only ask age at first marriage for those whose marital status indicates
// they are/were married
ask if MARITAL_STATUS in 2:4;
A common pattern in CSPro is to use the
ask if statement to implement other (specify) fields. Let's implement the other (specify) field for question
F08, roofing material. First we add a new alpha field to the dictionary to capture the "other" value. We can call it
ROOFING_MATERIAL_OTHER and drop it onto the form so that it comes right after
ROOFING_MATERIAL. We only want to ask for the "other" value if they selected "other" (code 5) for ROOFING_MATERIAL, otherwise we want to skip it. We can do that using ask if in the preproc for ROOFING_MATERIAL_OTHER.
PROC ROOFING_MATERIAL_OTHER
preproc
// ask this question only if "Other (specify)" is picked in roofing material.
ask if ROOFING_MATERIAL = 5;
Now let's add the skip between sign language (
B12) and marital status (
B13) to skip to the next person for household members under 10 years old. In this case, what do we skip to? We can't skip to
B01 (line number) since that will try to send us backwards to the line number for the current row. Instead, we use
skip to next which automatically skips to the first field in the next row of the roster. We will put this skip in the postproc of
SIGN_LANGUAGE.
PROC SIGN_LANGUAGE
// Skip to next person for household members under 10 years of age
if AGE < 10 then
skip to next;
endif;
Let's add the skip in section C, education, for those under 3 years of age. We are only supposed to fill in the education section for those aged three years and above. We can use
skip to next to skip over the education questions if the age is less than three. We need to do this in the preproc of
C01, the first field in the education roster,
ATTENDED_SCHOOL.
Note that since this field already has a
postproc we need to add the
preproc first and then add the word
"postproc" so that the original
postproc logic does not become part of the
preproc.
Let's fill in the line number automatically so that the interviewer doesn't have to enter it. We can do this in the preproc of PERSON_NUMBER:
PROC PERSON_NUMBER
preproc
// Fill in line number automatically
PERSON_NUMBER = curocc();
The CSPro function
curocc() gives us the current occurrence number of a repeating record or item. In other words, it gives the row number of the roster we are currently on.
To avoid having to hit enter to move through this field we can use the statement
noinput which accepts the assigned answer and automatically moves to the next field as if the interviewer had used the enter key.
Alternatively, we can make the field uneditable by checking the protected box in the field properties. With
noinput it is still possible to go back and modify the field, but protected fields cannot be modified except from logic. Be aware that if you do not set the value of a protected field in logic
before the interviewer gets to the field, CSEntry will give you a fatal error.
Group Exercise
In question
B10, mother line number, automatically fill in the code 88 (deceased) if the response to
B09, mother alive, is "no". You may be tempted to use the skip statement for this but you should use the noinput statement instead.
Instead of using the occurrence control field in the roster, we could ask the user if they want to terminate the roster. To do that, we first add a new field to the dictionary and it to the roster. Let's call it
MORE_PEOPLE and give it the value set Yes - 1, No – 2. We will put it at the end of the names roster. If the interviewer picks "no" then we use the command
endgroup which terminates entry of the current roster or repeating form.
With this, we no longer need to use the occurrence control field of the roster. However, since the other rosters (demographics and education) still rely on the variable NUMBER_OF_HOUSEHOLD_MEMBERS as a roster control field we need to set its value after completing the names roster. We can make it a protected field, move it after the names roster and set it using logic:
PROC NUMBER_OF_HOUSEHOLD_MEMBERS
preproc
// Set number of household members to size of person roster.
// It is used as roster occurrence control field for later rosters.
NUMBER_OF_HOUSEHOLD_MEMBERS = totocc(HOUSEHOLD_MEMBERS_ROSTER);
This uses the function
totocc() which gives the total occurrences of a repeating record or item. In other words, it gives us the total number of rows of a roster.
There is also the
endlevel command which is similar to endgroup but skips the rest of the current questionnaire (except for two level applications when in a second level node where it terminates the current node).
We only want to ask question
B12, sign language, if the household member is hearing disabled. We want to skip question
B12 if hearing disabled is not checked in question
B11. How can we tell in logic if hearing disabled is checked? Hearing disabled is option B in the value set so we need to determine if the set of all checked options contains the letter B.
In CSPro logic we can use the function
ischecked() which returns true if a value is one of the selected values in a checkbox variable. Using
ischecked() the logic for skipping sign language if hearing is not checked is:
Note that since we are adding a preproc to a variable that already has a postproc we need to explicitly add the
postproc.
While this works, it creates a problem with the
skip to next in the postproc. If we enter an individual with age less than 10 who has no difficulty hearing we no longer skip the marital status question. This is because the
ask if in the preproc skips over the variable and the postproc is not run. Where can we put the
skip to next so that it will work for those who have no difficulty hearing? We can move it to the preproc of
MARITAL_STATUS.
- Skip question F07, monthly rent, if dwelling is not rented in F06.
- In section E, deaths, implement the skip pattern for question E01, any deaths.
- In section E, deaths, implement the skip pattern for question E08, mother of deceased, based on the age at time of death E07.
- In section E, deaths, implement the skip pattern for question E09, died while pregnant.
- In section E, deaths, skip questions E09 and E10 for deceased household members who are NOT women aged 12-50.
- In section E, use logic to pre-fill the line number field E03. Make sure that the line number is protected.
- Skip all of section C for persons under 3 years of age.
- Add an additional question to F13 to determine if the respondent wants to give the distance to water in minutes or kilometers. If they choose kilometers then skip the distance in minutes question otherwise skip the distance in km question.
- Add the other(specify) field and skip pattern for F08, wall material.
- Add the other(specify) field for B15, languages spoken.
- Automatically fill in the the possession code in question G01.
- In question G01, household possessions, skip the value field if the quantity is zero.
- Add variables and a form for section D: Fertility. Add the variables to the person record but create a new form with its own roster just like we did for section C. Don't worry about the last question on the form that displays the total births. We will cover that in a later lesson. Add the skip patterns for the fertility section. Don't forget to skip the entire section for males and females NOT between 12 and 50 years old.