Loading XML cross-sub-domain with Javascript

Jan. 16, 2010, 3 p.m.

Loading XML with Javascript from a different site is generally infeasible due to the same origin policy in browsers. Access-Control nicely enables cross domain calls but is not (yet) supported by all browsers in use today.

However, you can load XML cross-sub-domain if you can add an XSLT to the XML.

And here is how

Suppose we run a site www.foo.com and would like to poll data from livedata.foo.com using Javascript. In our script on www.foo.com, we set document.domain to foo.com, provide a callback function receive_data and load the feed into a (hidden) iframe:

document.domain = 'foo.com'; // set to parent domain

function receive_data(data) {
 // display live data from http://livedata.foo.com/data.xml

var proxy = document.createElement('iframe');
proxy.src = 'http://livedata.foo.com/data.xml';

That works fine, the data from livedata.foo.com is correctly loaded into the (hidden) iframe. However, access to the iframe is denied because the two document.domains differ. We need to set the iframe's document.domain to foo.com which is tricky with an XML source but can be done using the following XSL on livedata.foo.com:

<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
 <xsl:template match="root">
   <script type="text/javascript">
    document.domain = 'foo.com';
 <!-- put templates that transform data into JSON here -->

This stylesheet transforms the iframe's xml source into a HTML document that contains a Javascript that sets the document.domain to foo.com. We now have access to the iframe and can use the data from livedata.foo.com on www.foo.com. Of course, since we are going to process that data using Javascript, we can convert it to JSON right here in the XSLT and send it to the parent by calling its receive_data callback.


This iframe-proxy/xslt/jsonp inspired hack obviously requires the browser to have XSLT-skillz but it actually works in most of the browsers we support, including IE6+, FF1.5+, and Opera8+. Both Safari and Chrome's security is too restrictive in this case but both support Access-Control which makes this fallback-hack unnecessary.

Unfortunately we eventually decided on a server-side proxy solution (cache & aggregation benefits) so I have no idea how this works in the real world but if you find out, let me know.