April 5, 2011, 5:57 p.m.
posted by maxidax
An XML namespace provides a qualified name for an XML element or attribute, the same way that a Java package provides a qualified name for a Java class. In most Java programs, classes are imported from other packages (java.io, javax.xml, and the rest). When the Java program is compiled, every operation performed on every object or class is validated against the class definition in the appropriate package. If Java didn't have package names, the classes in the Java core libraries (I/O, AWT, JDBC, etc.) would all be lumped together with developer-defined classes. Java package names allow us to separate Java classes into distinct namespaces, which improves organization and access control, and helps us avoid name conflicts (collisions). XML namespaces are similar to Java packages, and serve the same purposes; an XML namespace provides a kind of package name for individual elements and attributes.
1 An Example of Using Namespaces
Creating XML documents based on multiple markup languages is often desirable. For example, suppose we are building a billing and inventory control system for a company called Monson-Haefel Books. We can define a standard markup language for address information, the Address Markup Language, to be used whenever an XML document needs to contain address information. An instance of Address Markup is shown in Listing 2-7.
<?xml version="1.0" encoding="UTF-8" ?> <address category="business" > <name>Amazon.com</name> <street>1516 2nd Ave</street> <city>Seattle</city> <state>WA</state> <zip>90952</zip> </address>
Address Markup is used in Address Book Markup (nested in the addresses element) defined in Listing 2-1 at the start of this chapter, but it will also be reused in about half of Monson-Haefel Books' other XML markup languages (types of XML documents): Invoice, Purchase Order, Shipping, Marketing, and others.
Address Markup has its own schema, defined using either DTD (Document Type Definition) or the W3C XML Schema Language, which dictates how its elements are organized. Every time we use address information in an XML document, it should be validated against Address Markup's schema. For example, in Listing 2-8 the address information is included in the PurchaseOrder XML document.
<?xml version="1.0" encoding="UTF-8" ?> <purchaseOrder orderDate="2003-09-22" > <accountName>Amazon.com</accountName> <accountNumber>923</accountNumber> <address> <name>AMAZON.COM</name> <street>1850 Mercer Drive</street> <city>Lexington</city> <state>KY</state> <zip>40511</zip> </address> <book> <title>J2EE Web Services</title> <quantity>300</quantity> <wholesale-price>29.99</wholesale-price> </book> <total>8997.00</total> </purchaseOrder>
If the purchase-order document has its own schema (defined by the Purchase Order Markup Language) and the address information has its own schema (defined by the Address Markup Language), how do we indicate that the address element should conform to the Address Markup Language, while the rest of the elements conform to the Purchase Order Markup Language? We use namespaces.
We can state that the address elements conform to Address Markup by declaring the namespace of Address Markup in the address element. We can do the same thing for the purchase order elements by declaring, in the purchaseOrder element, that they conform to the Purchase Order Markup. Listing 2-9 illustrates.
<?xml version="1.0" encoding="UTF-8" ?> <purchaseOrder orderDate="2003-09-22" xmlns="http://www.Monson-Haefel.com/jwsbook/PO"> <accountName>Amazon.com</accountName> <accountNumber>923</accountNumber> <address xmlns="http://www.Monson-Haefel.com/jwsbook/ADDR"> <name>AMAZON.COM</name> <street>1850 Mercer Drive</street> <city>Lexington</city> <state>KY</state> <zip>40511</zip> </address> <book> <title>J2EE Web Services</title> <quantity>300</quantity> <wholesale-price>29.99</wholesale-price> </book> <total>8997.00</total> </purchaseOrder>
The xmlns attribute declares a specific XML namespace in the form xmlns="someURI". The value of an xmlns attribute is a URI reference, which must conform to the URI specification (RFC2396) defined by the IETF (Internet Engineering Task Force). URIs (Uniform Resource Identifiers) can take many different forms; the most common is the URL (Universal Resource Locator) . For example, in Listing 2-9 the URLs for both namespaces start with http://www.Monson-Haefel.com/jwsbook, which is the namespace used for examples throughout this book—it's the namespace of our fictitious wholesaler, Monson-Haefel Books. The final part of the URL (/PO or /ADDR in the example) completes the URL to create a unique identifier for each namespace.
In Listing 2-9, standard HTTP URLs are used, which may or may not point to an actual document or resource. It's important to remember that the URI used for the XML namespace should be unique to that markup language, but it doesn't have to point to an actual resource or document.
2 Default Namespaces, Prefixes, and Qualified Names
The xmlns declarations made in Listing 2-9 defined the default namespace for the element and all its descendants. The scope of a default namespace applies only to the element and its descendants, so the xmlns used in the address element applies only to the address, name, street, city, state, and zip elements. The default xmlns declared in the purchaseOrder element applies to all the elements except the address elements, because the address element overrides the default namespace of the purchaseOrder element to define its own default namespace.
Using default XML namespaces can get tricky, especially when elements are interleaved or when a lot of markup languages are used in the same document. To simplify things, XML Namespaces defines a shorthand notation for associating elements and attributes with namespaces. You can assign an XML namespace to a prefix, then use that prefix to fully qualify each element name. The code in Listing 2-10 assigns the prefix "addr:" to the http://www.Monson-Haefel.com/jwsbook/ADDR namespace and the prefix "po:" to the http://www.Monson-Haefel.com/jwsbook/PO namespace, then uses one prefix or the other to qualify each element.
<?xml version="1.0" encoding="UTF-8" ?> <po:purchaseOrder orderDate="2003-09-22" xmlns:po="http://www.Monson-Haefel.com/jwsbook/PO" xmlns:addr="http://www.Monson-Haefel.com/jwsbook/ADDR"> <po:accountName>Amazon.com</po:accountName> <po:accountNumber>923</po:accountNumber> <addr:address> <addr:name>AMAZON.COM</addr:name> <addr:street>1850 Mercer Drive</addr:street> <addr:city>Lexington</addr:city> <addr:state>KY</addr:state> <addr:zip>40511</addr:zip> </addr:address> <po:book> <po:title>J2EE Web Services</po:title> <po:quantity>300</po:quantity> <po:wholesale-price>29.99</po:wholesale-price> </po:book> <po:total>8997.00</po:total> </po:purchaseOrder>
The elements prefixed with addr: belong to the http://www.Monson-Haefel.com/jwsbook/ADDR namespace and the elements prefixed with po: belong to the http://www.Monson-Haefel.com/jwsbook/PurchaseOrder namespace.
It's not necessary to qualify every element with a namespace prefix. You can rely on default namespaces to determine the namespaces of all elements not explicitly prefixed, as in listing 2-11.
<?xml version="1.0" encoding="UTF-8" ?> <purchaseOrder orderDate="2003-09-22" xmlns="http://www.Monson-Haefel.com/jwsbook/PO" xmlns:addr="http://www.Monson-Haefel.com/jwsbook/ADDR"> <accountName>Amazon.com</accountName> <accountNumber>923</accountNumber> <addr:address> <addr:name>AMAZON.COM</addr:name> <addr:street>1850 Mercer Drive</addr:street> <addr:city>Lexington</addr:city> <addr:state>KY</addr:state> <addr:zip>40511</addr:zip> </addr:address> <book> <title>J2EE Web Services</title> <quantity>300</quantity> <wholesale-price>29.99</wholesale-price> </book> <total>8997.00</total> </purchaseOrder>
In this example the namespace for the entire document is declared to be http://www.Monson-Haefel.com/jwsbook/PO—it's the default for all of the children of the root element, purchaseOrder. Any element that doesn't have a prefix is, by default, a member of http://www.Monson-Haefel.com/jwsbook/PO.
When a namespace prefix is applied to an element, however, it overrides the default namespace. In Listing 2-11, the "addr:" prefix is assigned to the address elements, which makes http://www.Monson-Haefel.com/jwsbook/ADDR the namespace of the address, name, street, city, state, and zip elements.
The way you use prefixes with namespaces can depend on how the document is defined by its schema. The schema may determine whether you need to prefix all the elements, or just the parent elements, and whether default namespace declarations apply to unprefixed elements. The next chapter covers XML schemas in detail.
In XML-speak, a prefix combined with an element name is called a QName, which stands for "qualified name." Conceptually, a QName like addr:address can be dereferenced to http://www.Monson-Haefel.com/jwsbook/ADDR:address—but this is not done in practice.
A QName has two parts, the XML namespace and the local name. For example, the QName of the street element declared in Listing 2-10 is composed of the http://www.Monson-Haefel.com/jwsbook/ADDR XML namespace and the street local name.
XML namespaces based on URLs tend to be universally unique, which makes it easy for parsers and software applications to distinguish between instances of different markup languages within the same document. Namespaces help avoid name collisions, where two elements from different markups share a common local name. For example, a WSDL document can use Monson-Haefel's postal address element as well as the SOAP-binding address element in the same document. Although both elements are named address, they belong to different namespaces with different QNames, so there is no name conflict. Listing 2-12 illustrates.
<?xml version="1.0" encoding="UTF-8" ?> <definitions name="Address-Update" targetNamespace="http://www.monson-haefel.org/jwsbook/Address-Update" xmlns:tns="http://www.monson-haefel.org/jwsbook/Address-Update" xmlns:addr="http://www.Monson-Haefel.com/jwsbook/ADDR" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://schemas.xmlsoap.org/wsdl/"> ... <!-- message elements describe the paramters and return values --> <message name="AddressMessage"> <part name="address" element="addr:address" /> </message> ... <!-- service tells us the Internet address of a Web service --> <service name="AddressUpdateService"> <documentation>Update a customers mailing address</documentation> <port name="AddressUpdate_Port" binding="tns:AddressUpdate_Binding"> <soap:address location="http://www.monson-haefel.org/jwsbook/BookPrice" /> </port> </service> </definitions>
XML parsers and other tools can use XML namespaces to process, sort, and search XML elements in a document according to their QNames. This allows reusable code modules to be invoked for specific namespaces. For example, you can create a custom Java tool to map an instance of Address Markup to a relational database. It will be invoked only for address elements that belong to the Address Markup namespace, http://www.Monson-Haefel.org/addr, and not for address elements of any other namespace.
XML namespaces also allow for a great versioning system. If the Address Markup changes, we can assign the new version its own namespace, such as http://www.Monson-Haefel.org/ADDR-2, so it can be distinguished from its predecessor. We can support both the old and new versions of the Address Markup Language simultaneously, because the parser can uniquely identify each version by its namespace. Each version has its own markup for validation and perhaps its own code modules.