A.3 A Real-World Example

Despite the differences, comparisons between XForms and InfoPath are inevitable. Back in Chapter 2, we examined a UBL purchase order application. It is possible to recreate that application in InfoPath, and thus compare the results. Doing so is largely a hand-to-mouse experience with the InfoPath application. The result is shown in Figure A-1.

Figure A-1. InfoPath design-time
figs/xfe_aa01.gif

Limitations in InfoPath made a few changes necessary for example, there is no match for the range control but overall the solution ended up quite similar to that of XForms.

One notable difference, however, is that tables, which can be seen in Figure A-1 as dotted lines, are required for any kind of layout, which might make things more challenging for non-visual users.

The other major difference was the lack of declarative elements. In XForms, the bind element establishes a relationship that the XForms Processor sticks to at all times. In InfoPath, script attached to a number of different entry points is required. The purchase order application had four assertions to maintain:

  1. A single currency code is copied into each repeating line item.

  2. Since the currency code appears in two places in each line item, it is copied to the second location.

  3. For each line item, the extended price is calculated as price times quantity.

  4. The total of the extended price across all line items is summed up.

In XForms, these four assertions are accomplished through four bind elements:

<xforms:bind nodeset="cat:OrderLine/cat:LineExtensionAmount/@currencyID"      calculate="../../cat:LineExtensionTotalAmount/@currencyID"/> <xforms:bind nodeset="cat:OrderLine/cat:Item/cat:BasePrice/cat:PriceAmount/ @currencyID"      calculate="../../../../cat:LineExtensionTotalAmount/@currencyID"/> <xforms:bind nodeset="cat:OrderLine/cat:LineExtensionAmount"       type="xs:decimal"      calculate="../cat:Quantity * ../cat:Item/cat:BasePrice/cat:PriceAmount"/> <xforms:bind nodeset="cat:LineExtensionTotalAmount" type="xs:decimal"      calculate="sum(../cat:OrderLine/cat:LineExtensionAmount)"/>

In InfoPath, however, the needed script is somewhat more verbose:

XDocument.DOM.setProperty("SelectionNamespaces",     'xmlns:cat="urn:oasis:names:tc:ubl:CommonAggregateTypes:1.0:0.70"     xmlns:ns1="urn:oasis:names:tc:ubl:Order:1.0:0.70"     xmlns:my="http://schemas.microsoft.com/office/infopath/2003/myXSD/2003- 04-19T20:40:35"'); function XDocument::OnLoad(eventObj) { updateCurrency(  ); } // This function is associated with: /ns1:Order/cat:OrderLine/cat:Quantity function msoxd_cat_Quantity::OnAfterChange(eventObj) { recalcLineItem(eventObj.Site.parentNode); recalcTotal(  ); } // This function is associated with: /ns1:Order/cat:OrderLine/cat:Item/cat: BasePrice/cat:PriceAmount function msoxd_cat_PriceAmount::OnAfterChange(eventObj) { recalcLineItem(eventObj.Site.parentNode.parentNode.parentNode); recalcTotal(  ); } // This function is associated with: /ns1:Order/cat: LineExtensionTotalAmount/@currencyID function msoxd_ _LineExtensionTotalAmount_currencyID_attr:: OnAfterChange(eventObj) { updateCurrency(  ); } function recalcLineItem( lineNode ) { var quantity = lineNode.selectSingleNode("cat:Quantity"); var price = lineNode.selectSingleNode("cat:Item/cat:BasePrice/cat: PriceAmount"); var extended = lineNode.selectSingleNode("cat:LineExtensionAmount"); var extPrice = parseFloat(getElementValue(quantity)) *  parseFloat(getElementValue(price)); setElementValue(extended , floatToString(extPrice, 2)); } function recalcTotal(  ) { var dom = XDocument.DOM; var extended = dom.selectSingleNode("/ns1:Order/cat: LineExtensionTotalAmount"); var newTotal = sum("/ns1:Order/cat:OrderLine/cat:LineExtensionAmount"); setElementValue( extended, newTotal ); } function updateCurrency(  ) { var dom = XDocument.DOM; var copyFrom = dom.selectSingleNode("/ns1:Order/cat: LineExtensionTotalAmount/@currencyID"); var lines = dom.selectNodes("/ns1:Order/cat:OrderLine"); // loop through each line item, copying in the currencyID for (var idx=0; idx<lines.length; idx++) {   var copyTo = lines[idx].selectSingleNode("cat:LineExtensionAmount/ @currencyID");   copyTo.nodeValue = copyFrom.nodeValue;   copyTo = lines[idx].selectSingleNode("cat:Item/cat:BasePrice/cat: PriceAmount/@currencyID");   copyTo.nodeValue = copyFrom.nodeValue;   } } // Utility functions function getElementValue( node ) { if (node.firstChild)   return node.firstChild.nodeValue; else   return ""; } function setElementValue( node, newval ) { if (node.firstChild) {   node.firstChild.nodeValue = newval; } else {   var textnode = node.ownerDocument.createTextNode( newval );   node.appendChild( textnode );   } } function sum(xpath) { var nodes = XDocument.DOM.selectNodes(xpath); var total = 0; for (var idx=0; idx<nodes.length; idx++) {   total = total + parseFloat(getElementValue(nodes[idx]));   } return total; } function floatToString(value) { return "" + value; }

This script approach requires a bit of care in getting and setting values from XML elements. In accordance with the DOM worldview, actual data values are stored in a text node child of the element node, except that an empty value is signified by the lack of any text child node.

On my initial attempt at this script, I neglected to attach an OnLoad entry point. The solution worked well, but had a subtle bug: if the initial value in the currency selection list was never changed, the currency value never got propagated throughout the XML. One advantage of a declarative approach is that it applies equally to initial conditions as well as the ongoing state. The XForms example didn't have to be special-cased for initialization.

Though not used here, the extensive sample forms that come with InfoPath include a large library of script that can be reused via copy-and-paste. The resulting InfoPath document can be filled out in the same application that designed the form, as shown in Figure A-2.

Figure A-2. Completing an InfoPath form
figs/xfe_aa02.gif


XForms Essentials
Xforms Essentials
ISBN: 0596003692
EAN: 2147483647
Year: 2005
Pages: 117
Authors: Micah Dubinko

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net