Saturday 11 July 2009

jQuery - Copy XML from one object to another

Today I am going to go through, how to copy some XML structure and data from one XML object to another XML object. Now from what I have noticed when making use of jQuery, I have seen that it does not actually support XML as such, while it does support XHTML formatted in an XML structure. So in essense, we will be converting our XML object into an XHTML object, do all of our changes, and then convert it back. This may sound a bit long winded, but it's actually not as bad as it sounds.

First off, we need to add a function created by John Resig (http://ejohn.org/blog/javascript-array-remove/), which will allow us to remove items from an array.

Array.prototype.remove = function(fr, to) {
var rest = this.slice((to || from) + 1 || this.length);
this.length = from < 0 ? this.length + from : from;
return this.push.apply(this, rest);
};



And now we need to extend our XML to string function, as in good XML you tend to get the first line starting with a "
jQuery.XMLtoString = function(xmlData) {
var xData;
var xSplit;
if (window.ActiveXObject) {
xData = xmlData.xml;
} else {
xData = (new XMLSerializer()).serializeToString(xmlData);
}
xSplit = xData.split('\r\n');
if (xSplit[0].substr(0, 5) == ' xSplit.remove(0);
return xSplit.join('\r\n');
}



Now I have only just thrown this together, it works, however I will be making some changes to it at a later date by making use of some Regex, as well as giving you the ability to re-add the line you are removing. Anyway, let's give an example XML structure:








Scenario:

You want to copy all of the address tags, including all attributes and child nodes, onto a new location on a different XML object. Resulting in something like this:



45 Usura Place
Hailey
ID


3 Prufrock Lane
Stamford
CT


10 Bridge Tunnel
Harlem
NY



This is a fairly easy task, however the way you go about doing it, is not very obvious. Let's say you have done your AJAX request, received your XML, and have now passed the xml to your function. Here's what you should have inside your function.

Firstly, we need to convert our XML into a string (with the modified function), find our "address" tags, and convert the string into an object. You can do that all in a single line:

var xData = $($.XMLtoString(xml)).find("address");


If you are not already aware of this, encapsulating a string with $(), converts it to an object (with jQuery).

Now we have all the data we want from the XML document, but we need to create our new XML document to contain the data within. Now for some reason (which I am yet to investigate), the first element in a newly created object is removed upon creation, so we need to keep this in mind when creating it. We want a root of "", so we need to add a dummy node above that so that our one is not removed. Our code will look like this:

var xDoc = $("");


Next we need to specify where inside this new document, to inject our original data, which is done with a simple find() like so:

xDoc.find("locations").append(xData);


That's it, our data has been added to the new object. You can print it out to a textarea to view the results by calling the .html() function on the new document, so something like this:

$("#output").text(xDoc.html());


Here is what the resulting function would look like:

function parseXml(xml) {
var xData = $($.XMLtoString(xml)).find("address");
var xDoc = $("");
xDoc.find("locations").append(xData);
$("#output").text(xDoc.html());
}



As I said earlier, it's not very obvious, but when you know what to do, it's actually quite an easy task.

Friday 10 July 2009

jQuery - Searching XML

Earlier I discussed how to remove a node based on your search criteria, I will now go over briefly the different methods to select specified nodes from your XML with jQuery.

Basic selection:

var people = $(xml).find("person");


This will select all nodes with the name of "person".

Selection where attribute exists:

var people = $(xml).find("person").attr("id");


This will select all nodes with the name of "person" but which also have an attribute with the name of "id".

Selection based on attribute value:

var people = $(xml).find("person[id='1']");


This will select all nodes with the name of "person" but which also have an attribute with the name of "id" which in turn has a value of "1".

jQuery - Remove nodes based on value and attribute value

In this post we will go through the methods used to remove nodes from your XML Document/Object. To do this, we will be making use of the jQuery remove() function, along with some additional selectors.

Deleting nodes based on an attribute value is actually on of the easiest bits of code, due to the powerful selector engine in jQuery. You merely need to know the basic conditions for your search, and that's about it.

XML Example:




Philip Stone
28


Peter Jackson
32



Now let's say you want to completely remove the person node which has an ID of 2. To do that, you simply need to use:

$(xml).find("person[id='2']").remove();


Now the only thing you need to be careful with is that this will globally remove all nodes which match this criteria, so if you need to be a bit more specific, please do so, either with a more defined selector string, or some conditional statements. Speaking of conditional statements, you need to make basic use of them to remove a node based on it's value (rather than it's attributes value). So if you wanted to remove the 'name' node with the value of 'Peter Jackson', you would need:

$(xml).find("name").each(function() {
if ($(this).text() == "Peter Jackson")
$(this).remove();
});


The above code basically does a search for all name nodes, iterates through them all, checks if their value is matches our criteria, and then removes them. Obviously, as mentioned with the attribute removal, if you need additional conditional statements to be more precise in what you remove, please extend the code.

jQuery - XML to String

In my last post I demonstrated how to convert a string into XML, now I will demonstrate how to reverse this. Once again, Internet Explorer reacts differently to other web browsers, in that it requires ActiveX to do the work.

jQuery.XMLtoStr = function(xmlData) {
if (window.ActiveXObject) {
return xmlData.xml;
} else {
return (new XMLSerializer()).serializeToString(xmlData);
}
}


Usage:

$.XMLtoStr(xmlDoc);

jQuery - Create an XML Document/Object

Starting with the basics, we are going to create an XML Document/Object with JavaScript. Now as most developers should know, Internet Explorer behaves quite differently to all other web browsers, and for this, it will be no exception.

In short, Internet Explorer makes use of ActiveX to create XML, while other browsers have something called DOMParser. Now as it's not the same on every browser, we are best to create a function to create our object, and handle all the browser issues.

jQuery.strToXML = function(s) {
var xmlDoc;
if (window.ActiveXObject) {
xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
xmlDoc.async = "false";
xmlDoc.loadXML(s);
} else {
xmlDoc = (new DOMParser()).parseFromString(s, "text/xml");
}
}


Usage:

var xmlDoc = $.strToXML("");


Due to the nature of how you create the object, you can as you may have noticed also convert a regular string into an XML document (given that it is correctly structured obviously). You now have an XML Document/Object, now you can fill it up with a structure and some data.

An Introduction - jQuery and XML

I have had a few people asking me for help with numerous things related to jQuery, and have noticed that they are quite repetative questions, so I have decided to create this blog which will contain a series of tutorials with code snippets I have made, which should help bring some light on many questions.

My most recent set of questions were in regards to jQuery and XML, so I am going to go through this as best I can, and if anybody needs any further clarifications, please feel free to leave me some comments.