Ben Nadel
On User Experience (UX) Design, JavaScript, ColdFusion, Node.js, Life, and Love.
I am the chief technical officer at InVision App, Inc - a prototyping and collaboration platform for designers, built by designers. I also rock out in JavaScript and ColdFusion 24x7.
Meanwhile on Twitter
Loading latest tweet...
Ben Nadel at cf.Objective() 2011 (Minneapolis, MN) with:

Video Presentation: Manipulating XML With jQuery

By Ben Nadel on

NOTE: Right now, the following examples only work in Mozilla-based browsers (meaning, not in IE). I am working on an update that is IE-compatible.

We all know that jQuery is the most awesome Javascript library around. Every day, we are using jQuery to create richer, more dynamic, more effective user experiences on the web and in our AIR applications. Hands down, it's the fastest, most effective way to create Javascript-based user interfaces. But, jQuery is also quite good at reading and manipulating XML documents. Since XHTML is really just a subset of XML, it should be no surprise that just about everything we can do with XHTML documents, we can also do with XML documents by way of jQuery.

In the following mini video presentation, I demonstrate how to use jQuery to do all of the following:

  • Create XML documents from scratch.
  • Add new sub-trees to an XML document object model.
  • Perform contextual searches on the XML DOM.
  • Access, update, and create XML attributes.
  • Trim sub-trees from an XML document object model.
  • Even bind and trigger custom events on an XML tree.

In short, the video demonstrates that all of the actions you like to perform on XHTML, can also be performed on XML.

 
 
 
 
 
 
 
 
 
 

If you want to play around with this code yourself, here is the HTML page that I demonstrated in the video:

  • <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  • <html>
  • <head>
  • <title>Manipulating XML With jQuery</title>
  • <script type="text/javascript" src="jquery-1.3.2.js"></script>
  • <script type="text/javascript">
  •  
  • // When the DOM is ready, run the scripts.
  • $(function(){
  • // Build the base data XML object. We are building the
  • // XML collection in this cause, but this could have
  • // just as easily come from an AJAX call of type XML.
  • var jData = $( "<data></data>" );
  •  
  • // Output the info to the output.
  • output( "Data Size: " + jData.size() );
  •  
  •  
  • // ----------------------------------------------- //
  •  
  •  
  • // Append a dataum node to the XML collection.
  • jData.append(
  • "<datum id='1'>\
  • <name>Tricia</name>\
  • <hair>Brunette</hair>\
  • </datum>\n\
  • <datum id='2'>\
  • <name>Joanna</name>\
  • <hair>Brunette</hair>\
  • </datum>\n\
  • <datum id='3'>\
  • <name>Eva</name>\
  • <hair>Blonde</hair>\
  • </datum>"
  • );
  •  
  • // Query for all the datum nodes.
  • var jDatum = jData.find( "datum" );
  •  
  • // Output the size of the collection and the
  • // HTML (XML) of the data node.
  • output(
  • ("Datum Size: " + jDatum.size()),
  • jData.html()
  • );
  •  
  •  
  • // ----------------------------------------------- //
  •  
  •  
  • // Find Tricia's node. She is the datum record with
  • // the id of 1.
  • var jTricia = jDatum.filter( "[ id = 1 ]" );
  •  
  • // Output tricia's node.
  • output(
  • "Tricia's Node",
  • ("ID: " + jTricia.attr( "id" )),
  • jTricia.html()
  • );
  •  
  •  
  • // ----------------------------------------------- //
  •  
  •  
  • // Find the blond girl in the node set.
  • var jBlonde = jData.find(
  • "datum:has(hair:contains('Blonde'))"
  • );
  •  
  • // Output the blonde node.
  • output(
  • "Blonde's Node",
  • ("ID: " + jBlonde.attr( "id" )),
  • jBlonde.html()
  • );
  •  
  •  
  • // ----------------------------------------------- //
  •  
  •  
  • // Blondes might have more fun, but not in my
  • // programming world. Remove the blonde node from
  • // its parent data set (the data node).
  • jBlonde.remove();
  •  
  • // Output the data node to see if blondie was
  • // removed from the party.
  • output(
  • "Data (without Blondie):",
  • jData.html()
  • );
  •  
  •  
  • // ----------------------------------------------- //
  •  
  •  
  • // Let's rate the hottness of the remaining girls.
  • // To start with, let's add a default attribute with
  • // not value.
  • jDatum.attr( "hotness", "unknown" );
  •  
  • // Output the updated data set.
  • output(
  • "Data (with hotness attributes):",
  • jData.html()
  • );
  •  
  •  
  • // ----------------------------------------------- //
  •  
  •  
  • // Tricia is a total babe. If she were a children's
  • // cereal, she'd be magically babelicious. As such,
  • // let's take her existing node reference and update
  • // the hotness attribute.
  • jTricia.attr( "hotness", 10 );
  •  
  • // Output the updated data set.
  • output(
  • "Data (with Tricia update):",
  • jData.html()
  • );
  •  
  •  
  • // ----------------------------------------------- //
  •  
  •  
  • // Even though we are dealing with an XML document
  • // that is not rendered on the page, we can still
  • // bind and trigger events on it.
  • jData.bind(
  • "hug",
  • function( objEvent ){
  • // Get the target node for the event.
  • var jTarget = $( objEvent.target );
  •  
  • // Check to see if the target node of the hug
  • // event was a datum node (we don't care if
  • // another node triggered this event).
  • if (jTarget.is( "datum" )){
  •  
  • // Output that the given girl node was
  • // hugged (you sly dog you!).
  • output(
  • "Datum Node Hugged:",
  • jTarget.html()
  • );
  •  
  • }
  • }
  • );
  •  
  • // Trigger a hug event on Tricia.
  • jTricia.trigger( "hug" );
  •  
  •  
  • // ----------------------------------------------- //
  •  
  •  
  • // We are done. Let's empty the data set.
  • jData.empty();
  •  
  • // At this point, we have completely disconnected the
  • // Datum collection from the Data container. As such,
  • // we shouldn't be able to access the parent node of
  • // any of the datum nodes. To test this, try to grab
  • // Tricia's parent.
  • var jParent = jTricia.parent();
  •  
  • // Output the parent collection size and the size of
  • // data child collection.
  • output(
  • ("Parent Size: " + jParent.size()),
  • ("Data Child Size: " + jData.children().size())
  • );
  •  
  • });
  •  
  •  
  • // I output my arguments to the output, each on a new line
  • // followed by an extra line break.
  • function output(){
  • var jOutput = $( "#output" );
  •  
  • // Loop over arguments and output them.
  • $.each(
  • arguments,
  • function( index, value ){
  • // Clean the value.
  • value = $.trim( value );
  •  
  • // Remove tabs for demo.
  • value = value.replace(
  • new RegExp( "\\t+", "g" ),
  • " "
  • );
  •  
  • // Remove all leading spaces.
  • value = value.replace(
  • new RegExp( "^\\s+", "gm" ),
  • ""
  • );
  •  
  • // Append to existing content.
  • jOutput.val( jOutput.val() + value + "\n" );
  • }
  • );
  •  
  • // Output an additional line break.
  • jOutput.val(
  • jOutput.val() +
  • "\n-------------------------\n\n"
  • );
  • }
  •  
  • </script>
  • </head>
  • <body>
  •  
  • <h1>
  • Manipulating XML With jQuery
  • </h1>
  •  
  • <form>
  •  
  • <textarea
  • id="output"
  • style="width: 100% ; height: 400px ; font-size: 16px ;"
  • ></textarea>
  •  
  • </form>
  •  
  • </body>
  • </html>

If you still haven't looked into jQuery, do so immediately. If you'd like to get a great primer on the subject, take a look at my presentation: An Intensive Exploration of jQuery. It is one of the best Javascript libraries out there; and, as stated before, I'll never start another web development project without it.




Reader Comments

This is really embarassing, but this code does NOT work in Internet Explorer. I will debug this and post an update.

Reply to this Comment

Hi Ben,

I would like to express my sincere thanks for this fantastic video. I must say again as I said on my previous email - I think that your videos are head and shoulders above the rest.

Very clearly worded, and more specifically, extremely well exemplified.

Also, thanks for passing on extensive knowledge and support. I have really enjoyed watching the video and am very grateful for the opportunity to ask further questions.

Below I have some questions and also discuss the problems/bugs I encountered while trying the code:

1 - In IE6, the code does not run properly. I have debugged the code and this is the extract of code from the JQUERY library where it breaks:

Does the JQUERY library offers cross browser support including IE6?

2 - I have my own little javascript library which I use to work with xml. I use XPATH quite extensively to find the nodes I need in the xml. I use XPATH expression like this:

Is it possible to use XPATH with JQUERY?

3 - There is something that is still not clear to me. How do I move/copy an specific XML structure from one XML into another XML in a specific location ?

Suppose I have this xml:

XML1

Suppose I want to move/copy all the address elements from XML1 with all its attributes and child elements to another xml - XML2 under the addresses tag. I am not sure how to achieve this!!!

XML2

This would be the required output:

I would appreciate if you could show us some code examples.

Again thanks for your help.

Cheers

C

Reply to this Comment

I am sorry, but I was not able to post the xml and code sample since the blog was blocking my message.

Reply to this Comment

@Cleyton,

Don't worry about it. My blog blocks things that it thinks might be spammers (based on content). You probably just a link tag or something.

I got your email. Thanks for pointing out this *glaring* IE compatibility issue. I apologize for not testing this. I just assumed...

Reply to this Comment

Hi Ben,

I was wondering if the reason why the code does not work in IE6/7 is because in IE6/7 the way to create an xml document is different from Mozilla-based browsers.

IE uses Activex
new ActiveXObject("MSXML2.DOMDocument")//("MSXML2.DOMDocument.4.0")

FF uses

parser.parseFromString(nd, "text/xml")

of

document.implementation.createDocument

Hope this will shed some light.

One thing I don't understand about the JQuery library is how it treats an xml string you pass to it. Does it create an xml document?

Also, shouldn't the library be cross browser so that it would in IE6 as well?

Cheer

C

Reply to this Comment

Hi Ben,

Great work and thanks for sharing the info too. Once you've managed to spend some time getting it to work with IE, please post back here so that we can all take a look?

Thanks again,
David

Reply to this Comment

Hi Ben,

We have been waiting for a reply from you regardin the sample examples working only in Mozilla-based browsers (meaning, not in IE).

You said you were working on an update that woudl be IE-compatible.

Could you please shed some light on the outcome of your tests?

I have noticed that a lot of people are having the same problem i.e. to get JQuery to manipulate xml in IE and also in FF 3.0.

Based on my research I believe there is a bug in JQuery when it comes to working with XML.

What are your thoughts on that?

Cheers

C

Reply to this Comment

@Cleyton,

Sorry my man, I have been so busy with exploring the ColdFusion 9 alpha that I've hardly had any free time. I have a conference coming up next week, so I will most likely have more free time after that. Sorry for the suspense!

Reply to this Comment

Hi Ben, first of all thanks for this great video.

I've a problem using it when the JQuery XML comes from an Ajax call.
Even if I specify the XML dataType I get an error when I try to get the .html() of the document or of a single node.

Do you know if this is a JQuery bug or if I miss something?

Thanks

Reply to this Comment

@Stefano,

This might be the FireFox / IE discrepancy. I only tested this in FireFox and then realized that it doesn't quite work the same way in IE.

I have been meaning to find time to fix it up, but have been under a lot of deadlines. September should be more quiet and I'll see if I can get to the bottom of some of this.

Reply to this Comment

Hi Ben, sorry I forgot to say I'm using Firefox with JQuery 1.3.2

I've an .ajax call directly to an XML file with datatype specified as XML.
With the result I've no problem doing everything in your video but I can't access the .html() method.

I get an error on jquery file row 486: this[0].innerHTML is undefined.

This is not a big problem for me, cause I don't really need to get the .html() or I can get it using a different approach cause I'm developing only on firefox, but it seems really a strange behaviour.

Reply to this Comment

@Stefano,

Very interesting. I wonder if is has to do with the fact that I am manually building the XML data string locally, rather than getting it from a remote URL? Very curious.

Reply to this Comment

Ben -

First off, thanks for posting your work with jQuery - it's a big help!

I am trying to get this working in IE6 as well, and it appears that if I use a dataType of 'text', all works fine (in Safari) but not in IE6. When I switch the dataType to 'xml', as already mentioned in an earlier post, the html() property no longer works (in Safari or IE6). By using text() instead of html(), I can get the text, but not the XML elements themselves. Argh! Still looking, but so far I see no (browser-independent) way of serializing the xml object to it's string representation...anyone else having any luck???

Reply to this Comment

1.) there is not html() function for an xml node, because xml elements do not have a innerHTML property which is what the html() function utilizes. In fact by my understanding og JQ, using html on a pure xml doc shouldnt work at all unless the xml node in question happens to have the XHTML or HTML namespace attached to it. This means if you want to get the nodes as a sertialized string you need to create an extension or global utilitiy function to do so, for example:

<code>
$.fn.xmlString = function(){
var str = '';
this.each(function(){
if(window.ActiveXObject){
str += this.xml;
} else {
str += (new XMLSerializer()).serializeToString(this);
}
});

return str;
};
</code>

2.) I could be wrong about this because i just ran across the issue (in fact i found this post in trying to find proof that my suspicion is correct), but you cant simply move a node from document a to document b because they dont have the same owner document - at least this is the way it is in php when you using DOMDocument and/or SimpleXml. There are particular function you use for this... I think this is probably an issue with differences between the underlying implementation of XML in the browsers - oddly enough this implys Mozilla/Gecko is actually LESS strict than MS and Webkit. What really gets me is that i beleive both Webkit and Gecko use nearly identical if not the same XML DOM implementations (as implied by the simple if/else statement in the searializer above.

Hope that helps.

Reply to this Comment

Can we convert xml file into a csv file using this jQuery?If yes,can u please provide me the code.

Reply to this Comment

@Pavan,

Are you talking about simply creating a comma-delimited list? Or creating an actual physical file?

Reply to this Comment

Here is a simple test I put together to get around the IE problem.

if ($.browser.msie)
{
var xDom = new ActiveXObject("Microsoft.XMLDOM");
jData = xDom.loadXML("<data></data>");
}
else
{
jData = $("<data></data>");
}
alert(jData.size());

Reply to this Comment

This was really useful. I've been doing the same thing lately. But, I just can't get it to work in IE8... Anyone have succeeded in this?

Reply to this Comment

@Eirik,

My code won't work in IE, unfortunately. But, if I recall correctly, there's a number of comments above in which people have outlined how to get this to work in IE-based browsers. I believe you need to parse the XML a bit differently (using a proprietary IE technology).

Reply to this Comment

Hi,

IE8 uses the standard DOM class that is used by other browsers like FF.

In your code you could try to check if it is IE8 and then use the standard way to create an xml document.

Please let us know if this works.

Cheer

C

Reply to this Comment

Binding events and manipulating shared subtrees with multi-part selectors is all well and good, but how do I get Tricia's phone number?

Reply to this Comment

Binding events and manipulating shared subtrees with multi-part selectors is all well and good, but how do I get Tricia's phone number?

@Ben,

Reply to this Comment

@Ben,

This might be the FireFox / IE discrepancy. I only tested this in FireFox and then realized that it doesn't quite work the same way in IE.

I have been meaning to find time to fix it up, but have been under a lot of deadlines. September should be more quiet and I'll see if I can get to the bottom of some of this.

Reply to this Comment

Thanks for a great walk trough of how to use jQuery combined with XML. Really makes my mind bubbling with ideas.

Reply to this Comment

Post A Comment

You — Get Out Of My Dreams, Get Into My Comments
Live in the Now
Oops!
Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.