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.

MIND

Drag and Drop Data Manipulation Powered by XML

Scott Howlett and Jeff Dunmall

This article assumes you're familiar with JScript and XML

Level of Difficulty    1    2    3

Code for this article: Howlett0300.exe (41KB)

SUMMARY Building on the browser-based org chart featuring VML (Vector Markup Language) described previously in Microsoft Internet Developer, this article takes you through the process of refining that sample app by using XML, XSL, and JScript code to create a new, improved version. Drag and drop editing is added to the org chart interface thanks to built-in support found in Internet Explorer 5.0. XML and JScript allow data manipulated on the screen to be saved back to the server in its native format. The final product of this combination of XML, XSL, and VML is a high performance, scalable Internet app that uses processing on the client to reduce stress for the server.

In 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.
  We developed a sample application that produced two different views of an organization chart to help illustrate the efficiencies gained by manipulating data on the client. One was a graphic view using Vector Markup Language (VML) and the other was text-based using indentation to reflect the hierarchy. When we left off, the org chart was dynamicâ?"you could click on different nodes to expand or collapse them, as shown in Figure 1.

Figure 1 The Org Chart

Figure 1 The Org Chart

  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.
  Next, we'll manipulate the source XML data on the client. This is one of the primary benefits of using this design solution. We'll explain and use the built-in support for drag and drop operations in Microsoft® Internet Explorer 5.0 to rearrange the organization. After all, wouldn't it be nice if you could drag Bill's box in the org chart and have him report directly to Jane? (Warning: don't give this application to the CEO!)
  Finally, we'll add CRUD (create, read, update, delete) functionality on the client to make this application complete. Another XSL document will present the XML, allowing the user to add, edit, and delete people from the organization.
  Figure 2 provides an overview of the application architecture. The process starts with the server sending XML and XSL to the client. The XML is processed by two main XSL stylesheets that are responsible for the two areas of the screen: the org chart and the editing area. Updates are made to the local XML document, and the process completes when the user saves the results to the server. In total, there are five lines of code on the server, making Internet Information Server (IIS) more of a file server than an application server for this project.

Figure 2 The Org Chart Architecture

  Figure 2 The Org Chart Architecture

  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.
  To do this, the client must be able to query and filter the source data. A technology called XSL pattern matching fulfills this requirement by allowing the client application to query the source XML data without a round-trip to the server. Without the formal query syntax that pattern matching provides, it would be impossible to build powerful applications that fully exploited the processing capabilities of the client, especially Internet Explorer 5.0. A more thorough discussion of this topic can be found at https://www.texcel.no/whitepapers/xql-design.html.
  To make the sample application a little more interesting, we're going to extend the XML document from our January 2000 MIND article. Specifically, we're going to allow for three new tags on the <PEOPLE> element: <CERTIFICATION>, <DEGREE>, and <PUBLICATION>. Each <PEOPLE> element can contain zero or more of each of these three new elements. We'll extend the sample application to make use of these new XML fields. The new XML source is shown in Figure 3.

XSL Pattern Matching

  XSL 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:

  <xsl:when test="PEOPLE/PERSON">
  

 

  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.
  Let's jump right in to see what XSL pattern matching can do.

  • To retrieve all the people at Widget Corp. who have at least one degree, we would use this XSL pattern:

    //PERSON[DEGREE]
    

     

  • The following pattern retrieves all the people who have at least one degree and one publication:

    //PERSON[DEGREE][PUBLICATION]
    

     

  • Here's the XSL pattern for one degree or publication and an MCSD certification:

    //PERSON[(DEGREE or PUBLICATION)][CERTIFICATION='MCSD']
    

     

  • All people who are not certified would be represented this way:

    //PERSON[not (CERTIFICATION)]
    

     

  • The following retrieves all people who have a direct subordinate who is certified with MCSD:

    //PERSON[*/PERSON/CERTIFICATION='MCSD']
    

     

  • Finally, here's the XSL for all people whose last degree was a Masters degree:

    //PERSON[DEGREE[end()]='Master']
    

     

  All of the previous patterns could eventually be used in our sample application to filter the results using the selectNodes method of the XMLDOM object. selectNodes takes a single parameterâ?"an XSL pattern. The return value is a collection of XML nodes. To learn more about pattern matching, check out https://msdn.microsoft.com/xml/reference/xsl/XSLPatternSyntax.asp.
  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.

Figure 4 Org Chart Query

  Figure 4 Org Chart Query

  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.
  When a person is matched based on the XSL pattern, their name and title appear in blue. As you can see, Mary Hillor is the only person who matches the criteria that is specified in Figure 4.
  The code that performs the search is relatively straightforward, as you'll see shortly. Although we planned to do the search using XSL pattern matching, we wanted to display the results using plain DHTML to avoid redrawing the entire org chart. So we needed a simple way to link an XML node with the appropriate DHTML element in the org chart. We accomplished this by indexing the source XML document, dynamically providing an ID to each element in the document.
  Next, the XSL document was modified slightly to append an ID attribute to each <DIV> where the name and title were displayed. Providing an ID attribute proved easier than using a unique property of the person (such as the name), especially for providing CRUD functionality, which you'll see later on.
  The following code shows how the XML was indexed.

  function indexXML(XML)
  
{
var objCol = XML.getElementsByTagName("*");
for (var i=0; i< objCol.length; i++)
{
var att = XML.createAttribute("ID");
att.value = i;
objCol(i).attributes.setNamedItem(att);
}
}

 

  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.
  Once indexed, the XSL stylesheet assigned the ID to the DHTML <SPAN> element that contains the text. This allows us to access the element using JScript code:

  document.all.item("34").style.color = "blue";
  

 

  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:

  <xsl:element name="v:textbox">
  
<xsl:attribute name="style">padding-left: 0px
</xsl:attribute>
<SPAN style="font-size: 8pt" align="left">
<xsl:attribute name="ID"><xsl:value-of select="@ID"/>
</xsl:attribute>
<b><xsl:value-of select="NAME" /></b><BR/>
(<xsl:value-of select="TITLE"/>)
</SPAN>
</xsl:element>

 

  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.
  The code that performs the search is in the cmdSearch_onClick method in results.htm, which is shown in Figure 5. Half of the code is dedicated to building the XSL pattern based on what the user selected (ugh!). The meat of the code is in these lines:

  var objCol = infoxml.selectNodes(strPattern + "/@ID");
  
for (var i=0; i< objCol.length; i++)
document.all(objCol(i).text).style.color = "blue";

 

  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 Client

  So 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.

  1. The source nodes and destination nodes enable drag and drop support by handling the ondragstart, ondrop, ondragenter, and ondragover events. Ondragstart and ondrop handle the bulk of the operation, while ondragenter and ondragover are used to control the mouse cursor.
  2. In the handler for the ondragstart event, set the data that will be transferred to the destination node. In our case, we call event.dataTransfer.setData("Text", ele.id ). This sets the data to the ID of the node being dragged.
  3. In the handler for the ondrop event, you retrieve the data being transferred and implement the necessary action. In this example, we call event.dataTransfer.getData("Text") to retrieve the ID of the source node. Next, we call the MovePerson( SourceID, DestinationID ) method to actually change a person's position in the org chart.

  We modified orgchart.xsl to provide handlers for the ondragstart, ondrop, ondragenter, and ondragover methods for each of the nodes in our org chart. We also wanted to be able to use the drag and drop implementation to move someone to the top of the organization. To do this, we added drag and drop support for the Organization Chart header. This was done in the same manner as the nodes in the org chart. We gave the <DIV> a special ID called TOP so that it could easily be identified as the top-level node.
  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:

  event.returnValue = false;
  
event.dataTransfer.dropEffect = "move";

 

  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.
  By default, edit boxes will take the value in the Text part of the data transfer and place it inside the edit box. This means that if we drag a person from our org chart onto one of the text boxes on the screen, the textbox will get the value of the ID of the source node. Since we don't want this to happen, we need to handle the ondragenter event for the textboxes. In the handler, we cancel the event and set the cursor appropriately.

  event.returnValue = false;
  
event.dataTransfer.dropEffect = "none";

 

  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.
  Finally, to start a drag and drop operation, you have to have something selected to drag. So you first have to select some text inside the node, then you can drag it somewhere else.

Add, Edit, and Delete

  Until 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.

Figure 8 Add, Delete, and Edit

  Figure 8 Add, Delete, and Edit

  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.
  Let's take a closer look at the new XSL edit stylesheet. We need to render a new view of the data to allow a user to edit the name and title of a person, and we also want to make the XSL as flexible as possible. Should we decide to add another property (like their age) to each person later on, it would be wise to minimize the changes required to support the new properties.
  Figure 9 shows the core XSL that renders the edit version. A table is dynamically built based on the search results from the pattern specified in the template match attribute. In this case

  "PERSON/(NAME | TITLE)"
  

 

  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!
  The most important concept in this template is the OnChange event for the edit boxes. We want to dynamically generate a line of JScript that will insert the new value into the XML document. For example, if the user is currently editing the name Tom Tech and that element happens to have an ID of 96, the following JScript should run:

  infoxml.selectSingleNode(".//*[@ID
  
='96']").text = NAME96.value;

 

  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.
  Each person is rendered with an Add and Delete link. Clicking on Add calls the AddPerson function with the ID of the parent person element as a parameter. Figure 10 shows the code involved to add a person. It checks to make sure the name is unique by searching the <PERSON> elements:

  infoxml.selectSingleNode("CLIENT/PEOPLE//
  
PERSON[NAME= '" + strName + "']");

 

  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.
  To show how this is extensible, let's say you wanted to add a field called age to each person. First, you would have to add <AGE> elements to the existing people. Next, you would edit the template pattern expression to include the <AGE> element. That's it. All new <PEOPLE> elements could now have an editable age. To find all people who are older than 45, you could type the following into the Direct edit box:

  //PERSON[AGE > 45]
  

 

Back to the Server

  Finally, 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.

  <%@LANGUAGE=VBScript%>
  

<%

Set newxml = Server.CreateObject("Microsoft.XMLDOM")

newxml.async=false
newxml.load(Request)

newxml.save(Server.MapPath(Request.QueryString("Company") &
"/info.xml"))

%>

 

Conclusion

  The 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 checkXML 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.