Home & blog  /  Scripts  /  view post  /

XML Tree - visualise and traverse your XML

Overview

XMLTree is a utility for visualising and traversing XML in tree format. The script creates the tree from a specified XML file or from manually-fed XML. Callback functions can be specified to fire as you traverse the tree, to which are automatically passed the node you clicked, and its XPath. It is also possible to deep link to a point or points within the tree. Multiple trees on one page are supported.

Example

Using this sample XML about Nintendo game characters, we get (click the plus icon):

Here's the code behind this example:

1new XMLTree({

2     fpath: '../inc/script_demos/xmltree/xml.xml',

3     container: '#tree'

4});

Usage and params

As shown above, XMLTree is invoked by calling new xmltree(params), where params is an object including the following properties:

container (string) - a jQuery selector string targeting the container element you want to insert the tree into

fpath (string) - a path to the XML file you wish to use

xml (string / xml) - instead of referencing an XML file, you can pass literal XML into this argument

jsonp (boolean; false) - pass true if you are loading your XML over JSON-P rather than locally

startExpanded(bool; false) - by default, the tree will begin collapsed (unless you are linking to a specific point within it). Pass true here to begin the tree fully expanded

renderCallback (function) - a callback function to act on or interrogate the resultant tree HTML. It is automatically passed a jQuery reference to the tree ul as its only argument.

XMLCallback (function; null) - a callback function to act on or interrogate the XML data. Useful if you want to tweak the XML before tree output starts to be generated.

plusMinCallback (function) - a callback function to be invoked when a user clicks the plus/minus link next to a node, i.e. expands or collapses it. Your callback function will automatically be passed 4 arguments:

-- li (jQuery object) - a jQuery reference to the node LI

-- XPath (string) - the XPath of the node LI

-- event (event object) - a jQuery click event object

-- li (jQuery object) - a string, either 'open' or 'close', depending on whether the corresponding node LI's children are currently visible or hidden

clickCallback (function) - a callback to be invoked when a user clicks one of the nodes. It receives the same data as above, except the 4th argument

hideNodeNames (bool; false) - whether or not to show the names of nodes in the tree

openAtPath (string) - a jQuery selector pointing to a node within the XML that represents where the tree should open at, e.g. books book[author="Robert Rankin"]

attrs (string; 'show') - how attributes should behave in the resultant tree. Options: 'show' (they will be present and visible); 'hide' (present but hidden); 'ignore' (they will be absent from the tree). 'hidden' is useful if you want to interrogate the tree based on the existence or value of certain attributes, without them being visible to the user.

attrsAsClasses (boolean or array; null) - transfer some or all attributes from the XML to become classes on the LIs. Pass true to apply this to all attributes, or, for just some of them, an array of attribute names.

attrsAsData (boolean or array; null) - identical to attrsAsClasses, except attributes will become jQuery data (i.e. accessible via .data())on the element rather than classes

subTreeBranches (string or boolean, null) - branches that, when expanded, load more data. Pass true for this to apply to all branches. See Sub-tree requests.

subTreeRequest (function; null) - a callback function that, when a sub-tree branch (see the subTreeBranches arg) is expanded, returns the URL to the XML to load into it. It is automatically passed a jQuery reference to the clicked LI as its only argument.

noURLTracking (boolean; false) - if true, the steps taken navigating the tree will not be logged in the URL hash. Note that this will mean the tree returns to its original state on page refresh.

Sub-tree requests

XMLTree allows you to load data in stages. For example, you might initially load only the outer skeleton of the tree (i.e. the children of the root) and then load deeper levels of data only when (and if) the user expands one of those nodes. This is a common situation when the XML is being served up dynamically by a server-side web service.

Here's an example of how you can implement this. (For info on any of the discussed parameters, see Usage and params.)

1new XMLTree({

2     fpath: 'web_service.php?level=root',

3     container: '#tree',

4     subTreeBranches: true,

5     subTreeRequest: generate_sub_tree_url,

6     attrsAsData: true

7});

There, we initialise the tree, and fetch and load in the root-level data from the web service. We also stipulate that all branches, when expanded, should fire sub-tree requests, i.e. load data under themselves. We also transer all attributes from the XML to become jQuery data properties on the resultant LIs.

We then specify that, when sub-tree branch is expanded, the URL from which to fetch the data will be generated by a callback function, generate_sub_tree_url.

1function generate_sub_tree_url(li) {

2     return 'web_service.php?branch_id='+li.data('id');

3}

Our callback is automatically passed as its only argument a jQuery reference to the expanded LI. We can then interrogate that LI as a means to determine the URL from which to get the next batch of data.

We told XMLTree at initialisation to transfer XML attributes to become jQuery data properties on the resultant LIs. Assuming one of these attributes was id, we can then use that, as shown, in generating the URL to talk to the web service.

Deep linking

You will notice while traversing the tree that XMLTree tracks, via the URL hash, which branches are expanded at any given time. This has two positive implications:

  • One: when the page is refreshed, the tree retains its state
  • Two: you can link to points within the tree, rather than just to its root

To link to a specific point in the tree, you need to know the route to it - that is, the indexes of the nodes that lead to it.

So for example, in the above example, to link directly to recent games involving Nintendo's Kirby character, the link would be:

https://mitya.co.uk/scripts/xmltree-186#tree0:0,1,5;

Note the hash contains the tree instance ID, so it won't confuse it with another tree should you have multiple trees on one page. The structure thereafter is simply the indexes leading down to the desired node.

Linking to multiple nodes

It is possible to link to not just one but multiple nodes, too. To do this, use the pipe character in the above hash structure at the point where more than one branch is expanded.

So for example to link to both the Kirby and Bowser characters, the URL would be:

https://mitya.co.uk/scripts/xmltree-186#tree0:0,1|0,2;

If in doubt...

If you are unsure of the hash structure needed to link to a given node or nodes, just navigate it to it/them in the tree yourself and observe how the hash changes in your browser address bar.

Notes

jQuery

XMLTree requires jQuery version >= 1.5

post new comment

Comments (16)

khalid rizwan, at 30/01/'12 07:06, said:
hi guys i am trying to use clickCallback (function) to call a function by clicking on any node but it dont works.
khalid rizwan, at 30/01/'12 07:06, said:
hi guys i am trying to use clickCallback (function) to call a function by clicking on any node but it dont works.
Mitya, at 30/01/'12 14:36, said:
 - this was buggy, and is now fixed. Download the latest source code. Passing a callback function to clickCallback should now fire the callback on click to one of the nodes.
Jeff Romatoksi, at 8/08/'12 14:22, said:
I am trying to use the XmlTree control, but I have a few issues.

1). I cannot get this to work with IE9.  It seems to be having problems with the .prototype syntax.  In the debugger it gets an undefined on the the call to actOnXml.  When I step through your source it does not get the excpetion.  I cannot figure out what I am doing different.

2). It works on Mozilla, but I am trying to put two controls on the same page pointeing to different Xml files.  XML from the different files appear in the same control.  Is this supported?
Mitya, at 9/08/'12 12:04, said:
 - thanks for your interest. It should work in IE9; since I'm on Mac, I'll need to test on someone else's (Windows) machine and come back to you on this. Does the example on this page work in your IE9, or is that too broken?

Re: multiple instances, there is currently a bug that I have not been able to identify with regards to multiple instances. I remember being quite perplexed. I will look into this again and get back to you - clearly it should be supported.

I'll post comment updates right here when I know more about either issue. Thanks.
Brian, at 23/11/'12 02:59, said:
Multiple instances will work if line 170 is changed from this:

kids.each(function() { thiss.delve($(this)); });

to this:

kids.each(function() { thiss.delve(this); });
Brian, at 23/11/'12 23:03, said:
Sorry, I was mistaken.  That simply keeps the delve() function from working at all.  There's definitely an issue with delve().
Mitya, at 24/11/'12 09:24, said:
 - I spent quite a bit of time trying to debug what was up with multiple instances of trees on the same page, and I have to say I was stumped. Everything seemed to check out OK.  It's a shame, because XMLT is pretty powerful these days - it just has this one flaw. Fine if you want only one tree.
Tom, at 27/11/'12 15:25, said:
Hi, I tried to give xml as string using xml param in the plugin, but i am getting jquery error in the else block:

TypeError: this.actOnXML is not a function
[Break On This Error]        

this.actOnXML(jdo.xml);  ------line number 77 in xmltree.js file

the xml that i am passing is:

$(function() {var inxml='
xyz
'; new XMLTree({xml:inxml, container: '#tree', startCollapsed: true}); }); Is this correct way. Thanks.
Mitya, at 27/11/'12 15:38, said:
@Tom - there is currently a known bug concerning the passing of XML as a string. I will aim to fix it this week - please check back in the comments. Otherwise, if at all possible, load the XML from a web service or file.
Alan, at 14/12/'12 10:09, said:
Hi, Mitya, I liked your xmltree and now using it. I occasionally found the part of passing an xml string as the input is not working. And I think it's because the function is not defined at that time. My way to fix that is quite simple, just moving the definition of "XMLTree.prototype.actOnXML = function(xml) {...}" to the front.
Mitya, at 14/12/'12 10:49, said:
 - yes, there is a known issue with passing XML as a string. I promised @Tom a fix for this some weeks ago and have still not had chance to look at it. I will look at your suggestion and, if it fixes it, update the downloadable sourcecode. Thanks a lot.
Alan, at 7/01/'13 03:50, said:
A quick fix to solve the 'only one instance' problem: add 'var thiss = this;' to the beginning of the XMLTree.prototype.delve function. Seems that it works perfectly for me now. :)
Sergey, at 10/01/'13 14:29, said:
Hi, Mitya! Thank you for work! Is there any hope that the problem with the input string as a xml will be resolved?
Mitya, at 10/01/'13 15:50, said:
Hi Sergey - please see 's comment above, as he may have a fix for this issue.
Sergey, at 11/01/'13 08:32, said:
I tried this solution, but the error remains. There are other ways to solve the problem?
post new comment