XSLT 2.0 and XPath 2.0 Programmer's Reference, 4th Edition (70 page)

BOOK: XSLT 2.0 and XPath 2.0 Programmer's Reference, 4th Edition
5.06Mb size Format: txt, pdf, ePub

You can go beyond this, and define a type hierarchy. In a genealogical database, in addition to recording events in a person's life, you can also record properties of a person such as their occupation, religion, state of health, or (if you want) their height or eye color. GEDCOM hasn't modeled these particularly well; it treats them as events, which isn't a particularly good fit. They have a lot in common with events, in that you want to record the evidence for the information, but they tend to be independent of place and to be applicable over some extended period of a person's life. So in an ideal world we would probably model these using a separate type called, say,
ATTRIBUTE
(not to be confused with XML attributes, of course). The things that
EVENT
and
ATTRIBUTE
have in common could be defined in a third type from which both of these inherit: let's call this
DETAIL
. Then in an XPath expression, I can find all the events and all the attributes for a person with the single expression
element(*, DETAIL)
.

Sometimes you get the chance to write a schema with schema-aware XSLT and XQuery processing in mind. More often, however, you have to work with a schema that already exists, and which was written primarily for validation. In this case, it might not contain any very useful type hierarchies. But there's another device in XML Schema that allows elements to be referred to generically, namely substitution groups, and we'll look at what these have to offer in the next section.

Substitution Groups

The type of an element or attribute tells you what can appear inside the content of the element or attribute. Substitution groups, by contrast, classify elements according to where they can appear.

There is a schema for XSLT 2.0 stylesheets published as part of the XSLT Recommendation (see
http://www.w3.org/2007/schema-for-xslt20.xsd
). Let's look at how this schema uses substitution groups.

Firstly, the schema defines a type that is applicable to any XSLT-defined element, and that simply declares the standard attributes that can appear on any element:


  

  

  

                type=“xsl:prefix-list-or-all”/>

  

  

  


There's a good mix of features used to define these attributes. Some attributes use built-in types (
xs:anyURI
), while some use user-defined types defined elsewhere in the schema
(xsl:prefixes
). The

at the end says that XSLT elements can contain attributes from a different namespace, which are laxly validated (that is, the processor will validate the attribute if and only if a schema definition is available for it.)

Every XSLT element except the

element allows a standard
version
attribute (the

element is different because its
version
attribute is defined for a different purpose and has a different type). So the schema defines another type that adds this attribute:


  

    

      

    

  


The XSLT specification classifies many XSLT elements as
instructions
. This is not a structural distinction based on the attributes or content model of these elements (which varies widely), it is a distinction based on the way they are used. In particular, instruction elements are interchangeable in terms of where they may appear in a stylesheet: If you can use one instruction in a particular context, you can use any instruction. This calls for defining a substitution group:

            type=“xsl:versioned-element-type”

            abstract=“true”/>

Note that although the substitution group is defined using an element declaration, it does not define a real element, because it specifies
abstract = “true”
. This means that an actual XSLT stylesheet will never contain an element called

. It is a fictional element that exists only so that others can be substituted for it.

What this declaration does say is that every element in the substitution group for

must be defined with a type that is derived from
xsl:versioned-element-type
. That is, every XSLT instruction allows the attributes
default-collation
,
exclude-result-prefixes
,
extension-element-prefixes
,
use-when
,
xpath-default-namespace
, and
version
, as well as any namespace-prefixed attribute. This is in fact the only thing that XSLT instructions have in common with each other, as far as their permitted content is concerned.

Individual instructions are now defined as members of this substitution group. Here is a simple example, the declaration of the

element:


  

    

      

        

      

    

  


This shows that the

element is a member of the substitution group whose head is the abstract

element. It also tells us that the content model of the element (that is, its type) is defined as an extension of the type
xsl:sequence-constructor
, the extension being to require a
test
attribute whose value is of type
xsl:expression
—this is a simple type defined later in the same schema, representing an XPath expression that may appear as the content of this attribute.

The type
xsl:sequence-constructor
is used for all XSLT elements whose permitted content is a
sequence constructor
. A sequence constructor is simply a sequence of zero or more XSLT instructions, defined like this:


  

    

      

                                                     maxOccurs=“unbounded”/>

    

  



  

    

    

    

  


The first definition says that the
xsl:sequence-constructor
type extends
xsl:versioned-element-type
, whose definition we gave earlier. If it didn't extend this type, we wouldn't be allowed to put

in the substitution group of

. It also says that the content of a sequence constructor consists of zero or more elements, each of which must be chosen from those in the group
sequence-contructor-group
. The second definition says that every element in
sequence-contructor-group
is either an

(which implicitly allows any element in the substitution group for

, including of course

), or an

.

The

element is not defined as a member of the substitution group because it can be used in two different contexts: either as an instruction or as a top-level declaration in a stylesheet. This is one of the drawbacks of substitution groups: they can't overlap (this limitation disappears in XML Schema 1.1). The schema defines all the elements that can act as declarations in a very similar way, using a substitution group headed by an abstract

element. It's not possible in XML Schema 1.0 for the same element,

, to appear in both substitution groups, so it has been defined in neither, and needs to be treated as a special case.

If you need to use XSLT to access an XSLT stylesheet (which isn't as obscure a requirement as it may seem; there are many applications for this), then the classification of elements as instructions or declarations can be very useful. For example, you can match all the instructions that have an attribute in the Saxon namespace with the template rule:


assuming that the namespace prefix
saxon
has been declared appropriately. Here the expression
schema-element(xsl:instruction)
selects elements that are either named

or are in the substitution group with

as its head element, and the predicate
[@saxon:*]
is a filter that selects only those elements that have an attribute in the
saxon
namespace.

Other books

The Delusionist by Grant Buday
Bound in Darkness by Cynthia Eden
The Flood by Émile Zola
Mercy by Annabel Joseph
Not Quite a Mermaid by Linda Chapman
Currency of Souls by Burke, Kealan Patrick
Love Finds Lord Davingdale by Anne Gallagher