<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>uxebu » blog &#187; spreadsheet</title>
	<atom:link href="http://uxebu.com/tag/spreadsheet/feed/" rel="self" type="application/rss+xml" />
	<link>http://uxebu.com/blog</link>
	<description></description>
	<lastBuildDate>Mon, 23 Apr 2012 19:10:55 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<item>
		<title>JSONP for Google spreadsheets</title>
		<link>http://uxebu.com/blog/2009/04/30/jsonp-for-google-spreadsheets/</link>
		<comments>http://uxebu.com/blog/2009/04/30/jsonp-for-google-spreadsheets/#comments</comments>
		<pubDate>Thu, 30 Apr 2009 11:33:20 +0000</pubDate>
		<dc:creator>wolfram</dc:creator>
				<category><![CDATA[development tools]]></category>
		<category><![CDATA[dojo]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[uxebu]]></category>
		<category><![CDATA[google]]></category>
		<category><![CDATA[jsonp]]></category>
		<category><![CDATA[mashup]]></category>
		<category><![CDATA[spreadsheet]]></category>

		<guid isPermaLink="false">http://blog.uxebu.com/?p=343</guid>
		<description><![CDATA[Nikolai said yesterday &#8220;Is Google spreadsheet becoming the new Microsoft Access?&#8221;. You know the visual database and form designer. Well, for the web and pure mashup apps, that are mainly or completely based on the web&#8217;s infrastructure, so to say cloud services, one could answer &#8220;Yes, it can cover at least the database part&#8221;. It [...]]]></description>
			<content:encoded><![CDATA[<p>Nikolai said yesterday &#8220;Is Google spreadsheet becoming the new Microsoft Access?&#8221;. You know the visual database and form designer. Well, for the web and pure mashup apps, that are mainly or completely based on the web&#8217;s infrastructure, so to say cloud services, one could answer &#8220;Yes, it can cover at least the database part&#8221;. It may be poor in features, but a nice start.<br />
Well all this buzzy stuff aside, read on to see how to use JSONP with a Google spreadsheet, even though it&#8217;s not exactly provided.<br />
<span id="more-343"></span></p>
<p>For me as a front end engineer and JavaScript lover I always think twice before I set up a server system with a database and some Python or PHP code in between which then provides me with the data I need. This is painful, actually too much work for a lazy front-end dev  like me, I would also have to do the permission handling and let alone the maintenance. Of course there are projects where it is not possible to store everything in the cloud, as what would be the solution I would favor over the before mentioned server infrastructure. (Let me just get this straight: by storing in the cloud I mean storing my data on mashable online services, which I can access via JavaScript, you will see in a second.)<br />
Ideally JSONP is the solution of choice for getting the data, but sometimes there is not this choice and you have to look around for other ways.</p>
<h2>Why JSONP?</h2>
<p>The easiest and probably most relevant reason why to use JSONP (<a href="http://bob.pythonmac.org/archives/2005/12/05/remote-json-jsonp/">read here how it started</a>), is that it is native JavaScript. There is no mapping from one format to another required, so you get natural performance. Second it is just a simple technique for cross-domain communication. And you don&#8217;t have to setup no complicated event handling for getting informed about when the data are loaded, it&#8217;s all handled. </p>
<h2>Google spreadsheet</h2>
<p>Let&#8217;s take <a href="http://spreadsheets.google.com/pub?key=rai4OXpsbS2Bc04lWn575ZA">this tiny spreadsheet</a>, it contains the data I want to request, e.g. for showing on the uxebu.com website.<br />
<iframe width='95%' height='200' frameborder='0' style="margin:1em 0; border:1px outset grey;" src='http://spreadsheets.google.com/pub?key=rai4OXpsbS2Bc04lWn575ZA&#038;output=html&#038;widget=true'></iframe><br />
This spreadsheet is really easy to maintain, no geek knowledge is required for that, and this is the great thing about it. If that can serve as the data source for a web service or widget it just makes maintenance so much easier, and you can also tell your customer &#8220;just change the data as you like&#8221;. It&#8217;s not only, that changing is easy, also the permission handling is just a couple of clicks away. The data are hosted on one of the best working networks and you can be pretty sure that if you have no high-traffic site, that those data will just always be served at awesome speed. Enough reasons? I think so.</p>
<h2>How to get the data</h2>
<p>The <a href="http://code.google.com/apis/spreadsheets/docs/2.0/reference.html">google docs</a> unfortunately show nothing really nice about JSONP. Yes you can make the ATOM feed of the spreadsheet be <a href="http://spreadsheets.google.com/feeds/list/rai4OXpsbS2Bc04lWn575ZA/default/public/basic?alt=json-in-script">served as JSONP</a>, but look at the data format (better don&#8217;t :-)), it really is not what you expect when working with JSON. The data are linear in there, so you have to apply the logic that actually the spreadsheet has in it again to reformat the data, and may be convert and take them apart again. Just believe me it&#8217;s not what one expects. If you like the pain, try it out.<br />
And there is the CSV export of the data, that I always loved for it&#8217;s simplicity. Just add <code class="codecolorer text mac-classic"><span class="text">&amp;amp;output=csv</span></code> to the URL and you get your <a href="http://spreadsheets.google.com/ccc?key=rai4OXpsbS2Bc04lWn575ZA&#038;output=csv">spreadsheet as CSV</a>. Very nice. Unfortunately trying to load those data using <code class="codecolorer text mac-classic"><span class="text">dojo.io.script.get</span></code> of course fails:<br />
<div id="attachment_362" class="wp-caption alignleft" style="width: 619px">
<div class="mhx"><a href="http://hub.uxebu.com:33550/wp-content/uploads/2009/04/csv-load-fail.jpg"><img src="http://hub.uxebu.com:33550/wp-content/uploads/2009/04/csv-load-fail.jpg" alt="CSV loading fails" title="csv-load-fail" width="609" height="169" class="size-full wp-image-362" /></a></div>
<p><p class="wp-caption-text">CSV loading fails</p></div></p>
<p>Well, trying doesn&#8217;t cost a dime. Of course, I tried this first, though it was clear that it wouldn&#8217;t work.<br />
I didn&#8217;t want to give up on this nice format, it has all the goodies, the lines, columns of the spreadsheet, no overhead, easily human-readable (which is always nice for finding errors in the parsing process) and it just maps so well to JSON. That&#8217;s the clue, it maps to JSON, now I just need to get that done. And since I didn&#8217;t want to add the overhead of passing the data through a Yahoo! Pipe just for getting a JSONP format I thought, why not make the CSV look like JSONP. The two formats are close enough.</p>
<h2>JSONPed CSV</h2>
<p>After trying a little bit and seeing the result that google spit out and fixing it again I had the solution (<a href="http://spreadsheets.google.com/pub?key=rmlQvp80ksEJg6r49fJhjuw&#038;output=csv">the spreadsheet below</a>), pretty easy actually.<br />
<iframe width='95%' height='200' frameborder='0' style="margin:1em 0; border:1px outset grey;" src='http://spreadsheets.google.com/pub?key=rmlQvp80ksEJg6r49fJhjuw&#038;output=html&#038;widget=true'></iframe><br />
The CSV format is already comma separated, that is kind of half the way to JSON. At least the comma will make sure that we can distinguish the columns from one another. I ended up adding the callback name to the first cell on the left like this <code class="codecolorer text mac-classic"><span class="text">__callbackFunctionName__('</span></code> the opening parentheses and the apostrophe starts the function call that will be made inside the script tag you load it into. Now you can already guess that either every cell is surrounded by apostrophes, but that would just be too much hazzle and too error-prone, so I decided to just add a column before and one behind the data, when parsing the CSV those will just be dismissed, since they won&#8217;t contain a headline, therefore have no key to map the data to.<br />
The last line is a little special, it contains the extra cell containing <code class="codecolorer text mac-classic"><span class="text">0);</span></code> which is closing the function, this is actually only there to create an extra column, where each line has just a space in it, so we get the comma at the end of every line. So that in the end our <a href="http://spreadsheets.google.com/pub?key=rmlQvp80ksEJg6r49fJhjuw&#038;output=csv">JSONPed CSV</a> (the <a href="http://spreadsheets.google.com/pub?key=rmlQvp80ksEJg6r49fJhjuw">human-readable version here</a>) looks just like this:</p>
<div class="codecolorer-container javascript twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br /></div></td><td><div class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">__cfn__<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">',name,url,status,irc, '</span><span style="color: #339933;">,</span> &nbsp;<br />
&nbsp;<span style="color: #3366CC;">',dojango,http://dojango.org,released,http://mibbit.com/chat/?server=irc.freenode.net&amp;channel=%23dojango, '</span><span style="color: #339933;">,</span> &nbsp;<br />
&nbsp;<span style="color: #3366CC;">',dojodocs,http://dojodocs.uxebu.com,preview,, '</span><span style="color: #339933;">,</span> &nbsp;<br />
&nbsp;<span style="color: #3366CC;">',dools,http://code.google.com/p/dools,in progress,, '</span><span style="color: #339933;">,</span> &nbsp;<br />
&nbsp;<span style="color: #3366CC;">',xray,http://code.google.com/p/xray-project/,alpha,http://mibbit.com/chat/?server=irc.freenode.net&amp;channel=%23xray, '</span><span style="color: #339933;">,</span> &nbsp;<br />
&nbsp;<span style="color: #3366CC;">',d.js,http://code.google.com/p/ddotjs/,unreleased,, '</span><span style="color: #339933;">,</span><span style="color: #CC0000;">0</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></td></tr></tbody></table></div>
<h2>The client</h2>
<p>Every line is now a parameter for our callback function. Simply use dojo&#8217;s <code class="codecolorer text mac-classic"><span class="text">dojo.io.script.get()</span></code> hook onto the callback function and we got our spreadsheet data in any site within JavaScript. A little after-parsing and done.<br />
The dojo source code may look like this:</p>
<div class="codecolorer-container javascript twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:300px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br /></div></td><td><div class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">dojo.<span style="color: #660066;">require</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;dojo.io.script&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
dojo.<span style="color: #660066;">addOnLoad</span><span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #003366; font-weight: bold;">var</span> url <span style="color: #339933;">=</span> <span style="color: #3366CC;">&quot;http://spreadsheets.google.com/pub?key=rmlQvp80ksEJg6r49fJhjuw&amp;output=csv&quot;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; dojo.<span style="color: #660066;">io</span>.<span style="color: #660066;">script</span>.<span style="color: #660066;">get</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#123;</span>url<span style="color: #339933;">:</span>url<span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; dojo.<span style="color: #660066;">connect</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;__cfn__&quot;</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #003366; font-weight: bold;">var</span> args <span style="color: #339933;">=</span> dojo._toArray<span style="color: #009900;">&#40;</span>arguments<span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; colNames <span style="color: #339933;">=</span> args<span style="color: #009900;">&#91;</span><span style="color: #CC0000;">0</span><span style="color: #009900;">&#93;</span>.<span style="color: #660066;">split</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;,&quot;</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">slice</span><span style="color: #009900;">&#40;</span><span style="color: #CC0000;">1</span><span style="color: #339933;">,</span> <span style="color: #339933;">-</span><span style="color: #CC0000;">1</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; data <span style="color: #339933;">=</span> <span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000066; font-weight: bold;">for</span> <span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">var</span> i<span style="color: #339933;">=</span><span style="color: #CC0000;">1</span><span style="color: #339933;">,</span> l<span style="color: #339933;">=</span>args.<span style="color: #660066;">length</span><span style="color: #339933;">-</span><span style="color: #CC0000;">1</span><span style="color: #339933;">,</span> d<span style="color: #339933;">;</span> i<span style="color: #339933;">&lt;</span>l<span style="color: #339933;">;</span> i<span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #006600; font-style: italic;">// Convert the data using the colNames to an object.</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #006600; font-style: italic;">// (Might be an esoteric step, but correct this way.)</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; d <span style="color: #339933;">=</span> <span style="color: #009900;">&#123;</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; dojo.<span style="color: #660066;">forEach</span><span style="color: #009900;">&#40;</span>args<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span>.<span style="color: #660066;">split</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;,&quot;</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">slice</span><span style="color: #009900;">&#40;</span><span style="color: #CC0000;">1</span><span style="color: #339933;">,</span> <span style="color: #339933;">-</span><span style="color: #CC0000;">1</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">item</span><span style="color: #339933;">,</span> index<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #006600; font-style: italic;">// Do some CSV conversion.</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000066; font-weight: bold;">item</span> <span style="color: #339933;">=</span> <span style="color: #000066; font-weight: bold;">item</span>.<span style="color: #660066;">replace</span><span style="color: #009900;">&#40;</span><span style="color: #009966; font-style: italic;">/&quot;&quot;/g</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">'&quot;'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">item</span>.<span style="color: #660066;">charAt</span><span style="color: #009900;">&#40;</span><span style="color: #CC0000;">0</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">==</span><span style="color: #3366CC;">'&quot;'</span> <span style="color: #339933;">&amp;&amp;</span> <span style="color: #000066; font-weight: bold;">item</span>.<span style="color: #660066;">charAt</span><span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">item</span>.<span style="color: #660066;">length</span><span style="color: #339933;">-</span><span style="color: #CC0000;">1</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">==</span><span style="color: #3366CC;">'&quot;'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000066; font-weight: bold;">item</span> <span style="color: #339933;">=</span> <span style="color: #000066; font-weight: bold;">item</span>.<span style="color: #660066;">substr</span><span style="color: #009900;">&#40;</span><span style="color: #CC0000;">1</span><span style="color: #339933;">,</span> <span style="color: #000066; font-weight: bold;">item</span>.<span style="color: #660066;">length</span><span style="color: #339933;">-</span><span style="color: #CC0000;">2</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; d<span style="color: #009900;">&#91;</span>colNames<span style="color: #009900;">&#91;</span>index<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #000066; font-weight: bold;">item</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; data.<span style="color: #660066;">push</span><span style="color: #009900;">&#40;</span>d<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; dojo.<span style="color: #660066;">query</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;.theProjects&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#91;</span><span style="color: #CC0000;">0</span><span style="color: #009900;">&#93;</span>.<span style="color: #660066;">innerHTML</span> <span style="color: #339933;">=</span> dojo.<span style="color: #660066;">toJson</span><span style="color: #009900;">&#40;</span>data<span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">true</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></td></tr></tbody></table></div>
<p>You can <a href="http://static.uxebu.com/~cain/JSONPedCSV.html">download and try out a test page here</a>.</p>
<p>Of course, there are a couple of drawbacks.</p>
<ol>
<li>
You have to make the spreadsheet adhere to a certain style, the first column, the last column, etc. and one error in there may break it entirely. So there is not much fault tolerance. Additionally you are not supposed to use new lines in the content of the spreadsheet!
</li>
<li>The callback name is fix, though if you are using this sheet in one app this should be ok.
</li>
</ol>
<p>But see the advantages, you get permission handling for editors for free, you can let your customer edit the data without your involvement and so on. As always, when the use case requires this solution you can pull it out of your sleeve.<br />
Oh, the source code above is also still not handling the escaped commas I guess, so there are still places where this can be improved.</p>
<h2>Further thinking</h2>
<p>Another way I though about was simply only surrounding the CSV by /* and */ which would relieve us from any JavaScript parsing error, since everything is a comment. But my quick test using innerHTML didn&#8217;t work. And innerHTML is not that relieable anyway so it might be better I didn&#8217;t waste more time on it. May be loading this into CSS tag enables us reading the data back &#8230; I don&#8217;t know, those are just random thoughts.<br />
Another thought Nikolai had was &#8220;A spreadsheet-based CMS&#8221;. Of course, why not. You can basically store any kind of data in the spreadsheet, even HTML if you really would want to.</p>
<p>This can spin of more discussions and interesting ideas, let&#8217;s see what the future will bring.<br />
The web is becoming more fun every day!</p>
]]></content:encoded>
			<wfw:commentRss>http://uxebu.com/blog/2009/04/30/jsonp-for-google-spreadsheets/feed/</wfw:commentRss>
		<slash:comments>20</slash:comments>
		</item>
	</channel>
</rss>

