Video Presentation: Manipulating XML With jQuery

Posted July 10, 2009 at 10:24 AM

Tags: Javascript / DHTML

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:

 Launch code in new window » Download code as text file »

  • <!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.

Download Code Snippet ZIP File

Post Comment  |  Ask Ben  |  Other Searches  |  Print Page





Reader Comments

Jul 10, 2009 at 7:37 PM // reply »
7,572 Comments

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


Jul 10, 2009 at 7:38 PM // reply »
4 Comments

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


Jul 10, 2009 at 7:41 PM // reply »
4 Comments

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


Jul 10, 2009 at 7:43 PM // reply »
7,572 Comments

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


Jul 10, 2009 at 8:46 PM // reply »
1 Comments

Hi Ben.
Excelent video.
Thanks for share the knowlege.


Jul 11, 2009 at 6:27 AM // reply »
1 Comments

Nice video, what programs are you using to produce these?


Jul 12, 2009 at 2:02 PM // reply »
4 Comments

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


Jul 13, 2009 at 2:32 PM // reply »
1 Comments

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


Jul 18, 2009 at 5:11 PM // reply »
7,572 Comments

@Andy,

I've been using JING to make most of these.


Jul 30, 2009 at 12:37 PM // reply »
4 Comments

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


Aug 5, 2009 at 10:07 AM // reply »
7,572 Comments

@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!


Sep 8, 2009 at 10:13 AM // reply »
2 Comments

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


Sep 8, 2009 at 12:44 PM // reply »
7,572 Comments

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


Sep 9, 2009 at 4:41 AM // reply »
2 Comments

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.


Sep 12, 2009 at 10:49 PM // reply »
7,572 Comments

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


Oct 8, 2009 at 5:53 PM // reply »
1 Comments

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???


Oct 8, 2009 at 7:03 PM // reply »
1 Comments

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.


Post Comment  |  Ask Ben

Recent Blog Comments
Mar 21, 2010 at 3:59 PM
Exploring ColdFusion Component Runtime Class Properties And Serialization
@Elliott, according to Ben's experiment, serializeJSON() doesn't access the private data by default - it doesn't even access the getHair() method - so trying to clone a Girl.cfc via serializeJSON/des ... read »
Mar 21, 2010 at 3:49 PM
Ask Ben: Javascript String Replace Method
I'm confused a bit by what you are asking, but if had this sentence: The color, red, is in the style statement; style: red;. and wanted to remove all or change all of the commas, colons, and semi-c ... read »
Mar 21, 2010 at 3:13 PM
Ask Ben: Javascript String Replace Method
I am trying to make a java program to count the number of times that these punctuation marks occur in a body of text: , : ; . ! - ' " ? / \ I am using this piece to ferret out the commas: numcommas ... read »
Mar 21, 2010 at 11:13 AM
A New Wrist Pain
@chiropractor suwanee, Spoken like someone trying to sell something. Other than for minor, temporary relief from some back pain, chiropractic treatment is nothing but placebo effect and quackery. ... read »
Mar 21, 2010 at 6:32 AM
ColdFusion CFPOP - My First Look
Apologies... The field name in the db for C. is "BounceCode" It stores the code / message which is returned in the email. Sorry for the confusion. ... read »
Mar 21, 2010 at 6:29 AM
ColdFusion CFPOP - My First Look
@Jose Galdamez, Hi Ben and Jose 1st of all.. big thanks to Jose for his Skype chat a few weeks back. Your time was much appreciated. I have come up with a rather unelegant solution to my problem a ... read »
Mar 21, 2010 at 3:42 AM
A New Wrist Pain
Chiropractic treatment is one of the best methods for treating numerous health problems naturally. After years of experience being a chiropractor, I have found that it is a powerful way to solve many ... read »
Mar 20, 2010 at 12:07 PM
Drawing On The iPhone Canvas With jQuery And ColdFusion
Simply awesome. Saved my day. ... read »