Declaring Types


As we saw in the overview section, XSLT 2.0 allows you to define the type of a variable. Similarly, when you write functions or templates, you can declare the type of each parameter, and also the type of the returned value.

Here is an example of a function that takes a string as its parameter, and returns an integer as its result:

  <xsl:function name="my:length" as="xs:integer">   <xsl:param name=:"in" as="xs:string"/>   <xsl:sequence select="max((string-length(upper-case($in)),   string-length(lower-case($in))))"/>   </xsl:function>  

And here's a named template that expects either an element node or nothing as its parameter, and returns either a text node or nothing as its result:

  <xsl:template name ="sequence-nr" as="text()?">   <xsl:param name="in" as="element()?"/>   <xsl:number level="any" select="$in" format="i"/>   </xsl:template>  

You don't have to include type declarations in the stylesheet: If you leave out the «as » attribute, then as with XSLT 1.0, any type of value will be accepted. However, I think it's a good software engineering practice always to declare the types as precisely as you can. The type declarations serve two purposes:

  • The XSLT processor has extra information about the permitted values of the variables or parameters, and it can use this information to generate more efficient code.

  • The processor will check (at compile time, and if necessary at runtime) that the values supplied for a variable or parameter match the declared types, and will report an error if not. This can detect many errors in your code, errors that might otherwise have led to the stylesheet producing incorrect output. As a general rule, the sooner an error is detected , the easier it is to find the cause and correct it, so defining types in this way leads to faster debugging. I have heard stories of users upgrading their stylesheets from XSLT 1.0 to XSLT 2.0 and finding that the extra type checking revealed errors that had been causing the stylesheet to produce incorrect output which no one had ever noticed.

These type declarations are written using the «as » attribute of elements such as <xsl:variable> , <xsl:param> , <xsl:function> , and <xsl:template> . You don't need to use a schema-aware processor to use the «as » attribute, because many of the types you can declare (including those in the two examples above) are built-in types, rather than types that need to be defined in your schema. For example, if a function parameter is required to be an integer, you can declare it like this:

  <xsl:param name="in" as="xs:integer"/>  

which will work whether or not your XSLT processor is schema-aware, and whether or not your source documents are validated using an XML Schema.

The rules for what you can write in the «as » attribute are defined in XPath 2.0, not in XSLT itself. The construct that appears here is called a sequence type descriptor, and it is explained in detail in Chapter 9 of XPath 2.0 Programmer's Reference. Here are some examples of sequence type descriptors that you can use with any XSLT processor, whether or not it is schema-aware:

Construct

Meaning

xs:integer

An atomic value labeled as an integer

xs:integer *

A sequence of zero or more integers

xs:string ?

Either a string, or an empty sequence

xs:date

A date

xdt:anyAtomicType

An atomic value of any type (for example integer, string, and so on)

node()

Any node in a tree

node() *

Any sequence of zero or more nodes, of any kind

element()

Any element node

attribute() +

Any sequence of one or more attribute nodes

document-node()

Any document node

The types that are available in a basic XSLT processor are shown in Figure 4-1, which also shows where they appear in the type hierarchy:

The shaded boxes show concrete types, and the empty boxes represent abstract types. The difference is that a value can never belong to an abstract type unless it also belongs to one of the concrete subtypes of that type.

The most general type here is «item() », which allows any kind of item. The two kinds of items are atomic values, shown on the left-hand branch of the type hierarchy, and nodes, shown on the right-hand branch.

click to expand
Figure 4-1

In a sequence type descriptor, any of the item types listed in Figure 4-1 may be followed by one of the occurrence indicators «* » , «+ » , or «? » . The occurrence indicator defines how many items (of the given item type) may appear in the value. They have the following meanings:

Occurrence indicator

Meaning

*

Zero or more occurrences allowed

+

One or more occurrences allowed

?

Zero or one occurrence allowed

If there is no occurrence indicator, then the value must contain exactly one item of the specified type.

In a schema-aware processor, this type hierarchy is extended in the following two ways:

  • Firstly, all the built-in atomic types defined in the XML Schema specification become available. These include additional primitive types such as xs: hexBinary and xs:gYearMonth , and types derived from xs:string and xs:integer , for example xs:normalizedString and xs:nonNegativeInteger . A full list of these types, with explanations of their meanings, is given in Chapter 3 of XPath 2.0 Programmer's Reference.

  • Secondly, user -defined types can be imported from an XML Schema definition.

To make user-defined types available for use in type declarations in a stylesheet, the schema must first be imported into the stylesheet. This can be done with an <xsl:import-schema> declaration, which might take the form:

  <xsl:import-schema namespace="http://acme.org/ns" schema-location="acme.xsd"/>  

The <xsl:import-schema> declaration is described in more detail later in this chapter (see page 168). You can import any number of schemas into a stylesheet, provided that the namespaces do not clash . If you want to refer to types defined in a schema by name, then you must import that schema into the stylesheet using an <xsl:import-schema> declaration. However, you don't need to import a schema simply because you are using it to validate source or result documents.

The types defined in a schema are either complex types or simple types, and simple types in turn divide into union types, list types, and atomic types.

When atomic types are imported from a schema, they can be used in a stylesheet in just the same way as the built-in atomic types. For example, if the schema defines an atomic type mf:part-number as a subtype of xs: string constrained to conform to a particular pattern, then in the stylesheet you can declare a variable:

  <xsl:variable name="part" as="mf:part-number" select="EXPRESSION"/>  

which informs the system that the value of the $part variable will always be a part number. The expression in the select attribute must return a valid part number according to these rules, or the transformation will fail.

Important  

Note that to conform to this type, it's not enough to supply a string that matches the schema-defined pattern. The value must actually be labeled as an mf:part-number . To achieve this, you typically have to convert the value to the required type using a constructor function. For example, you could write:

 <xsl:variable name="part" as="mf:part-number"                           select="mf:part-number('BFG94623<)"/> 

Atomic values can exist independently of any node in a document, which is why you can use an atomic type directly as the type of a value. In contrast, instances of complex types, union types, and list types can exist only as the content of a node in a document. This means that the names of these types can't be used directly in an «as » attribute defining the type of (say) a variable or parameter. You can use them, however, to qualify a type that describes a node. Examples of such sequence type descriptors are shown in the table below:

Construct

Meaning

element(*, mf:invoice)

An element node validated against the complex type mf:invoice defined in an imported schema

attribute(*, xs:NMTOKENS)

An attribute validated against the built-in schema list type xs:NMTOKENS

document-node (element (*, mf:invoice ))

A document node representing a well- formed XML document whose outermost element has been validated against the complex type mf:invoice defined in an imported schema

Often the structure of an element is defined in the schema not by creating an explicitly named <xs:complexType> definition, but rather by means of an <xs: element> declaration that contains an unnamed <xs:complexType> . Here's a typical example, taken from the schema for XSLT 2.0 stylesheets:

  <xs:element name="apply-imports" substitutionGroup="xsl:instruction">   <xs:complexType>   <xs:complexContent>   <xs:extension base="xsl:versioned-element-type">   <xs:sequence>   <xs:element ref="xsl:with-param" minOccurs="0" maxOccurs="unbounded"/>   </xs:sequence>   </xs:extension>   </xs:complexContent>   </xs:complexType>   </xs:element>  

To allow for the fact that many of the types defined in a typical schema are anonymous, there is another form of the element() test that is used to refer to elements conforming to this named element declaration. If you write:

  <xsl:param name="ai" as="schema-element(xsl:apply-imports)"/>  

then you are saying that the value of the parameter must be an element that has been validated against the element declaration xsl:apply-imports in this schema. The name of the element passed as the parameter must either be xsl:apply-imports , or must match an element defined in the schema to be a member of the substitution group of xsl:apply-imports .

You can similarly refer to top-level attribute declarations in the schema using the syntax «schema-attribute (nnn) » , though this form is not seen very often because it is unusual to find top-level attribute declarations in a schema.

Sequence type descriptors can also be used within XPath expressions. The expressions that use them are described in Chapter 9 of XPath 2.0 Programmer's Reference, which also defines the syntax and semantics in much greater detail than defined here. The operators that use sequence type descriptors are as follows :

  • «instance of » , which tests whether a given value is an instance of a given type. For example, «@dob instance of attribute (*, xs:date) » returns true if the attribute @dob is labeled with the type annotation xs:date (or a type derived from xs:date ), which will be true only if the attribute contains a valid date and has been validated using a schema that declares the type of the attribute as xs:date .

  • «treat as » , which asserts that a given value is an instance of a given type, causing a runtime failure if it is not. This operator is useful mainly with XPath processors that do strict static type-checking, which is unlikely to apply in an XSLT environment unless the processor has a diagnostic mode to do this extra level of checking.




XSLT 2.0 Programmer's Reference
NetBeansв„ў IDE Field Guide: Developing Desktop, Web, Enterprise, and Mobile Applications (2nd Edition)
ISBN: 764569090
EAN: 2147483647
Year: 2003
Pages: 324

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