XPath Powers: Calculating Totals

InfoPath makes it trivial to track totals for repeating structures, such as customer orders. Just create a repeating table of line items, and sum up the totals for individual line items. However, sometimes, totals for line items may not be available; it is still possible to perform dynamic calculations across the repeating structure, even when interim results (line item totals) are not stored in the data source. This article will explain a way to make this work without code.

Let's explore the simple case first.

 Form at Runtime Data Source
  

Line item total is set by using a default value (price * quantity) on the lineItemTotal node. Creating an order total is just a matter of adding an expression box that uses the built-in SUM function:

sum(my:group1/my:lineItems/my:lineItemTotal)

And voila, we're done, totals will be calculated correctly.

The reason why we are here: the complex case.

What if the interim results (line item totals in our scenario) cannot be persisted in the data source? This situation might arise if you're operating on a fixed schema, or if you're an "XML purist" (I know I am :-)), arguing that there is unnecessary redundancy in your XML if you store calculated values.

The goal is still the same - but the data source is different.

 Form at Runtime Data Source
     

The line item total would be an expression box instead of the text box; it would be calculated simply as (price * quantity).

But how do we calculate the order total? Your first instinct may suggest to use sum (price * quantity), but you'll soon discover that the SUM XPath function only takes a nodeset...

Let's recall the clever technique of iterating through repeating items by using just XPath: it was described in detail in this article. Let's use the following value for the order total expression box:

sum(xdMath:Eval(my:lineItems, "my:price * my:quantity"))

Why does this work? Let's go inside-out:

1) The eval function evaluates the price * quantity expression in the context of line items, and returns a nodeset with the results.
2) The sum function takes in a nodeset as a parameter, and sums up its contents, giving us the desired total.

I'm attaching a sample form template that has this technique implemented; save the XSN locally before opening it up.

This method works in InfoPath 2003, 2007, and is supported in browser-enabled form templates.

Alex Weinstein
Program Manager

OrderTotal.xsn