This article may contain URLs that were valid when originally published, but now link to sites or pages that no longer exist. To maintain the flow of the article, we've left these URLs in the text, but disabled the links.
Drag and Drop Data Manipulation Powered by XML |
|||||||||||||||||||||||||||
Scott Howlett and Jeff Dunmall | |||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||
n a previous article, "VML Provides XML-based Graphics for the Web," in the January 2000 issue of Microsoft Internet Developer (see https://www.microsoft.com/mind/0100/vml/vml.asp), we introduced a design pattern that presented an alternative to traditional three-tier Internet development. We showed the advantages of simplifying data models by storing data directly as XML and described how to push XML datasets to client machines for presentation processing.
In this article we're going to add three more features to the sample application and show you some interesting technology along the way. First, we're going to add functionality so you can query the org chart with requests like, "Show me all the people with degrees at Widget Corp." In the process, we'll show you how to apply XSL pattern matching in your applications.
As we mentioned earlier, one of the main advantages of using XML is that you can get the source data to the client in its native format. This is very difficult to do if the source data is stored in a relational database. But if you use XML, you can manipulate and present the data, and eventually send it back to the server in its native format. XSL Pattern MatchingXSL pattern matching allows developers to query and filter XML documents programmatically. Not surprisingly, pattern matching is a part of a more complete specification called XML Query Language (XQL). Here, we'll only cover the pattern matching portion of XQL. More information about XQL can be found at https://www.w3.org/TandS/QL/QL98/pp/xql.html. Internet Explorer 5.0 is currently the only browser that supports XSL and pattern matching. First and foremost, pattern matching is declarative, meaning each pattern describes the types of nodes to return from the source XML document. If you read our previous article, you've already seen some simple pattern matching. To apply a conditional test to put a shadow on different nodes in the org chart, you would use syntax like this:
In this case, use the <xsl:when> element to determine if there were subordinates for this person element. The declarative statement test="PEOPLE/PERSON" returns true whenever one or more nodes are returned as the result of the pattern execution.
As you can see, XSL pattern matching gives Web developers a pretty good mechanism for filtering and searching an XML document on the client. Let's add this powerful searching mechanism to the sample app. The first thing to do is build a user interface where the user can specify search parameters. We added a couple of simple HTML form fields, as shown in Figure 4.
There are three checkboxes: Certifications, Degrees, and Publications. If a checkbox is checked, the search will only return values for people with the appropriate qualification (that is, if the Degree checkbox is checked, only people with degrees will be highlighted). Below each checkbox is an edit box where the user can enter exact search criteria. There is also a Direct option where the user can enter a custom XSL pattern.
Calling XMLDOM.getElementsByTagName("*") returns all the elements in the document. Next, we iterated through the collection, adding an ID attribute to each XML element. We set the ID equal to a number that was incremented after each element, thereby guaranteeing unique values. Dynamically indexing the source XML and assigning unique ID attributes proved critical to the application's success.
To add the ID to the DHTML <SPAN>, we modified the XSL document slightly. We added some code to the <v:textbox> element definition inside the person template. The specified code is shown in blue:
The previous code is an excerpt from orgchart.xsl, which can be accessed by downloading the sample code from the link at the top of this article.
Notice that we append "/@ID" to the pattern. This selects all the ID attributes from the nodes that match the pattern. That way we can access the ID of the node using objCol(i).text which, when input into document.all, will return the DHTML element we want. In effect, we've linked XML elements to DHTML elements. Very handy! Modifying XML on the ClientSo now we have a full-featured app, but one that relies on XML that is generated and maintained by someone else on the server. As we've been saying, using the XML/XSL design approach has a great advantage because it lets you modify the native XML on the clientâ€"the same XML that is stored on the server. Now we're going to add drag and drop support to this app. We're not going to use any Java-language applets or ActiveX® controlsâ€"just straight DHTML. In the end, we'll be able to drag a person from one parent node to another. In our example, we'll move John Smith from reporting to Bill Onliane and have him report to Jane Financeâ€"all with a simple drag of the mouse. Using the dataTransfer property of the event object, it is easy to implement drag and drop operations in Internet Explorer 5.0. The operation is performed in three programmatic steps.
Key to this implementation is the ID attribute that links a DHTML <DIV> to the corresponding XML <PERSON> element. The drag and drop operation is reduced to making the person with an ID of 96 a subordinate of the person with an ID of 34. Most of this work is done in the MovePerson method, which is shown in Figure 6. The MovePerson code is fairly straightforward. We found the source and destination nodes using XSL pattern matching. Next, we removed the source node and added it to the destination node using the AddPersonToPeople method (see Figure 7). Finally, we reloaded the screen by reapplying the XSL stylesheets. Remember, reloading the screen in this case does not require a round-trip to the server. The AddPersonToPeople method first tries to add the node to the <PEOPLE> collection of the destination node. If this fails, it is because the <PEOPLE> element doesn't exist. In the catch block, we create the <PEOPLE> collection and then add the <PERSON> node to it. There are some other things to note in the overall drag and drop operation. First, we handled the ondragenter and ondragover events to cancel the action that Internet Explorer 5.0 will perform by default. To cancel the default action we called:
This also keeps the cursor showing a move icon until the item is dropped. The previous handlers were also added to the orgchart.xsl stylesheet.
Another gotcha is that for some reason, the drag and drop operation does not work with <SPAN> elements. In our January 2000 MIND article, we used a <SPAN> to hold the name and title of each person. However, the <SPAN> would not participate in the drag and drop operation at all. Changing the <SPAN> to a <DIV> did not affect the visual layout of the org chart and supported the drag and drop operation. Add, Edit, and DeleteUntil now, we've been searching and manipulating the same XML source document. We can see a graphical representation of the people in an organization, do searches to find people with a particular skill set, and drag people around to reflect recent reorganizations in the company. However, we still cannot add, edit, or delete a person. Figure 8 shows the result of the new edit XSL stylesheet that provides this functionality. Each person has an Add and Delete option. Clicking on the Add link next to Tom Tech should add a new subordinate for Tom to the org chart. Figure 8 also shows the editing capabilities. To change a person's title, simply click on their name to display the edit boxes and type in their new title.
To edit, add, or remove a person, we need to update the source XML. To provide this functionality, we're going to take advantage of the ID attributes that were added to the source XML document when it was first retrieved from the server and combine it with a little more pattern matching.
returns all name and title elements for each person, eliminating the <DEGREE>, <PUBLICATION>, and <CERTIFICATION> elements that were added earlier. To add more elements to edit, simply modify the match expression and change the apply-templates element to change the select attribute. Give it a try!
This takes the current value of the edit box (NAME96.value) and assigns it to the element with an ID of 96 in the XML document. If we had tried to use the name as the unique key for each person, we would have run into trouble changing the name more than once. For example, if we had changed Bill's name to Fred, the XML document would be updated, but the pattern match expression would still be looking for Bill. The IDs solve this problem.
If a person doesn't already exist with the same name, we make a copy of the source node using the CloneNode method. Cloning a person node saves some grief because we don't have to explicitly create all the attributes and children elements of a person (such as title and name). This gives us the flexibility to add additional <PROPERTY> elements for each person in the future, and any additional properties would automatically get copied when the node was cloned. Then the code removes the <PEOPLE> element, if there is one. This ensures we are only copying the parent person, not its subordinates. After erasing the contents of the clone, we call AddPersonToPeople, the same method the drag and drop functionality uses to make it part of the XML document.
Back to the ServerFinally, a quick word about the Save button you saw in Figure 8. Now that we can edit, add, delete, and move to our heart's content, we need a way to save the information back to the server. For the purposes of this demo, we're storing the XML on the server as a file. Note that a more robust version would store the XML as a string in a database. First, we need to remove ID attributes that we added earlier. Calling removeIndexXML does just that. With the XML cleaned up, we can submit it back to an ASP page that saves the XML back to a file. To do this, we use the XMLHTTP object. Quite simply, SaveXML opens a connection to the server, strips the ID attributes, and then sends the XML document. If there is no response from the server, everything worked correctly. SaveXML and removeIndexXML are shown in Figure 11. The ASP page is just as straightforward. It loads the resulting XML from the request object, and saves it to the server as info.xml in a subdirectory specified by the company name.
ConclusionThe proper use of XML, XSL, and VML results in high performance, scalable Internet applications. More importantly, solutions that move processing to client machines will be more scalable than solutions that don't. Additional benefits of using this design approach include the reduction of data transformation layers and a code base that is much smaller than typical server-based solutions. A year ago, building a graphical organization chart for a browser would have been next to impossible. Today, you can do it easily and, at the same time, take advantage of the processing power on client machines. |
|||||||||||||||||||||||||||
For related articles see: https://www.microsoft.com/mind/0100/vml/vml.asp https://msdn.microsoft.com/xml/default.asp https://msdn.microsoft.com/theshow/default.asp Background information: https://msdn.microsoft.com/standards/vml/default.asp Also check XML in Action, William J. Pardi (Microsoft Press). Jeff Dunmall and Scott Howlett are the cofounders of iMason.com, an Internet consulting company specializing in legacy integration for companies building business-to-business and line-of-business applications. Reach them via e-mail at jeff@iMason.com and scott@iMason.com. |
From the March 2000 issue of MSDN Magazine.