Chapter 10. Union and list types

In Chapter 8, we learned how to define atomic simple types. This chapter covers the other two varieties of simple types: union types and list types.

10.1. Varieties and derivation types

As we saw in Chapter 8, there are three varieties of simple types: atomic types, list types, and union types.

Atomic types have values that are indivisible, such as 10 and large.

List types have values that are whitespace-separated lists of atomic values, such as <availableSizes>10 large 2</availableSizes>.

Union types may have values that are either atomic values or list values. What differentiates them is that the set of valid values, or “value space,” for the type is the union of the value spaces of two or more other simple types. For example, to represent a dress size, you may define a union type that allows a value to be either an integer from 2 through 18, or one of the string values small, medium, or large.

Each newly defined simple type must be based on an existing type, using one of the following methods:

• A restriction of another type, known as the base type of the restriction. This results in a type of the same variety as the base type, with a restricted set of valid values. For example, you can define a SmallInteger type that restricts the value space of the integer type.

• A list of another type (either an atomic or union type), known as the item type of the list. This results in a type that allows a whitespace-separated list of values of the item type. For example, you can define an IntegerList type that is a list of integer values.

• A union of one or more other types, known as the member types of the union. This results in a type that allows values that are valid for any of its member types. For example, you can define an IntegerOrString type that allows either an integer or a string.

The variety of the resulting type depends on both the derivation type and the variety of the original type. Table 10–1 shows all possible combinations of derivation types and original type varieties. The important thing to understand is that when you restrict, for example, a list type, the resulting type is still a list type. All the rules for list types, such as applicable facets, also apply to this new type.

Table 10–1. Varieties of derived types

Image

10.2. Union types

10.2.1. Defining union types

Union types allow a value to conform to any one of several different simple types. The syntax to define a union type is shown in Table 10–2.

Table 10–2. XSD Syntax: union type

Image

To continue with our DressSizeType example, perhaps we want to allow a value to be either an integer from 2 to 18, or one of the specific values small, medium, or large. Example 10–1 shows the definition of a union type that accomplishes this.

Example 10–1. Defining a union type


<xs:simpleType name="SizeType">
  <xs:union>
    <xs:simpleType>
      <xs:restriction base="xs:integer">
        <xs:minInclusive value="2"/>
        <xs:maxInclusive value="18"/>
      </xs:restriction>
    </xs:simpleType>
    <xs:simpleType>
      <xs:restriction base="xs:token">
        <xs:enumeration value="small"/>
        <xs:enumeration value="medium"/>
        <xs:enumeration value="large"/>
      </xs:restriction>
    </xs:simpleType>
  </xs:union>
</xs:simpleType>


The simple types that compose a union type are known as its member types. Member types must always be simple types; there is no such thing as a union of complex types. There must be at least one member type, and there is no limit for how many member types may be specified.

In Example 10–1, the member types are defined anonymously within the union, as simpleType children. It is also possible to specify the member types using a memberTypes attribute of the union element, as shown in Example 10–2. It is assumed that DressSizeType and SMLSizeType are defined elsewhere in the schema.

Example 10–2. Using the memberTypes attribute


<xs:simpleType name="SizeType">
  <xs:union memberTypes="DressSizeType SMLSizeType"/>
</xs:simpleType>


You can also combine the memberTypes attribute with simpleType children, as shown in Example 10–3.

Example 10–3. Combining memberTypes and simpleType


<xs:simpleType name="SizeType">
  <xs:union memberTypes="DressSizeType">
    <xs:simpleType>
      <xs:restriction base="xs:token">
        <xs:enumeration value="small"/>
        <xs:enumeration value="medium"/>
        <xs:enumeration value="large"/>
      </xs:restriction>
    </xs:simpleType>
  </xs:union>
</xs:simpleType>


10.2.2. Restricting union types

It is possible to restrict a union type. The syntax for restricting a union type is shown in Table 10–3.

Table 10–3. XSD Syntax: union type restriction

Image

Of all the facets, only three may be applied to union types: pattern, enumeration, and assertion. These restrictions are considered to be in addition to the restrictions of the individual member types. Example 10–4 shows a restriction of SizeType that only allows integers 2, 4, and 6, and the value small. A value of the type SmallSizeType is first validated against the enumerations defined in SmallSizeType, then validated against each of the member types of SizeType until it is successfully validated against one.

Example 10–4. Restricting a union


<xs:simpleType name="SmallSizeType">
  <xs:restriction base="SizeType">
    <xs:enumeration value="2"/>
    <xs:enumeration value="4"/>
    <xs:enumeration value="6"/>
    <xs:enumeration value="small"/>
  </xs:restriction>
</xs:simpleType>


10.2.3. Unions of unions

It is possible to define a union type that has another union type as its member type. For example, if you want to expand your size type yet again, to include non-US sizes, you might define a new type InternationalSizeType that is the union of SizeType (which is itself a union) and a new anonymous type, as shown in Example 10–5.

Example 10–5. A union of a union


<xs:simpleType name="InternationalSizeType">
  <xs:union memberTypes="SizeType">
    <xs:simpleType>
      <xs:restriction base="xs:integer">
        <xs:minInclusive value="24"/>
        <xs:maxInclusive value="54"/>
      </xs:restriction>
    </xs:simpleType>
  </xs:union>
</xs:simpleType>


The only caveat is that union type references cannot be circular, either directly or indirectly. For example, you cannot define a union type union1 that has another type union2 among its member types, if union2 also has union1 among its member types.

10.2.4. Specifying the member type in the instance

An instance element can optionally use the xsi:type attribute to specify its type. In the case of union types, you can use xsi:type to specify which of the member types the element conforms to. This allows more targeted validation and provides a clue to the application that processes the instance about what type of value to expect. Example 10–6 shows what an instance element might look like.

Example 10–6. Specifying the member type in the instance


<size xsi:type="DressSizeType">12</size>


Naturally, this technique only works for elements, not attributes. In the previous example, if size were an attribute, you would have no way of specifying its member type, because attributes cannot have attributes.

If the xsi:type attribute is not used in the instance, an element is considered to have the first member type for which it is valid.

10.3. List types

10.3.1. Defining list types

List types are whitespace-separated lists of atomic values. A list type is defined by designating another simple type (an atomic or union type) as its item type. Table 10–4 shows the syntax for defining a list type.

Table 10–4. XSD Syntax: list type

Image

Example 10–7 shows a simple type that allows a list of available dress sizes.

Example 10–7. Defining a list type using an itemType attribute


<xs:simpleType name="AvailableSizesType">
  <xs:list itemType="DressSizeType"/>
</xs:simpleType>


An instance element of the type AvailableSizesType is shown in Example 10–8.

Example 10–8. List instance


<availableSizes>10 12 14</availableSizes>


Example 10–7 uses the itemType attribute to designate a global simple type named DressSizeType as its item type. Alternatively, the item type can be specified anonymously in a simpleType child within the list type definition, as shown in Example 10–9. Either the itemType attribute or the simpleType child must appear, not both.

Example 10–9. Defining a list type using a simpleType child


<xs:simpleType name="AvailableSizesType">
  <xs:list>
    <xs:simpleType>
      <xs:restriction base="xs:integer">
        <xs:minInclusive value="2"/>
        <xs:maxInclusive value="18"/>
      </xs:restriction>
    </xs:simpleType>
  </xs:list>
</xs:simpleType>


There is no way to represent an absent or nil item in a list. The whiteSpace facet for all list types is fixed at collapse, which means that if multiple whitespace characters appear consecutively, they are collapsed into one space. In Example 10–8, even though there are two spaces between the values 12 and 14, there are only three items in the list.

10.3.2. Design hint: When should I use lists?

When representing sequences of like values, you are faced with a decision whether to use a list, such as:

<availableSizes>10 12 14</availableSizes>

or use markup to separate the distinct values, such as:

<availableSizes>
  <size>10</size>
  <size>12</size>
  <size>14</size>
</availableSizes>

The advantage of using a list is obvious: It is less verbose. However, there are a number of disadvantages of lists.

• They are not appropriate for values that may contain whitespace (see Section 10.3.4 on p. 195).

• If you later wish to expand the values by adding children or attributes, this will not be possible if you use a list. For example, if you use markup, you can later add an attribute to size to indicate the measurement system, such as <size system="US-DRESS">.

• There is no way to represent nil values.

• There may be limited support for lists in other XML technologies. For example, individual values in a list cannot be accessed via XPath 1.0 or XSLT 1.0.

10.3.3. Restricting list types

The syntax for restricting a list type is shown in Table 10–5. A limited number of facets may be applied to list types. These facets have a slightly different behavior when applied to a list type, because they apply to the list as a whole, not to the individual items in the list. To restrict the values of each item in the list, you should restrict the item type, not the list type itself.

Table 10–5. XSD Syntax: list type restriction

Image

When applying facets to a list type, you do not specify the facets directly in the list type definition. Instead, you define the list type, then define a restriction of that list type. This can be done with two separate named simple types, or it can be accomplished all in one definition as shown in Example 10–10.

Example 10–10. Length facet applied to a list


<xs:simpleType name="AvailableSizesType">
  <xs:restriction>
    <xs:simpleType>
      <xs:list itemType="SMLSizeType"/>
    </xs:simpleType>
    <xs:maxLength value="3"/>
  </xs:restriction>
</xs:simpleType>


10.3.3.1. Length facets

Length facets length, minLength, and maxLength may be used to restrict list types. The length is measured as number of items in the list, not the length of each item. Example 10–10 shows a list that is restricted by a maxLength facet.

Example 10–11 shows a valid instance of AvailableSizesType. It is valid because the number of items in the list is not more than three. The fact that the strings medium and large are longer than three characters is not relevant. To restrict the length of each item in the list, apply the maxLength facet to the item type itself (SMLSizeType), not to the list type.

Example 10–11. Valid instance of a length-restricted list


<availableSizes>medium large</availableSizes>


When you define a list type, there are no automatic restrictions on the length of the list. Therefore, a list with zero items (i.e., empty elements or just whitespace) is considered valid. If you do not want a list to be valid if it is empty, restrict the list type by setting its minLength to 1.

10.3.3.2. Enumeration facet

The enumeration facet may also be used to restrict list types. However, the enumeration specified applies to the whole list, not to each item in the list. For example, to restrict the values in a list to a specific set, you may be tempted to define a simple type like the one shown in Example 10–12.

Example 10–12. Enumeration applied inappropriately to a list type


<xs:simpleType name="AvailableSizesType">
  <xs:restriction>
    <xs:simpleType>
      <xs:list itemType="xs:token"/>
    </xs:simpleType>
    <xs:enumeration value="small"/>
    <xs:enumeration value="medium"/>
    <xs:enumeration value="large"/>
  </xs:restriction>
</xs:simpleType>


However, this would not behave as you expect. It would restrict the value of the entire list to only one of the values: small, medium, or large. Therefore, <availableSizes>small</availableSizes> would be valid, but <availableSizes>small medium</available-Sizes> would not. Instead, apply the enumeration to the item type, as shown in Example 10–13.

Example 10–13. Enumeration applied to the item type of a list


<xs:simpleType name="AvailableSizesType">
  <xs:list>
    <xs:simpleType>
      <xs:restriction base="xs:token">
        <xs:enumeration value="small"/>
        <xs:enumeration value="medium"/>
        <xs:enumeration value="large"/>
      </xs:restriction>
    </xs:simpleType>
  </xs:list>
</xs:simpleType>


There may be cases where you do want to restrict the entire list to certain values. Example 10–14 shows a list that may only have two values, as shown.

Example 10–14. Enumeration correctly applied to a list type


Schema:

<xs:simpleType name="ApplicableSizesType">
  <xs:restriction>
    <xs:simpleType>
      <xs:list itemType="SizeType"/>
    </xs:simpleType>
    <xs:enumeration value="small medium large"/>
    <xs:enumeration value="2 4 6 8 10 12 14 16 18"/>
  </xs:restriction>
</xs:simpleType>

Instance:

<applicableSizes>small medium large</applicableSizes>
<applicableSizes>2 4 6 8 10 12 14 16 18</applicableSizes>


10.3.3.3. Pattern facet

The pattern facet may also be applied to list types. Like the length and enumeration facets, the pattern facet in this case applies to the entire list, not the items in the list. For example, suppose you want to represent vector information as a list of integers. You want your list to always contain zero or more groups of three integers each, separated by whitespace. The restriction shown in Example 10–15 enforces this constraint.

Example 10–15. Pattern applied to a list type


<xs:simpleType name="VectorType">
  <xs:restriction>
    <xs:simpleType>
      <xs:list itemType="xs:unsignedInt"/>
    </xs:simpleType>
    <xs:pattern value="d+s+d+s+((d+s+){3})*d+"/>
  </xs:restriction>
</xs:simpleType>


10.3.4. Lists and strings

Be careful when deriving list types from string-based types whose values may contain whitespace. This includes the built-in types string, normalizedString, and token, as well as user-defined types derived from them. Since list items are separated by whitespace, strings that contain whitespace may give unexpected results when included as items in a list. Example 10–16 shows the definition of AvailableSizesType as a list of SMLXSizeType, which is derived from token and allows the values small, medium, large, and extra large.

Example 10–16. Defining a list of a string-based type


<xs:simpleType name="AvailableSizesType">
  <xs:list itemType="SMLXSizeType"/>
</xs:simpleType>
<xs:simpleType name="SMLXSizeType">
  <xs:restriction base="xs:token">
    <xs:enumeration value="small"/>
    <xs:enumeration value="medium"/>
    <xs:enumeration value="large"/>
    <xs:enumeration value="extra large"/>
  </xs:restriction>
</xs:simpleType>


Example 10–17 shows an invalid instance of AvailableSizesType. The schema processor would consider this instance to be a list of three items (“small”, “extra”, and “large”) rather than the expected two items (“small” and “extra large”). When it attempts to validate the value “extra” against the enumerated values, it will find it invalid.

Example 10–17. Invalid instance of AvailableSizesType


<availableSizes>
small
extra large
</availableSizes>


10.3.5. Lists of unions

Lists of union types are no different from lists of atomic types. Each item in the list must simply be a valid value of one of the member types of the union type. Example 10–18 defines our now familiar union type SizeType, then defines a list type AvailableSizesType whose item type is SizeType.

Example 10–18. Defining a list of a union


<xs:simpleType name="SizeType">
  <xs:union memberTypes="DressSizeType SMLXSizeType"/>
</xs:simpleType>

<xs:simpleType name="AvailableSizesType">
  <xs:list itemType="SizeType"/>
</xs:simpleType>


Example 10–19 shows a valid instance of AvailableSizesType. Note that both the integers and the enumerated small, medium, and large are valid list items, in any order.

Example 10–19. Instance of a list of a union


<availableSizes>10 large 2</availableSizes>


The only restriction on lists of unions is that the union type cannot have any list types among its member types. That would equate to a list of lists, which is not legal.

10.3.6. Lists of lists

Lists of lists are not legal. The item type of a list type cannot be a list type itself, nor can it be derived at any level from another list type (for example, as a restriction of a list, or a union of a list). Example 10–20 is illegal as it attempts to define a simple type TwoDimensionalArrayType as a list of lists.

Example 10–20. Illegal list of lists


<xs:simpleType name="RowType">
  <xs:list itemType="xs:integer"/>
</xs:simpleType>

<xs:simpleType name="TwoDimensionalArrayType">
  <xs:list itemType="RowType"/>
</xs:simpleType>


Instead, you should put markup around the items in the lists. Example 10–21 shows a complex type definition that accomplishes this and a valid instance.

Example 10–21. An array using markup


Schema:

<xs:complexType name="VectorType">
  <xs:sequence maxOccurs="unbounded">
    <xs:element name="e" type="xs:integer"/>
  </xs:sequence>
</xs:complexType>

<xs:complexType name="ArrayType">
  <xs:sequence maxOccurs="unbounded">
    <xs:element name="r" type="VectorType"/>
  </xs:sequence>
</xs:complexType>

<xs:element name="array" type="ArrayType"/>

Instance:

<array>
  <r>  <e>1</e>  <e>12</e> <e>15</e> </r>
  <r>  <e>44</e> <e>2</e>  <e>3</e>  </r>
</array>


10.3.7. Restricting the item type

Once you have defined a list type, you cannot derive another list type from it that restricts the item type. For example, it is impossible to derive a list of MediumDressSizeType from a list of DressSizeType. Instead, you must restrict the item type (in this case DressSizeType), then define a new list type of the new restricted atomic type (e.g., MediumDressSizeType).

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

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