This article originally appeared as a Web Development Zone e-newsletter.
By Phillip Perkins
When you consider combining Vector Markup Language (VML), XML, and HTML to create an organizational chart, it only seems logical. Think about it: VML provides a simple way to create graphical objects in IE; XML provides an inherent hierarchical structure for data; HTML provides a simple method for text format and layout. So let's get to work.
In order to create the hierarchy chart, I need a basic building block for each piece of the chart. The chart will consist of a series of blocks that contain the text box for data and the connecting lines to show the relationships between the class levels. Here's the VML code to accomplish this. Click here.
Now imagine this basic shape that we'll use to build our chart:
These lines and rectangles will be "turned on and off" according to the shape's position in the organizational chart.
Look at the VML and you'll see that the VML follows the same rules for positioning as HTML. All the positions are relative. This makes it easy to include many of these shapes in one <v:group> and not get wrapped up in the calculations for their positions. (Ignore the coordinate values for now.)
I'm going to use the power of XML and XSL to create this organizational chart dynamically. First, I need to know what my XML structure is going to look like and how I can use it inside my XSL.
The initial thing to do is to figure out the best structure for easy processing within my XSL. Instead of having to change my XSL every time I add a new level, I want my XSL to be able to handle new levels added to the hierarchy. The best method for this is recursion. If every employee in the organizational chart has a defined structure, we can embed employees within employees. When we hit an employee node within another employee node, we simply call the same <xsl:apply-templates> tag. Here's an example of some XML data that will allow this type of task. Click here.
If you examine this XML structure, you'll see that Jim Doe is a direct report to John Doe. Jack Doe is a direct report to Jim Doe. Each <employee> node contains another <employee> node with the same structure. The skeleton code for navigating this XML in XSL is pretty simple. Click here.
The navigation starts at the outermost <employee> tag and calls the "employee" template. (You'll see where I've set up some comments to do the work to create my object and set the coordinates.) After creating all of my objects, I call the "employee" template for any <employee> tag inside the current <employee> tag. This creates the recursion that allows my organizational chart to have limitless levels.
Note: This article uses Microsoft's XML and XSLT technologies. It also relies heavily on the <msxsl:script> tag in XSLT to process coordinate values. VML is another Microsoft product, but it can be replaced with Scalable Vector Graphics (SVG).
Make the actual VML/HTML that creates the organizational chart
In the XSL skeleton code, I created two templates: the root template and an "employee" template. In the root template, I need to set up the <v:group> element that will contain all of the employee graphical nodes. The <v:group> element creates the coordinate space that will be the canvas where we will place each of the graphical nodes. Click here.
If you translate the above code, you'll see that I create the <v:*> elements using the <xsl:text . . .> tags. I do this so I don't have to worry about namespace declarations and other headaches. You'll also see that I set up some calculations inside the style and coordsize attributes. These calculations are for fine-tuning the size of the coordinate space and the size of the <v:group> element on the Web page.
I use an <xsl:apply-templates . . .> tag to select the next level of employee nodes. Along with this call, I include the level parameter. The level is located in the XML and is used for calculating the coordinates of each object. Now, we create the shapes that create the graphical employee nodes. Click here.
If you examine the above XSL, you'll notice that I still use the <xsl:text . . .> element to create the individual <v:*> elements. The node is composed of four lines and one rectangle. An extra line is added at the top to join the previous node from the same level to the current node. The coordinates don't make much sense until you see the <msxsl:script . . .> that accompanies the stylesheet. However, if you look at the creation of the individual shapes, you'll see that I use a little logic to include certain shapes in the output. I also use a function call fn:setTop($level) with each employee iteration to increment the y coordinate by the height of each node. Click here.
Here's the code that calculates the coordinates for the individual objects. If you look at the commented section where I show the textual representation of the node, you'll see where the coordinate points are that I return from the fn:getCoord(. . .) function. The width and the height of each node area is stored in two variables: m_width and m_height, respectively. The current y coordinate is stored in the variable m_top. The value of m_top is stored as -480, so the first call to fn:setTop(. . .) returns 0. The variable max_y stores an associative array so the last maximum y coordinate is stored for each level. This y coordinate is retrieved to create the extra line that connects two sister nodes. This is needed when one node has multiple descendents. The next sister node will have to create the line that links to two.
In order for your Web page to display correctly, you need to have the following structure in your HTML. Click here.
This example relies on Microsoft's XSLT and VML technologies. This example has been proven to run in IE 5.5 and above. If you wish to obtain the complete source for this article, including the ASP source that handles the transformation, you may find it here: http://www.geocities.com/phil_perkins_1/articles/hierarchy.zip
Phillip Perkins is a contractor with Ajilon Consulting. His experience ranges from machine control and client/server to corporate intranet applications.