jfhovinne

JSS: JavaScript Simple Syndication

2007-07-16

jFeed, the jQuery RSS/ATOM feed parser plugin I wrote lately has a drawback: you must use a server-side proxy to load cross-domain feeds.

It's a little bit annoying, so I looked for a more elegant solution.

There exist some web services and libraries that convert RSS/ATOM feeds to JavaScript code, so you can embed external content in your HTML document, but I'd prefer something more generic.

Another JSS proposal is to convert XML data (e.g. RSS) to JSON at the server-side, and to dynamically load it as a JS script at the client side.

There's a XSLT to do the conversion from XML to JSON, XSLTJSON, but unfortunately it uses XSLT 2.0, which isn't very wide-spread at the moment.

So I searched for another solution and got the best results with the BadgerFish convention, implemented (among others) in PHP.

I wrote a simple PHP class to use it:

<?php
require_once('BadgerFish.php');

class JSS {
   public static function encode($url, $callback) {
       $doc = new DOMDocument;
       $doc->load($url);
       $out = BadgerFish::encode($doc);
       return($callback . '(' . $out . ');');
   }
}
?>

JSS::encode loads the local or external XML document, applies the BadgerFish transformation, and returns the JSON data as the callback function argument, in the form:

callback({...JSON data...});

Note: the external JS script will be loaded asynchronously, thus we need a callback function.

This is the actual PHP file which will output the data:

<?php
require_once('jss/JSS.php');

$callback = $_REQUEST['callback'];
$url = 'rss.xml';

header("Content-Type: application/x-javascript");
echo(JSS::encode($url, $callback));
?>

And now the client-side JavaScript part:

var JSS = {

   counter: -1,
   getFeed: function(url, callback) {

       this.counter ++;
       JSS[this.counter] = callback;
       var body = document.getElementsByTagName('body')[0];
       var script = document.createElement('script');
       script.type = 'text/javascript';
       script.src = url + '?callback=JSS[' + this.counter + ']';
       body.appendChild(script);
   }
};

We append the external script in the document's BODY, passing the callback function name in the query, in the form:

<script type="text/javascript" src="...url...?callback=JSS[counter]"></script>

And finally, the HTML document which will import the JSON data and execute the callback:

<!DOCTYPE ...
<html>
<head>
...
<script type="text/javascript">
function initJss() {
   JSS.getFeed('http://www.hovinne.net/feed/jss.php', function(data) {
       console.log(data); //use Firebug console
   });
};
</script>
</head>
<body onload="initJss();">
...
</body>
</html>

A JSS implementation example is available, as well as the JSS source code, licensed under MIT license.

Next step: parse the JSON feeds with jFeed !