|
By Chris Webster and Marina Sum, Updated: October 30, 2006
|
|
|
Part 1 of this series introduces XML namespaces and their application in XML schemas. This part explains how to create aggregate schemas with import and include statements.
In XML schema language, you can use globally defined components, such as types and elements that are direct descendants of schema, from instance documents and other schema files. To use components from the latter, you usually turn to import and include statements.
NetBeans Enterprise Pack 5.5 supports schema characteristics, including import and include. Be sure to check it out!
Contents
import Statements
With import statements, you can introduce types from other namespaces. An import statement contains two attributes:
namespace, which must match the target namespace of the imported schema. This attribute is omitted for schemas without a target namespace.
schemaLocation, which points to the location of the schema artifact. Even though this attribute is optional, validation libraries, such as javax.xml.Validation, take advantage of its value.
Importing a schema without a namespace requires that the default namespace remains undefined in the scope in which the elements from that schema are in use. That's because no prefixes are allowed when you refer to those elements. Furthermore, an import statement only introduces and locates the referenced schema. In addition to the import statement, you must also create a prefix definition to reference the components from the imported schema.
An import statement clearly shows the major difference between referencing an attribute or element and using a type, as follows:
- In a reference, you effectively use the attribute or element as you would in the imported schema. Thus, the namespace for the attribute or element is the target namespace of the referenced schema.
- In a type, you reuse the content; however, the attribute or element name is in the target namespace of the defining schema.
Here is an example. First, take a look at this schema, which contains a type and an element:
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:tns="urn:base"
targetNamespace="urn:base"
elementFormDefault="qualified">
<xsd:simpleType name="baseType">
<xsd:restriction base="xsd:string">
<xsd:maxLength value="7"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:element name="baseElement" type="tns:baseType"/>
</xsd:schema>
|
This file defines two components:
- A simple type that restricts the size of the string to seven characters
- An element of the newly created type
Both the type and the element are in the namespace urn:base.
Next, build a schema that incorporates both the element and the type you just created into another namespace with the import statement, as follows:
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:tns="urn:aggregate"
targetNamespace="urn:aggregate"
xmlns:base="urn:base"
elementFormDefault="qualified">
<xsd:import namespace="urn:base" schemaLocation="base.xsd"/>
<xsd:element name="root">
<xsd:complexType>
<xsd:sequence>
<xsd:element ref="tns:elementWithTypeRef"/>
<xsd:element ref="tns:elementWithElementRef"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="elementWithTypeRef">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="aggregateElement" type="base:baseType"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="elementWithElementRef">
<xsd:complexType>
<xsd:sequence>
<xsd:element ref="base:baseElement"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>
|
Because it uses elements from another namespace, this schema requires an import statement, a prefix, and, optionally, the schemaLocation attribute. See the instance document, as follows:
<?xml version="1.0" encoding="UTF-8"?>
<agg:root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:agg="urn:aggregate"
xmlns:base="urn:base"
xsi:schemaLocation="urn:aggregate import.xsd">
<agg:elementWithTypeRef>
<agg:aggregateElement>value</agg:aggregateElement>
</agg:elementWithTypeRef>
<agg:elementWithElementRef>
<base:baseElement>v</base:baseElement>
</agg:elementWithElementRef>
</agg:root>
|
Here, at a glance—
agg:root/agg:elementWithTypeRef/agg:aggregateElement and agg:root/agg:elementWithElementRef/base:baseElement contain different namespaces even though they share the same type. You must prefix the referenced element with the base prefix, where the referenced type uses the agg prefix. Even though the types are the same, the namespace, which is determined by the location in which the elements are actually named, varies.
- Despite the two prefix definitions, only a single
xsi:schemaLocation attribute is in place. schemaLocation functions as navigation during validation.
include Statements
An include statement enables global components that are defined in other schemas to act as extensions to the including file's namespace. To support the components that you have added into the namespace, an included schema must be either in the same or no namespace.
Because you can only define schemaLocation in an include statement, the included file can adapt, if necessary, to the namespace of the including file. You can include schemas with no namespaces, called chameleon schemas, into any namespace and have those schemas adopt that namespace.
Note: include statements with incomplete schemas can cause subtle problems. An example is if the included schema references an element or type that is assumed to be declared in the referencing schema. This approach effectively enables the content model to vary according to where the schema is included.
Here is an example that's derived from that in the preceding section. As before, the following schema defines both a global simple type and a global element but not a target namespace.
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
elementFormDefault="qualified">
<xsd:simpleType name="baseType">
<xsd:restriction base="xsd:string">
<xsd:maxLength value="7"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:element name="baseElement" type="baseType"/>
</xsd:schema>
|
Consequently, the attribute and type that are defined in the base schema adopt the urn:aggregate namespace. See below.
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:tns="urn:aggregate"
targetNamespace="urn:aggregate"
elementFormDefault="qualified">
<xsd:include schemaLocation="baseinclude.xsd"/>
<xsd:element name="root">
<xsd:complexType>
<xsd:sequence>
<xsd:element ref="tns:elementWithTypeRef"/>
<xsd:element ref="tns:elementWithElementRef"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="elementWithTypeRef">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="aggregateElement" type="tns:baseType"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="elementWithElementRef">
<xsd:complexType>
<xsd:sequence>
<xsd:element ref="tns:baseElement"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>
|
Given that the aggregate file can reference included types in the same way as locally defined types, the elementWithTypeRef and elementWithElementRef elements contain both the same content model and the same namespace. See the instance document, as follows:
<?xml version="1.0" encoding="UTF-8"?>
<agg:root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:agg="urn:aggregate"
xmlns:base="urn:base"
xsi:schemaLocation="urn:aggregate include.xsd">
<agg:elementWithTypeRef>
<agg:aggregateElement>value</agg:aggregateElement>
</agg:elementWithTypeRef>
<agg:elementWithElementRef>
<agg:baseElement>v</agg:baseElement>
</agg:elementWithElementRef>
</agg:root>
|
Conclusion
With an include statement, you can assimilate schemas—even incomplete ones—of the same or no namespace into the including schema. This flexibility enables the division of a schema into multiple files. By adding import statements, you can use components from another namespace—that is, reuse them.
References
|
Chris Webster, a member of Sun's Java enterprise tools development team, focuses on the J2EE platform and is currently developing SOA tools. He's a coauthor of the NetBeans IDE Field Guide. Before joining Sun, Chris was a computer scientist at the Lawrence Livermore National Laboratory. He blogs regularly on technical topics.
|
Marina Sum is a staff writer for Sun Developer Network. She has been writing for Sun since 1989, mostly in the technical arena. Marina blogs on Sun products, technologies, events, and publications.
|
|