Posts in Category "Performance Tuning"

Object Expressions in XFA

Form authors tend to resolve SOM (Script Object Model) expressions inside calls to resolveNode() more often than they need to. As a result, their JavaScript code is less readable than it could be. There are alternatives coding patterns I can recommend, but first some background.

Object expressions vs SOM expressions

If you wanted to get the value of a field in a purchase order form, there are a couple of ways to get it:;



The first form is an object expression.  In the second form, the argument passed to resolveNode() is a SOM expression. These are not evaluated the same way, but they almost always return the same result.

Dotted expressions are evaluated by the JavaScript interpreter. Every time the JavaScript interpreter reaches a dot in an expression, it calls into the XFA processor to evaluate the token following the dot. De-constructing the first example:

  1. The JavaScript engine encounters “xfa”. It resolves this easily since “xfa” has been pre-registered with the engine as a known global object.
  2. JS encounters “.form”. It asks the XFA processor for the “form” property of the xfa object. XFA returns the form model object.
  3. JS encounters “.purchaseOrder”. It asks the XFA processor for the “purchaseOrder” property of the form object. XFA returns the purchaseOrder subform object.
  4. We continue to evaluate dots until we reach the “city” object. Then when JS asks XFA for the “rawValue” property of the “city” object, XFA returns a scalar value.

De-constructing the second example:

  1. The JavaScript engine encounters “xfa”, and returns the pre-registered xfa global object..
  2. JS encounters “resolveNode(…)”.It asks the xfa object to evaluate the method resolveNode(). XFA resolves the SOM expression and returns the city object
  3. JS encounters “.rawValue” and asks XFA for the rawValue property of city.

You can see we take two very different paths, but have ended up in the same place.

The main difference is that the object expression yields more readable code, but is less efficient. Resolving SOM expressions internally is more efficient than the many more round-trips from JS to the XFA engine. However, in the vast majority of cases, the performance difference is negligible in the context of overall processing. My bias is toward using object expressions for the sake of code readability – unless we know we are in an area of performance critical code.

Note that FormCalc handles object expressions differently from JavaScript. The expression: is not evaluated dot-by-dot. The FormCalc engine will pass the entire expression to XFA for evaluation as a SOM expression.

Using "#" in SOM

We use the "#" character to disambiguate properties (font, border, caption etc) from containers (fields, subforms etc). Using "#" tells the SOM parser to treat the following token as a className rather than as a named object. Take this example:

<subform name="Country">
    <field name="border"/>

The expression “Country.border” is ambiguous. It could refer to either the <border> property or the field named “border”. The rules are that by default the named object takes precedence. If you want to explicitly get the border property you must use “Country.#border”.

Since the "#" character is illegal in JavaScript, any expressions that use it are usually wrapped in a call to resolveNode(). E.g.:

Country.resolveNode("#border").presence = "visible";

As it turns out, there is a more terse syntax available. JavaScript properties can be accessed by two different syntaxes. e.g. A.B can also be expressed as: A["B"]. So the expression above could also be coded as:

Country["#border"].presence = "visible";

But simpler yet, if we are not worried about ambiguity, we can code this as:

Country.border.presence = "visible";

(As I write this, I realize that some of the script in my samples is not careful enough. Any general purpose re-usable code that references the subform.border property really must use the #border notation.)

As I said, in the case where you are not worried about ambiguity, you do not need to qualify with the “#” symbol. In the case with field properties we don’t really need to worry about name conflicts. Unlike subforms, fields do not have children with user-defined names. (ok, that’s not true, but let’s pretend it is for now.) You should be able to code “field.border” without worrying about ambiguity.

Accessing instead of field["#property"] is possible as long as the property does not have an unlimited number of occurrences. This means that we cannot refer to “field.event” – because fields can have any number of <event> elements.

We’ll work through this case with an example. I have seen code that changes the email address of a submit button that looks something like:

this.resolveNode("SubmitButton.#event[0].#submit").target =  
                                       "mailto:" + email.rawValue;

For starters, this could be expressed more tersely as:

SubmitButton["#event"] = "mailto:" + email.rawValue;

But do not do this.  This is fragile code. It assumes there is only one event, and addresses the first <event> element. To
make this easier, Designer has started populating the name property on the <event> element:

<field name="SubmitButton"> 
  <event name="event__click" activity="click"> 
    <submit format="xml" textEncoding="UTF-8" 

As a result, the script can now be reliably be coded as: = "mailto:" + email.rawValue;

Finally, to close the loop on what I said above: “fields do not have children with user-defined names.”. As you see, events (and a couple other properties) can have arbitrary names. But we shouldn’t have to worry about name collisions. There is no interface in designer for naming these properties. When Designer names them, it generates unique names. As long as nobody has modified their XML source and changed their event to look like <event name="border">, then field.border remains unambiguous.

Transparent Subforms

You will often see references to "#subform[0]". As in:


The reason you see “#subform” in this expression is because the subform is nameless.

This is the most explicit possible SOM expression that leads us to Button1.

However, this expression also gets us there:


We don’t need the [0] references because by default, object expression will always return the first occurrence.

The reason we can omit the #subform is because nameless subforms are treated as transparent.

In this example that means that all the children of the nameless subform may be referenced as if they were children of form1.


As noted above, SOM parser evaluation is faster than JavaScript object evaluation.  If you have an expression that must be executed many, many times, then it is better to wrap it in resolveNode() or use FormCalc.  However, for most forms with modest amounts of script, the difference in overall form performance is negligible. Most of the time ease-of-scripting and code readability are more important.

However, whether using SOM or not, reducing evaluations is good practise.

Beware of coding patterns that look like this:

xfa.form.form1.header.address.Button1.presence = "hidden";
xfa.form.form1.header.address.Button2.presence = "hidden";
xfa.form.form1.header.address.text1.presence = "hidden";
xfa.form.form1.header.address.text2.presence = "hidden";
xfa.form.form1.header.address.text3.presence = "hidden";

In cases like these, it is more efficient (and readable) to resolve a variable to the common parent node e.g.:

var addr = xfa.form.form1.header.address;
addr.Button1.presence = "hidden";
addr.Button2.presence = "hidden";
addr.text1.presence = "hidden";
addr.text2.presence = "hidden";
addr.text3.presence = "hidden";

When resolveNode() is Necessary

Some parts of SOM syntax are not supported by the object evaluation of our script engines. I can think of two examples:

  • SOM predicates (see previous blog entry)
  • The elipsis operator (..) that recurses down the hierarchy finding nodes. While it is handled by FormCalc, it is not legal in JavaScript.

Here is a sample script that shows how these can be combined using resolveNode() to make all hidden fields in a nested subform visible:

var vHiddenList = xfa.resolveNodes('xfa.form..address.#field.[presence == "hidden"]');
for (i=0; i<vHiddenList.length;i++)
  vHiddenList.item(i).presence = "visible";

The Deep End


When comparing object expressions to SOM evaluation I said: “These are not evaluated the same way, but they almost always return the same result.”

You might want to know under what circumstances they will return different results.  The difference between object expressions and SOM evaluation is that SOM evaluation will take into account the relative occurrence numbers (index) of objects, while object expressions cannot. In the example below we have fields bound to this data:







The form looks like this:

<subform name="order">

   <field name="price"/>

   <field name="quantity"/>

   <field name="subtotal">


         <script contentType="application/x-javascript">

           order.price.rawValue * order.quantity.rawValue;




   <field name="price"/>

   <field name="quantity"/>

   <field name="subtotal">


         <script contentType="application/x-javascript">

           order.price.rawValue * order.quantity.rawValue





The calculations for the subtotal fields will both return the result “20.00”. This is because when we evaluate the expression: order.price and order.quantity from the context of the subtotal field, the JavaScript engine will always return the first occurrence of the price and quantity fields – for both occurrences of the subtotal field. However, we could change the calculation to:

subtotal.resolveNode("order.price").rawValue *


In this case the second occurrence of the subtotal field would evaluate to “60.00”. This is because the occurrence number of the subtotal field causes the SOM evaluator to return the second occurrence of the price and quantity fields. If we were using FormCalc, then the expression order.price * order.quantity would return the expected result, since FormCalc uses SOM natively.  Fortunately, we don’t encounter this pattern very often, so most form authors can assume that there is no difference between SOM evaluation and object expression.

Naked Field references

Based on what I’ve described above, you might wonder how we are able to resolve “order.price” in JavaScript. How does JS resolve a naked reference to “order”? We can’t register all field names with the JavaScript interpreter. If you were used to coding in Acroforms, you used expressions like


in order to find field objects.

The way the XFA processor works is that when JavaScript encounters an unrecognized object, it tries to resolve it as a property of “this”. In our example, “order” is really evaluated as “this.order”. Technically the subtotal field doesn’t have a property called “order”, but XFA does a check to see if there is an object called “order” that is in scope of subtotal.

While this is really great for keeping the code easy to write and readable, it has a side-effect that causes grief. When encountering an unknown token, the JavaScript engine first asks the XFA processor to resolve the token, and if not found, then checks JavaScript variables.  This order of evaluation causes issues for a calculation script that looks like:

var x = 42;

field.rawValue = x;

In this example. the field will get populated with the value of the x property (this.x).  This is one of the reasons why I normally prefix my variable names with a "v", in order to reduce the likelihood of a conflict with a property name.

Note that FormCalc allows variables to take precedence over properties.  In FormCalc the script above would behave as expected and populate the field with "42".  The reason for the evaluation order in JavaScript is due to a limitation with the engine when this feature was first implemented.  As far as we know, that limitation is now gone.  As some point we would like to change the order of evaluation for JavaScript — but would do so in a safe way so that older forms continue to behave as they do today.

Adventures with JavaScript Objects

I have to start with an admission — I’m not a trained JavaScript programmer.  This became evident to me as I reviewed the latest version of the exclusion group sample form.  I was not happy with the performance, so I thought I would stick in a timer and see if I could measure and improve performance.  Adding the timer was no problem.  I changed the code on the subform remove button.  Note the time calculations at the beginning and end:

form1.#subform[0].NPSA3.NPTable.Row1.Cell14::click – (JavaScript, client)

var vTime1 = (new Date()).getTime(); // gets the time in milliseconds

// Removing a subform in the middle of a slie can
// change the SOM expressions of subforms later in the list
// This means that we have to clear the error list

if (_Row1.count > _Row1.min)
// rebuild the error list

var vTime2 = (new Date()).getTime();
console.println(vTime2 – vTime1);


For my test I added 20 subform rows.  With a total of 21 rows there are 65 exclusion groups on the form.  Deleting a row causes all 65 groups to be re-evaluated.  (actually most of them get evaluated twice, but that is a bug behavior that I cannot control).  With the measurement in place I could see that deleting one row was taking 2753 milliseconds on my laptop.  As I deleted more, the deletions sped up — since there were fewer groups to evaluate each time.  By the time I was down to two rows, the delete took 454 milliseconds.  All much too slow.

It did not take long for me to realize that my problem was the JavaScript objects I had defined to implement exclusion group behavior.  Here is where I expose my JavaScript naiveté.  I wanted to define an abstract group definition so that the implementation could be either based on a subform or on an array group.  When I set up the base class, I followed a C++ pattern.  I defined a base class with methods that the derived classes would override:

function exclusionGroup()
exclusionGroup.prototype.length = function() {return 0;}
exclusionGroup.prototype.item   = function(nItem) {return null;}
exclusionGroup.prototype.getMax = function() {return null;}
exclusionGroup.prototype.getMin = function() {return null;}

One of the derived classes:

// Implementation of exclusionGroup for a subform container
function subformGroup(vSubform)
    this.mSubform = vSubform;
subformGroup.prototype         = new exclusionGroup();

subformGroup.prototype.length  = function()        
    {return this.mSubform.nodes.length;};

subformGroup.prototype.getMax  = function()        
    {return this.mSubform.vMaxSelected.value;}

subformGroup.prototype.getMin  = function()        
    {return this.mSubform.vMinSelected.value;}

subformGroup.prototype.selectedContainer = function()
    if (this.mSubform.vOldSelectedContainer.value == "")
        return null;
    return this.mSubform.resolveNode(this.mSubform.vOldSelectedContainer.value);

What I failed to take into account is that JavaScript is completely interpreted.  e.g. When the getMax() method on the derived class gets called, it matters none that the method exists in a base class.  The interpreter simply checks the class instance to see if it has the getMax() method.  The base class was just extra processing overhead with no benefit.  The base class might have had some benefit if we had shared implementations of some methods — but we didn’t. So I removed the base class.  I created two classes: subformGroup and arrayGroup that both define the same member variables and functions.  There is no type checking.  The onus is on the programmer to make sure the property names, methods and parameters all match. 

The other revelation is that I did not need to extend the objects using prototype.  Using prototype impacts the class definition — i.e. all instances of a class.  You can extend a single instance of a class without bothering with prototype.  That seemed to improve performance as well.

In the revised form, my object definitions looked like:

// Implementation of exclusionGroup for a subform container
function subformGroup(vSubform)
    this.mSubform          = vSubform;
    this.len               = vSubform.nodes.length;
    this.maximum           = vSubform.vMaxSelected.value;
    this.minimum           = vSubform.vMinSelected.value;
    this.selectedContainer = function()
        if (this.mSubform.vOldSelectedContainer.value == "")
            return null;
        return this.mSubform.resolveNode

// Implementation of exclusionGroup for an array group
function arrayGroup(vHost)
    this.mHost             = vHost;
    this.len               = vHost.length.value; 
    this.maximum           = vHost.max.value;
    this.minimum           = vHost.min.value;
    this.selectedContainer = function()
        if (this.mHost.vOldSelectedContainer.value == "")
            return null;

        return this.mHost.parent.resolveNode

Simplifying the object definitions had a big impact on performance.  Deleting the 21st subform went from 2753 milliseconds to 1236 milliseconds.  Well over a 2x improvement.  Still not fast enough for my liking, but good enough for one round of performance tuning.  Now maybe I’ll go out and buy a JavaScript book…