XML namespaces

XML namespaces provide a way to create globally unique names to distinguish between elements and attributes with the same name but of different terminologies. For example, in an XML invoice document for a bookstore, the name "date" could be used by accounting for the date of the order and by order fulfillment for the date of publication.

An XML namespace is identified by a Uniform Resource Identifier (URI), a short string that uniquely identifies resources on the Web. The elements and attributes in each namespace can be uniquely identified by prefixing the element or attribute name (the local name) with the URI of the namespace.

Associating a prefix with a namespace

You declare an XML namespace using xmlns as part of a namespace declaration attribute. With the namespace declaration attribute, you can associate a prefix with the namespace.

For example, the following namespace declaration attribute declares the http://www.pre.com namespace and associates the prefix pre with this namespace:

xmlns:pre="http://www.pre.com"

Default XML namespace

If an XML namespace declaration does not specify a prefix, the namespace becomes a default XML namespace. For example, the following element, digicom, declares the namespace http://www.digital_software.com:

<digicom xmlns="http://www.digital_software.com" />

The namespace http://www.digital_software.com is the in-scope default namespace for the element digicom and any child elements that digicom might contain. The child elements of digicom will automatically be in this namespace.

The NONAMESPACE declaration

The following namespace declaration is known as the NONAMESPACE declaration:

xmlns=""

The containing element and its child elements are declared to be in no namespace. An element that is in the NONAMESPACE namespace has its namespace prefix and URI set to empty strings.

Initial state

When a PBDOM_ELEMENT or a PBDOM_ATTRIBUTE is first created, it has no name, and the namespace information is by default set to the NONAMESPACE namespace (that is, its namespace prefix and URI are both empty strings). The SetName method is used to set the local name and the SetNamespace method is used to set the namespace prefix and URI.

The name is required

The name is a required property of a PBDOM_ELEMENT and PBDOM_ATTRIBUTE, but the namespace information is not.

Retrieving from a parsed document

If a PBDOM_ELEMENT or PBDOM_ATTRIBUTE is retrieved programmatically from a parsed document, then its name and namespace information are inherited from the Element or Attribute contained in the parsed document. However, even after parsing, the name and namespace information of the PBDOM_ELEMENT and PBDOM_ATTRIBUTE can be further modified with the SetName and SetNamespace methods.

The name and namespace information are stored separately internally. Changing the name of a PBDOM_ELEMENT or PBDOM_ATTRIBUTE does not affect its namespace information, and changing its namespace information has no effect on its name.

Setting the name and namespace of a PBDOM_ATTRIBUTE

The W3C "Namespaces in XML" specification (in section 5.3) places restrictions on setting the name and namespace of a PBDOM_ATTRIBUTE. No tag can contain two attributes with identical names, or with qualified names that have the same local name and have prefixes that are bound to identical namespace names.

The specification provides the following examples of illegal and legal attributes:

<!-- http://www.w3.org is bound to n1 and n2 -->
<x xmlns:n1="http://www.w3.org" 
   xmlns:n2="http://www.w3.org" >
   <bad a="1"  a="2" />
   <bad n1:a="1"  n2:a="2" />
</x> 
<!-- http://www.w3.org is bound to n1 and is the default -->
<x xmlns:n1="http://www.w3.org" 
   xmlns="http://www.w3.org" >
   <good a="1"  b="2" />
   <good a="1"  n1:a="2" />
</x> 

In the first example, <bad a="1" a="2" /> violates the rule that no tag can contain two attributes with identical names. In the second tag, the attributes have the same local name but different prefixes, so that their names are different. However, their prefixes point to the same namespace URI, http://www.w3.org, so it is illegal to place them inside the same owner element.

PBDOM scenarios

The following scenarios illustrate how PBDOM conforms to these requirements.

  • When the PBDOM_ATTRIBUTE SetName method is invoked:

    If the PBDOM_ATTRIBUTE pbdom_attr1 has an owner PBDOM_ELEMENT that contains an existing PBDOM_ATTRIBUTE with the same name that is to be set for pbdom_attr1 and has the same namespace URI as pbdom_attr1, the EXCEPTION_INVALID_NAME exception is thrown.

  • When the PBDOM_ATTRIBUTE SetNamespace method is invoked:

    If the PBDOM_ATTRIBUTE pbdom_attr1 has an owner PBDOM_ELEMENT that contains an existing PBDOM_ATTRIBUTE with the same name as pbdom_attr1 and the same namespace URI that is to be set for pbdom_attr1, the EXCEPTION_INVALID_NAME exception is thrown.

  • When the PBDOM_ELEMENT SetAttribute(pbdom_attribute pbdom_attribute_ref) method is invoked:

    If the PBDOM_ELEMENT already contains an attribute that has the same name and namespace URI as the input PBDOM_ATTRIBUTE, the existing attribute is replaced by the input PBDOM_ATTRIBUTE. The existing attribute is thus removed (detached) from the owner element.

  • When the PBDOM_ELEMENT SetAttributes(pbdom_attribute pbdom_attribute_array[]) method is invoked:

    If any two PBDOM_ATTRIBUTE objects in the array have the same name and namespace URI, the EXCEPTION_INVALID_NAME exception is thrown. If there is no name or namespace conflict within the array, all the existing attributes of the PBDOM_ELEMENT are replaced by the PBDOM_ATTRIBUTE objects in the array.

    Note

    All the above scenarios apply to PBDOM_ATTRIBUTE objects that are contained in the NONAMESPACE namespace.

  • When the PBDOM_ELEMENT SetAttribute(string strName, string strValue) method is invoked:

    A new PBDOM_ATTRIBUTE with the specified name and value is created and set into the PBDOM_ELEMENT. If the PBDOM_ELEMENT already contains an attribute that has the same name and that is contained within the NONAMESPACE namespace, it is removed (detached) from the PBDOM_ELEMENT.

  • When the PBDOM_ELEMENT SetAttribute(string strName, string strValue, string strNamespacePrefix, string strNamespaceUri, boolean bVerifyNamespace) method is invoked:

    A new PBDOM_ATTRIBUTE with the specified name, value, and namespace information is created and set into the PBDOM_ELEMENT. If the PBDOM_ELEMENT already contains a PBDOM_ATTRIBUTE that has the same name and namespace URI as the input namespace URI, it is removed (detached) from the PBDOM_ELEMENT.

Example

The following example demonstrates the impact of setting a PBDOM_ATTRIBUTE for a PBDOM_ELEMENT where the PBDOM_ELEMENT already contains an attribute of the same name and namespace URI as the input PBDOM_ATTRIBUTE.

The example creates a PBDOM_DOCUMENT based on the following document:

<root xmlns:pre1="http://www.pre.com" xmlns:pre2="http://www.pre.com">
   <child1 pre1:a="123"/>
</root>

Then it creates a PBDOM_ATTRIBUTE object and set its name to a and its prefix and URI to pre2 and http://www.pre.com. The bVerifyNamespace argument is set to FALSE because this PBDOM_ATTRIBUTE has not been assigned an owner PBDOM_ELEMENT yet, so that the verification for a predeclared namespace would fail. The text value is set to 456.

The child1 element already contains an attribute named a that belongs to the namespace http://www.pre.com, as indicated by the prefix pre1. The new PBDOM_ATTRIBUTE uses the prefix pre2, but it represents the same namespace URI, so setting the new PBDOM_ATTRIBUTE to child1 successfully replaces the existing pre1:a with the new PBDOM_ATTRIBUTE pre2:a.

PBDOM_BUILDER pbdom_buildr
PBDOM_DOCUMENT pbdom_doc
PBDOM_ATTRIBUTE pbdom_attr

string strXML = "<root xmlns:pre1=~"http://www.pre.com~" xmlns:pre2=~"http://www.pre.com~"><child1 pre1:a=~"123~"/></root>"



try

  pbdom_buildr = Create PBDOM_BUILDER
  pbdom_doc = pbdom_buildr.BuildFromString (strXML)
  
  // Create a PBDOM_ATTRIBUTE and set its properties
  pbdom_attr = Create PBDOM_ATTRIBUTE
  pbdom_attr.SetName ("a")
  pbdom_attr.SetNamespace ("pre2", &
     "http://www.pre.com", false)
  pbdom_attr.SetText("456")
  
  // Attempt to obtain the child1 element and 
  // set the new attribute to it
  pbdom_doc.GetRootElement(). &
    GetChildElement("child1").SetAttribute(pbdom_attr)
  
  pbdom_doc.SaveDocument &
     ("pbdom_elem_set_attribute_1.xml")

catch (PBDOM_EXCEPTION except)
  MessageBox ("PBDOM_EXCEPTION", except.GetMessage())
end try

The XML output from SaveDocument looks like the following:

<root xmlns:pre1="http://www.pre.com" xmlns:pre2="http://www.pre.com">
   <child1 pre2:a="456"/>
</root>