XML.com: XML From the Inside Out
oreilly.comSafari Bookshelf.Conferences.

advertisement

DOM for Web Services, Part 2

November 11, 2003

Using MSXML to Generate Web Service User Interfaces

In the first article of this series, I discussed web service usage models and described XML processing requirements in web services. I also introduced W3C Document Object Model (DOM) and two of its popular implementations, MSXML and Xerces.

This second article discusses MSXML in detail. I use MSXML DOM to perform a WSDL to HTML transformation in order to generate a user interface for a web service. I will demonstrate the use of MSXML on both client and server sides. On the client side, I'll use JavaScript inside a browser and, on the server side, MSXML inside an ASP.NET page.

While explaining the WSDL to HTML transformation, I'll cover XML processing as well as HTML authoring with MSXML. This will provide an opportunity to demonstrate the following XML processing issues, as well as some DOM-HTML authoring techniques:

XML processing issues:

  1. Creating a new DOM object
  2. Loading an XML document into the DOM object
  3. Handling errors while parsing a DOM Document
  4. Finding the root element
  5. Working with the name of an element
  6. Working with namespaces
  7. Reading the local name of an element node
  8. Getting the children of an element
  9. Checking the type of a node
  10. Reading an attribute value
  11. Visiting a particular child of an element
  12. Reading textual content of an element
  13. Visiting an element with a particular attribute value

MSXML offers some proprietary, non-standard, DOM-related features. As the focus in this series of articles is mainly on standard W3C DOM I will mention some of the proprietary features of MSXML DOM in this article, but will not go into their details.

In order to try the code developed for this article, you will need MSXML version 4.0 installed on your machine. You just need to install MSXML once on your machine: your browser and .NET visual development environment will both work using the same MSXML installation.

Let's start with our WSDL to HTML transformation example.

MSXML with JavaScript

Have a look at Listing 1, which is a WSDL file. Listing 2 is an HTML file, which uses MSXML inside JavaScript code to process Listing 1 and generate its HTML-based presentation. The body element in Listing 2 simply calls the ProcessWSDLDocument() method, which generates the complete HTML structure of Listing 3. Let's see how.

The document object in a browser

W3C DOM contains a core module which defines interfaces for all the different types of XML DOM nodes (e.g. element, attribute, text, comment etc.). W3C DOM also defines an HTML module which defines HTML-specific interfaces (e.g. the HTMLDocument interface for an HTML document, the HTMLHtmlElement interface for HTML element, HTMLBodyElement interface for the body element, the HTMLTableElement interface for the table element, etc.).

The HTML module uses the functionality of the core module. All interfaces in the HTML module inherit from some interface in the core module. For example, the HTMLDocument interface in the HTML module inherits from the Document interface of the core module and the HTMLElement interface module inherits from the Element interface.

Internet Explorer browsers (IE) have their own DOM implementations, which do not accurately follow W3C DOM. You can use the browser object model to author an HTML page dynamically from JavaScript code. IE (version 3.0 and later) provides an object named "document". The document object represents the entire HTML document being displayed inside the IE window. You don't need to instantiate this object, as its instance is already available. You can directly call its methods to create elements.

Creating a new paragraph

The document object exposes many methods, some of which follow standard W3C DOM, while others are Microsoft specific. The document object exposes four very useful standard W3C methods, namely createElement(), createTextNode(), appendChild() and insertBefore().

Moreover, the HTML module in W3C DOM defines HTML attributes as standard properties for element nodes. The document object allows us to create element nodes and use their properties. When you set a property of an HTML element node, the property will appear as an attribute value in the resulting HTML code.

So let's create a new paragraph (a p element) and set text alignment property. The first line in the ProcessWSDLDocument()method in Listing 2 (var para = document.createElement("p");) creates a new p element. The second line (para.align="center";) sets its text alignment as center-aligned. This code will generate the following HTML:

<p align="center" />

We have created a new p element by calling the document.createElement() method. The newly created p tag belongs to the document object, but we have still not attached it at a particular place in the document.

The third line (document.body.appendChild(para);) appends the newly created p element into the HTML document body. Notice that you can directly fetch the body of the HTML document by referencing document.body.

The object that the document.body returns exposes the methods defined by the HTMLBodyElement interface of W3C DOM. Once we have the HTML body object, we can call its appendChild() method to append the p element to the body. We have simply attached the p element to the document body, without specifying a particular place where the p element needs to be inserted. The result is that the p element gets attached as the last existing child of the HTML body:


<html>
   <head></head>
   <script></script>  
   <body>
      <p align="center" />
   </body>
</html>

Listing 2 contains the hard coded html, head, and script elements, etc., which automatically appear in the document object. Whatever we author using the interfaces exposed by different DOM objects is added to the already available elements.

Creating a new DOM object

The next step is to load a WSDL file into an XML DOM object. For this purpose, we will need to instantiate an MSXML DOM document as an ActiveX object. The var xmlDoc = new ActiveXObject("MSXML2.DOMDocument.4.0"); line in the ProcessWSDLDocument() method creates a new MSXML DOM object named xmlDoc. The xmlDoc object exposes the IXMLDOMDocument interface of MSXML.

The IXMLDOMDocument interface is equivalent to the Document interface of standard W3C DOM. The IXMLDOMDocument interface in MSXML inherits from the IXMLDOMNode interface, which corresponds to the generic Node interface of W3C DOM. All the other W3C interfaces inherit from the DOM Node interface.

So now we have two DOM objects in the JavaScript of our Listing 2. The first is the browser document object, which represents the HTML page that we are authoring. The second is the xmlDoc XML DOM object in which we will shortly load our WSDL file.

Loading an XML document into the DOM object

The MSXML document object is now ready and we can load a WSDL file into the DOM object. We can use the xmlDoc.load(xmlFileName) method for this purpose.

The load() method is part of the IXMLDOMDocument interface in MSXML. However, note that W3C DOM Level 2 does not define any mechanism for loading an XML document into a DOM object. Therefore, implementations define their own methods of loading XML files in DOM objects.

Note that DOM level 3 defines standard methods for loading an XML file into a DOM object. MSXML does not implement DOM level 3. I will discuss DOM level 3 in the next article of this series.

The xmlDoc.async="false" property is used in conjunction with xmlDoc.load() method call. The xmlDoc.load() method can work synchronously or asynchronously. The default behavior is asynchronous. Asynchronous loading means that the load() method will return immediately without waiting for the XML-to-DOM loading process to complete. The synchronous way of loading means that the load() method will not return until the XML loading into the DOM object is complete.

We are using synchronous loading (meaning the entire document will be loaded into DOM before you can start to process the file), so we have set the async property of the xmlDoc object to "false".

If you are downloading the HTML file of Listing 2 from a web server and want to download the WSDL from the server as well, you may want to specify a complete URL instead of just the WSDL file name (e.g. xmlDoc.load("http://myServer/WSDL_Service.wsdl")).

Handling errors while parsing a DOM Document

The IXMLDOMDocument interface has a property named parseError, an object that exposes IXMLDOMParseError interface. This is an MSXML-specific interface. An IXMLDOMParseError object contains information about the errors that occurred during parsing. The property errorCode wraps an error code, which is zero if there was no error.

Finding the root element

Our WSDL file of Listing 1 is now loaded in the xmlDoc IXMLDOMDocument object. Now let's proceed with the parsing of our WSDL file. The documentElement property of the IXMLDOMDocument interface returns the root node of the XML document. So the definitionsElement = xmlDoc.documentElement line in Listing 2 stores the root node object in a variable named definitionsElement.

Working with the name of an element

Our next task is to read the name of the root node and check whether the name of the root node is "definitions".

The IXMLDOMNode interface contains a property named nodeName. The nodeName property is available in the IXMLDOMElement interface, as it inherits from the IXMLDOMNode interface.

The nodeName property, according to W3C DOM, returns the qualified name of an element. The qualified name of the element contains the complete name including the namespace prefix as well as the local name of the element.

In order to demonstrate the use of qualified names and their handling with W3C DOM, we have provided the WSDL file of Listing 4, which is the equivalent form of Listing 1, but only differs in the use of XML namespace prefixes. The local name of the root element in Listing 4 is wsdl:definitions, instead of just definitions as it was in Listing 1.

The definitionsElement.nodeName property returns the complete qualified name. So for Listing 1, the definitionsElement.nodeName will return "definitions", while for Listing 4, the same method call will return "wsdl:definitions".

That's why if we use definitionsElement.nodeName property to check the name of the root node, we will be relying on the namespace prefix in the WSDL file. We cannot be sure what prefix the author of the WSDL file will use. Therefore, it is not appropriate to use the complete qualified name for checking the name of an element. We should rather check that:

  1. The namespace URI associated with the root definitions element should be that of a WSDL file (http://schemas.xmlsoap.org/wsdl/).
  2. The local name of the root element node is "definitions".

Pages: 1, 2, 3

Next Pagearrow