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:
- Read the "name" attribute value of the port element.
- Fetch a list of all siblings of the definitions element.
- 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
|
- Other namespaces ?
2003-11-23 11:02:02 Christian Bilham - Other namespaces ?
2003-11-23 11:01:15 Christian Bilham