You say Tomato, I say My:Tomato
Updated June 20, 1999
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:
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.
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.
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".
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:
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).
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.