Back to Blog

Cross Domain Ajax Request with XML response for IE,Firefox,Chrome, Safari – jQuery

July 14, 2011

By Matt Mombrea
21 Comments

In a previous post I discussed how to accomplish cross domain JSON requests and some caveats to be aware of. That example involved a scenario in which you had control of the web service environment and were able to allow the cross domain requests on the server side. But what do you do when this isn’t an option, and furthermore,  the response is not JSON but XML?

There are two challenges here:

  1. Bypassing the cross domain AJAX request restriction
  2. Consuming and parsing the XML response

Making a cross domain request – the hard way

I say the hard way, but if you have no way of modifying the source server it may be your only option. The trick here is to use the Yahoo API library (Specifically YQL) to act as a proxy between your AJAX call and the server. This is a free, publicly available service that accepts an SQL style query for scraping web responses. If you’re struggling with this cross domain issue, you’ve no doubt tried making a request to the server you’re trying to reach via your web browser directly instead of through an AJAX request and found that it works. It’s frustrating that you can see your data in this way but not through the request that you need.

The YQL service will basically perform the same type of request that you would make directly through your web browser, then parse the results into an object and return the result to you regardless of the origin domain. This adds considerable latency due the fact that you’re now making several more web requests than you’d like and also doing some processing work, but it is what it is and can be a life saver.

Here is the function to make this indirect cross domain request via YQL:

// Accepts a url and a callback function to run.
function requestCrossDomain(site, callback) {

    // If no url was passed, exit.
    if (!site) {
        alert('No site was passed.');
        return false;
    }

    // Take the provided url, and add it to a YQL query. Make sure you encode it!
    var yql = 'http://query.yahooapis.com/v1/public/yql?q=' + encodeURIComponent('select * from xml where url="' + site + '"') + '&format=xml&callback=?';

    // Request that YSQL string, and run a callback function.
    // Pass a defined function to prevent cache-busting.
    $.getJSON(yql, cbFunc);

    function cbFunc(data) {
        // If we have something to work with...
        if (data.results[0]) {
            if (typeof callback === 'function') {
                callback(data);
            }
        }
        // Else, Maybe we requested a site that doesn't exist, and nothing returned.
        else throw new Error('Nothing returned from getJSON.');
    }
}

Note that there are some parameters you can set in the query depending on the type of data you are working with. You can read up on YQL here.

Making a cross domain request – the easy way

If you are able to modify the web service you’re working with, you can avoid the YQL work around by adding a response header to the web service response indicating that cross domain requests are OK. The header you want to add to the response is:

Access-Control-Allow-Origin: *

This will allow any website to perform AJAX requests on this service. You can restrict this to specific domains by replacing the * with the URL you want to allow.

In a .NET WCF service, it’s easiest to add this to the global.asax of your service like so:

protected void Application_BeginRequest(object sender, EventArgs e)
{
    HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin","*");
}

Consuming and Parsing the XML Response

USING YQL

Your data is going to come back as a string and you’re going to want to get that string into an XML Document so that you can parse it easily using the DOM parser. Similar to the previous article, you have to perform the task differently for IE than you do for other browsers.

function readFeed(limit) {
    requestCrossDomain('http://www.yourservice.com/xml', function (result) {
        var num = 1;

        var browserName = navigator.appName;
        var doc;
        if (browserName == 'Microsoft Internet Explorer') {
            doc = new ActiveXObject('Microsoft.XMLDOM');
            doc.async = 'false'
            doc.loadXML(result.results);
        } else {
            doc = (new DOMParser()).parseFromString(result.results, 'text/xml');
        }
        var xml = doc;

        $(xml).find('news').each(function () {

            if (num <= limit) {
                var date = $(this).attr('date');
                var headlines = $(this).find('headlines').text();
                var link = $(this).find('link').text();

                var content = "<p>" + headlines + "</p><a class='more' href='" + link + "'>continue reading</a>";
                $("#news" + num).html(content);
                num++;
            }
        });
    });
}

This code will call our requestCrossDomain() function and create the callback function to process the response. In this example, we are accepting a limit variable for processing news articles. As you can see, we start out by building an XML doc object in one of two ways depending on the browser. Then with this line:

$(xml).find('news').each(function () {

We search through the XML document using jQuery to find each root element that we’re interested in, in this case, the <news> element. For <news> element we find, store it’s children elements <date>, <headlines>, and <link> into variables for use in our HTML content. What you do here will depend on your data and goals but the same principals apply.

NOT USING YQL

If you do not need to use YQL because you have added the header

Access-Control-Allow-Origin: *

Then you can make a standard AJAX call like so:

function readFeed(limit) {
    $.get('http://www.yourservice.com/xml', function (result) {
        var num = 1;

        var browserName = navigator.appName;
        var doc;
        if (browserName == 'Microsoft Internet Explorer') {
            doc = new ActiveXObject('Microsoft.XMLDOM');
            doc.async = 'false'
            doc.loadXML(result.results);
        } else {
            doc = (new DOMParser()).parseFromString(result.results, 'text/xml');
        }
        var xml = doc;

        $(xml).find('news').each(function () {

            if (num <= limit) {
                var date = $(this).attr('date');
                var headlines = $(this).find('headlines').text();
                var link = $(this).find('link').text();

                var content = "<p>" + headlines + "</p><a class='more' href='" + link + "'>continue reading</a>";
                $("#news" + num).html(content);
                num++;
            }
        });
    });
}
Matt Mombrea

Matt Mombrea

Matt is a longtime entrepreneur and software engineer. He also sits on the board of Computer Science at SUNY Fredonia. Born and raised in Buffalo, Matt is passionate about building and maintaining great businesses in Buffalo. Apart from leading Cypress North, Matt architects our company’s datacenter, engineers dozens of custom applications, and directs the rest of the development team.

See Matt's Most Recent Posts

Share this post

21 comments

bohus September 12, 2014Reply

Hi, i try easy way without yql but then i dont get any result. Where must i put Access-Control-Allow-Origin: * ? Im using php

swa September 5, 2013Reply

Please look at this code

$.ajax({
url:”http://polymerupdate.com/web/news-desk.asmx/PCWReports”,
dataType: ‘jsonp’, // Notice! JSONP <– P (lowercase)
success:function(responce){
// do stuff with json (in this case an array)
alert(XML);
},
error:function(jqXHR, textStatus, errorThrown,responce){
alert(textStatus)
}
});

Brice Durand July 29, 2013Reply

Thanks Matt!

I’ve got another issue, my request is not on port 80 and I get an error from Yahoo :

Invalid URL http://my-url:8086/bla : Invalid HTTP destination port

(I replaced the URL by a fake one obviously, but the real url returns a valid XML)

Did they block other ports? Any way to get around this?

Matthew Mombrea July 29, 2013Reply

Brice,

It looks like a recent yahoo update is causing the issue, I’m not sure if they are going to correct or if it’s intended. http://stackoverflow.com/questions/16599722/cant-request-xml-from-url-invalid-http-destination-port

venkat July 20, 2013Reply

Hi,

Thanks for you Code.

My Code:

// Accepts a url and a callback function to run.
function requestCrossDomain(site, callback) {

// If no url was passed, exit.
alert(site);
if (!site) {
alert(‘No site was passed.’);
return false;
}

// Take the provided url, and add it to a YQL query. Make sure you encode it!
var yql = ‘http://query.yahooapis.com/v1/public/yql?q=’ + encodeURIComponent(‘select * from xml where url=”‘ + site + ‘”‘) + ‘&format=xml&callback=?’;

// Request that YSQL string, and run a callback function.
// Pass a defined function to prevent cache-busting.
$.getJSON(yql, cbFunc);

function cbFunc(data) {
// If we have something to work with…
if (data.results[0]) {
if (typeof callback === ‘function’) {
callback(data);
}
}
// Else, Maybe we requested a site that doesn’t exist, and nothing returned.
else {//throw new Error(‘Nothing returned from getJSON.’);
alert(‘Failure’);
}
}
}

It is not work for me .

Where i am wrong this code.

Thanks,
Venkat

Hardik Patel January 26, 2013Reply

Thanks a lot.
Firefox ajax query is working for cross domain

George November 13, 2012Reply

Huge help! Thank you very much!

Cross Site Request with Ajax | … Tech Addicted ! June 29, 2012Reply

[…] Here is a good link about Cross Site Domain request via Ajax. Share this:ShareTwitterLinkedInLike this:LikeBe the first to like this. […]

Haseeb June 9, 2012Reply

Error: could not load the page.

Here is my code:
//feel free to add querystring vars to this
var site = “http://www.edreams.es/edreams/espanol/hotels/bookingEngine/partners/HotelSearch.jhtml?mktportal=tradedoubler&city=Madrid&checkInDate=10062012&checkOutDate=12062012&rooms=1&adults=2&childs=1&utm_campaign=tradedoubler-15407”;

var yql = ‘http://query.yahooapis.com/v1/public/yql?q=’ + encodeURIComponent(‘select * from xml where url=”‘ + site + ‘”‘) + ‘&format=xml&callback=?’;

//make the call to YQL
$.getJSON(yql,
function (data) {
if (data.results[0]) {
//this data.results[0] is the return object you work with,
//if you actually want to do something with the returned json
alert(data.results[0]);
} else {
var errormsg = ‘Error: could not load the page.’;
//output to firebug’s console
//use alert() for other browsers/setups
console.log(errormsg);
}
}
);

Matt Mombrea June 9, 2012Reply

Haseeb,

It doesn’t look like your site url is returning anything, just an error message.

Regardless, I was able to get a response by using the code above. Here is the JS Fiddle of the script:
http://jsfiddle.net/NdkPU/

Rohit April 17, 2012Reply

Awesome Stuff Man !! YQL worked for me!

Doug April 13, 2012Reply

sorry, when i said i copied and pasted i did change the site to my site.

Doug April 13, 2012Reply

I copied and pasted your code, and added the header to the response, and it doesn’t work. I get a XML parse error. I verified that the xml is valid (i can hit the url directly in browser and it works and is valid xml) If i step through it with firebug, i get to the method function cbFunc(data) and it goes to that else else throw new Error(‘Nothing returned from getJSON.’);

Matt Mombrea April 13, 2012Reply

If you get an XML Parse error there is probably something being returned in the XML that the Parser doesn’t like. Take a look at cleaning up any invalid characters etc. in the XML response.

Doug April 13, 2012Reply

I did look at the xml and it has no problems. I even took the xml and pasted it in a xml file locally in my project and hit that instead of the url and it works

Doug April 13, 2012Reply

Sorry, i misspoke on my first comment, the parse xml error was before i implemented this sites code. With the code from this site, no error that i can see, but the cbFunc method has 0 results. Which according to the site means the site doesn’t exist, but it does and i can hit it and get back xml in browser.

Matt Mombrea April 13, 2012

Doug, I think I see the issue. It looks like in my example for the section “The Easy Way” I’m still calling the function that executed the YQL call. That is a mistake. The Easy Way should not use YQL, just a standard AJAX request. Try changing the first line in the readFeed function from:

requestCrossDomain(‘http://www.yourservice.com/xml’, function (result) {

to

$.get(‘http://www.yourservice.com/xml’, function (result) {

JDB February 24, 2012Reply

dude, this was a lifesaver. Thanks!

KntL October 1, 2011Reply

a nice lifesaver article. thank you!

John July 29, 2011Reply

Thank for the info, very good read!

Leave a Reply

Search our blog

Start A Project

Categories

What's next?

Well...you might like one of these

Article

How To Exclude Mobile Apps From AdWords...

If you're like me, you probably wish there were sweeping,...

Read article

Article

Celebrating “New” This Week...

As a journalist, I was taught not to bury the lead, so I...

Read article

Article

Facebook’s Pay-to-Play Model: Why...

The goal of any type of marketing is to sell product....

Read article