<!DOCTYPE html> <?xml version="1.0" encoding="utf-8"?><html lang="en"><head><meta charset="utf-8"><link rel="canonical" href="https://www.onperl.org/blog/onperl/page/rayfish"><title>On Perl :: Index</title><meta name="description" content="This is a site on Perl."><link rel="shortcut icon" href="/blog/onperl/page/favicon.ico"><script src="/scripts/common.js"></script><style type="text/css" media="all">@import "/styles/clean.css";</style><meta name="robots" content="follow,index,noarchive"><meta name="viewport" content="width=device-width,initial-scale=1"></head><body><div id="boundary"><a href="/"><img loading="lazy" id="mast" src="/images/onperl.png" alt="onperl"></a><div id="sidebar"><div></div><div class="navigation"><div class="link"><a href="/blog/onperl/latest/10">recent</a></div><div class="link"><a href="/blog/onperl/archive/10">archive</a></div><div class="link"><a href="/blog/onperl/page/about">about</a></div><div class="link"><a href="/feed/onperl">feed</a></div><div class="link last">etc...</div></div></div><div id="content"><h1 class="post-title">Serving XML as JSON</h1><div class="post-content"><p>The <a href="http://www.json.org/">JSON</a> standard is the good way to deliver data to a JavaScript application, because it <em>is</em> JavaScript. XML is a good way to publish data because it is a popular standard. If only there were some glue to stick these two good things together...</p><p>Turns out Perl is a good way to glue. So here's a little script that will run as a CGI to deliver an XML document as a JSON object. It does this on-the-fly using <a href="/resources/rayfish.xsl">a XSL stylesheet</a> and the <a href="http://www.annocpan.org/~PAVELH/XML-Sablotron-1.01">XML-Sablotron</a> module.</p><p>The trick is to set the URL of this script to be the source of your <code>script</code>tag.</p><pre class="code">
&lt;script src="http://example.com/cgi-bin/json.pl?foo=data.xml"&gt;
&lt;/script&gt;
</pre><p>Notice the query-string stuck on the end of the URL. It has two parts: the first is the name of the JavaScript variable that will hold the JSON object, and the other is the XML document on the server that will be transformed. So, if things are working as they should, if we have a file named "data.xml" like the one below...</p><pre class="code">

&lt;books&gt;
  &lt;fiction&gt;
    &lt;title&gt;Or All The Seas with Oysters&lt;/title&gt;
  &lt;/fiction&gt;
&lt;/books&gt;
</pre><p>The following would be delivered by our perl script, which is just the same data transformed into a JavaScript object...</p><pre class="code">
var foo =
{   "#name": "books",
    "#text": "",
    "#children": [
    {   "#name": "fiction",
        "#text": "",
        "#children": [
        {   "#name": "title",
            "#text": "Or All The Seas with Oysters",
            "#children": [
            ]
        }
        ]
    }
    ]
}
;
</pre><p>And then we have the source for "json.pl" which uses Sablotron, but any XSLT software should work as well...</p><pre class="code">
#!/usr/bin/perl

use strict;
use warnings;

use CGI;
use CGI::Carp qw(fatalsToBrowser);
use XML::Sablotron qw(:all);

my $cgi = new CGI;
my $sab = new XML::Sablotron();

my $data_name = shift @{[$cgi-&gt;param()]};
my $data_file = $cgi-&gt;param($data_name);

# I'll leave real security checks up to you...
$data_name =~ s/[^a-zA-Z0-9_]//g;
$data_file =~ s/\.\.//g;

$sab-&gt;runProcessor('rayfish.xsl', $data_file,
                   'arg:/result', undef, undef);
my $result = $sab-&gt;getResultArg('arg:/result');

print $cgi-&gt;header('application/x-javascript');
unless($result) {
        print "alert('Error getting the XML data.');\n";
}
else { print "var $data_name = \n$result" }
</pre><p>If you're wondering what to do with that blob of JSON data you'll have to wait for the next entry on this, which will link to a JavaScript path language for querying JSON objects, but that is for another day.</p></div></div><div id="footer">© <a href="mailto:michael@mathews.net">michael mathews</a></div></div></body></html>