The Typeswitch Expression

The typeswitch expression provides a convenient syntax for performing special processing based on the type of an expression. An example is shown in Example 14-1.

Example 14-1. Binding variables to typeswitch expressions

typeswitch ($myProduct)
  case element(*,prod:HatType) return xs:string($myProduct/size)
  case element(*,prod:ShirtType)
       return xs:string(concat($myProduct/size/@system, ": ",
                               $myProduct/size))
  case element(*,prod:UmbrellaType) return "none"
  default return "n/a"

The example assumes that $myProduct is bound to a product element. In the schema, assume that product elements are declared to have type ProductType. However, in the input document, a product element may carry an xsi:type attribute that indicates another type that is derived by extension from ProductType, such as HatType, ShirtType, or UmbrellaType.

ProductType itself does not allow a size child. Depending on which subtype it has, it may or may not have a size child. The typeswitch expression will return a different value depending on the type annotation of the product element.

The syntax of a typeswitch expression is shown in Figure 14-1. The typeswitch keyword is followed by an expression in parentheses (called the operand expression), which evaluates to the sequence whose type is to be evaluated. This is followed by one or more case clauses, plus a required default clause that indicates the value if none of the case clauses applies.

Syntax of a typeswitch expression

Figure 14-1. Syntax of a typeswitch expression

The processor uses sequence type matching (described in Chapter 11) to determine whether a case clause applies. This means that if the type of the items in the sequence is the same as, or is derived from, the type identified by the case clause, it matches. If more than one case clause is applicable, the first one is used. Remember, with sequence type matching, it is not enough that the items are valid according to the specified type, they must actually have been validated and have that type (or a type derived from it) as their type annotation.

Each of the case and default clauses can have an optional variable name before the return keyword. That variable is bound to the value of the operand expression. This is useful if the return expression is dependent on the sequence being tested. In Example 14-2, the $h, $s, and $p variables are bound to the $myProduct value, and the return expression references the variable. This example uses user-defined schema types, which are explained in the previous chapter.

Example 14-2. Binding variables to typeswitch expressions

typeswitch ($myProduct)
  case $h as element(*,prod:HatType) return xs:string($h/size)
  case $s as element(*,prod:ShirtType)
       return xs:string(concat($s/size/@system, ": ", $s/size))
  case element(*,prod:UmbrellaType) return "none"
  default return "n/a"

The typeswitch expression can serve as shorthand for multiple if-then-else expressions that use instance of expressions to determine the type of the variable. Example 14-3 shows this alternative, which is similar to Example 14-2.

Example 14-3. Alternative to a typeswitch expression

if ($myProduct instance of element(*,prod:HatType))
then xs:string($myProduct/size)
else if ($myProduct instance of element(*,prod:ShirtType))
     then xs:string(concat($myProduct/size/@system, ": ", $myProduct/size))
     else if ($myProduct instance of element(*,prod:UmbrellaType))
          then "none"
          else "n/a"

However, there is an important difference between the two: an implementation that supports static typing will raise a type error with Example 14-3. This is because, as far as the processor knows, $myProduct is of type ProductType, which does not allow a size child. Even though the processor is aware that there are subtypes that allow a size child, the static typing feature does not extend to parsing out the if expressions to determine that you would never evaluate the expression $myProduct/size on anything that didn't allow a size child. The typeswitch expression in Example 14-2, on the other hand, assures the processor that the branch that contains $h/size will only ever be evaluated for elements of type HatType. Remember that static typing is pessimistic; it will give you an error if anything could go wrong, not only if it knows that things will go wrong.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
52.15.38.176