Chapter 7. Attribute declarations

This chapter covers the other basic building block of XML: attributes. It explains how to declare attributes and assign types to them. It also describes fixed and default values as they apply to attributes.

7.1. Attributes vs. elements

Whether to model data values as elements or attributes is an often-discussed question. XML Schema, with its ability to define data types for elements, eliminates many of the advantages of attributes in DTDs. The advantages of using attributes are:

• They are less verbose.

• For narrative content, attributes are typically used for values that should not appear in the content—that is, for metadata. In a typical (X)HTML document, elements are used for the content that appears on a page, while attributes specify style and other information that is used by the browser but not directly by the end user. This is a convenient separation for some narrative XML vocabularies.

• If you plan to validate using DTDs as well as schemas, you can perform some minimal type checking on attribute values. For example, color can be constrained to a certain set of values. Elements’ values character data content cannot be validated using DTDs.

• Attributes can be added to the instance by specifying default values; elements cannot (they must appear to receive a default value).

image

• Attributes can be inherited by descendant elements, as described in Section 7.6 on p. 126.

image

The advantages of using elements are:

• They are more extensible because attributes can later be added to them without affecting a processing application. For example, if you realized that you needed to keep track of what currency a price is expressed in, you can declare a currency attribute in the price element declaration. If price is an attribute, this is not possible.

• They can contain other elements. For example, if you want to mark up a textual description using XHTML tags, this is not possible if description is an attribute.

• They can be repeated. An element may only appear once now, but later you may wish to extend it to appear multiple times. For example, if you decide later that a product can have multiple colors, you can allow a color child to appear more than once. Attributes may only appear once per element.

• You have more control over the rules of their appearance. For example, you can say that a product can have either a number or a productCode child. This is not possible for attributes.

• They can be used in substitution groups.

• They can be given nil values.

• They can use type substitution to substitute derived types in the instance.

• Their order is significant, while the order of attributes is not. Obviously, this is only an advantage if you care about the order.

• When the values are lengthy, elements tend to be more readable than attributes.

As you can see, there are many more advantages to using elements than attributes, but attributes are useful in some cases. A general recommendation is to use attributes for metadata and elements for data. For example, use an attribute to describe the units, language, or time dependence of an element value. Additionally, attributes should be used for ID and IDREF values as well as XLink expressions. Elements should be used for everything else.

7.2. Global and local attribute declarations

Attribute declarations are used to name an attribute and associate it with a particular simple type. This is accomplished using an attribute element. Attribute declarations may be either global or local.

7.2.1. Global attribute declarations

Global attribute declarations appear at the top level of the schema document, meaning that their parent must be the schema element. These global attribute declarations can then be used in multiple complex types, as described in Section 12.6 on p. 281. Table 7–1 shows the syntax of a global attribute declaration.

Table 7–1. XSD Syntax: global attribute declaration

Image

Example 7–1 shows two global attribute declarations: system and dim. A complex type is then defined which references those attribute declarations by name using the ref attribute.

Example 7–1. Global attribute declarations


<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           xmlns="http://datypic.com/prod"
           targetNamespace="http://datypic.com/prod">

  <xs:attribute name="system" type="xs:string"/>
  <xs:attribute name="dim" type="xs:integer"/>

  <xs:complexType name="SizeType">
    <xs:attribute ref="system" use="required"/>
    <xs:attribute ref="dim"/>
  </xs:complexType>

</xs:schema>


The qualified names used by global attribute declarations must be unique in the schema. This includes not just the schema document in which they appear, but any other schema documents that are used with it.

The use attribute, which indicates whether an attribute is required or optional, appears in the attribute reference rather than attribute declaration. This is because it applies to the appearance of that attribute in a complex type, not the attribute itself. Attribute references are covered in Section 12.6 on p. 281.

The name specified in an attribute declaration must be an XML non-colonized name, which means that it must start with a letter or underscore, and may only contain letters, digits, underscores, hyphens, and periods. The qualified name consists of the target namespace of the schema document plus the local name in the declaration. In Example 7–1, the system and dim attributes take on the target namespace http://datypic.com/prod.

Since globally declared attribute names are qualified by the target namespace of the schema document, it is not legal to include a namespace prefix in the value of the name attribute. If you want to declare attributes in another namespace, you must create a separate schema document with that namespace as target and import it into the original schema document. If you simply want to specify an attribute from another namespace, such as xml:lang, use the ref attribute to reference it in a complex type.

7.2.2. Local attribute declarations

Local attribute declarations, on the other hand, appear entirely within a complex type definition. They may only be used in that type definition, and are never reused by other types. Table 7–2 shows the syntax for a local attribute declaration.

Table 7–2. XSD Syntax: local attribute declaration

Image
Image

Example 7–2 shows two local attribute declarations, system and dim, which appear entirely within a complex type definition.

Example 7–2. Local attribute declarations


<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           xmlns="http://datypic.com/prod"
           targetNamespace="http://datypic.com/prod">

  <xs:complexType name="SizeType">
    <xs:attribute name="system" type="xs:string" use="required"/>
    <xs:attribute name="dim" type="xs:integer"/>
  </xs:complexType>

</xs:schema>


Unlike global attribute declarations, local attribute declarations can have a use attribute, which indicates whether an attribute is required or optional.

The name specified in a local attribute declaration must also be an XML non-colonized name. If its form is qualified, it takes on the target namespace of the schema document. If it is unqualified, it is considered to be in no namespace. See Section 7.4 on p. 122 for more information on qualified versus unqualified attribute names.

Locally declared attribute names are scoped to the complex type in which they are declared. It is illegal to have two attributes with the same qualified name in the same complex type definition. This is explained further in Section 12.6 on p. 281.

7.2.3. Design hint: Should I use global or local attribute declarations?

Global attribute declarations are discouraged unless the attribute is used in a variety of element declarations which are in a variety of namespaces. This is because globally declared attribute names must be prefixed in instances, resulting in an instance element that looks like this:

<prod:size prod:system="US-DRESS" prod:dim="1"/>

Prefixing every attribute is not what users generally expect, and it adds a lot of extra text without any additional meaning.

Two examples of global attributes are the xml:lang attribute that is part of XML and the xsi:type attribute that is part of XML Schema. Virtually any element in any namespace may have these two attributes, so in this case it is desirable to distinguish them by their namespace.

If you are tempted to use a global attribute declaration because you want to be able to reuse it multiple times, consider these two alternatives:

• Put it into an attribute group. This makes it, effectively, a local attribute declaration, while still allowing you to reuse it.

• Define a named simple type that can be reused by multiple local attribute declarations.

7.3. Declaring the types of attributes

Regardless of whether they are local or global, all attribute declarations associate an attribute name with a simple type. All attributes have simple types rather than complex types, which makes sense since they cannot themselves have child elements or attributes. There are three ways to assign a simple type to an attribute.

1. Reference a named simple type by specifying the type attribute in the attribute declaration. This may be either a built-in type or a user-derived type.

2. Define an anonymous type by specifying a simpleType child.

3. Use no particular type, by specifying neither a type attribute nor a simpleType child. In this case, the actual type is anySimpleType, which may have any value, as long as it is well-formed XML.

Example 7–3 shows four attribute declarations with different type assignment methods.

Example 7–3. Declaring the types of attributes


<xs:attribute name="color" type="ColorType"/>

<xs:attribute name="dim" type="xs:integer"/>

<xs:attribute name="system">
  <xs:simpleType>
    <xs:restriction base="xs:string">
      <xs:enumeration value="US-DRESS"/>
      <!--...-->
    </xs:restriction>
  </xs:simpleType>
</xs:attribute>

<xs:attribute name="anything"/>


The first example uses the type attribute to assign ColorType to the attribute color. The second example also uses the type attribute, this time to assign the built-in type integer to the attribute dim. The xs prefix is used because the built-in types are part of the XML Schema Namespace. For a complete explanation of the use of prefixes in schema documents, see Section 3.3.5 on p. 52.

The third example uses an inline anonymous simple type, which is defined entirely within the system attribute declaration. Finally, the fourth attribute, anything, does not specify a particular type, which means that any value is valid.

For a detailed discussion of using named or anonymous types, see Section 8.2.3 on p. 133.

7.4. Qualified vs. unqualified forms

XML Schema allows you to exert some control over using namespacequalified or unqualified attribute names in the instance. Since default namespace declarations do not apply to attributes, this is essentially a question of whether you want the attribute names to be prefixed or unprefixed.

This is indicated by the form attribute, which may be set to qualified or unqualified. If the form attribute is not present in a local attribute declaration, the value defaults to the value of the attributeFormDefault attribute of the schema element. If neither attribute is present, the default is unqualified. The form and attributeFormDefault attributes only apply to locally declared attributes. If an attribute is declared globally (at the top level of the schema document), it must always have a qualified (prefixed) name in the instance.

Example 7–4 shows a schema that declares several attributes, along with a valid instance. In the instance, the global attribute’s name is qualified (prefixed) because it is globally declared. The attributes unqual and qual both have a form attribute specified, and their names appear in the instance as designated. The unspec attribute’s name is unqualified (unprefixed) because that is the default when neither form nor attributeFormDefault are present.

Qualified attribute names should only be used for attributes that apply to a variety of elements in a variety of namespaces, such as xml:lang or xsi:type. For locally declared attributes, whose scope is limited to the type definition in which they appear, prefixes add extra text without any additional meaning.

The best way to handle qualification of attribute names is to ignore the form and attributeFormDefault attributes completely. Then, globally declared attributes will have qualified names, and locally declared attributes will have unqualified names, which makes sense. Section 21.7.3 on p. 575 provides a more complete coverage of the pros and cons of unqualified local names for both elements and attributes.

Example 7–4. Qualified and unqualified attribute names


Schema:

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           xmlns="http://datypic.com/prod"
           targetNamespace="http://datypic.com/prod">
  <xs:attribute name="global" type="xs:string"/>
  <xs:element name="size" type="SizeType"/>
  <xs:complexType name="SizeType">
    <xs:attribute ref="global"/>
    <xs:attribute name="unqual" form="unqualified"/>
    <xs:attribute name="qual" form="qualified"/>
    <xs:attribute name="unspec"/>
  </xs:complexType>
</xs:schema>

Valid instance:

<prod:size xmlns:prod="http://datypic.com/prod"
           prod:global="x" unqual="x" prod:qual="x" unspec="x"/>


7.5. Default and fixed values

Default and fixed values are used to augment an instance by adding attributes when they are not present. If an attribute is absent, and a default or fixed value is specified in its declaration, the schema processor will insert the attribute and give it the default or fixed value.

Default and fixed values are specified by the default and fixed attributes, respectively. Only one of the two attributes (default or fixed) may appear; they are mutually exclusive. If an attribute has a default value specified, it cannot be a required attribute. This makes sense, because if the attribute is required, it will always appear in instances, and the default value will never be used.

The default or fixed value must be valid for the type of that attribute. For example, it is not legal to specify a default value of xyz if the type of the attribute is integer.

7.5.1. Default values

A default value is filled in if the attribute is absent from the element. If the attribute appears, with any value, it is left alone. Example 7–5 shows the declaration of size with one attribute, dim, that has a default value specified.

Example 7–5. Declaring a default value for an attribute


<xs:element name="size">
  <xs:complexType>
    <xs:attribute name="dim" type="xs:integer" default="1"/>
  </xs:complexType>
</xs:element>


Table 7–3 describes how attribute default values are inserted in different situations, based on the declaration in Example 7–5. Note that the only time the default value is inserted is when the attribute is absent. If the attribute’s value is the empty string, it is left as is. In that case, if an empty string is not valid for that type, which it is not for integer, an error is raised. This is different from the behavior of default values for elements, described in Section 6.4.1 on p. 102.

Table 7–3. Default value behavior for attributes

Image

7.5.2. Fixed values

Fixed values are inserted in all the same situations as default values. The only difference is that if the attribute appears, its value must be equal to the fixed value. When the schema processor determines whether the value of the attribute is in fact equal to the fixed value, it takes into account the attribute’s type.

Table 7–4 shows some valid and invalid instances for attributes declared with fixed values. The dim attribute has the type integer, so all forms of the integer “1” are accepted in the instance, including “01”, “+1”, and “ 1 ” surrounded by whitespace. The whitespace is acceptable because the whiteSpace facet value for integer is collapse, meaning that leading and trailing whitespace is stripped before validation takes place.

Table 7–4. Attributes with fixed values

Image

The system attribute, on the other hand, has the type string. The string “01” is invalid because it is not considered equal to the string “1”. The string “ 1 ” is also invalid because the whiteSpace facet value for string is preserve, meaning that the leading and trailing spaces are kept. For more information on type equality, please see Section 11.7 on p. 253.

image

7.6. Inherited attributes

In version 1.1, it is possible to declare an attribute to be inheritable. Conceptually, this means that it is relevant not just to the element on which it appears, but to the descendant elements as well. A good example is a language attribute which could be declared as an allowed attribute of a chapter element, but could be overridden in a descendant p element, as shown in Example 7–6.

Example 7–6. Instance containing an inherited attribute


<chapter language="en">
  <p>This is not a pipe.</p>
  <p language="fr">Ceci n'est pas une pipe.</p>
</chapter>


The implication is that the language of the chapter is English (en), and all descendant elements have that language unless otherwise specified with another language attribute. In this case, the first paragraph doesn’t have a language attribute, so it inherits the value en from the chapter. The second paragraph does not inherit the value, because it overrides it by saying its language is French (fr).

Example 7–7 is a schema for the example. The language attribute declaration uses inheritable="true" to indicate that language attributes are inheritable from chapters down to their descendants.

Note that using an inheritable language attribute declaration in ChapterType does not mean that the attribute can be automatically valid on all descendants of a chapter. In fact, this example requires a separate language attribute declaration within ParaType.1

Example 7–7. Declaring an inheritable attribute


<xs:element name="chapter" type="ChapterType"/>
<xs:complexType name="ChapterType">
  <xs:sequence>
    <xs:element name="p" type="ParaType" maxOccurs="unbounded"/>
  </xs:sequence>
  <xs:attribute name="language" type="xs:language"
                inheritable="true"/>
</xs:complexType>
<xs:complexType name="ParaType">
  <xs:simpleContent>
    <xs:extension base="xs:string">
      <xs:attribute name="language" type="xs:language"/>
    </xs:extension>
  </xs:simpleContent>
</xs:complexType>


A practical implication of declaring an attribute inheritable is that inherited attributes can be used in the type alternatives that are defined for the descendant elements. This is described further in Section 14.2.6 on p. 382.

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

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