You say Tomato, I say My:Tomato

 

Charles Heinemann
Microsoft Corporation

Updated June 20, 1999

Download Xml.exe.

Contents

Declaring Namespaces Within the XML Document Accessing Namespace Information Through the XML Object Model Creating Namespace Qualified Nodes Conclusion

As you probably know by now, the whole concept behind XML is to enable you to mark up your data semantically. This means that you can have tags, such as <purchase_order>, that describe the data within the tags. This works fine on a local scale (if the application scope is limited), but XML is made for a more global arena: the Web. In the vastness of the Web, <purchase_order> loses its specific meaning, since there are probably innumerable XML documents with <purchase_order> tags. These <purchase_order> tags can then refer to content that may be completely different in terms of logical and physical structure.

The solution to such problems is the use of namespaces. By declaring tags to be of a specific namespace, the creator of the data can explicitly describe his tags, differentiating them from other tags of the same base name. For instance, with namespaces, we can differentiate between a "purchase_order" element from Joe's Soda Supply and one from Mary's Canned Hams:

<joes:purchase_order/>
<marys:purchase_order/>

In this article, I will describe how to declare namespaces and how to utilize the namespace support provided within the MSXML parser. In addition, I'll throw in a little Visual BasicĀ® code that uses the MSXML parser to fill an MSFlexGrid with an XML document's namespace information.

Declaring Namespaces Within the XML Document

The following XML document contains information about the inventory of an online camera retailer. The cameras that are available on the site are of two types (photo and digital) and, as a result, are described differently. It seems reasonable that both types of cameras can be described as a "camera." However, if we do so, we need a method of discerning one from the other:

<cameras xmlns:dig="x-schema:digSchema.xml"
         xmlns:photo="x-schema:photoSchema.xml">
  <dig:camera prodID="P663" name="Click-N-Go Camera"
     pixels="410000" output_res="640 x 480" int_mem="2 MB"
     price="300.99"/>
  <photo:camera productID="K29B3" name="Super-photo 35 mm Camera"
     lens="35mm" zoom="70mm" warranty="1 yr" price="99.00"/>
</cameras>

In the above XML code, the information about digital cameras is of the "dig" namespace and information about photo cameras is of the "photo" namespace. This allows us to validate and process the information about the two types of camera according to their specific type, making the data more flexible and precise.

It is important to note that although the prefixes ("dig" and "photo") appear only on the element name, the attributes on that element are scoped to that element's namespace. This means that all the attributes on the dig:camera element, for instance, are also of the "dig" namespace.

Accessing Namespace Information Through the XML Object Model

In order to analyze an XML document in terms of namespaces, I built a little Visual Basic executable that loads an XML document and fills an MSFlexGrid control with information about the namespaces declared within that XML document.

Before any XML is loaded, the MSFlexgrid control is reset. In short, the Rows property on the control is set to 1 (to clear out all existing rows) and the headings for the columns are set:

Function resetGrid()
  Form1.MSFlexGrid1.Cols = 5
  Form1.MSFlexGrid1.Rows = 1
  Form1.MSFlexGrid1.ColWidth(0) = 1000
  Form1.MSFlexGrid1.ColWidth(1) = 1000
  Form1.MSFlexGrid1.ColWidth(2) = 750
  Form1.MSFlexGrid1.ColWidth(3) = 1000
  Form1.MSFlexGrid1.ColWidth(4) = 3000
  Form1.MSFlexGrid1.Col = 0
  Form1.MSFlexGrid1.Row = 0
  Form1.MSFlexGrid1.CellFontBold = True
  Form1.MSFlexGrid1.Text = "nodeType"
  Form1.MSFlexGrid1.Col = 1
  Form1.MSFlexGrid1.Row = 0
  Form1.MSFlexGrid1.CellFontBold = True
  Form1.MSFlexGrid1.Text = "nodeName"
  Form1.MSFlexGrid1.Col = 2
  Form1.MSFlexGrid1.Row = 0
  Form1.MSFlexGrid1.CellFontBold = True
  Form1.MSFlexGrid1.Text = "prefix"
  Form1.MSFlexGrid1.Col = 3
  Form1.MSFlexGrid1.Row = 0
  Form1.MSFlexGrid1.CellFontBold = True
  Form1.MSFlexGrid1.Text = "baseName"
  Form1.MSFlexGrid1.Col = 4
  Form1.MSFlexGrid1.Row = 0
  Form1.MSFlexGrid1.CellFontBold = True
  Form1.MSFlexGrid1.Text = "namespaceURI"
End Function

With the grid reset, the user can now enter the location of the XML file into the XMLlocation text box. Once this information is entered, the following code loads the XML from that source:

Dim xmldoc1 As New MSXML.DOMDocument
Dim docRoot As IXMLDOMNode
xmldoc1.async = False
xmldoc1.Load (XMLlocation.Text)
If xmldoc1.parseError.reason <> "" Then
  MsgBox xmldoc1.parseError.reason & vbCr & xmldoc1.parseError.srcText
Else
  Set docRoot = xmldoc1.documentElement
End If

At this point, the application accesses the namespace information within the XML document. The following function is passed a node and, accessing that node's namespace information, populates a row in the grid (the "indent" variable acts to offset the attributes of an element):

Function fillGrid(curNode As IXMLDOMNode, indent As Boolean)
  Dim strType As String
  Dim strName As String
  Dim strPrefix As String
  Dim strBase As String
  Dim strNSURI As String

  Dim strIndent As String
  strIndent = "  "

  If indent = True Then
  strType = strIndent & curNode.nodeTypeString
  Else: strType = curNode.nodeTypeString
  End If
  strName = curNode.nodeName
  strPrefix = curNode.prefix
  strBase = curNode.baseName
  strNSURI = curNode.namespaceURI
  Form1.MSFlexGrid1.AddItem (strType & vbTab & strName & vbTab &
  strPrefix & vbTab & strBase & vbTab & strNSURI)
End Function

From the XML Document Object Model you can get three bits of namespace information on a node: the prefix, baseName, and namespaceURI. The nodeName of the node is the combination of the prefix and the baseName separated by a colon ("ns:foo"). The namespaceURI is the URI of the namespace. For example, if we have the following start tag

<cameras xmlns:dig="x-schema:digSchema.xml"
         xmlns:photo="x-schema:photoSchema.xml">

then all elements in the "dig" namespace would have the namespaceURI property set to "x-schema:digSchema.xml".

Creating Namespace Qualified Nodes

In addition to the above DOM properties that allow you to get at namespace information, you can also create namespace qualified nodes. The createNode method on the XML Document Object allows you to do just this, as shown in the following code:

Xmldoc.createNode("element","foo", "x-schema:fooSchema.xml")

The above code creates an element with the name of foo and of the namespace at "fooSchema.xml". There are a couple of things to watch out for when doing this, however. First, creating a namespace qualified node does not automatically give that node a prefix. Second, because the parser does not validate at run time, it is possible to add a node whose namespace conflicts with another pre-existing namespace (two foo namespaces, for instance).

Conclusion

Namespaces make the XML useful in a Web environment. They provide a method of making tag names unique and of localizing the description of sub-elements. The MSXML parser supports namespaces through the DOM by allowing you to gather namespace information and by allowing you to create namespace qualified nodes.

Namespaces are also supported through XSL, where templates can be matched using prefixes and wildcards. Check out more on the namespace support within the MSXML parser by going to the XML area on MSDN. For more introductory material on namespaces, you can also go to the namespaces area of the XML Guide.

Charlie Heinemann is a program manager for Microsoft's XML team. Coming from Texas, he knows how to think big.