Use Google to find help fast. For example, search on "xpressdox choosefromlist".

Dynamic Captions – changing captions on the fly

With the advent of The OnExitSet and OnEnterSet Commands, it became possible to have the captions (or footing text or heading text) of a data element in the interview change in response to the user entering data.

Getting the features around this to work was not all that easy for the template author, and so now we have introduce the concept of the Dynamic Caption. This feature also applies to heading and footing text.

Getting Started

Suppose you want the First Name, Last Name and Date of Birth of someone to be entered in the interview. In the case where there are a number of names of various parties to be entered, it might become confusing, when it comes to the Date Of Birth, as to whose Date of Birth should be entered. Here’s an example of how easy the Dynamic Caption feature makes this:

«Caption(DateOfBirth,Enter the Date of Birth of <FirstName||[First Name of Person]> <LastName||[Last Name of Person]>)»

When the interview is first displayed, the caption for the Date of Birth will read:

Enter the Date of Birth of [First Name of Person] [Last Name of Person]

If the value “John” is entered for FirstName and “Smith” for LastName, then as soon as those values have been typed in, then caption for Date Of Birth will read:

Enter the Date of Birth of John Smith

Some Advanced Techniques

If you are going to need the FirstName and LastName in a number of different captions (or headings or footings) in the interview, then you could define the dynamic caption in a Script, and use that Script name where ever you want the dynamic caption. For example:

«Script(FullName)»«concat(FirstName, ' ', LastName)»«ScriptEnd()»

«Caption(DateOfBirth,Enter the Date of Birth of <FullName()||[Primary Contact]>)»

«Footing(RegistrationCertificate,|Make sure the the Registration Certificate for <FullName()||[Defendant Name]> is available.)»

What to Expect of the Conversion from HotDocs


The HotDocs® (HD) converter released with Version 11 of XpressDox will attempt as far as possible to prepare a set of XpressDox templates which, ideally, the user will be able to run as-is after the conversion is complete.

Firstly, there are quite a few terminological and usage differences. Here are some of them:

  • A dialog becomes a Tab in XpressDox
  • In XpressDox, a data element is an item of information that typically is captured by the user in the interview, but may also originate in a database or other source of data.  A variable in XpressDox is something that the template author defines, and is only available when the template is being assembled.  Both of these are called variables in HD.
  • XpressDox has what many HD users call a “multiple choice” feature, but is probably what XpressDox calls a “Set All Group”.  In XpressDox, this can be a set of check boxes or radio buttons.  In the latter case, each choice can have more than two options.
  • The XpressDox command CaptureInGrid achieves something similar to what the “spreadsheetOnParent” option in HD is used for.
  • XpressDox is basically an XML engine.  The data are all in XML, which does not have the concept of a data type – every element value is a string.  So where HD has the concept of a field being a number, or a date, etc., XpressDox has the Rule command which the template author can employ to ensure that users enter data in the correct format.  Some of these Rules (like IsNumber and IsDate) are applied automatically if XpressDox can infer from usage that this is appropriate. The converter will apply those rules where necessary.

A look at the converted documents

There are three types of documents that the conversion produces: the templates themselves, and then an “Interview” template and a “Scripts” template. The latter two are generated from one or more of the component (.cmp) files.

Typically a set of templates would have a few “main” templates – i.e. those that the user will actually ask to be run. These main templates then include (HotDocs INSERT) sub-templates. Most XpressDox authors will create a “code template” with all of the XpressDox commands which control the interview, and another template with all the scripts. These would then be included in the main templates, usually at the start. If you have a look at any of the templates which the converter produced, you will see that there are one or two Include commands at the top which refer to the generated Interview template and/or the Scripts template. The converter might have surrounded the Includes with Comments, because when there are multiple templates in a suite, it is not easy to determine whether a template is a main template or an included template. Only the main templates should have the Interview and Scripts templates included by them.

It may be that some HD fields cannot be handled by the converter. These are copied as-is into the converted template, but will be surrounded in a function call to a function called “Unconverted”. The fillpoints containing this function call are highlighted in yellow. Some examples of HD fields that will not be converted are:

    1. There is a HD variable which has not been defined in the component file.
    2. The format specification “a, b, and c” is accomplished in such different ways in XpressDox that a direct conversion from HD is not possible.
    3. Setting a repeating instance of a variable (e.g SET ABC[counter] TO “Something”) is achievable in XpressDox using Arrays, but is probably not what an XpressDox template author would do.
    4. The HD FILTER concept – again this is achievable in such a different way in XpressDox that a direct translation is not really possible.
    5.  A format specification that refers either to a computation or a HD variable.
    6. None of the HD commands related to interview construction will be converted.  Most are ignored and won’t even appear as Unconverted.

XpressDox requires that placement of “block” commands conform to some rules. A block command is any XpressDox command whose scope is terminated by an «End()» command. In other words, If, ForEach and RepeatWhile. The rule is that if the starting command and ending command are in separate paragraphs in the document, then the start (e.g. If()) and End() must each be in their own paragraph.

This is one situation where the first time a converted template is run will probably result in some XpressDox messages asking you to put fillpoints into their own paragraphs. It is a situation that will be addressed in a future version of XpressDox.

If there are any Unconverted instances that don’t conform to the above, or you have any other suggestions to make, please let us know at

The Interview Template

In the Beginning

The first 3 commands in the Interview template are generated automatically regardless of the contents of the HD component file. They are:

«InterviewIsWizard(Yes)»: The actual interview generated by this will (in the Desktop at least) look more like what HD users are used to than the default XpressDox interview.

«ExpectXSLTFormatNumbers(Yes)»: It is good practice to have this command active in every template.  It is rather complicated, and so it would be best to have a look at Arithmetic in XpressDox for more information. For the moment, just leave this command here, it will do a lot of useful work for you, even if you don’t understand why.

«AlignCaptions(Right)»: It seems that HD authors typically use fairly long captions for some of the variables – now data elements. Aligning the captions to the right makes it easier for the eye to follow the shorter captions.

Dialogs and Tabs

After this, the Interview template contains a section for each dialog in the HD component file. Each section contains the name of the HD dialog in a Word Heading style, so that the entire document can be easily navigated via the Word navigation pane. The reason that this kind of documentation can be provided in the Interview template is that it will be included with the IncludeCodeTemplate command. This command will ignore any line (paragraph) which has no XpressDox fillpoints in it.

For non-repeating data elements, an XpressDox Tab command is created, with the name (or Title) of the HD dialog, followed by the data elements which will be in that Tab. This is the time to note that XpressDox data elements, since they are really XML element names, cannot (unlike HD variable names) contain spaces or other punctuation. The converter will translate these non-XML characters to underscores. There is a mechanism by which you can instruct the converter to change the HD variable names to what might be totally different XpressDox data element names. This will be discussed later.

Sequence of data elements in the interview

The Tab commands have been produced in the Interview template in the sequence in which the dialogs were found in the component file – which is alphabetical. This is probably not the sequence in which you would like them to appear in the interview. The way to get the Tabs into the sequence that you would like them in the interview, is to move them to the top of the Interview template, and then put them in the sequence in which you would like them to appear in the template.

The general rule for positioning of data elements in the interview is that they will be sequenced in the order in which they are first encountered in the template – in this case the Included templates are also taken into account.  Hence if your Interview template is the first to be Included in any template, then the sequence of the data elements in the interview will be dictated by the Interview template.  (Even then you can modify the sequence for any particular template by using The CaptureLater Command)

Escaping special characters

You will probably notice that in some places there is an exclamation mark (point) in front of certain characters, such as in

«Caption(Amount,Enter the amount !(without a dollar sign!))»

This is called “escaping” the character after the !, and is required when that character is to appear in the Caption and not be regarded as the closing parenthesis of the command.
Characters which should be escaped in this way are:



There are some places where the converter can recognize that a list of items should rather be sourced from a file as against hard coding the list in the template. Typically this will be when the user needs to choose from a list of states. Then you would usually like either the name of the state, or the abbreviation to appear in the document.

In addition, there are often many parties for which a choice of states must be made. This situation as well as the above can both be achieved by having one file with a list of all the state names and abbreviations, and have the same list be presented for each party where a state is required.

The converter will generate both the file and the ChooseFromFile command. Unfortunately, it will produce one file for each different multiple choice variable in HD, but it should be fairly straightforward to change these ChooseFromFile commands to refer to only one file. Have a look at The ChooseFromFile Command.


Where a multiple choice list in HD presents a list of options, but also allows an “other” or “none of the above” option, then the interview generator will produce the XpressDox ChooseFromSamples command. This command, by definition, allows the user to type in a value which is not in the drop down list. The interview generator will explicitly exclude the option “other”. In the templates, or scripts, the HD OTHER function is translated in a way that, if the user did actually type in a value not in the drop down list (i.e. an OTHER value), then the value that the user typed is returned, but if they DID choose one of the samples, the translation of the OTHER function returns an empty string (because it is not an OTHER value). It might be that this is not what you want, but an edit of the template, or the interview, would be easy to achieve.

The Scripts Template

Each HD computation is translated into an XpressDox Script, with the name being a straight forward translation from the non-XML HD format to an acceptable XML format. The converter understands HD parameters, and creates a Script with parameters. There are also at least two standard Scripts that are generated, and used internally by the converter. They are the Scripts named OrdinalValue and ShowOrDefault. More may be added with time.

There are two Script files that are produced – one where, for each HD computation/script, each of the lines in the computation is converted into an XpressDox fillpoint. The second Scripts file has SingleFillpoints in the name. It is recommended that you start off with the default Scripts file – i.e. the one for which the converter will put an IncludeTemplate command at the top of the converted template. It will probably be that as you start to run the converted templates, XpressDox will issue a message saying something like: “In order the use a script as a function, the script body must consist of exactly one fillpoint”. If this happens, then locate the script in question, and copy it from the “SingleFillpoints” Scripts template. You could decide to just use the SingleFillpoints Scripts template in its entirety, but then you might bump into some of the issues highlighted in the Advanced Usage section below.

Advanced Usage

Although the fairly simple templates in both systems will be similar to each other, as soon as the more complex features of HD have been used, then there will be more and more striking differences between how things are done in the two systems. In order to achieve the aim of making a set of templates which can be run with as little modification as possible, some features of the converted templates are not what an experienced XpressDox author would use to achieve the same objective. This is particularly true of the converted computations, and especially those reduced to single fillpoints. In fact, a few new functions have been introduced into XpressDox with the sole purpose of achieving a runnable result from the conversion.

These new functions are RepeatForEach, While, and IIfSet. They can be used by anyone, but are not included in the XpressDox Command Editor because there are much better ways to achieve the same objectives taking into account that XpressDox is basically an XML engine, and each fillpoint is an XPATH expression. XPATH is a syntax for navigating an XML dataset. You can read about it here: XML and XPATH. If you are a serious document assembly template author (and if your are reading this far, then you probably qualify for that description) then understanding XPATH will be indispensable for advanced template authoring in XpressDox.

The converter is not an artificial intelligence engine, but, in order to come as close as possible to the aim of having a runnable solution with as few changes as possible, the converter needs to perform the conversion in an almost literal fashion. A little like taking the the works of Shakespeare one sentence at a time and passing each sentence through Google Translate – you will get a passable translation but nothing like what a human translator can achieve.

Some Examples of Rewrites


An example of where a script would benefit from a total re-write using XpressDox features would be the following typical computation conversion. The HD computation is called “ABC in Community CO”, and has a script which looks like:

IF ABC Option MC = "c"

The converter will produce the following XpressDox Script:

IIf((ABC_Option_MC = 'c'),
«ScriptEnd(ABC in Community CO)»

The above XpressDox script would work, but, if written by an experienced XpressDox template author, would become:

«count(ABC[ABC_Option_MC = 'c']) > 0»

In fact, so simple that the author might even decide not to put it into a Script but to write it directly into the template wherever necessary.


The IIfSet function is very similar to the IIf function, but in the context of a single fillpoint script, it is needed instead of an IIf where a variable will be set in either the “then” or “else” branch of the IIf. (IIf is short for InlineIf.)

Firstly, just about any Script containing an IIfSet would benefit from a re-write, if for no other reason than to make it more readable.  Here is a Script that will work as-is, and its re-write:

«Execute(IIfSet((Case_type_MC = 'Custody'),'SetV(<RESULT>,<final decree>)','SetV(<RESULT>,<final parenting plan>)'),GetV('RESULT'))»
«ScriptEnd(Final decree or pp CO)»

The re-write:

«Execute(SetV('RESULT',IIf((Case_type_MC = 'Custody'),'final decree','final parenting plan')),GetV('RESULT'))»
«ScriptEnd(Final decree or pp CO)»

Or, even better:

«IIf((Case_type_MC = 'Custody'),'final decree','final parenting plan'))»
«ScriptEnd(Final decree or pp CO)»

Here are two related Scripts, produced by the converter, which will not work as-is:

«ScriptEnd(ABC account CO)»

«ABC_ch = 'c' and ABC_aw != 'res'»
«ScriptEnd(Filter ABC accounts CO)»

When the first script is invoked somewhere in the template (or in another Script) then it would produce a syntax error. A re-write of the first Script would be:

«ABC_account[Filter_ABC_accounts_CO()]> 0)»
«ScriptEnd(ABC account CO)»

The SetWebInterviewMinimumHeight Command

The interview in the browser can vary in height depending on the existence of tabs and other factors. The template author can control the minimum height of the web interview with the SetWebInterviewMinimumHeight command.


This will set the minimum height of the web interview to 200 pixels.

This feature is available from Version 10.4 onwards.

Show the result of Date arithmetic in the interview

When entering dates for a contract, it is important to get them right during the interview. It might be possible to control this via the Rule command, but often it is very useful to reflect this to the user as they are typing into the interview.

For the purposes of this example, we start off with one date, called StartDate, which the user will capture in the interview, and then allow the user to enter a number of years, months and days to define the duration of the contract. During the entry of these data elements, we want to be able to show the end date of the contract, in the interview, which will change as the user changes the various values. The example will use the OnExitSet command, the Script command, and various date manipulation functions.

Step 1. Capture the date and a number of years.

Here is the XpressDox code to capture the date (StartDate) and the number of years (Years) and show the result of adding the number of years (IncrementDate) to that start date in a Heading on the Place Holder called Show_EndDate:

«Heading(Show_EndDate,|@Red/Microsoft Sans Serif/8.2@ )»
«OnExitSet(Years,Show_EndDate,HeadingText,(), FormatDate(IncrementDate(IncrementDate(StartDate,Years,'Y'),-1,'d'),'d MMM yyyy'),,EvenWhenNotEmpty)»

If you copy and paste this code into a template and run that template, see what happens after you enter a number into the Years and press Tab.

Note that there are two IncrementDate functions – the second subtracts one day, because the last day of a contract is always the duration less one day.

Step 2. Capture the number of months and days as well as the years.

This gets a bit more complicated, but the principle is the same. Now we want the number of Years, Months and Days to be added to the StartDate whenever we change the values of any of those three durations. This means we need an OnExitSet for each of the 3 duration elements. Here is the OnExitSet for the Years data element:

«OnExitSet(Years,Show_EndDate,HeadingText,(), FormatDate(IncrementDate(IncrementDate(IncrementDate(IncrementDate(StartDate,Years,'Y'),Months,'M'),Days,'D'),-1,'d'),'d MMM yyyy'),,EvenWhenNotEmpty)»

This OnExitSet will add the Years, Months and Days to the StartDate, subtract 1 day and set that value into the heading of the ShowEnd_Date placeholder.

Diversion: Chaining functions

One obvious point to make is that the syntax of this OnExitSet is quite difficult to read (and quite difficult to write!), because of the need to nest the function calls. To address this complexity, the concept of “function chaining” was introduced with version 10.2 of XpressDox. Using this concept, the above OnExitSet can be re-written as:

IncrementDate(StartDate,Years,'Y')->IncrementDate(^,Months,'M')->IncrementDate(^,Days,'D')->IncrementDate(^,-1,'d')->FormatDate(^,'d MMM yyyy'),

The “->” symbol can be read as “pass the result into”, or “goes into”.

This means that the entire set of commands needed to show the result of adding all three duration elements to StartDate (and then subtracting one day) and showing the value in the interview is:

«Heading(Show_EndDate,|@Red/Microsoft Sans Serif/8.2@  )»

IncrementDate(StartDate,Years, 'Y')->IncrementDate(^,Months, 'M')->IncrementDate(^,Days, 'D')->IncrementDate(^,-1, 'd')->FormatDate(^,'d MMM yyyy'),

IncrementDate(StartDate,Years, 'Y')->IncrementDate(^,Months, 'M')->IncrementDate(^,Days, 'D')->IncrementDate(^,-1, 'd')->FormatDate(^,'d MMM yyyy'),

IncrementDate(StartDate,Years, 'Y')->IncrementDate(^,Months, 'M')->IncrementDate(^,Days, 'D')->IncrementDate(^,-1, 'd')->FormatDate(^,'d MMM yyyy'),

Step 3. Introduce a Script with Parameters

It is fairly obvious that the three OnExitSets are going to do the job, but it does seem a bit clumsy. The creation of the three would probably be done with copy-and-paste from the first, and change the Years to Months and Days in the second two, respectively.

It would also be nice, in future, to re-use this code for other dates, maybe even in the same template, without the copy-and-paste issues.

Looking at the three OnExitSets, the code is exactly the same, except for the trigger data element in each case, and so now the common code is put into a Script, with the trigger data element name being a parameter, like this:

IncrementDate(StartDate,Years,'Y')->IncrementDate(^,Months,'M')->IncrementDate(^,Days,'D')->IncrementDate(^,-1,'d')->FormatDate(^,'d MMM yyyy'),

And instead of the three, long-winded, OnExitSets, we now have:


Notice how it is not necessary to use «UseScript(ShowDateOnExit, Years)» (although this will have the same effect). The syntax for invoking the Script is similar to that of any other XpressDox command.

The full set of XpressDox code to define the PlaceHolder, Heading and the OnExits looks like this:

IncrementDate(StartDate,Years,'Y')->IncrementDate(^,Months,'M')->IncrementDate(^,Days,'D')->IncrementDate(^,-1,'d')->FormatDate(^,'d MMM yyyy'),

«Heading(Show_EndDate,|@Red/Microsoft Sans Serif/8.2@ )»


The MaximumRepeats Command

There are times when you have a repeater but you do not want the user to be able to add more than a certain number of instances of the repeater in the interview.

You could use a Rule command, but then the user will only get the message once they have pressed the “OK”, or “Assemble” button.

The command


would prevent the user from entering more than 3 Child instances in the interview.

The command is very flexible, and supports a function or data element in the second argument. This makes it possible to have a different MaximumRepeats for different situations.

For example, you could say that if there is no Parent value, then the number of children should be zero, otherwise the maximum should be 2, like this:

«MaximumRepeats(Child,IIf((Parent = ''),0,2))»

For completeness sake – the Required command will ensure that at least one Child is entered, if that’s what is needed:


This would ensure that at least one but at most 3 Child elements would be input in the interview.

The PdfUserPassword Function

This function gives you the ability to provide a user password to a PDF that is created by running a template. In other words, a person wanting to open the PDF file produced will have to supply the password to the application (e.g. Adobe Acrobat) which is being used to open the document.

As an example:


This will create the user password which is the date of birth provided in the interview.

The template will also need the «SaveAsPDF()» command to be present in order for the feature to take effect.

The DateAsNumber Function

If you want to compare two dates, then typically you want to know whether one date is later than another. The default way that dates are stored in XpressDox is in the format yyyy-MM-dd (e.g. 2018-05-02), but can also be understood by XpressDox in other formats, like “May 2, 2018”. The hyphens or other non-numeric characters inside the date means that the only comparison that can be made between two dates is whether they are equal or not. In order to compare two dates to see which one is before or after the other, the dates need to be made into numbers.

This could be be done by the following:

«If(FormatDate(Date1, ‘yyyyMMdd’) < FormatDate(Date2, ‘yyyMMdd’))»Date1 is less than Date2«End()»

The DateAsNumber function is a shortcut for the above (which is open to "finger trouble" and mis-typing), as follows:

«If(DateAsNumber(Date1) < DateAsNumber(Date2))»Date1 is less than Date2«End()»

Saving Assembled Documents into iManage


All that is needed for this feature to be enabled is that a drive letter be configured to refer to the iManage system.  This configuration operation can be accomplished by a user with a Supervisor license, which will give the user access to the Foreign File Systems tab in the XpressDox configuration screen.


Choose the Foreign File Systems tab, click the Add New button on the left, and then enter the name and drive letter that you would like to use. The name is purely a description, and any drive letter that you know is unused can be chosen.  You will see that two file systems are currently supported, i.e. Windows and iManage – but Windows is disabled as this is the default and it is not necessary to define the Windows file system for any drive letters.  But you do need to choose the iManage radio button.

It is then necessary to click the Use File System’s Editor button which will present you with a form to complete.


Notice that the various fields can contain the <> syntax – in the above example the values of the iManageUserName and iManagePassword data elements which are active at the time access to the iManage system is done will be filled in.

After saving the configuration, you can then press the Test button to make sure the information has been configured correctly.

Addressing the iManage System

Once this configuration has been done, saving assembled documents into iManage is done just by specifying the path to the folder or sub-folder and using normal syntax for a file path for the Windows file system. For example

The file name will be provided either by a command in the template, or will default to the template file name with a .docx extension.

There are many “profile properties” that can be set for a document in the iManage system.  XpressDox will default some of them, but all of the defaults, plus the custom properties, can be set inside the template using the SetCustomDocumentProperty command, as in the following examples, that set the custom1 and custom3 properties for the document:



Note that XpressDox will regard custom document properties with the name starting with XDfsProf- as being applied to document management systems, and the part of the name following that prefix is the name of the DMS profile property.


The GetDataset Function

This function was introduced to enable the entire dataset to be saved as a BLOB in a data base.

Typically, this function will be used in the context of a SetDataSourceData function, something like this:

«SetDataSourceData(‘StagingDataSource’,Guid(), 'XMLBlob',GetDataset(), 'Description',Name)»

In the above, the value of the Guid() function would be used as an arbitrary, unique, ID of a staging table, XMLBlob is the name of the BLOB column into which the data set (from GetDataset()) is written, and the Description and Name are the name and value (respectively) to be written into another column in that row in the table.