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

advertisement

DOM for Web Services, Part 2
by Faheem Khan | Pages: 1, 2, 3

Appending a table row to the table body

So we have created one row of our table. Let's return to our discussion on tBody.appendChild(createRow("Name of Service", serviceElement.getAttribute("name"))) method inside the getServiceTable() method. The createRow() method, as we have already explained, authors and returns a complete table row. The tBody.appendChild() method appends the table row to the table body.

Visiting a particular child of an element

Our next task is to fetch the documentation child element of the service element. For this purpose, we have used the serviceElement.childNodes property call, which returns a list of all child nodes of the service element. A for loop follows, which checks all the child nodes of the service element and finds a child node of type "element" and whose local name is documentation. When it finds such a child element, it creates a row of the service table and writes the documentation in the row.

Reading textual content of an element

Notice that in order to read the textual description of the service documentation, we have used the documentationElement.firstChild.nodeValue property.

The documentationElement.firstChild property returns the first child of the documentation element. Here we are assuming that the documentation element contains only one child node, which is of type "Text" and wraps the entire textual description of the service.

The documentationElement.firsatChild.nodeValue property returns the value of the text node. The value of a text node, by W3C DOM definition, is the actual textual content of the text node. We have simply passed the textual content to the createRow() method, which creates a row of textual description in our table.

The next step is to read the port element child of the service element. The port element contains the type of the port (type means the abstract definition of the port).

We have written a getChild() helper method in Listing 2, which takes a parent node object and the local name of a child element and returns the first matching child node object. Please have a look at the getChild() method implementation in Listing 2. We have already explained all concepts that we have used to implement this method.

The getChild() method fetches the port element child of the service element.

Visiting an element with a particular attribute value

The port element has an attribute named "name". The name attribute value matches with the name attribute value of a portType element. We want to reach the portType element whose name attribute value matches with the name attribute value of the port element. Notice from Listing 1 that portType and service elements are siblings (immediate children of the definition element). So in order to fetch the required portType element, we have to perform the following tasks:

  1. Read the "name" attribute value of the port element.
  2. Fetch a list of all siblings of the definitions element.
  3. Find a service sibling named "portType" whose name attribute value matches with the "name" attribute value of the port element (from point 1).

The portElement.getAttribute("name") method call in Listing 2 performs the first task.

The serviceElement.parentNode.childNodes line performs the second task; that is, it retrieves a list of all siblings of the service element, including the service element itself as well. Note that W3C DOM does not have any method to fetch the list of all siblings of an element directly. That's why, in order to fetch the list of siblings, we first have to fetch the parent of a node and then all children of the parent.

The for-if combination just after the serviceElement.parentNode.childNodes line in Listing 2 performs the third job. The for (var i=0; i<serviceSiblings.length;i++) loop checks each of the service siblings one by one. The if statement inside the for loop checks whether the service sibling is a portType element and whether its name attribute value matches with the name attribute value of the portType element.

So when the if statement becomes true, we are sure we have found the required portType element.

Inside the for-if block, we have simply passed the portType element to a method named attachPortTypeSetOfRows(), which performs the rest of the XML processing to author table rows corresponding to the port type. Note that we have also passed the tBody node object to the attachPortTypeSetOfRows() method, so that the method authors the table rows and attaches the rows to the same table body that contains some of the rows that have already authored.

The portType element in Listing 1 contains two operation child elements. The portType element may contain any number of operation child elements. Each operation element is actually a web service method. Therefore, we need to generate presentation logic (i.e., HTML code) for each of the operation elements.

The attachPortTypeSetOfRows() method contains a loop, which reads each of the operation child elements of the portType element and passes the operation element to a method named getOperationSetOfRows(), which will author the table rows corresponding to a single operation element.

Inside the attachOperationSetOfRows() method, we first create a row corresponding to the name attribute value of the operation element. The name attribute value is actually the name of the operation.

We then read documentation child of the operation element and create a row corresponding to the documentation (textual description) of the operation.

After that, we try to fetch an input child element of the operation element. There can be at a maximum of one input child element of the operation element. If there is an input element, we read its message attribute value and store the attribute value in a variable named inputMessage.

The message attribute value matches with the name attribute value of a message element. Notice from the WSDL file of Listing 1 that all message elements are direct children of the root definitions element. Therefore, in order to fetch the required message element, we first move to the root definitions element (OperationElement.parentNode.parentNode) and then fetch all the children of the definitions element (OperationElement.parentNode.parentNode.childNodes). Once we have all the children of the definitions element, we check them one by one, by using a for-if combination, to see if it is the required message element whose name attribute value matches with the name attribute value of the input element.

When we reach inside the for-if block, we are sure we have found the required message element, so we simply pass the message element to a method named attachMessageRows(). The attachMessageRows() method authors all the table rows associated with a message.

Authoring a data entry form

Now inside the attachMessageRows() method, we again do some table authoring. First we create a new form element and set its action and method attributes.

<form action=" http://localhost/DOM4WS/SoapRequestGenerator" method="GET" />

We then fetch a list of all child nodes of the message element. Then inside a for loop, we pass all part child nodes one by one to a method named attachPartRow(). The attachPartRow() method authors a table row corresponding to a single part of the message element.

When the for loop finishes, we know we have authored all the message rows corresponding to all part elements. For each part element, the attachPartRow() method authors a single row with two cells. The first cell contains the "name" attribute of the part and the second cell contains a text entry input box for the user to enter data related to the part element. We have already explained the HTML authoring process; you create an HTML element using document.createElemet() method, set its attributes (if any) and then append the newly created HTML element to its parent node. The attachPartRow() method appends the a table row to the form element that we created in the last step. The form element now looks like this:


<form action=" http://localhost/DOM4WS/SoapRequestGenerator" method="GET">
    <tr>
        <td>EnterCityName</td>
        <td><input type="text" /></td>
    </tr>
    <!--Other possible rows, one for each part of the message-->
</form>

After calling the attachPartRow() method for each part element, the attachMessageRows() method authors an HTML Submit Query button. The user will press this button after entering data in the text entry boxes for each part of the message and the user input will be passed to the HTML file mentioned in action attribute value of the form element. Now the complete HTML form representing a single WSDL operation will look like this:


<form action=" http://localhost/DOM4WS/SoapRequestGenerator" method="GET">
    <tr>
        <td>EnterCityName</td>
        <td><input type="text" /></td>
    </tr>
    <!--Other possible rows, one for each part of the message-->
    <tr>
        <td></td>
        <td><input type="submit" value="Submit Query" /></td>
    </tr>
</form>

A web service may contain more then one operation elements. The attachMessageRows() and attachPartRow() methods work together to author an HTML form for each operation. We then embed the completed form element inside the table body.

MSXML with ASP.NET

Listing 5 demonstrates the use of MSXML inside an ASP.NET page. You will need to place Listing 5 as a WebForm1.aspx file in an ASP.NET project virtual directory. You will also have to add a COM reference to MSXML4.dll file (which implements MSXML version 4) to the ASP.NET project. The .NET Visual Studio provides a graphical environment for adding COM references to your ASP.NET projects. We have provided a link to an article in the resources section that describes how to add COM references in ASP.NET projects.

ASP.NET code of Listing 5 is almost the same as the "JavaScript" code of Listing 2 except a few minor differences as noted below:

Listing 5 is server side code, while Listing 2 is client side code. Therefore, you will notice syntax-related differences between Listing 2 and Listing 5. On server side we can't use the browser's document object, so we have used a separate XML DOM document object for HTML authoring. Therefore, you will find two DOM document objects (named htmlDoc and xmlDoc) in Listing 5. The htmlDoc object is for HTML authoring, while xmlDoc object is for WSDL processing.

We have defined the htmlDoc object as a global object in Listing 5, so that it is accessible at all places just like the document object in client side JavaScript code (Listing 2).

Next time we will demonstrate how to use Xerces, the popular Java-based implementation of W3C DOM. We will also discuss the new features that DOM level 3 introduces.

Resources

  • If you want to try the code from this article, you may download the code.zip file. which contains all the source code and a self explanatory Readme.txt file. It also contains a few WSDL and HTML file pairs, generated using Listing 5 of this article.
  • Check out the DOM main page at W3C.
  • Download MSXML4.0 from the Microsoft site.
  • This article provides an introduction to MSXML4.0.
  • Read this Introduction to Web services and WSDL.
  • This article explains how to provide COM references to ASP.NET projects.
  • This book explains XML application development using MSXML4.0.


1 to 2 of 2
  1. Other namespaces ?
    2003-11-23 11:02:02 Christian Bilham
  2. Other namespaces ?
    2003-11-23 11:01:15 Christian Bilham
1 to 2 of 2