Workflow Information Storage Toolkit

Workflow Information Storage Toolkit ("WIST") is a set of libraries and tools that allow multi-step workflow systems to be designed and deployed rapidly by abstracting workflows into reusable core components that can be added and arranged through a simple, intuitive configuration and template mechanism. The system also acts as a uniform application layer, which hides the details of the backend storage of information from the frontend user interface. This decoupling allows the backend storage engine and/or user interface to be changed independent of any other components in the system.

WIST Workflow Usage Requirements

Workflows generated with WIST require the end-user to use a modern web browser, that supports at least DOM level 2 and ECMA-262 edition 3 standards. While our goal is to support the most common browsers and platforms, our testing is limited to Microsoft Internet Explorer 6 and 7, and Mozilla Firefox 2.0 on Windows XP. Some additional testing is performed using Mozilla Firefox 1.5 on Linux and on OS X. In general, your browser must support the Document Object Model (DOM), Javascript, and some form of the XMLHttpRequest or equivalent object for AJAX. Typically, this includes Internet Explorer 5+, Firefox 1+, Mozilla 1+, Safari 1.2+, and Opera 7.6+. Finally, the end-user's browser must have cookie support enabled.

Creating Workflows

Workflows are defined using a special template language. Each workflow must contain a minimum of one workflow step as well as information that allows WIST to properly store the data it has collected from the various steps in your workflow. An unlimited number of steps are supported. Even though workflow branching is supported, it is recommended that the steps in a multi-step workflows be defined in a linear fashion. WIST currently does not validate that a defined workflow is properly configured to allow a user to reach the final commit step (see Internal Block Declarations section, below). Similarly, if branching is used, WIST cannot validate that your workflow is free of cycles. Workflows should be thoroughly tested prior to deployment!

Workflow templates are stored in the WIST workflow template directory of your particular installation. You should consult with your WIST administrator to determine where to create new workflows. Workflow templates have the extension .wf. The filename chosen for your workflow template (excluding the extension .wf) becomes the name of your workflow in the WIST system. For example, if your workflow template has a filename of, then the name of your workflow is my_test_workflow. The workflow template contains two types of sections -- step declarations, which define each step of your workflow and internal block declarations, which define how WIST handles your data for various operations. To support creating records, each workflow template must contain at least one step declaration and one commit declaration. The following two sections describe how to create step declarations and how to define internal block declarations.

Workflow Step Declaration

Each step declaration contains three parts. First, steps must be defined using a step block declaration, which minimally contains:


Step names must be a single word beginning with a letter followed by zero or more word characters ([_A-Za-z0-9]). There are several step names which are reserved by WIST as internal block identifiers and which cannot be used to label any steps in your workflow. These names currently include global, load, browse, view, edit, and commit. These internal block identifiers define how WIST interacts with the backend storage engine and therefore must usually be defined. Please see the Internal Block Declarations sections below for more information about each of these special blocks, how to define them, and how WIST will use them.

You may also provide an optional description for any of the steps you are defining:

   [stepName:Insert Description For This Step Here]

Step descriptions are not required however their presence will greatly assist end-users in identifying which step of a workflow they're completing. The description is used in the HTML document title and displayed as a heading on the rendered form. If no description is given, the workflow step's block name will be used instead and in most cases due to its formatting limitations, is less useful to end-users.

Workflow Step-Specific Options

The second part of a step declaration is to configure step-specific options. At present these include the template, nextStep, exportEnv, and type attributes.

The template value specifies which layout template WIST will use to render this step of the workflow. If this option is not specified, the automatic layout engine will be used to produce a simple tabular layout (example below). The template name will correspond to a WIST HTML template located in the HTML template directory of your installation with the prefix layout. and extension .tmpl. For example,

   [step1:The Initial Step]

will cause WIST to use the HTML template called layout.myworkflow.tmpl in the WIST HTML template directory. For more details on creating WIST HTML templates, please see the WIST Macro Markup Language section below. Writing custom WIST HTML templates is not required unless the layout provided by the automatic template isn't suitable for a particular workflow or workflow step. In all other cases, we recommend using auto for an aesthetically pleasing tabular form output (example below). The auto template is used by default if a template is not specified or inherited from a declaration in the global block.

The nextStep value tells WIST to which step a user should be directed upon completion of this step. In general, this should refer to the next step in your workflow. There is an internal block called commit (described in more detail below in the Internal Block Declarations section, below) to which the last step in your workflow should point. Failing to configure the last step of your workflow to direct to commit will prevent workflow data from being saved. Each step must explicitly define a nextStep value. Branching is supported by specification of a field value's macro as part of the nextStep value. This allows certain portions of your workflow to take different paths based on the value or values specified in any previous step. For example,

   [step1:The Initial Step]
   [step2_type1:Form for Analysis "Type 1"]
   [step2_type2:Form for Analysis "Type 2"]

specifies that the second step in the workflow be a function of the value specified for a field called analysisType. This could be a drop-down selection box with a number of different analysis types with values type1, type2, etc. It is also perfectly reasonable to branch, and eventually merge back into a single workflow step if only a portion of the workflow differs.

The exportEnv value allows a particular workflow step to export any one of the available environment variables to be used internally by WIST, either as a display template macro value or as a value in any of the internal block declarations. For example, this is useful to capture variables exported by the web server, which often includes the remote user's IP address and any authentication information being used. For example, the Apache web server often exports REMOTE_ADDR, which contains the remote user's IP address. Please see your web server's documentation for a list of variables exported as part of the Common Gateway Interface (or CGI).

The type value specifies the storage engine WIST should use. At present, only the type db is supported, however we may support a file based storage engine in the future.

The third and final part of each step declaration are the field declarations. A step declaration need not contain any fields. For example, in the last step of your workflow you may wish to present the user with the information they supplied and ask them to verify it prior to committing the information. In this or any similar confirmation step, only information from previous steps will be used in the display and no additional data is collected, therefore this particular step will not have any fields declared. In general, however, each step will contain at least one field declaration. Each field has a specific type, optional descriptive label, and optional verification criteria. There are also options specific for each field type. The general field declaration will look like:

   fieldName = {
                  type=fieldType ...fieldOptions...

fieldName is a one word string defined similarly to the step name (above) and must be unique for each field within a workflow. The fieldName is referred to later in designing custom layout templates as well as in internal block declarations and therefore should be short, relevant, and easy to remember. Mixing up field names may result in your form being improperly rendered, or during other operations such as creating a new record or updating an existing record, may result in loss or corruption of data.

fieldType specifies the input user interface component to be used in rendering the field. At present, ten (10) input component types are supported, as defined by the table below. The column Supports Multi indicates whether the input component type supports the allowMulti option. This option allows the input component to self-replicate up to the maximum number of components specified by the multiMax attribute and is useful in cases where a particular field can support one or more values. Details on using the allowMulti option are described below in the Field-Specific Options section.

Type Description Supports Multi
checkbox On/off check box no
date Date input component no
datetime Date and time input component no
file File upload component yes
multiselect A list of options allowing a user to select one or more options no
parsed A pseudo-field used to accept bulk data to be parsed and inserted en masse (see Parsed Fields below) no
radio Radio buttons allow a user to select one of a number of predefined options where all options are visible no
select Drop down box allows a user to select one option yes
text Single-line text input box yes
textbox Multi-line text input box no
time Time input component no

Parsed Fields

WIST supports fields that can be used to accept bulk data to be parsed and inserted en masse. Parsed fields are different from the other field types in that it only makes sense to use them when creating new records. When editing an entry from a workflow that contains a parsed field, the parsed field will be disabled and a message will be displayed above the form element stating This is a parsed field and is only used when creating new records. When viewing an entry from a workflow that contains a parsed field, the parsed fields are treated as hidden (see Field-Specific Options, below) and will not be displayed. The WIST Browser supports parsed fields however you must configure the field to be shown and define the appropriate database queries for populating the field. Parsed fields still rely on an underlying field in order to accept information. At present, only text, textbox, and file fields are allowed. Please see the special parsed field options below. Some attributes are always required and are indicated as such in their respective descriptions.

Field Type Attribute Description
subtype=<text,textbox,file> (required) Specify the field to be used to accept the parsed data. At present, only text, textbox, and file field types are supported.
format=<tab,csv,custom> (required) Specify the format of the bulk data to be input. tab, the default if no format is specified, indicates the bulk data will be in tab-delimited format. csv indicates the bulk data will be in Excel CSV, or comma-delimited format. Data containing embedded delimiter characters must be enclosed in double quotes to prevent incorrect parsing. The custom type allows you to define a regular expression using the customRegExp attribute to capture entries from the input data. Use this type for any data that is not encapsulated in tab- or comma-delimited formats.
customRegExp=<regexp> (required if format=custom) Specify the regular expression to be used to extract individual entries from the bulk data. Your regular expression must export subpattern groups representing individual fields from the data that correspond to the columns definition.
columns=<c1,c2,...> (required) Specify the names of the fields included in each entry in the bulk data. For tab and csv formats, this corresponds to the columns in the spreadsheet. For the custom format, this corresponds to each subpattern group that is exported by customRegExp.
strict[=<boolean>] Enable strict parsing. By default, entries that do not contain sufficient fields according to the columns definition are still added with any missing fields blank. Also, individual fields from each entry that do not match their specified regular expression pattern regexp_<columnName> will still be added. Enabling strict parsing will prevent these rows from being added.
regexp_columnName=<regexp> Each column defined in the columns attribute can also have an associated regular expression. Data from this field or column will be tested against the specified pattern and a warning will be generated if the input data does not match. In strict mode, the entire row will be rejected. columnName is case sensitive and must match exactly the column name provided in the columns attribute.

Additionally, any of the field-specific options supported by the specified subtype field are also supported. Please see the Field-Specific Options, below.

The data that is exported for parsed fields to the commit block is also slightly different. The following table explains what macros will be exported and the format of the data.

Macro Description
%fieldName This is the primary data structure which will contain the bulk data in an array, therefore to access all data you must iterate over this data structure using the foreach construct. Each entry contains exported macros according to the column names defined in the columns attribute. For example if you specified columns=a,b,c,d, each iteration of the foreach loop will export %a, %b, %c, and %d macros.
%fieldName_file_id If the parsed field subtype is file, the Pcapstore id for the stored parsed file will be exported using this macro
%fieldName_num_entries This value corresponds to the number of extracted entries. For tab and csv types, this will correspond to the total number of non-empty lines in the input data. For custom data, this will correspond to the number of entries extracted using the supplied regular expression customRegExp.
%fieldName_bad_entries This value corresponds to the number of rejected entries. This value will always be 0 unless strict mode is enabled
%fieldName_bad_fields This value corresponds to the total number of field values that failed to match their specified regular expression patterns. Note this does not necessarily mean the row was rejected.

Field-Specific Options

Each field type listed in the previous section supports its own set of modifiers, which generally control how the input component is rendered. For example, if you have a single-line text-input box, one option controls how wide the box is. Since there are very few field-specific options that are universal, each set of options for each input component type will be described below. Some attributes may be replicated from type to type and except as noted have the same modification properties across types. The following is a table of all presently supported field-specific options, by field type.

Type Field Type Attribute Description
global default=<value> Set the default value for any field. You must use a format compatible with the field type. For field-specific usage, see the default attribute for the specific WIST field type. All fields support retrieving the default value from a database query or on-the-fly using an external function or field-dependent database query called using AJAX. To use a database query use a value formatted as db:(host,user,password,database):<query> where host is the database hostname, user and password are the database credentials, and database is the name of the database or schema that contains the table or tables from which your query obtains the value, and query is an SQL query which must return at least one row with a column value corresponding to the value you wish to use as default. If multiple rows are returned, the value from the first row is used. On-the-fly default values via AJAX can be generated using an external function or database query. If your database query does not depend on a value in the current workflow step, you should use the database method outlined above. The AJAX method is only required for external functions or for database queries that depend on values in the current workflow step. To use the AJAX method for an external function specify a value of ajax(function):<Namespace::Function(%field1,%field2,...)> where Namespace::Function is the full namespace and function name of the external function and %field1, etc represent field identifiers from previous workflow steps or from the current workflow step whose values are required in order for the external function to function. Only the fields you specify will be exported to your external function. To use the AJAX method for a database query specify a value of ajax(db_query[,host,user,password,database]):<query> where the database parameters are optional and identical to those described above and the SQL query follows the same conventions as with the database method described above. It must select at least one row containing a column value and should include references to at least one %field in the current workflow step.
global readonly[=<boolean>] If true, the field's value cannot be changed
global hidden[=<boolean>] If true, the field is not displayed in the entry viewer; this is useful for internal values
multi n/a multi fields allow individual fields to be replicated dynamically by the user or by a linked value or field. multi is currently supported for text, select, and file and all multi options are available for each of those types
multi allowMulti[=<boolean>] Allow multiple values to be submitted for a single field component. By default, multiShowMin input fields are displayed (or the value defined in the WIST configuration property multi[multiShowMin], if multiShowMin is not declared) and up to multiMax (or the value defined in the WIST configuration property multi[multiMax], if multiMax is not declared) input fields may be added dynamically by the user.
multi multiShowMin=<value> If allowMulti is enabled, show <value> fields by default. If not declared, the value from the WIST configuration property multi[multiShowMin] will be assumed.
multi multiMax=<value> If allowMulti is enabled, allow up to <value> fields to be present. If not declared, the value from the WIST configuration property multi[multiMax] will be assumed.
multi multiNumFields=<int or %field > If allowMulti is enabled, the number of fields will be the number specified if multiNumFields is set to an integer value. If multiNumFields is linked to a field and the field's value controls the number of displayed fields. The linked field must be in the same workflow step or a previous workflow step and its value must be an integer. The linked field type can be text or select only. Specifying multiNumFields disables user-controlled adding/removing of fields and overrides any settings in multiShowMin and multiMax.
checkbox default=<boolean> Set whether the checkbox should be checked by default; use a boolean value: true/false corresponding to checked/unchecked, respectively
date useCalendar[=<boolean>] Enable the pop-up calendar for selecting dates? If this option is specified without a value, true is assumed.
date useFreeform[=<boolean>] Enable free-form text input of the date? By default, each field of the date is selected from a drop-down box or selected from a calendar if useCalendar is enabled. If this option is specified without a value, true is assumed.
date default=<value> Set the default date for the input field. The date must be specified in a format consistent with the WIST configuration property date[format]. The keyword now is supported and is also default if this option is omitted.
time useFreeform[=<boolean>] Enable free-form text input of the time? By default, each field of the time is selected from a drop-down box. If this option is specified without a value, true is assumed.
time default=<value> Set the default time for the input field. The time must be specified in a format consistent with the WIST configuration property time[format]. The keyword now is supported and is also default if this option is omitted.
datetime useCalendar[=<boolean>] Enable the pop-up calendar for selecting dates? If this option is specified without a value, true is assumed.
datetime useFreeform[=<boolean>] Enable free-form text input of the date and time? By default, each field of the date and time is selected from a drop-down box or selected from a calendar if useCalendar is enabled. If this option is specified without a value, true is assumed.
datetime default=<value> Set the default date and time for the input field. The date must be specified in a format consistent with the WIST configuration property datetime[format]. The keyword now is supported and is also default if this option is omitted.
multiselect allowNewValues[=<boolean>] Allow the user to add new values to this select list? By default, select lists are read-only. If this option is enabled, you must also define the newValues attribute, which defines how WIST stores new values added through the user interface.
multiselect maxSelected=<value> Limit the number of options that can be selected for an individual field to <value>. By default, unlimited options may be selected. NOTE: This feature remains unimplemented.
multiselect valuesSource=<source> Defines how WIST should populate this select list. As of the time of this writing, select list values may be declared as a fixed set of options or retrieved dynamically from a database using the following syntax. For fixed option sets, define the list of values and descriptions using opts:<value1:description1,value2:description2,...,valueN:descriptionN>. You may also omit the description for any of the values in a fixed set of options. The value will be used as the description if no description is specified. For example opts:<value1,value2:description2,value3> is valid and equivalent to opts:<value1:value1,value2:description2,value3:value3>. For database option sets, define the database parameters and SQL query for retrieving the value and description list using db(host,user,password,database):<SQL query>. The SQL query must alias the value and description columns retrieved to id and value respectively, such as in this example: <SELECT `userId` AS `id`, `name` AS `value` FROM `mydb`.`myusers` ORDER BY `name` ASC>. The id column contains values equivalent to the set value1,value2,...,valueN from the fixed option set and the value column contains values equivalent to the set description1,description2,...,descriptionN. In both cases, the id values represent the values that are internally stored by WIST whereas the value values represent the display values used in rendering the list only.
multiselect newValues=<storage> If allowNewValues is enabled, and valuesSource is not read-only (such as a fixed option set), this attribute defines how WIST should store new values supplied by the user. Unfortunately, since WIST deals with only an internal id value and display value, the user interface only supports adding new entries by display value only. For example, if selecting from a list of PCAP users where the user's name is the option description, it must be possible to create new values in the PCAP user database by simply inserting a row with the name of the new user. In short, the id value must be auto-generated by the database table and all other fields must be optional. WIST currently does not support pop-up forms for creating new entries with the ability to populate other fields. At present, only database storage of new values is supported with the following syntax: db(host,user,password,database,table,id_key,value_key). The table value specifies the name of the database table to which new values will be inserted and id_key and value_key specify the names of the fields representing the id and value columns, respectively. When adding new values that require a unique integer identifier, the table must automatically generate this id through the use of an autoincrement integer primary key as WIST is unable to generate these id values.
multiselect default=<value1[,value2,...,valueN]> Specifies which options in the select list should be selected by default. Note, the value must match or or more of the values in the id column if valuesSource specifies a database option set. Multiple values may be selected by default by supplying a comma-delimited list of option values. By default if this attribute is omitted, none of the options will be selected.
radio default=<value> Specifies which radio button option is selected by default. If not present, none of the options will be selected by default.
select allowNewValues[=<boolean>] Allow the user to add a new value to this select list? Works similarly to the allowNewValues attribute for the multiselect field type; see description, above.
select valuesSource=<source> Defines how WIST should populate this select list. Works identically to the valuesSource attribute for the multiselect field type; see description, above.
select newValues=<storage> If allowNewValues is enabled, and valuesSource is not read-only (such as a fixed option set), this attribute defines how WIST should store the new value supplied by the user. Works identically to the newValues attribute for the multiselect field type; see description, above.
select default=<value> Specifies which option in the select list should be selected by default. Note, the value must match one of the values in the id column if valuesSource specifies a database option set. By default if this attribute is omitted, none of the options will be selected.
text width=<value> Specifies the width of the text input field, in <value> characters. This modifier is browser-dependent and may not produce identical results across different browsers. If not specified, the value in the WIST configuration property text[width] will be assumed. If this value is not defined or if the value is set to 0, the browser's default width will be used.
text maxLength=<value> Specifies the maximum number of characters that can be supplied as input for the text input field to <value> characters. Note this is an HTML limit, which some browsers may choose to ignore. It is therefore recommended that this attribute not be used in place of the maxLength verification option, described below in the Field Verification Options section. If not specified, the value in the WIST configuration property text[maxLength] will be assumed. If this value is not defined or if the value is set to 0, the HTML-based restriction is imposed.
text default=<value> Specifies the default value for the text input field. If the default value exceeds the maximum length defined by the maxLength attribute described above, the value may or may not be truncated depending on the browser.
textbox width=<value> Specify the width of the multi-line text box, in characters. If this attribute is not defined, the value in the WIST configuration property textbox[width] will be assumed.
textbox height=<value> Specify the height of the multi-line text box, in lines. If this attribute is not defined, the value in the WIST configuration property textbox[height] will be assumed.
textbox default=<value> Specifies the default value for the multi-line text box field.

Field Verification Options

Values supplied by the user can be verified against any of the following criteria by specifying the desired verification keyword, and any required arguments in the formats described below. When multiple verification criteria are specified, they are evaluated left-to-right and must all evaluate to true. The only exception is when a field's value is not required using the required keyword. In this case, if the user's supplied value is empty or contains only whitespace characters the value will be considered empty and none of the verification checks will be performed. Most of the verification checks are performed in Javascript, however some are processed by WIST and require the form to be posted before the checks can be performed. This accounts for the difference in behavior between some checks being instantaneous versus requiring an additional page-load.

Verification Option Javascript? Description
lengthRange=<range> Yes Requires the length of the supplied value be within the inclusive range specified as min-max, min ≤ max. Any leading or trailing whitespaces are trimmed before this verficiation criteria is tested.
maxLength=<value> Yes Requires the length of the supplied value be less than or equal to <value>. Any leading or trailing whitespaces are trimmed before this verification criteria is tested.
minLength=<value> Yes Requires the length of the supplied value be greater than or equal to <value>. Any leading or trailing whitespaces are trimmed before this verification criteria is tested.
required[=<value>] Yes A value is required for the specified field. Any leading or trailing whitespaces are trimmed before this verification criteria is tested. For multi fields, specify as the value the minimum number of required values for the specified field, or the special keyword all that requires all multi sub-fields are given a non-empty value. For multi fields, if no value is specified with this attribute, one value is required.
valueRange=<range> Yes Requires the supplied value be within the inclusive range specified as min-max, min ≤ max, for integer fields only. Javascript's parseInt is used on the trimmed string value to determine its integer value.
valueRegExp=<regexp> Yes Requires the supplied value match the specified regular expression.
function=<function> No Requires the specified <function> return a true (integer value '1') status value when given the supplied value as an argument. When specifying the function, you must specify the full Perl namespace unless the function is globally exported (which is not the case for most user-written functions). The function takes minimally one input argument, which is the user-supplied value, however when your function is called two arguments will be passed in as arguments. The second is a reference to a hash containing all of the current session variables, which allows you to access the user-supplied values for any other field in the current step of the workflow or from any previous step. To access session values, use a key corresponding to the fieldName specified for the field whose value you wish to retrieve. Your function must return a reference to an array containing two elements. The first is a status code -- an integer value '1' corresponds to successful validation of the value and an integer value '0' corresponds to validation failure. The second field is optional and generally only used when a non-successful validation has occurred. It is used to specify an error message to be returned to the user. The error message will be prefaced by the string Field '<fieldLabel>'. Your function should attempt to deal with all possible errors, however in the event of a fatal error your function can return a scalar status code. If the returned value is scalar, it is treated as an error regardless of the value of the status code.
in_set=<source> No Requires the supplied value match one of the values in the specified set defined by <source>. The set is defined similarly to the valuesSource attribute for select and multiselect fields. You may specify a fixed set of values by using the syntax opts:<val1,val2,...>. For example, the following would require that the user's supplied value be either 1, 3, or 5: in_set=opts:<1,3,5>. You may also specify an SQL query to retrieve a set of values from the database using the syntax db(dbHost,dbUser,dbPassword,dbDatabase):<SQL query>. The <SQL query> must retrieve or alias at least one field called value and only the values from this column will be used to build the set. The query can reference any value from a previous step or the current step in the workflow through the use of %macros.
not_in_set=<source> No Requires the supplied value not match any of the values in the specified set defined by <source>. The set is defined identically to the above in_set verification directive.

Other Field Options

There are several optional field attributes that generally provide for a more user-friendly workflow. It is recommended that as many of these field attributes be used when appropriate to assist the end-user in using the workflow. Other field attributes control how empty values are treated by the database storage engine and for providing more descriptive error messages for verification failures. You may also selectively disable the use of certain WIST features for a given workflow. The table below describes all of the optional field attributes.

Field Option Description
dbNullValues=<val1,val2,...> Specify a list of values which should be interpreted as NULL values by the database storage engine. The special keyword _blank_ can be used to describe an empty value. All leading and trailing whitespace characters are trimmed from the supplied value before being compared to this set. If this option is not specified, the value as supplied by the user will be sent to the database storage engine.
description=<value> Specify a description of the field's purpose and any restrictions placed its acceptable values. The description is displayed when the end-user hovers the mouse over the field's display label.
label=<value> Specify the field's display label. This is used in the workflow to describe each input element. If this option isn't specified, the field's name will be used as its display label.
verificationDescription=<value> Specify a more descriptive error message that encapsulates the restrictions placed on the values for this field. By default WIST will generate its own error messages, which are often not very user-friendly. The error message is prefixed with the string Field '<fieldLabel>'. Currently it's not possible to specify a different error message for each verficiation criteria so a single message must be all-encompassing of restrictions placed on this field's value.

Internal Block Declarations

Internal block declarations are defined similarly to workflow step declarations, however the block identifier name is reserved and each internal block serves a specific function. Specifically, each block defines a basic operation required by WIST in order to interact with the backend storage engine. Not all internal blocks must be defined however your workflow will lack some functionality, according to the table below.

Internal Blocks Required WIST Function/Operation
browse WIST Browser capability allows users to browse data for a particular workflow allowing the user to filter and sorting data using any of the configured fields and presenting information in an easy-to-read paginated format
commit WIST's add record capability allows users to create new records for a particular workflow
load, edit WIST's edit record capability allows users to modify a record in a particular workflow
view WIST Viewer capability allows users to view a record from a particular workflow

These blocks are required because certain functions require a field's display value whereas others require the field's internal id value. For example, a drop-down field is a list of options where each option has a unique identifier and some descriptive text. When you select a value, WIST stores only the unique identifier to save space in the storage engine, however when viewing an entry one would generally like to see the descriptive text instead of the unique identifier. Essentially, conversion of the WIST's internally stored values to the desired values is accomplished through the use of SQL queries, which must be defined in the blocks listed above if the associated functionality is desired.

Another example of this is a date field. SQL databases have an internal representation of dates and times that can be used for sorting and range/delta operations that may or may not be the same as the date and time format defined by your WIST administrator. Therefore, when a date or time is displayed it must be converted from the SQL internal format to the format defined by your WIST administrator, however if the user is sorting on a date field, we want to ensure that the internal SQL value is used in order to ensure proper sorting.

global Block

If defined, this should be the first block defined in your workflow. This block can be used to set global values for certain attributes that apply to all workflow steps and/or some or all internal block declarations. For example, if all of your workflow steps use template=auto, you can simply set the template attribute in the global block once instead of replicating it for every step. This has the added benefit that if you wish to change a particular attribute later, you need only modify it in one place. Other than the template attribute, you may wish to define the storage engine type attribute, along with the database parameters that would otherwise have to be defined for the other internal block declarations: dbHost, dbUser, dbPassword, dbDatabase.

Use of the global block is not required and it is perfectly acceptable, albeit potentially more difficult to maintain, to simply replicate the attributes for every block even if they have the same value.

Here, you may also disable certain WIST workflow features by using the disableFeature attribute:

Attribute Description
disableFeature=<f1,f2,...> Specify a comma-delimited list of WIST features that you wish to disable for this workflow. Select one or more from the following list: create, edit, view, browse.

browse Block

This block defines some necessary parameters in order for the WIST browser to view the data generated through a particular workflow. First, you must define the fieldOrder, which lists all the desired fields you wish to display in the browser as columns and the order in which the fields should sppear. It isn't required and it often isn't desired to display all workflow fields as this may result in a view that requires the user to horizontally scroll to see the entire table. The value for the fieldOrder attribute should be a comma-separated list of fieldNames as defined in the various steps of the workflow.

If a field's value can be used for hyperlinking to another workflow browser or entry viewer, you should define its fieldUrl attribute. The fieldUrl attribute is an associative array where the fieldNames are used as keys and the value contains a URL generated using macros (see details below). Any of the retrieved values from this block's script definition can be used, along with any global WIST attributes as defined by your WIST administrator. These include at least %cgiUrl, %workflowCgi, %workflowViewCgi, %workflowBrowseCgi, %workflowGetFileCgi, and %workflowImageThumbnailCgi. Here is a complete example:


As mentioned above concerning internal vs. displayed date and time formatting, all date and time fields present in the fieldOrder attribute must also have a sort attribute. The sort attribute is an associative array whose keys represent fieldNames and whose values map fieldNames to internal table values to be used when sorting on date/time fields in the WIST browser. The table field reference should include the table or table alias as well, for example:


The optional fieldLabel attribute can be used to overwrite the label given to a particular field. It is also an associative array whose keys represent fieldNames. For example, if the label defined for contact_user_id is too long for browsing purposes, one need only overwrite it using:


The maxRows attribute sets the maximum number of entries/rows to be displayed per page.

If the browser detects that a displayed file field contains an image, it will attempt to generate, cache, and display a thumbnail if the image. You can control the thumbnail's width by setting the thumbnailWidth attribute. Image thumbnails cannot be disabled other than by disabling the column containing the image from being displayed in the browser.

Finally, the script attribute defines the SQL query used by the browser to retrieve data from your workflow. The query must be defined on a single line. This query is quite complex and you should start by first defining a query which retrieves all of displayed field's internal WIST values, along with the record's primary id value, which must be aliased to id. If your data is stored across multiple tables, this will require JOIN or sub- SELECT queries. You must alias each retrieved field to match its corresponding fieldName as defined by the workflow, except for internal id values which must be mapped to display values. For these fields, you should alias them to their corresponding fieldName and append the suffix _id. For example, if a drop-down field's name is contact, you should alias the internal contact id as contact_id. Next, you must join to all supplemental and referenced tables in order to map internal id values to display values. The display value must always be assigned to the fieldName defined by the workflow. In the previous example, we would join with the referenced contact table and retrieve the name value from that table aliased as contact. Again, note, the internal id should be given an alias of the fieldName with a suffix of _id (contact_id in the example) whereas the display value is given an alias of the fieldName (contact). Date and time fields, which require conversion from the SQL format to the WIST format require the use of the DATE_FORMAT (present in MySQL) or equivalent function. Keep in mind that a literal % (percent character) has a special notation of %%# due to its use in the WIST Macro Markup Language.

Now that you have this query, it should retrieve a total of i + 2j + 1 fields, where i is the total number of fields listed in fieldOrder and j represents the number of fields from fieldOrder whose display values must be mapped from internal values, j ≤ i. This query should retrieve all records associated with your workflow.

There are several internal macros defined specifically for the WIST browser and these must be appended to the query generated above in the correct order according to the SQL syntax of your backend database. The example given below indicates the exact SQL query suffix for MySQL.

The %sort_filters_ macro contains a HAVING clause limiting which rows are returned by the database storage engine. HAVING is preferred over WHERE due to the latter's inability to deal with aliased columns, despite additional overhead incurred in using the former. The %sort_field_ macro contains the name of a field which should be used to sort the results in an ORDER BY clause. Note, if you've defined a sort attribute for a particular field, it's value from the sort attribute is substituted as %sort_field_ instead of the field name itself. The %sort_direction_ is either ASC for ascending sort or DESC for descending sort and generally follows the ORDER BY clause. Finally, the %start_record_ and %maxRows macros define the starting record and maximum number of rows to return, respectively and in MySQL are used in the LIMIT clause.

In MySQL, the following suffix should be appended to the query you generated above:

%sort_filters_ ORDER BY %sort_field_ %sort_direction_ LIMIT %start_record, %maxRows

The following is a fictitious example, to illustrate a proper browse block. Note that if all of your workflow values are stored in a single table with references to other tables, you may be able to use the WIST Builder to generate the entire workflow for you. See below for more details on the WIST Builder.

Our example workflow contains three values: a, b, and c, stored in the table foo corresponding to the workflow fields alpha, bravo, and charlie, respectively. The table field c is an SQL DATE field and the WIST preferred date format is dd-MM-YYYY or %d-%b-%Y in strftime format. Refer to your database storage engine's Date and Time types section for conversion functions and how to properly use them. This example assumes use of MySQL. The table field b is an integer id value which references the table bar. This table contains a number of fields, however we wish to use the name field as b 's display value. The following browse block is required for our example workflow:

script = {

SELECT AS id, foo.a AS alpha, foo.b AS bravo_id, AS bravo, DATE_FORMAT(foo.c, '%%#d-%%#b-%%#Y') AS charlie FROM foo JOIN bar ON (foo.b = %sort_filters_ ORDER BY %sort_field_ %sort_direction LIMIT %start_record, %maxRows


commit Block

The commit block defines how workflow values are saved to the backend storage engine. In general, it involves defining the script attribute, similarly to that defined in the browse block, above. However, in addition, once values are saved, a template is displayed to the user that usually notifies the end-user that his/her entry has been saved. The template attribute defines which template is displayed to the user and its value will correspond to a template file in the WIST template directory with the prefix commit. and suffix .tmpl.

The script attribute should define one or more SQL statements, which will be executed sequentially, to properly store all workflow field values into the database. Each SQL statement must be wholly contained on a single line. All field value macros are available and any values that must be post-processed or converted prior to insertion into a database table must be handled by the SQL only. Any date, time, or datetime field must be converted from the WIST string format to a format accepted by the database server for each data type. In MySQL, this can be done using the STR_TO_DATE function, which uses strftime macros, similar DATE_FORMAT. Please see your database server's date/time functions for an equivalent function if you're not using MySQL.

Based on the example from the browse block, here is the corresponding commit block:

script = {

INSERT INTO foo (a, b, c) VALUES (%alpha, %bravo, STR_TO_DATE(%charlie, '%%#d-%%#b-%%#Y'))


load Block

The load block only has a single attribute script, which defines how a single entry from your workflow is loaded for editing. WIST allows users to edit entries using the same user interface that allows users to create entries, therefore we wish to load internal values as opposed to display values as in the browse block except for date, time, and datetime fields. These fields need to be converted from SQL internal values to WIST display values using the DATE_FORMAT or equivalent function. Since this query is retrieving a single entry, you must limit the results using a WHERE clause along with the special macro %edit_id_.

script = {

SELECT a AS alpha, b AS bravo, DATE_FORMAT(c, '%%#d-%%#b-%%#Y') AS charlie FROM foo WHERE id = '%edit_id_'


edit Block

The edit block is almost identical to the commit block. The template attribute specifies a display template to be used upon a successful record update. The corresponding template file is also given a prefix of commit. and a suffix of .tmpl, since both commit and edit use the same underlying processing engine. Finally, the script attribute defines the query to use to update a single record. As with the load block, a special macro %edit_id_ specifies the record's primary record id value. The script attribute, like in the commit block, must also convert display values for date, time, and datetime fields to their SQL-equivalent format using the STR_TO_DATE or equivalent function.

script = {

UPDATE foo SET a = %alpha, b = %bravo, c = STR_TO_DATE(%charlie, '%%#d-%%#b-%%#Y') WHERE id = '%edit_id_'


view Block

The view block is similar to the load block in that it contains information that tells WIST how to load values for a single entry. The main difference is that the view block is used to load the display values for every field in the workflow whereas the load block was used to primarily load the values stored by WIST (with the exception of date, time, and datetime fields). Since this data is used to generate the view for a single record, it has some similar features to the browse block, which controls how data is retrieved and formatted for displaying multiple records. As with the browse block, fields which can be hyperlinked to other workflows or to external references can be configured via the fieldUrl attribute. Likewise, you may also overwrite the defined label for a given field by using the fieldLabel attribute. Also, file fields that are determined to be images will be shown with a thumbnail preview automatically and as with the browse block, the thumbnailWidth attribute controls how wide the thumbnail is, in pixels. Finally, the script attribute contains the SQL query to load the display values for every field in the workflow. As with the browse block, fields that internally contain ids that reference other tables should have the id value aliased to the fieldName with a prefix of _id and the display value aliased to the fieldName. The browse block contains more details. The record id is passed through a special macro %view_id_.

script = {

SELECT AS id foo.a AS alpha, foo.b AS bravo_id, AS bravo, DATE_FORMAT(c, '%%#d-%%#b-%%#Y') AS charlie FROM foo JOIN bar ON (foo.b = WHERE = '%view_id_'


Using WIST Builder to Create Workflows

WIST Builder is a tool to create single-step workflows where data from all of the fields in a workflow are stored in a single table. You must first create the underlying table and establish all foreign key relationships before using WIST Builder to create the workflow template.

WIST Builder is divided into several steps. The first step is to configure the database parameters, then to select the database and table for which you wish to build a workflow. At this time WIST Builder only supports InnoDB tables in MySQL. As mentioned above, you must already have created the underlying table and established all foreign key relationships. In addition, your table must have an integer auto-incrementing primary key to be used as one of the unique record identifiers.

Once you have selected the table you wish to use, you are asked to configure some basic parameters about each WIST field derived from the fields in the selected table. The WIST Builder attempts to automatically set the basic parameters based on information retrieved from the database server, however you should check all fields for correctness. Fields identified as being foreign keys are automatically referenced to their parent record by WIST Builder. You may also exclude fields extracted from the selected table for which you do not wish to expose a workflow step field.

After configuring the basic parameters, the next step allows you to configure all of the WIST field details, such as the field label and any restrictions on the data type, such as its maximum length or regular expression pattern. For fields that are foreign keys to other tables, you are asked to select which field from the parent table will be used as the display value.

For fields that are foreign keys to the PCAP-specific enumerated value table, you are asked to select which value group label identifies the values you wish to use to populate the list. You must create any new groups in advance of using WIST builder as otherwise they will not be available for selection. PCAP-specific enumerated value groups are not present or available in non-PCAP installations of WIST.

Next, you will be asked to configure some workflow details, such as the workflow's name and some other attributes such as the maximum number of rows to display in the browser. After completing this step, WIST Builder will generate the workflow template for you and output it to the screen. At this point you can copy and paste it into a new workflow template file, modify anything the WIST Builder did not allow you to configure and finally, deploy the form for testing.

WIST Macro Markup Language

All web user-interface templates and SQL scripts (when appropriate) in WIST use the WIST Macro Markup Language to allow on-the-fly substitution of values using a macro replacement system, as well as basic value formatting, conditional statements, and iteration. This section is divided into 6 sections cover Macros, Data Formatting, Conditional Statements, Iteration, Display Templates, and SQL Script Templates.


Macros are specially formatted variables whose values are replaced on-the-fly by WIST. They must begin with % sign and be followed by a macro identifier. This identifier must begin with a letter and can be followed by one or more optional letters, numbers, or underscore (_) characters. Identifiers may be of any length, however they must be unique within a template. Basic variable scoping is supported such that new macros introduced within the context of an iteration block may safely co-exist with other macros having the same name. In this case, all global macros are copied and new macros are added, overwriting any global macro that has the same name. Once the iteration block terminates, the global macros are restored.

A WIST display template contains a mix of WIST macros and HTML and is automatically expanded with all available macros replaced. For examples of how to write custom WIST display templates, please see the existing templates in your WIST template directory and see the section below on Display Templates.

Here is a short example:


If the %title macro contained the string "This is a test!", the following would represent the translated template as it would be displayed to the end-user:

   <TITLE>This is a test!</TITLE>

Finally, if a macro must be separated from trailing word characters, you must enclose the macro's name in { }, for example %{title} otherwise any valid characters will be assumed to be part of the macro name. For example, if you wish to append the word foo to the macro %test, specifying %testfoo is invalid, however %{test}foo will work as expected.

Data Formatting

There are several built-in data formatting and conversion options, generally meant for string formatting. They are listed below in a table and any number of data formatting commands may be specified comma-delimited following the macro name, enclosed in { } braces. If multiple data formatting options are specified, they are applied in left-to-right order. For example, %{test,lc,uc} will first apply lc (lower-case; see table below) and then will apply uc (upper-case).

Formatting Option Description
[i] For array values, return a scalar corresponding to the specified index i; see iteration below
lc All alphabetic characters in the string will be made lower-case.
lcf Only the first character in the string will be made lower-case. If the first letter is not an alphabetic character, this formatting option has no effect.
len[gth] Replace the string with a numeric value corresponding to its length
ltrim Remove leading whitespace characters from a string
proper The first alphabetic character of each word token will be made upper-case while all other letters in the word token will be made lower-case.
rtrim Remove trailing whitespace characters from a string
substr(start:[len]) Extract only the substring defined by the starting position (0-based) and length. For example if the macro %test contains the string "hello world", %{test,substr(0:5)} would display "hello".
trim Remove leading and trailing whitespace characters from a string
uc All alphabetic characters in the string will be made upper-case.
ucf Only the first character in the string will be made upper-case. If the first letter is not an alphabetic character, this formatting option has no effect.
unquote Unquote an escaped string, such as one escaped using DBI->quote()
%printf Reformat the value using the specified printf formatting option. For example, %{value,%0.2f} will format value according to the printf formatting option %0.2f.

Conditional Statements

Conditional statements allow you to display (or not display) certain elements or portions of your display template based on the value or certain macros. For example, if there are no rows in a table one could use a conditional statement to display an error versus displaying a table header with no rows. The basic if and else constructs are supported using the syntax below. Having an else block is not required. Unfortunately, a Perl-like elsif construct is not supported and must instead be written using nested if and else statements.

%[if condition]
   ...display element 1...
   ...display element 2...

The condition is a statement that is evaluated by Perl using the eval function. This generally works as expected, with one exception as explained below. For example, the condition could be %value > 0. You can even use the formatting options from the previous section in the condition, such as %{value,length} > 0. All macros and optional formatting options in your condition string will be replaced first, then the string will be evaluated by Perl. For this reason, when comparing string values, you must enclose macros in double quotes. For example, if the macro %test contains the string "this is a test", and the condition is %test eq "this is a test", the final string will be this is a test eq "this is a test", which of course will not evaluate to a proper Perl expression. Adding the double quotes around all macros solves this issue: "%test" eq "this is a test" will work as expected.


Data structures generated by WIST that contain multiple records or values can be used for iteration using a Perl-like foreach construct. If a macro %array contains multiple scalar values, it will be treated as an array of records containing a single key with the same name. As an example, if I assign the array [1, 2, 5, 7] to the macro %array, the following display template:

%[foreach %array]
  one value from the array: %array

will produce the following output:

  one value from the array: 1
  one value from the array: 2
  one value from the array: 5
  one value from the array: 7

For macros referencing an array of records, during each iteration pass, the record's internal macros are exported. Since this block exports macro values, you should pay close attention to variable scope. In addition, a special internal macro %i__ is exported, which corresponds to an internal counter starting at 0 and incrementing for each iteration loop until n-1 for n loops. This macro is generally not used for single array iteration but is useful for parallel arrays (see SQL Script Templates, below).

%[foreach %array]
  one value from the array: %array [index: %i__]

will produce the following output:

  one value from the array: 1 [index: 0]
  one value from the array: 2 [index: 1]
  one value from the array: 5 [index: 2]
  one value from the array: 7 [index: 3]

Display Templates

There are two classes of display templates -- one class controls the layout of the various components of WIST such as the layout of fields in a workflow step or the layout of data in the WIST Browser, and the other class of templates are used for general display purposes, such as for notifications. In general, one need not ever create a display template as WIST is bundled with stock templates that work in most cases, however WIST's templating system provides a very flexible means to customize the look, feel, and usability of workflows and other WIST components.

General Templates

General templates are further divided into two types -- internal templates and workflow-specific templates. Internal templates control the general look and feel of most WIST-generated pages and includes the page header and footer. Workflow-specific templates control all other non-layout aspects of the look and feel of WIST-generated pages, such as the message displayed to users when data they've submitted has been accepted and a new record created. Internal templates contain components that must be present in order for WIST to function properly and thus are described in more detail below.

For rendering of workflow-specific display templates, WIST will always export scalar global attributes from the WIST configuration, including attributes useful for building URLs, such as documentUrl, cgiUrl, imageUrl, workflowCgi, etc. It is important to use the global attributes to build URLs as static URLs may no longer function if WIST's configuration is modified. Please see the table below of typical WIST attributes used in building URLs. Please contact a WIST administrator for assistance with other WIST global attributes.

Attribute Description
cgiUrl Contains the absolute URI path to the WIST CGI root (Default: /wist/cgi-bin)
documentUrl Contains the absolute URI path to the WIST document root (Default: /wist)
imageUrl Contains the absolute URI path to the WIST static image directory (Default: /wist/images)
jsUrl Contains the absolute URI path to the WIST javascript directory (Default: /wist/js)
workflowCgi Contains the name of the primary workflow CGI script (Default: wist)
workflowViewCgi Contains the name of the WIST entry viewer CGI script (Default: wistView)
workflowBrowseCgi Contains the name of the WIST browser CGI script (Default: wistBrowse)
workflowGetFileCgi Contains the name of the WIST tool for retrieving documents from PCAPStore (Default: wistGetFile)
workflowImageThumbnailCgi Contains the name of the WIST tool for generating thumbnails of image files asynchronously (Default: wistImageThumbnail)

In addition to scalar global attributes, WIST will also export one macro for each field completed in previous steps. It is important to note that the values associated with these macros are WIST internal values and not display values. For example, a drop-down field will export a value corresponding to the id of the selected option rather than the description of that option. In addition, if you've configured exportEnv as part of the workflow's global block or current step's block, any of the listed environment variables to export that exist will also be exported to WIST. For example, if the workflow specified exportEnv=REMOTE_USER,REMOTE_ADDR, the two macros %REMOTE_USER and %REMOTE_ADDR would be exported (assuming an Apache web server).

To summarize, any scalar value from the WIST configuration, values from exported environment variables, and values from fields of previously completed steps are all available when designing general workflow-specific templates.

Internal Templates

There are three general internal templates that allow you to customize the overall look and feel of WIST pages, the footer, header, and error templates. The header and footer are displayed before and after every page generated by WIST and generally contain javascript, style sheets, and other basic formatting. The error template is displayed for all WIST errors. These templates have special macros and components without which portions of WIST will not function. These macros and components are described below.

header Internal Template

The header component is displayed before each page generated by WIST. It includes the page's title (%formTitle), loads required style sheets and javascript used by WIST, provides a placeholder for WIST javascript data structures, and provides a hook to allow javascript code to execute when the entire page has finished loading. The general header structure should remain as is, however changes to style sheets or the addition of a logo or other navigation components can be added to the header.

The %dynamicScript macro is a placeholder for WIST javascript data structures. Since the macro's value contains javascript data structure declarations and assignments, the macro itself must be contained within tags otherwise it will not be correctly parsed by the end-user's browser.

Finally, WIST will export a macro %bodyOnload which contains javascript to execute when the page has finished loading. Note that the ONLOAD directive is guarded by a condition so that if its value is blank, the ONLOAD directive will not be used. This is primarily used by the WIST browser for asynchronously retrieving image thumbnails however it may be used by other WIST components in the future. Omitting the BODY statement shown below will result in these features no longer working.

The stock header template is shown here:

        <style type="text/css">@import url(/wist/js/jscalendar/calendar-win2k-1.css);</style>
        <script type="text/javascript" src="/wist/js/jscalendar/calendar.js"></script>
        <script type="text/javascript" src="/wist/js/jscalendar/lang/calendar-en.js"></script>
        <script type="text/javascript" src="/wist/js/jscalendar/calendar-setup.js"></script>
        <script type="text/javascript" src="/wist/js/wistFunctions.js"></script>
<SCRIPT LANGUAGE="javascript">


// -->

<BODY%[if %{bodyOnload,length} > 0] ONLOAD="%bodyOnload"%[endif]>

footer Internal Template

Similarly, the footer template is displayed at the bottom of every WIST-generated page. It is much simpler than the header having only one requirement, which is to insert a javascript placeholder %postCheckAlerts, which contain javascript-generated warnings and error messages for WIST-generated pages. As with the %dynamicScript macro in the header, the %postCheckAlerts must also be contained within tags. The footer is a great place to put contact information for your organization and to give users a way to contact a WIST administrator for assistance.

error Internal Template

Finally, the error template is used to display all WIST-generated errors. It has only one exported macro, %error, which contains the specific error message. The header and footer are not displayed when an error message is generated.

Layout Templates

This section describes what macros are exported for a given field in your workflow step and globally for all workflows, and how to use these macros to design your own display template. There are also required elements for every display template and some feature-specific elements that will prevent certain features from working if not implemented correctly. There are two types of display templates based on how information from the workflow is accessed. The first is an iterative display template that uses iteration to automatically display each field. This has the benefit of being fairly simple but has less flexibility as it requires all fields be rendered in a similar fashion, such as one field per row in a table. The second type is a custom display template. These templates allow you to place fields anywhere you want and are very customizable with respect to look and feel, however they are typically designed in a manner that does not allow the template to be reused for any other step in your workflow, or for other workflows.

Some components of a layout template are identical regardless of whether the fields are rendered iteratively or through custom placement. The first is the layout template header, which contains internal information used by WIST. An example header is shown below.

<form method="post" enctype="multipart/form-data" action="%nextUrl" onsubmit="return validateForm(this);">
<input type="hidden" name="__thisStep" value="%formStep">
<input type="hidden" name="__referer" value="%referer">

The layout template footer minimally contains workflow step navigation buttons, such as to return to a previous step or continue to the next step. Some of the following footer example may be changed so long as the display logic remains:

%[if %{prevFormStep,len} > 0]
        <input type="submit" name="__backTo" onclick="bypassValidation=true;" value="&lt;&lt; Previous step">
%[if %{referer,len} > 0]
        <input type="submit" name="__backToReferer" onclick="bypassValidation=true;" value="Cancel">
        <input type="reset" value="Reset form">
%[if %nextConfirm]
        <input type="submit" value="Submit data">
        <input type="submit" value="Next step &gt;&gt;">


Some features of WIST require that field elements be encapsulated in table cells, where the cell is given an id of field_%name. For example, when a validation criteria fails, WIST will attempt to highlight the field in red so that the end-user is able to see the problem field more easily. If the field elements are not encapsulated in table cells, this functionality is disabled.

For example, you may have chosen to encapsulate the display of your workflow into a table. If you would like the navigation elements to be part of this table, you will need to modify the above footer appropriately. For more information on how to display the fields in a workflow step please see the following two sections.

Iterative Display Layout Template

Iterative display layout templates are the simplest way of creating your own display template although it requires each field in a workflow step to be rendered more or less the same way. This can be done in any number of ways however in general, you will probably display the fields top-down, one field per "row". Iterative display layout templates do not allow you to choose the placement of each field manually, but you can accomplish this instead using a custom display layout template. For iterative display layouts, WIST will export a single macro data structure called %formElements containing all of the fields for a given workflow step. Using a foreach loop, you can iterate over each field in turn accessing information specific to each field that you'll need in order to display it. The following table contains a list of the macros exported by each field element:

Macro Description
%element The field's HTML element, self-encapsulated
%label The field's display label, or the field's internal name if no display label was defined in the workflow template
%name The field's internal name

One example of how you might iterate over the workflow step elements follows:

%[foreach %formElements]
        <th class="vertical">%label</th>
        <td id="field_%name"><a name="anchor_%name"></a>%element</td>

Here is an example of the layout generated by the template:


It is recommended that you look at the template, as it is an iterative display layout template.

Custom Display Layout Template

Custom display layout templates allow you full flexibility in placing the fields within a workflow step, however it requires that you know a lot more about HTML and each step within a workflow will need its own template as custom display templates are not portable to other steps within the same workflow or to other workflows. Instead of exporting a single data structure containing all fields, WIST will export two macros for each field with the names %label_fieldName and %element_fieldName containing the field's label and self-encapsulated HTML element. As such, one must have a priori knowledge of all fieldNames for a given workflow step in order to design a custom layout template.

Using iterative display layout templates requires that each field be rendered independently, however in some cases you may wish to place two or more fields adjacent to each other and/or change the orientation of the field labels with respect to the fields themselves, such as in this example:


The above sample workflow is shown with three fields with names firstName, middleInitial, and lastName, respectively. The custom layout template used to achieve the above display layout is shown below:

<link rel="stylesheet" type="text/css" href="/wist/css/wist.css" />
<form method="post" enctype="multipart/form-data" action="%nextUrl" onsubmit="return validateForm(this);">
<input type="hidden" name="__thisStep" value="%formStep">
<input type="hidden" name="__referer" value="%referer">
        <th class="alt" style="background-color: #a1cbf7;" colspan="3"><h1><font color=black>%formTitle</font></h1></th>
        <td id="field_firstName"><a name="anchor_firstName"></a>%element_firstName<div style="font-size: xx-small;">%label_firstName</div></td>
        <td id="field_middleInitial"><a name="anchor_middleInitial"></a>%element_middleInitial<div style="font-size: xx-small;">%label_middleInitial</div></td>
        <td id="field_lastName"><a name="anchor_lastName"></a>%element_lastName<div style="font-size: xx-small;">%label_lastName</div></td>
        <th class="alt" colspan="3">
%[if %{prevFormStep,len} > 0]
        <input type="submit" name="__backTo" onclick="bypassValidation=true;" value="&lt;&lt; Previous step">
%[if %{referer,len} > 0]
        <input type="submit" name="__backToReferer" onclick="bypassValidation=true;" value="Cancel">
        <input type="reset" value="Reset form">
%[if %nextConfirm]
        <input type="submit" value="Submit data">
        <input type="submit" value="Next step &gt;&gt;">

It is recommended that you avoid the use of custom display layouts as they are typically difficult to debug and maintain.

SQL Script Templates

SQL scripts, such as those found in the internal block script declarations, also use the WIST macro markup language. In general, the script declaration contains just a single query (on one line), however both the edit and commit blocks allow two or more queries, one query per line. It is important to reiterate that a single query must be wholly contained on a single line. Queries may not be split over multiple lines at this time.

The use of macros within the SQL scripts should be obviously--simply use a macro in place of the actual value that you wish to substitute in before the query is executed. However, conditional and iterative constructs may also be used as needed. For example, a particular field may allow a variable number of values which are stored in a separate table and linked by the parent record's id. In order to accomplish this, one must first create the parent record, obtain its newly created id, then iterate over the field with the variable number of values inserting each value into a referenced table along with the parent record's id. Here is an example using MySQL:

script = {

INSERT INTO mytable (field1, field2, ...) VALUES (%field1, %field2, ...)
%[foreach %field3]
    INSERT INTO mytable_field3data (mytable_id, data) VALUES (@id, %field3)


If your commit script inserts multiple records into one or more tables, you must insert the primary record last such that a query SELECT LAST_INSERT_ID() will correctly retrieve the record's id. In cases where you must create the primary record first, then subsequently add child or related records referencing the parent record's id, such as in the example above, you must store the primary record's id in a special variable @id. Failure to do this will result in improper navigation links following the commit.

If you wish to create a parent record and along with multiple child records, where each child record has multiple fields, you must make use of the parallel array technique explained in the Iteration section above since each child record's fields will be returned to WIST as parallel arrays. Each child record's constituent fields will have the same index position in the parallel arrays, thus:

script = {
    INSERT INTO `table1` (....) VALUES (....)
    %[foreach %childField1]
        INSERT INTO `table2` (...) VALUES (..., %{childField2,[%i__]}, %{childField3,[%i__]}, ...)

In the above example, we use the [i] modifier described above (Data Formatting) with the internal iteration macro %i__ exported by the foreach loop iterating over %childField1 to access each child entry's corresponding field values from the %childField2 and %childField3 arrays.

WIST Limitations

  • Workflows are not presently validated for syntax (fix with more rigorous grammar and parser)
  • Workflows are not presently validated for logical flow or lack of cycles (no plans to fix)