Thursday, January 7, 2010

Schematron: Using the Number() Function Versus Casting

There are situations where it becomes necessary to test the value of a numeric element to ensure it meets some minimum or maximum value.  As Schematron is capable of treating any element as a string, it is generally a best practice to cast the value to a numeric data type first. 

For example, on a citation or a complaint document it may be necessary to check the fine or bail amount to ensure it is greater than zero.  This could be done with the following Schematron assert statement:

<assert test="xsd:double(nc:ObligationDueAmount) &gt; 0">
  Bail amount may not be less than zero.
</assert>

While the above would work when a value is provided in the nc:ObligationDueAmount element, an XSLT error would be raised in the following circumstances:

  • Value is blank or null
      • <nc:ObligationDueAmount></nc:ObligationDueAmount>
  • Value is omitted
      • <nc:ObligationDueAmount/>
  • Value is a string value
      • <nc:ObligationDueAmount>N/A</nc:ObligationDueAmount>

For this reason, it is often preferable to use the native XPath function number().  As described by Ms. Priscilla Walmsley in her O’Reilly book XQuery, this function will prevent the XSLT parser from throwing an error and instead return the value ‘NaN’ (Not a Number).  The following would be the same way the Schematron test could be written using the number() function instead:

<assert test="number(nc:ObligationDueAmount) &gt; 0">
  Bail amount may not be less than zero.
</assert>
<assert test="nc:ObligationDueAmount and string-length(nc:ObligationDueAmount) &gt; 0">
  Bail amount may not be left blank or otherwise omitted.
</assert>

While a few more lines are required, this prevents a runtime parser error from being raised and causing havoc with the validation engine.

No comments:

Post a Comment