<?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>We Heart Code &#187; tutorial</title>
	<atom:link href="http://www.weheartcode.com/category/tutorial/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.weheartcode.com</link>
	<description>A discourse on programming</description>
	<lastBuildDate>Sun, 17 Jan 2010 02:16:44 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.4</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Easily Creating Fixed Length Flat Files With Groovy</title>
		<link>http://www.weheartcode.com/2009/01/21/easily-creating-fixed-length-flat-files-with-groovy/</link>
		<comments>http://www.weheartcode.com/2009/01/21/easily-creating-fixed-length-flat-files-with-groovy/#comments</comments>
		<pubDate>Wed, 21 Jan 2009 13:42:27 +0000</pubDate>
		<dc:creator>Tim</dc:creator>
				<category><![CDATA[groovy]]></category>
		<category><![CDATA[tip]]></category>
		<category><![CDATA[tutorial]]></category>

		<guid isPermaLink="false">http://www.weheartcode.com/2009/01/21/easily-creating-fixed-length-flat-files-with-groovy/</guid>
		<description><![CDATA[Here's an (I think elegant) way to create flat files with Groovy.
I want this script to be easy to read by future developers. So if someone wants to know what the format of the file is they can see it just by opening the script.
Classes We'll Use
Groovy:

SQL: We'll use this library to access the database, [...]]]></description>
			<content:encoded><![CDATA[<p>Here's an (I think elegant) way to create flat files with Groovy.</p>
<p>I want this script to be easy to read by future developers. So if someone wants to know what the format of the file is they can see it just by opening the script.</p>
<h2>Classes We'll Use</h2>
<p>Groovy:</p>
<ul>
<li><a href="http://docs.codehaus.org/display/GROOVY/Tutorial+6+-+Groovy+SQL">SQL</a>: We'll use this library to access the database, it has some nice closure methods like eachRow which make iterating over results easy.</li>
<li><a href="http://groovy.codehaus.org/groovy-jdk/java/lang/String.html">String</a>: Groovy includes a string class that has some nice methods like padRight and padLeft, handy for making fixed length files.</li>
</ul>
<p>Java:</p>
<ul>
<li><a href="http://java.sun.com/j2se/1.5.0/docs/api/java/io/FileWriter.html">File Writer</a>: The easiest way to create files in java.</li>
</ul>
<h2>The Plan</h2>
<p>Define our file in a map at the top of the file, it will be SQL Alias Name : Length.</p>
<p>Execute our SQL, for each row iterate through our file definition map and pad each value by the appropriate length.</p>
<h2>The Code</h2>
<p>Pretty self explanatory -- a few neat groovy things we use in this script:</p>
<ul>
<li>Triple quotes for a multiline string (our sql)</li>
<li>The format method to easily format a date (bye bye simple date format) for the file name</li>
<li>The elvis operator <code>?:</code> makes the results null safe so we can call padRight.</li>
<li>The each method on Groovy's Map that accepts a closure, we use that to iterate through our file definition.</li>
</ul>
<div class="syntax_hilite">
<div id="java-2">
<div class="java"><span style="color: #a1a100;">import groovy.sql.Sql</span></p>
<p><span style="color: #a1a100;">import java.io.File;</span><br />
<span style="color: #a1a100;">import java.io.FileWriter;</span></p>
<p>&nbsp; &nbsp; def fileName = <span style="color: #ff0000;">"FLATFILE"</span> + <a href="http://www.google.com/search?q=allinurl%3AString+java.sun.com&amp;bntl=1"><span style="color: #aaaadd; font-weight: bold;">String</span></a>.<span style="color: #006600;">format</span><span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'%tY%&lt;tm%&lt;td'</span>,<span style="color: #000000; font-weight: bold;">new</span> <a href="http://www.google.com/search?q=allinurl%3ADate+java.sun.com&amp;bntl=1"><span style="color: #aaaadd; font-weight: bold;">Date</span></a><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span> + <span style="color: #ff0000;">".txt"</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; def sql = Sql.<span style="color: #006600;">newInstance</span><span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">"jdbc:oracle:thin:@localhost:1521:midb01"</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff0000;">"xxx"</span>,<span style="color: #ff0000;">"xxx"</span>, <span style="color: #808080; font-style: italic;">//user,pass</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff0000;">"oracle.jdbc.driver.OracleDriver"</span><span style="color: #66cc66;">&#41;</span> <span style="color: #808080; font-style: italic;">//jdbc driver</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <a href="http://www.google.com/search?q=allinurl%3AFileWriter+java.sun.com&amp;bntl=1"><span style="color: #aaaadd; font-weight: bold;">FileWriter</span></a> writer = <span style="color: #000000; font-weight: bold;">new</span> <a href="http://www.google.com/search?q=allinurl%3AFileWriter+java.sun.com&amp;bntl=1"><span style="color: #aaaadd; font-weight: bold;">FileWriter</span></a><span style="color: #66cc66;">&#40;</span>fileName<span style="color: #66cc66;">&#41;</span>;<br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;">//this map defines the field length based on alias id from the SQL</span><br />
&nbsp; &nbsp; def fileDef = <span style="color: #66cc66;">&#91;</span>COLUMN1:<span style="color: #cc66cc;">14</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; COLUMN2:<span style="color: #cc66cc;">9</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; COLUMN3:<span style="color: #cc66cc;">5</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; COLUMN4:<span style="color: #cc66cc;">16</span><span style="color: #66cc66;">&#93;</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; def qry = <span style="color: #ff0000;">""</span><span style="color: #ff0000;">"SELECT column1,column2,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; column3,column4 FROM OurTable"</span><span style="color: #ff0000;">""</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; def test = sql.<span style="color: #006600;">eachRow</span><span style="color: #66cc66;">&#40;</span>qry<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#123;</span>row -&gt; <br />
&nbsp; &nbsp; &nbsp; &nbsp; fileDef.<span style="color: #006600;">each</span><span style="color: #66cc66;">&#123;</span> k,v-&gt; writer.<span style="color: #006600;">append</span> <span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#40;</span>row<span style="color: #66cc66;">&#91;</span>k<span style="color: #66cc66;">&#93;</span> ?: <span style="color: #ff0000;">" "</span><span style="color: #66cc66;">&#41;</span>.<span style="color: #006600;">padRight</span><span style="color: #66cc66;">&#40;</span>v<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; writer.<span style="color: #006600;">append</span> <span style="color: #ff0000;">"<span style="color: #000099; font-weight: bold;">\n</span>"</span><br />
&nbsp; &nbsp; <span style="color: #66cc66;">&#125;</span><br />
&nbsp; &nbsp; writer.<span style="color: #006600;">close</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span></div>
</div>
</div>
<p></p>
<!-- Social Bookmarks BEGIN --><div class="social_bookmark"><em>Bookmark to:</em><br /><a class="social_img" onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://del.icio.us/post?url=http://www.weheartcode.com/2009/01/21/easily-creating-fixed-length-flat-files-with-groovy/&amp;title=Easily+Creating+Fixed+Length+Flat+Files+With+Groovy" title="Add 'Easily Creating Fixed Length Flat Files With Groovy' to Del.icio.us"><img src="http://www.weheartcode.com/wp-content/plugins/social_bookmarks/delicious.png" title="Add 'Easily Creating Fixed Length Flat Files With Groovy' to Del.icio.us" alt="Add 'Easily Creating Fixed Length Flat Files With Groovy' to Del.icio.us" /></a><a class="social_img" onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://digg.com/submit?phase=2&amp;url=http://www.weheartcode.com/2009/01/21/easily-creating-fixed-length-flat-files-with-groovy/&amp;title=Easily+Creating+Fixed+Length+Flat+Files+With+Groovy" title="Add 'Easily Creating Fixed Length Flat Files With Groovy' to digg"><img src="http://www.weheartcode.com/wp-content/plugins/social_bookmarks/digg.png" title="Add 'Easily Creating Fixed Length Flat Files With Groovy' to digg" alt="Add 'Easily Creating Fixed Length Flat Files With Groovy' to digg" /></a><a class="social_img" onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://furl.net/storeIt.jsp?t=Easily+Creating+Fixed+Length+Flat+Files+With+Groovy&amp;u=http://www.weheartcode.com/2009/01/21/easily-creating-fixed-length-flat-files-with-groovy/" title="Add 'Easily Creating Fixed Length Flat Files With Groovy' to FURL"><img src="http://www.weheartcode.com/wp-content/plugins/social_bookmarks/furl.png" title="Add 'Easily Creating Fixed Length Flat Files With Groovy' to FURL" alt="Add 'Easily Creating Fixed Length Flat Files With Groovy' to FURL" /></a><a class="social_img" onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://reddit.com/submit?url=http://www.weheartcode.com/2009/01/21/easily-creating-fixed-length-flat-files-with-groovy/&amp;title=Easily+Creating+Fixed+Length+Flat+Files+With+Groovy" title="Add 'Easily Creating Fixed Length Flat Files With Groovy' to reddit"><img src="http://www.weheartcode.com/wp-content/plugins/social_bookmarks/reddit.png" title="Add 'Easily Creating Fixed Length Flat Files With Groovy' to reddit" alt="Add 'Easily Creating Fixed Length Flat Files With Groovy' to reddit" /></a><a class="social_img" onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.technorati.com/faves?add=http://www.weheartcode.com/2009/01/21/easily-creating-fixed-length-flat-files-with-groovy/" title="Add 'Easily Creating Fixed Length Flat Files With Groovy' to Technorati"><img src="http://www.weheartcode.com/wp-content/plugins/social_bookmarks/technorati.png" title="Add 'Easily Creating Fixed Length Flat Files With Groovy' to Technorati" alt="Add 'Easily Creating Fixed Length Flat Files With Groovy' to Technorati" /></a><a class="social_img" onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.google.com/bookmarks/mark?op=edit&amp;output=popup&amp;bkmk=http://www.weheartcode.com/2009/01/21/easily-creating-fixed-length-flat-files-with-groovy/&amp;title=Easily+Creating+Fixed+Length+Flat+Files+With+Groovy" title="Add 'Easily Creating Fixed Length Flat Files With Groovy' to Google Bookmarks"><img src="http://www.weheartcode.com/wp-content/plugins/social_bookmarks/google.png" title="Add 'Easily Creating Fixed Length Flat Files With Groovy' to Google Bookmarks" alt="Add 'Easily Creating Fixed Length Flat Files With Groovy' to Google Bookmarks" /></a></div>
<!-- Social Bookmarks END -->]]></content:encoded>
			<wfw:commentRss>http://www.weheartcode.com/2009/01/21/easily-creating-fixed-length-flat-files-with-groovy/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Reading An Excel File With Ruby</title>
		<link>http://www.weheartcode.com/2007/10/05/reading-an-excel-file-with-ruby/</link>
		<comments>http://www.weheartcode.com/2007/10/05/reading-an-excel-file-with-ruby/#comments</comments>
		<pubDate>Fri, 05 Oct 2007 13:31:35 +0000</pubDate>
		<dc:creator>Tim</dc:creator>
				<category><![CDATA[ruby]]></category>
		<category><![CDATA[tutorial]]></category>

		<guid isPermaLink="false">http://www.weheartcode.com/2007/10/05/reading-an-excel-file-with-ruby/</guid>
		<description><![CDATA[This tutorial will cover how to read (or parse) an excel file with ruby. I had to write a script to unpivot some data for a co-worker that saved him hours of time, and I got to write a ruby script, so it was a win-win. Here's how you can do the same thing.

Installing Parseexcel
Parseexcel [...]]]></description>
			<content:encoded><![CDATA[<p>This tutorial will cover how to read (or parse) an excel file with ruby. I had to write a script to unpivot some data for a co-worker that saved him hours of time, and I got to write a ruby script, so it was a win-win. Here's how you can do the same thing.</p>
<p><span id="more-35"></span></p>
<h2>Installing Parseexcel</h2>
<p><a href="http://raa.ruby-lang.org/project/parseexcel/">Parseexcel</a> is a ruby port of the perl parseexcel module.</p>
<p>It's installable via a nice gem like so:</p>
<div class="syntax_hilite">
<div id="code-10">
<div class="code">gem install parseexcel</div>
</div>
</div>
<p></p>
<p>That's that, now remember since it's a gem library we have to tell our script to use the gem libs when we run the script from the console using the -rubygems switch.</p>
<h2>Using Parseexcel</h2>
<p>Parseexcel is a very straight forward library, you can't do too much with it, but it gets the job done.</p>
<h3>Getting a Workbook</h3>
<div class="syntax_hilite">
<div id="code-11">
<div class="code">Spreadsheet::<span style="">ParseExcel</span>.<span style="">parse</span><span style="color:#006600; font-weight:bold;">&#40;</span>filenameandpath<span style="color:#006600; font-weight:bold;">&#41;</span></div>
</div>
</div>
<p>
This returns the actual excel file's workbook, from there we need to determine what worksheet we're on.</p>
<h3>Getting a Worksheet</h3>
<div class="syntax_hilite">
<div id="code-12">
<div class="code">worksheet = workbook.<span style="">worksheet</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#800000;">0</span><span style="color:#006600; font-weight:bold;">&#41;</span></div>
</div>
</div>
<p>
Will return the first worksheet, you could also use the each method on the workbook to iterate over all the worksheets.</p>
<h3>Iterating over rows and columns</h3>
<p>The worksheet object has a very nice each method that will allow us to iterate over the rows like so</p>
<div class="syntax_hilite">
<div id="ruby-13">
<div class="ruby">worksheet.<span style="color:#9900CC;">each</span> <span style="color:#006600; font-weight:bold;">&#123;</span> |row|<br />
&nbsp; j=<span style="color:#006666;">0</span><br />
&nbsp; i=<span style="color:#006666;">0</span><br />
&nbsp; <span style="color:#9966CC; font-weight:bold;">if</span> row != <span style="color:#0000FF; font-weight:bold;">nil</span><br />
&nbsp; row.<span style="color:#9900CC;">each</span> <span style="color:#006600; font-weight:bold;">&#123;</span> |cell|<br />
&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">if</span> cell != <span style="color:#0000FF; font-weight:bold;">nil</span><br />
&nbsp; &nbsp; &nbsp; contents = cell.<span style="color:#9900CC;">to_s</span><span style="color:#006600; font-weight:bold;">&#40;</span>'latin1'<span style="color:#006600; font-weight:bold;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color:#CC0066; font-weight:bold;">puts</span> <span style="color:#996600;">"Row: #{j} Cell: #{i} #{contents}"</span><br />
&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
&nbsp; &nbsp; i = i+<span style="color:#006666;">1</span><br />
&nbsp; <span style="color:#006600; font-weight:bold;">&#125;</span><br />
&nbsp; j = j +<span style="color:#006666;">1</span><br />
&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
<span style="color:#006600; font-weight:bold;">&#125;</span></div>
</div>
</div>
<p></p>
<h3>Getting Cell Data</h3>
<ul>
<li><b>Getting a String</b>: cell.to_s('latin1')</li>
<li><b>Getting a Float</b>: cell.to_s('latin1')</li>
<li><b>Getting a Int</b>: cell.to_i</li>
<li><b>Getting a Date</b>: cell.date</li>
</ul>
<h3>Getting A Specific Cell</h3>
<div class="syntax_hilite">
<div id="ruby-14">
<div class="ruby">cell = row.<span style="color:#9900CC;">at</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#006666;">3</span><span style="color:#006600; font-weight:bold;">&#41;</span> <span style="color:#008000; font-style:italic;">#returns cell at column 3 </span></div>
</div>
</div>
<p></p>
<h3>A basic script for dumping an excel file</h3>
<div class="syntax_hilite">
<div id="ruby-15">
<div class="ruby"><span style="color:#CC0066; font-weight:bold;">require</span> 'parseexcel'</p>
<p><span style="color:#008000; font-style:italic;">#Open the excel file passed in from the commandline</span><br />
workbook = Spreadsheet::ParseExcel.<span style="color:#9900CC;">parse</span><span style="color:#006600; font-weight:bold;">&#40;</span>ARGV<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#006666;">0</span><span style="color:#006600; font-weight:bold;">&#93;</span><span style="color:#006600; font-weight:bold;">&#41;</span></p>
<p><span style="color:#008000; font-style:italic;">#Get the first worksheet</span><br />
worksheet = workbook.<span style="color:#9900CC;">worksheet</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#006666;">0</span><span style="color:#006600; font-weight:bold;">&#41;</span></p>
<p><span style="color:#008000; font-style:italic;">#cycle over every row</span><br />
worksheet.<span style="color:#9900CC;">each</span> <span style="color:#006600; font-weight:bold;">&#123;</span> |row|<br />
&nbsp; j=<span style="color:#006666;">0</span><br />
&nbsp; i=<span style="color:#006666;">0</span><br />
&nbsp; <span style="color:#9966CC; font-weight:bold;">if</span> row != <span style="color:#0000FF; font-weight:bold;">nil</span><br />
&nbsp; <span style="color:#008000; font-style:italic;">#cycle over each cell in this row if it's not an empty row</span><br />
&nbsp; row.<span style="color:#9900CC;">each</span> <span style="color:#006600; font-weight:bold;">&#123;</span> |cell|<br />
&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">if</span> cell != <span style="color:#0000FF; font-weight:bold;">nil</span><br />
&nbsp; &nbsp; &nbsp; <span style="color:#008000; font-style:italic;">#Get the contents of the cell as a string</span><br />
&nbsp; &nbsp; &nbsp; contents = cell.<span style="color:#9900CC;">to_s</span><span style="color:#006600; font-weight:bold;">&#40;</span>'latin1'<span style="color:#006600; font-weight:bold;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color:#CC0066; font-weight:bold;">puts</span> <span style="color:#996600;">"Row: #{j} Cell: #{i}&gt; #{contents}"</span><br />
&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
&nbsp; &nbsp; i = i+<span style="color:#006666;">1</span><br />
&nbsp; <span style="color:#006600; font-weight:bold;">&#125;</span><br />
&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
<span style="color:#006600; font-weight:bold;">&#125;</span></div>
</div>
</div>
<p></p>
<p>To run the script, remember to use the -rubygems switch so that you can find the parsexcel library.</p>
<div class="syntax_hilite">
<div id="code-16">
<div class="code">ruby -rubygems excelparse.<span style="">rb</span> myfile.<span style="">xls</span></div>
</div>
</div>
<p></p>
<!-- Social Bookmarks BEGIN --><div class="social_bookmark"><em>Bookmark to:</em><br /><a class="social_img" onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://del.icio.us/post?url=http://www.weheartcode.com/2007/10/05/reading-an-excel-file-with-ruby/&amp;title=Reading+An+Excel+File+With+Ruby" title="Add 'Reading An Excel File With Ruby' to Del.icio.us"><img src="http://www.weheartcode.com/wp-content/plugins/social_bookmarks/delicious.png" title="Add 'Reading An Excel File With Ruby' to Del.icio.us" alt="Add 'Reading An Excel File With Ruby' to Del.icio.us" /></a><a class="social_img" onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://digg.com/submit?phase=2&amp;url=http://www.weheartcode.com/2007/10/05/reading-an-excel-file-with-ruby/&amp;title=Reading+An+Excel+File+With+Ruby" title="Add 'Reading An Excel File With Ruby' to digg"><img src="http://www.weheartcode.com/wp-content/plugins/social_bookmarks/digg.png" title="Add 'Reading An Excel File With Ruby' to digg" alt="Add 'Reading An Excel File With Ruby' to digg" /></a><a class="social_img" onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://furl.net/storeIt.jsp?t=Reading+An+Excel+File+With+Ruby&amp;u=http://www.weheartcode.com/2007/10/05/reading-an-excel-file-with-ruby/" title="Add 'Reading An Excel File With Ruby' to FURL"><img src="http://www.weheartcode.com/wp-content/plugins/social_bookmarks/furl.png" title="Add 'Reading An Excel File With Ruby' to FURL" alt="Add 'Reading An Excel File With Ruby' to FURL" /></a><a class="social_img" onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://reddit.com/submit?url=http://www.weheartcode.com/2007/10/05/reading-an-excel-file-with-ruby/&amp;title=Reading+An+Excel+File+With+Ruby" title="Add 'Reading An Excel File With Ruby' to reddit"><img src="http://www.weheartcode.com/wp-content/plugins/social_bookmarks/reddit.png" title="Add 'Reading An Excel File With Ruby' to reddit" alt="Add 'Reading An Excel File With Ruby' to reddit" /></a><a class="social_img" onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.technorati.com/faves?add=http://www.weheartcode.com/2007/10/05/reading-an-excel-file-with-ruby/" title="Add 'Reading An Excel File With Ruby' to Technorati"><img src="http://www.weheartcode.com/wp-content/plugins/social_bookmarks/technorati.png" title="Add 'Reading An Excel File With Ruby' to Technorati" alt="Add 'Reading An Excel File With Ruby' to Technorati" /></a><a class="social_img" onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.google.com/bookmarks/mark?op=edit&amp;output=popup&amp;bkmk=http://www.weheartcode.com/2007/10/05/reading-an-excel-file-with-ruby/&amp;title=Reading+An+Excel+File+With+Ruby" title="Add 'Reading An Excel File With Ruby' to Google Bookmarks"><img src="http://www.weheartcode.com/wp-content/plugins/social_bookmarks/google.png" title="Add 'Reading An Excel File With Ruby' to Google Bookmarks" alt="Add 'Reading An Excel File With Ruby' to Google Bookmarks" /></a></div>
<!-- Social Bookmarks END -->]]></content:encoded>
			<wfw:commentRss>http://www.weheartcode.com/2007/10/05/reading-an-excel-file-with-ruby/feed/</wfw:commentRss>
		<slash:comments>40</slash:comments>
		</item>
		<item>
		<title>Easy XML Generation with Ruby and ERB</title>
		<link>http://www.weheartcode.com/2007/09/18/easy-xml-generation-with-ruby-and-erb/</link>
		<comments>http://www.weheartcode.com/2007/09/18/easy-xml-generation-with-ruby-and-erb/#comments</comments>
		<pubDate>Tue, 18 Sep 2007 15:42:25 +0000</pubDate>
		<dc:creator>Tim</dc:creator>
				<category><![CDATA[code generation]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[tutorial]]></category>

		<guid isPermaLink="false">http://www.weheartcode.com/2007/09/18/easy-xml-generation-with-ruby-and-erb/</guid>
		<description><![CDATA[Ah, the bracket tax. XML-Situps, whatever you want to call them, if you write any code (especially if you use java) it should be your sworn enemy. The other day I had to create about 40 XML files for some Java Webstart configs. Instead of doing them by hand, I decided to check out the [...]]]></description>
			<content:encoded><![CDATA[<p>Ah, the bracket tax. XML-Situps, whatever you want to call them, if you write any code (especially if you use java) it should be your sworn enemy. The other day I had to create about 40 XML files for some Java Webstart configs. Instead of doing them by hand, I decided to check out the ERB class for easy "templating" that's built into Ruby. It makes doing code generation very easy!</p>
<h3>Our Task</h3>
<p>Create a custom XML file for each .jar file in a directory.</p>
<p>...more after the jump!<br />
<span id="more-31"></span></p>
<h3>Strategy</h3>
<p>With any code generation project we need to identify a few things.</p>
<ol>
<li>Static template: The code/text that will stay the same.</li>
<li>Dynamic variables: These are the pieces that will change in our template.</li>
<li>Input source: The input for our dynamic variables.</li>
</ol>
<p>For me, the static template is a JNLP XML file that looks like this:</p>
<div class="syntax_hilite">
<div id="xml-24">
<div class="xml"><span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;</span>?xml <span style="color: #000066;">version</span>=<span style="color: #ff0000;">"1.0"</span> <span style="color: #000066;">encoding</span>=<span style="color: #ff0000;">"UTF-8"</span>?<span style="font-weight: bold; color: black;">&gt;</span></span><br />
<span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;jnlp</span><br />
&nbsp; <span style="color: #000066;">spec</span>=<span style="color: #ff0000;">"1.0+"</span><br />
&nbsp; <span style="color: #000066;">codebase</span>=<span style="color: #ff0000;">"http://redacted.com/libs/com.redacted.dao_1.3"</span><br />
&nbsp; <span style="color: #000066;">href</span>=<span style="color: #ff0000;">"RcpWebStart.jnlp"</span><span style="font-weight: bold; color: black;">&gt;</span></span><br />
&nbsp; <span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;information<span style="font-weight: bold; color: black;">&gt;</span></span></span><br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;title<span style="font-weight: bold; color: black;">&gt;</span></span></span>RedactedLibs<span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;/title<span style="font-weight: bold; color: black;">&gt;</span></span></span><br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;vendor<span style="font-weight: bold; color: black;">&gt;</span></span></span>Redacted<span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;/vendor<span style="font-weight: bold; color: black;">&gt;</span></span></span><br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;description<span style="font-weight: bold; color: black;">&gt;</span></span></span><span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;strong<span style="font-weight: bold; color: black;">&gt;</span></span></span>com.redacted.dao_1.3.1.jar<span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;/strong<span style="font-weight: bold; color: black;">&gt;</span></span></span><span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;/description<span style="font-weight: bold; color: black;">&gt;</span></span></span><br />
&nbsp; <span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;/information<span style="font-weight: bold; color: black;">&gt;</span></span></span><br />
&nbsp; <span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;security<span style="font-weight: bold; color: black;">&gt;</span></span></span><br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;all</span>-permissions<span style="font-weight: bold; color: black;">/&gt;</span></span><br />
&nbsp; <span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;/security<span style="font-weight: bold; color: black;">&gt;</span></span></span><br />
&nbsp; <span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;resources<span style="font-weight: bold; color: black;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;j2se</span> <span style="color: #000066;">version</span>=<span style="color: #ff0000;">"1.4+"</span><span style="font-weight: bold; color: black;">/&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;jar</span> <span style="color: #000066;">href</span>=<span style="color: #ff0000;">"com.redacted.dao_1.3.1.jar"</span><span style="font-weight: bold; color: black;">/&gt;</span></span><br />
&nbsp; <span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;/resources<span style="font-weight: bold; color: black;">&gt;</span></span></span><br />
&nbsp; <span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;component</span>-desc<span style="font-weight: bold; color: black;">/&gt;</span></span><br />
<span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;/jnlp<span style="font-weight: bold; color: black;">&gt;</span></span></span></div>
</div>
</div>
<p></p>
<p>The dynamic bits will be anywhere a jar is referenced as well as the directory for the jar.</p>
<h3>The Template</h3>
<p>The template defines our static text, and the variables and/or ruby code that will be substituted into the text by ERB.</p>
<p>We use
<div class="syntax_hilite">
<div id="code-25">
<div class="code">&lt;%= %&gt;</div>
</div>
</div>
<p> blocks to substitute in variables from our ruby script.</p>
<p>Here's what my template looks like, I have four variables that I want to substitute in.</p>
<ul>
<li><strong>basedir</strong>: the base directory of where I'm storing my jar.</li>
<li><strong>shortname</strong>: the name of the jar sans the version.</li>
<li><strong>jarname</strong>: the full name of the jar file.</li>
</ul>
<div class="syntax_hilite">
<div id="xml-26">
<div class="xml"><span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;</span>?xml <span style="color: #000066;">version</span>=<span style="color: #ff0000;">"1.0"</span> <span style="color: #000066;">encoding</span>=<span style="color: #ff0000;">"UTF-8"</span>?<span style="font-weight: bold; color: black;">&gt;</span></span><br />
<span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;jnlp</span><br />
&nbsp; <span style="color: #000066;">spec</span>=<span style="color: #ff0000;">"1.0+"</span><br />
&nbsp; <span style="color: #000066;">codebase</span>=<span style="color: #ff0000;">"http://redacted.net/libs/&lt;%=basedir%&gt;</span>/<span style="color: #009900;">&lt;%=shortname%&gt;</span>_<span style="color: #009900;">&lt;%=version%&gt;</span>&quot;<br />
&nbsp; href=&quot;RcpWebStart.jnlp&quot;&gt;<br />
&nbsp; <span style="color: #009900;">&lt;information&gt;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;title&gt;</span><span style="color: #009900;">&lt;%=basedir%&gt;</span><span style="color: #009900;">&lt;/title&gt;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;vendor&gt;</span>Redacted<span style="color: #009900;">&lt;/vendor&gt;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;description&gt;</span><span style="color: #009900;">&lt;%=jarname%&gt;</span><span style="color: #009900;">&lt;/description&gt;</span><br />
&nbsp; <span style="color: #009900;">&lt;/information&gt;</span><br />
&nbsp; <span style="color: #009900;">&lt;security&gt;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;all-permissions/&gt;</span><br />
&nbsp; <span style="color: #009900;">&lt;/security&gt;</span><br />
&nbsp; <span style="color: #009900;">&lt;resources&gt;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;j2se version="</span><span style="color: #cc66cc;">1</span>.<span style="color: #cc66cc;">4</span>+<span style="color: #ff0000;">"/&gt;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;jar href="</span><span style="font-weight: bold; color: black;">&lt;</span>%=jarname%<span style="font-weight: bold; color: black;">&gt;</span></span>&quot;/&gt;<br />
&nbsp; <span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;/resources<span style="font-weight: bold; color: black;">&gt;</span></span></span><br />
&nbsp; <span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;component</span>-desc<span style="font-weight: bold; color: black;">/&gt;</span></span><br />
<span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;/jnlp<span style="font-weight: bold; color: black;">&gt;</span></span></span></div>
</div>
</div>
<p></p>
<h3>The Code</h3>
<p>Let's examine some code. The first thing I do is create the template string, i Use the %q{ shortcut to avoid having to worry about quotes.</p>
<p>Next, I need to define my template, that's what this line does.</p>
<div class="syntax_hilite">
<div id="ruby-27">
<div class="ruby">jnlp = ERB.<span style="color:#9900CC;">new</span><span style="color:#006600; font-weight:bold;">&#40;</span>template, <span style="color:#006666;">0</span>, <span style="color:#996600;">"%&lt;&gt;"</span><span style="color:#006600; font-weight:bold;">&#41;</span>;</div>
</div>
</div>
<p></p>
<p>It says, create a new ERB object using the string 'template' as the template and the "%&lt;&gt;" as my template escape operators.</p>
<p>Our next step is to loop through all the jar's in a directory and create a new file for each one, here's the juicy bits to accomplish that.</p>
<div class="syntax_hilite">
<div id="ruby-28">
<div class="ruby">b = <span style="color:#CC0066; font-weight:bold;">binding</span><br />
&nbsp; &nbsp; &nbsp;jarname = File.<span style="color:#9900CC;">basename</span><span style="color:#006600; font-weight:bold;">&#40;</span>path<span style="color:#006600; font-weight:bold;">&#41;</span><br />
&nbsp; &nbsp; &nbsp;basedir = ARGV<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#006666;">1</span><span style="color:#006600; font-weight:bold;">&#93;</span><br />
&nbsp; &nbsp; &nbsp;shortname = jarname.<span style="color:#CC0066; font-weight:bold;">gsub</span><span style="color:#006600; font-weight:bold;">&#40;</span>/<span style="color:#006600; font-weight:bold;">&#40;</span>.+?<span style="color:#006600; font-weight:bold;">&#41;</span>_<span style="color:#006600; font-weight:bold;">&#40;</span>\d.+<span style="color:#006600; font-weight:bold;">&#41;</span>$/,'\<span style="color:#006666;">1</span>'<span style="color:#006600; font-weight:bold;">&#41;</span><br />
&nbsp; &nbsp; &nbsp;version = jarname.<span style="color:#CC0066; font-weight:bold;">gsub</span><span style="color:#006600; font-weight:bold;">&#40;</span>/<span style="color:#006600; font-weight:bold;">&#40;</span>.+?<span style="color:#006600; font-weight:bold;">&#41;</span>_<span style="color:#006600; font-weight:bold;">&#40;</span>\d\.\d<span style="color:#006600; font-weight:bold;">&#41;</span><span style="color:#006600; font-weight:bold;">&#40;</span>.+<span style="color:#006600; font-weight:bold;">&#41;</span>$/,'\<span style="color:#006666;">2</span>'<span style="color:#006600; font-weight:bold;">&#41;</span></p>
<p>&nbsp; &nbsp; &nbsp;dirname = shortname + <span style="color:#996600;">"_"</span> + version<br />
&nbsp; &nbsp; &nbsp;ourfile = jnlp.<span style="color:#9900CC;">result</span><span style="color:#006600; font-weight:bold;">&#40;</span>b<span style="color:#006600; font-weight:bold;">&#41;</span></div>
</div>
</div>
<p></p>
<p>Notice that we create a binding variable called b and then pass that to our ERB object (jnlp), that binding variable tells ERB to use template variables in the same scope as it. It's some ruby black magic that makes our lives easier.<br />
The rest of the script actually creates some directory and writes the created file to a directory based on the name of the jar.</p>
<div class="syntax_hilite">
<div id="ruby-29">
<div class="ruby"><span style="color:#CC0066; font-weight:bold;">require</span> <span style="color:#996600;">"erb"</span><br />
<span style="color:#CC0066; font-weight:bold;">require</span> <span style="color:#996600;">"find"</span></p>
<p>template = %q<span style="color:#006600; font-weight:bold;">&#123;</span><br />
&lt;?xml version=<span style="color:#996600;">"1.0"</span> encoding=<span style="color:#996600;">"UTF-8"</span>?&gt;<br />
&lt;jnlp<br />
&nbsp; spec=<span style="color:#996600;">"1.0+"</span><br />
&nbsp; codebase=<span style="color:#996600;">"http://redacted.net/libs/&lt;%=basedir%&gt;/&lt;%=shortname%&gt;_&lt;%=version%&gt;"</span><br />
&nbsp; href=<span style="color:#996600;">"RcpWebStart.jnlp"</span>&gt;<br />
&nbsp; &lt;information&gt;<br />
&nbsp; &nbsp; &lt;title&gt;&lt;%=basedir%&gt;&lt;/title&gt;<br />
&nbsp; &nbsp; &lt;vendor&gt;Redactedl&lt;/vendor&gt;<br />
&nbsp; &nbsp; &lt;description&gt;&lt;%=jarname%&gt;&lt;/description&gt;<br />
&nbsp; &lt;/information&gt;<br />
&nbsp; &lt;security&gt;<br />
&nbsp; &nbsp; &lt;all-permissions/&gt;<br />
&nbsp; &lt;/security&gt;<br />
&nbsp; &lt;resources&gt;<br />
&nbsp; &nbsp; &nbsp; &lt;j2se version=<span style="color:#996600;">"1.4+"</span>/&gt;<br />
&nbsp; &nbsp; &nbsp; &lt;jar href=<span style="color:#996600;">"&lt;%=jarname%&gt;"</span>/&gt;<br />
&nbsp; &lt;/resources&gt;<br />
&nbsp; &lt;component-desc/&gt;<br />
&lt;/jnlp&gt;<span style="color:#006600; font-weight:bold;">&#125;</span></p>
<p>&nbsp; jnlp = ERB.<span style="color:#9900CC;">new</span><span style="color:#006600; font-weight:bold;">&#40;</span>template, <span style="color:#006666;">0</span>, <span style="color:#996600;">"%&lt;&gt;"</span><span style="color:#006600; font-weight:bold;">&#41;</span>;</p>
<p>&nbsp; <span style="color:#008000; font-style:italic;">#Search for jar files here</span><br />
&nbsp; Find.<span style="color:#9900CC;">find</span><span style="color:#006600; font-weight:bold;">&#40;</span>ARGV<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#006666;">0</span><span style="color:#006600; font-weight:bold;">&#93;</span><span style="color:#006600; font-weight:bold;">&#41;</span> <span style="color:#9966CC; font-weight:bold;">do</span> |path|</p>
<p>&nbsp; &nbsp;<span style="color:#9966CC; font-weight:bold;">if</span> !FileTest.<span style="color:#9900CC;">directory</span>?<span style="color:#006600; font-weight:bold;">&#40;</span>path<span style="color:#006600; font-weight:bold;">&#41;</span><br />
&nbsp; &nbsp; &nbsp;b = <span style="color:#CC0066; font-weight:bold;">binding</span><br />
&nbsp; &nbsp; &nbsp;jarname = File.<span style="color:#9900CC;">basename</span><span style="color:#006600; font-weight:bold;">&#40;</span>path<span style="color:#006600; font-weight:bold;">&#41;</span><br />
&nbsp; &nbsp; &nbsp;basedir = ARGV<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#006666;">1</span><span style="color:#006600; font-weight:bold;">&#93;</span><br />
&nbsp; &nbsp; &nbsp;shortname = jarname.<span style="color:#CC0066; font-weight:bold;">gsub</span><span style="color:#006600; font-weight:bold;">&#40;</span>/<span style="color:#006600; font-weight:bold;">&#40;</span>.+?<span style="color:#006600; font-weight:bold;">&#41;</span>_<span style="color:#006600; font-weight:bold;">&#40;</span>\d.+<span style="color:#006600; font-weight:bold;">&#41;</span>$/,'\<span style="color:#006666;">1</span>'<span style="color:#006600; font-weight:bold;">&#41;</span><br />
&nbsp; &nbsp; &nbsp;version = jarname.<span style="color:#CC0066; font-weight:bold;">gsub</span><span style="color:#006600; font-weight:bold;">&#40;</span>/<span style="color:#006600; font-weight:bold;">&#40;</span>.+?<span style="color:#006600; font-weight:bold;">&#41;</span>_<span style="color:#006600; font-weight:bold;">&#40;</span>\d\.\d<span style="color:#006600; font-weight:bold;">&#41;</span><span style="color:#006600; font-weight:bold;">&#40;</span>.+<span style="color:#006600; font-weight:bold;">&#41;</span>$/,'\<span style="color:#006666;">2</span>'<span style="color:#006600; font-weight:bold;">&#41;</span></p>
<p>&nbsp; &nbsp; &nbsp;dirname = shortname + <span style="color:#996600;">"_"</span> + version</p>
<p>&nbsp; &nbsp; &nbsp;<span style="color:#008000; font-style:italic;">#pass in the binding variable and create a string from the template</span><br />
&nbsp; &nbsp; &nbsp;ourfile = jnlp.<span style="color:#9900CC;">result</span><span style="color:#006600; font-weight:bold;">&#40;</span>b<span style="color:#006600; font-weight:bold;">&#41;</span></p>
<p>&nbsp; &nbsp; &nbsp;<span style="color:#008000; font-style:italic;">#create a new directory and file, and output the template string to it.</span><br />
&nbsp; &nbsp; &nbsp;Dir.<span style="color:#9900CC;">mkdir</span><span style="color:#006600; font-weight:bold;">&#40;</span>basedir + <span style="color:#996600;">"/"</span> + dirname<span style="color:#006600; font-weight:bold;">&#41;</span><br />
&nbsp; &nbsp; &nbsp;outfile = File.<span style="color:#9900CC;">new</span><span style="color:#006600; font-weight:bold;">&#40;</span>basedir + <span style="color:#996600;">"/"</span> + dirname +&nbsp; <span style="color:#996600;">"/RcpWebStart.jnlp"</span>,<span style="color:#996600;">"w+"</span><span style="color:#006600; font-weight:bold;">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp;outfile &lt;&lt;ourfile<br />
&nbsp; &nbsp;<span style="color:#9966CC; font-weight:bold;">end</span></div>
</div>
</div>
<p></p>
<h3>The fun doesn't stop there</h3>
<p>This is an elementary example, but ERB also allows you to embed real ruby code in the template, this allows you to accomplish looping. </p>
<p>So we could pass in an array of person objects and loop through them with a template like this:</p>
<div class="syntax_hilite">
<div id="xml-30">
<div class="xml"><span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;people<span style="font-weight: bold; color: black;">&gt;</span></span></span><br />
&nbsp; &nbsp;<span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;</span>%@people.each do |person| %<span style="font-weight: bold; color: black;">&gt;</span></span><br />
&nbsp; &nbsp;<span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;name<span style="font-weight: bold; color: black;">&gt;</span></span></span><span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;</span>%=person.name%<span style="font-weight: bold; color: black;">&gt;</span></span><span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;/name<span style="font-weight: bold; color: black;">&gt;</span></span></span><br />
&nbsp; <span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;</span>%end%<span style="font-weight: bold; color: black;">&gt;</span></span><br />
&nbsp;<span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;/people<span style="font-weight: bold; color: black;">&gt;</span></span></span></div>
</div>
</div>
<p></p>
<!-- Social Bookmarks BEGIN --><div class="social_bookmark"><em>Bookmark to:</em><br /><a class="social_img" onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://del.icio.us/post?url=http://www.weheartcode.com/2007/09/18/easy-xml-generation-with-ruby-and-erb/&amp;title=Easy+XML+Generation+with+Ruby+and+ERB" title="Add 'Easy XML Generation with Ruby and ERB' to Del.icio.us"><img src="http://www.weheartcode.com/wp-content/plugins/social_bookmarks/delicious.png" title="Add 'Easy XML Generation with Ruby and ERB' to Del.icio.us" alt="Add 'Easy XML Generation with Ruby and ERB' to Del.icio.us" /></a><a class="social_img" onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://digg.com/submit?phase=2&amp;url=http://www.weheartcode.com/2007/09/18/easy-xml-generation-with-ruby-and-erb/&amp;title=Easy+XML+Generation+with+Ruby+and+ERB" title="Add 'Easy XML Generation with Ruby and ERB' to digg"><img src="http://www.weheartcode.com/wp-content/plugins/social_bookmarks/digg.png" title="Add 'Easy XML Generation with Ruby and ERB' to digg" alt="Add 'Easy XML Generation with Ruby and ERB' to digg" /></a><a class="social_img" onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://furl.net/storeIt.jsp?t=Easy+XML+Generation+with+Ruby+and+ERB&amp;u=http://www.weheartcode.com/2007/09/18/easy-xml-generation-with-ruby-and-erb/" title="Add 'Easy XML Generation with Ruby and ERB' to FURL"><img src="http://www.weheartcode.com/wp-content/plugins/social_bookmarks/furl.png" title="Add 'Easy XML Generation with Ruby and ERB' to FURL" alt="Add 'Easy XML Generation with Ruby and ERB' to FURL" /></a><a class="social_img" onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://reddit.com/submit?url=http://www.weheartcode.com/2007/09/18/easy-xml-generation-with-ruby-and-erb/&amp;title=Easy+XML+Generation+with+Ruby+and+ERB" title="Add 'Easy XML Generation with Ruby and ERB' to reddit"><img src="http://www.weheartcode.com/wp-content/plugins/social_bookmarks/reddit.png" title="Add 'Easy XML Generation with Ruby and ERB' to reddit" alt="Add 'Easy XML Generation with Ruby and ERB' to reddit" /></a><a class="social_img" onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.technorati.com/faves?add=http://www.weheartcode.com/2007/09/18/easy-xml-generation-with-ruby-and-erb/" title="Add 'Easy XML Generation with Ruby and ERB' to Technorati"><img src="http://www.weheartcode.com/wp-content/plugins/social_bookmarks/technorati.png" title="Add 'Easy XML Generation with Ruby and ERB' to Technorati" alt="Add 'Easy XML Generation with Ruby and ERB' to Technorati" /></a><a class="social_img" onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.google.com/bookmarks/mark?op=edit&amp;output=popup&amp;bkmk=http://www.weheartcode.com/2007/09/18/easy-xml-generation-with-ruby-and-erb/&amp;title=Easy+XML+Generation+with+Ruby+and+ERB" title="Add 'Easy XML Generation with Ruby and ERB' to Google Bookmarks"><img src="http://www.weheartcode.com/wp-content/plugins/social_bookmarks/google.png" title="Add 'Easy XML Generation with Ruby and ERB' to Google Bookmarks" alt="Add 'Easy XML Generation with Ruby and ERB' to Google Bookmarks" /></a></div>
<!-- Social Bookmarks END -->]]></content:encoded>
			<wfw:commentRss>http://www.weheartcode.com/2007/09/18/easy-xml-generation-with-ruby-and-erb/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Using Protototype AJAX &amp; JSON with J2EE and Struts</title>
		<link>http://www.weheartcode.com/2007/05/16/using-protototype-ajax-json-with-j2ee-and-struts/</link>
		<comments>http://www.weheartcode.com/2007/05/16/using-protototype-ajax-json-with-j2ee-and-struts/#comments</comments>
		<pubDate>Wed, 16 May 2007 20:27:58 +0000</pubDate>
		<dc:creator>Tim</dc:creator>
				<category><![CDATA[JSON]]></category>
		<category><![CDATA[ajax]]></category>
		<category><![CDATA[j2ee]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[struts]]></category>
		<category><![CDATA[tutorial]]></category>

		<guid isPermaLink="false">http://www.weheartcode.com/2007/05/16/using-protototype-ajax-json-with-j2ee-and-struts/</guid>
		<description><![CDATA[We don't always get to use the latest greatest web framework, but just because you're using a crusty old dinosaur J2EE XML framework from the pits of hell, doesn't mean you can't make girls cry with your AJAX/JSON skills.
This tutorial will show how to use prototype to return JSON data to your jsp.

Prerequisites
This tutorial will [...]]]></description>
			<content:encoded><![CDATA[<p>We don't always get to use the latest greatest web framework, but just because you're using a crusty old dinosaur J2EE XML framework from the pits of hell, doesn't mean you can't make girls cry with your AJAX/JSON skills.</p>
<p>This tutorial will show how to use prototype to return JSON data to your jsp.<br />
<span id="more-18"></span></p>
<h3>Prerequisites</h3>
<p>This tutorial will be Struts-centric, but really is adaptable to any Java/J2EE platform. I'm not going to include any DB Layer specific code since that seems to change so much, but you should know how to take a query result and put it in a hash map.</p>
<h3>The Goal</h3>
<p>Create a Struts Action class that queries the database and returns the result in a JSON object back to a JSP with as little fuss as possible.</p>
<h3>The JSP</h3>
<p>In this example, I want to populate a text box in my form with data returned from an AJAX request in the background. For example, sometimes you want to pull out a person's name based on some internal ID. This saves our user from having to type it in by hand and also eliminates spelling mistakes.</p>
<p>So let's assume we have a text box where the user would type in the id as well as a text box where they would type the full name, the code would look something like this</p>
<div class="syntax_hilite">
<div id="html-35">
<div class="html"><span style="color: #009900;"><a href="http://december.com/html/4/element/input.html"><span style="color: #000000; font-weight: bold;">&lt;input</span></a> <span style="color: #000066;">type</span>=<span style="color: #ff0000;">"text"</span> <span style="color: #000066;">id</span>=<span style="color: #ff0000;">"theId"</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">"theId"</span>/<span style="color: #000000; font-weight: bold;">&gt;</span></a></span><br />
<span style="color: #009900;"><a href="http://december.com/html/4/element/input.html"><span style="color: #000000; font-weight: bold;">&lt;input</span></a> <span style="color: #000066;">type</span>=<span style="color: #ff0000;">"text"</span> <span style="color: #000066;">id</span>=<span style="color: #ff0000;">"fullName"</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">"fullName"</span>/<span style="color: #000000; font-weight: bold;">&gt;</span></a></span></div>
</div>
</div>
<p></p>
<p>We'll then have a javascript function that uses <a href="http://www.prototypejs.org">prototype</a> to create an AJAX request that hits a struts action to to the database look up, then populates the fullName text box with the fullName property from the returned JSON object.</p>
<div class="syntax_hilite">
<div id="javascript-36">
<div class="javascript"><span style="color: #003366; font-weight: bold;">function</span> lookup<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span><br />
<span style="color: #66cc66;">&#123;</span><br />
&nbsp; <span style="color: #003366; font-weight: bold;">new</span> Ajax.<span style="color: #006600;">Request</span><span style="color: #66cc66;">&#40;</span><span style="color: #3366CC;">'&lt;html:rewrite page=&quot;/util/namelookup.do&quot;/&gt;'</span>, <span style="color: #66cc66;">&#123;</span><br />
&nbsp; &nbsp;parameters: <span style="color: #66cc66;">&#123;</span>theId: $<span style="color: #66cc66;">&#40;</span><span style="color: #3366CC;">'theId'</span><span style="color: #66cc66;">&#41;</span>.<span style="color: #006600;">value</span><span style="color: #66cc66;">&#125;</span>,<br />
&nbsp; &nbsp; onSuccess: <span style="color: #003366; font-weight: bold;">function</span><span style="color: #66cc66;">&#40;</span>transport, json<span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span><br />
&nbsp; &nbsp; &nbsp;<span style="color: #000066; font-weight: bold;">if</span><span style="color: #66cc66;">&#40;</span>json.<span style="color: #006600;">executeError</span><span style="color: #66cc66;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #66cc66;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #000066;">alert</span><span style="color: #66cc66;">&#40;</span>json.<span style="color: #006600;">executeError</span><span style="color: #66cc66;">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; <span style="color: #66cc66;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #000066; font-weight: bold;">else</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #66cc66;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; $<span style="color: #66cc66;">&#40;</span><span style="color: #3366CC;">'fullName'</span><span style="color: #66cc66;">&#41;</span>.<span style="color: #006600;">value</span> = json.<span style="color: #006600;">fullName</span>;<br />
&nbsp; &nbsp; &nbsp; <span style="color: #66cc66;">&#125;</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span style="color: #66cc66;">&#125;</span><br />
<span style="color: #66cc66;">&#125;</span><span style="color: #66cc66;">&#41;</span>;</div>
</div>
</div>
<p></p>
<h3>The Java</h3>
<p>Our goal here is to do some work and put that work in a JSON object, for me the easiest way is to just query the DB and throw the results into a hashmap or java bean. To do the JSON lifting in this example I use the open source <a href="http://json-lib.sourceforge.net/">json-lib</a>. If an error occurs we'll put error text in a key in the JSON object called executeError so that we can display that in our javascript.</p>
<div class="syntax_hilite">
<div id="java-37">
<div class="java"><span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> NameLookupAction <span style="color: #000000; font-weight: bold;">extends</span> <a href="http://www.google.com/search?q=allinurl%3AAction+java.sun.com&amp;bntl=1"><span style="color: #aaaadd; font-weight: bold;">Action</span></a><br />
<span style="color: #66cc66;">&#123;</span></p>
<p>&nbsp; <span style="color: #000000; font-weight: bold;">public</span> ActionForward execute<span style="color: #66cc66;">&#40;</span>ActionMapping mapping, ActionForm form,<br />
&nbsp; &nbsp; HttpServletRequest request, HttpServletResponse response<span style="color: #66cc66;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">throws</span> <a href="http://www.google.com/search?q=allinurl%3AException+java.sun.com&amp;bntl=1"><span style="color: #aaaadd; font-weight: bold;">Exception</span></a><br />
&nbsp; <span style="color: #66cc66;">&#123;</span></p>
<p>&nbsp; &nbsp; <a href="http://www.google.com/search?q=allinurl%3AString+java.sun.com&amp;bntl=1"><span style="color: #aaaadd; font-weight: bold;">String</span></a> theId = request.<span style="color: #006600;">getParameter</span><span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">"theId"</span><span style="color: #66cc66;">&#41;</span>;</p>
<p>&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">try</span><br />
&nbsp; &nbsp; <span style="color: #66cc66;">&#123;</span></p>
<p>&nbsp; &nbsp; &nbsp; <span style="color: #808080; font-style: italic;">//Do your database work here to grab the name and populate our HashMap hm</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #808080; font-style: italic;">//In this example I'll just hard-code the name though.</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp;<a href="http://www.google.com/search?q=allinurl%3AHashMap+java.sun.com&amp;bntl=1"><span style="color: #aaaadd; font-weight: bold;">HashMap</span></a> hm = <span style="color: #000000; font-weight: bold;">new</span> <a href="http://www.google.com/search?q=allinurl%3AHashMap+java.sun.com&amp;bntl=1"><span style="color: #aaaadd; font-weight: bold;">HashMap</span></a><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp;hm.<span style="color: #006600;">put</span><span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">"fullName"</span>,<span style="color: #ff0000;">"Joe Blow"</span><span style="color: #66cc66;">&#41;</span>;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #808080; font-style: italic;">//each key from our hash map becomes a key in our JSON object</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; JSONObject json = JSONObject.<span style="color: #006600;">fromObject</span><span style="color: #66cc66;">&#40;</span>hm<span style="color: #66cc66;">&#41;</span>;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #808080; font-style: italic;">//Plop it in the header so prototype can grab it.</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; response.<span style="color: #006600;">setHeader</span><span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">"X-JSON"</span>, json.<span style="color: #006600;">toString</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>;</p>
<p>&nbsp; &nbsp; &nbsp; <span style="color: #66cc66;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #66cc66;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">catch</span> <span style="color: #66cc66;">&#40;</span><a href="http://www.google.com/search?q=allinurl%3AException+java.sun.com&amp;bntl=1"><span style="color: #aaaadd; font-weight: bold;">Exception</span></a> e<span style="color: #66cc66;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #66cc66;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; <a href="http://www.google.com/search?q=allinurl%3AHashMap+java.sun.com&amp;bntl=1"><span style="color: #aaaadd; font-weight: bold;">HashMap</span></a> hm = <span style="color: #000000; font-weight: bold;">new</span> <a href="http://www.google.com/search?q=allinurl%3AHashMap+java.sun.com&amp;bntl=1"><span style="color: #aaaadd; font-weight: bold;">HashMap</span></a><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; hm.<span style="color: #006600;">put</span><span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">"executeError"</span>, <span style="color: #ff0000;">"Couldn't find the Full Name because an error occured."</span><span style="color: #66cc66;">&#41;</span>;</p>
<p>&nbsp; &nbsp; &nbsp; JSONObject json = JSONObject.<span style="color: #006600;">fromObject</span><span style="color: #66cc66;">&#40;</span>hm<span style="color: #66cc66;">&#41;</span>;</p>
<p>&nbsp; &nbsp; &nbsp; response.<span style="color: #006600;">setHeader</span><span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">"X-JSON"</span>, json.<span style="color: #006600;">toString</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>;</p>
<p>&nbsp; &nbsp; <span style="color: #66cc66;">&#125;</span></p>
<p>&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">return</span> mapping.<span style="color: #006600;">findForward</span><span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">"success"</span><span style="color: #66cc66;">&#41;</span>;</p>
<p>&nbsp; <span style="color: #66cc66;">&#125;</span></div>
</div>
</div>
<p></p>
<p>So that's all there is to it, as you can see it's pretty simple stuff but quite powerful. I like to create utility classes that return a whole bunch of info from a query, they're quite handy to have around to quickly display information in your web app without having to do a lot of leg work of new windows and new jsp pages, etc.</p>
<h3>Extra struts-config.xml Stuff</h3>
<p>If you're using struts you need to forward to a jsp of some sort, this is just going to be an empty JSP page, the JSON info is stored in the response header, anyway here's what your struts-config.xml entry might look like for this action.</p>
<div class="syntax_hilite">
<div id="xml-38">
<div class="xml"><span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;action</span> <span style="color: #000066;">path</span>=<span style="color: #ff0000;">"/util/namelookup"</span> <span style="color: #000066;">scope</span>=<span style="color: #ff0000;">"request"</span> <span style="color: #000066;">type</span>=<span style="color: #ff0000;">"com.yourcompany.NameLookupAction"</span> <span style="color: #000066;">validate</span>=<span style="color: #ff0000;">"false"</span><span style="font-weight: bold; color: black;">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;forward</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">"success"</span> <span style="color: #000066;">path</span>=<span style="color: #ff0000;">"/WEB-INF/jsp/ajax/empty.jsp"</span><span style="font-weight: bold; color: black;">/&gt;</span></span><br />
&nbsp; <span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;/action<span style="font-weight: bold; color: black;">&gt;</span></span></span></div>
</div>
</div>
<p></p>
<!-- Social Bookmarks BEGIN --><div class="social_bookmark"><em>Bookmark to:</em><br /><a class="social_img" onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://del.icio.us/post?url=http://www.weheartcode.com/2007/05/16/using-protototype-ajax-json-with-j2ee-and-struts/&amp;title=Using+Protototype+AJAX+%26%23038%3B+JSON+with+J2EE+and+Struts" title="Add 'Using Protototype AJAX &#038; JSON with J2EE and Struts' to Del.icio.us"><img src="http://www.weheartcode.com/wp-content/plugins/social_bookmarks/delicious.png" title="Add 'Using Protototype AJAX &#038; JSON with J2EE and Struts' to Del.icio.us" alt="Add 'Using Protototype AJAX &#038; JSON with J2EE and Struts' to Del.icio.us" /></a><a class="social_img" onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://digg.com/submit?phase=2&amp;url=http://www.weheartcode.com/2007/05/16/using-protototype-ajax-json-with-j2ee-and-struts/&amp;title=Using+Protototype+AJAX+%26%23038%3B+JSON+with+J2EE+and+Struts" title="Add 'Using Protototype AJAX &#038; JSON with J2EE and Struts' to digg"><img src="http://www.weheartcode.com/wp-content/plugins/social_bookmarks/digg.png" title="Add 'Using Protototype AJAX &#038; JSON with J2EE and Struts' to digg" alt="Add 'Using Protototype AJAX &#038; JSON with J2EE and Struts' to digg" /></a><a class="social_img" onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://furl.net/storeIt.jsp?t=Using+Protototype+AJAX+%26%23038%3B+JSON+with+J2EE+and+Struts&amp;u=http://www.weheartcode.com/2007/05/16/using-protototype-ajax-json-with-j2ee-and-struts/" title="Add 'Using Protototype AJAX &#038; JSON with J2EE and Struts' to FURL"><img src="http://www.weheartcode.com/wp-content/plugins/social_bookmarks/furl.png" title="Add 'Using Protototype AJAX &#038; JSON with J2EE and Struts' to FURL" alt="Add 'Using Protototype AJAX &#038; JSON with J2EE and Struts' to FURL" /></a><a class="social_img" onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://reddit.com/submit?url=http://www.weheartcode.com/2007/05/16/using-protototype-ajax-json-with-j2ee-and-struts/&amp;title=Using+Protototype+AJAX+%26%23038%3B+JSON+with+J2EE+and+Struts" title="Add 'Using Protototype AJAX &#038; JSON with J2EE and Struts' to reddit"><img src="http://www.weheartcode.com/wp-content/plugins/social_bookmarks/reddit.png" title="Add 'Using Protototype AJAX &#038; JSON with J2EE and Struts' to reddit" alt="Add 'Using Protototype AJAX &#038; JSON with J2EE and Struts' to reddit" /></a><a class="social_img" onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.technorati.com/faves?add=http://www.weheartcode.com/2007/05/16/using-protototype-ajax-json-with-j2ee-and-struts/" title="Add 'Using Protototype AJAX &#038; JSON with J2EE and Struts' to Technorati"><img src="http://www.weheartcode.com/wp-content/plugins/social_bookmarks/technorati.png" title="Add 'Using Protototype AJAX &#038; JSON with J2EE and Struts' to Technorati" alt="Add 'Using Protototype AJAX &#038; JSON with J2EE and Struts' to Technorati" /></a><a class="social_img" onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.google.com/bookmarks/mark?op=edit&amp;output=popup&amp;bkmk=http://www.weheartcode.com/2007/05/16/using-protototype-ajax-json-with-j2ee-and-struts/&amp;title=Using+Protototype+AJAX+%26%23038%3B+JSON+with+J2EE+and+Struts" title="Add 'Using Protototype AJAX &#038; JSON with J2EE and Struts' to Google Bookmarks"><img src="http://www.weheartcode.com/wp-content/plugins/social_bookmarks/google.png" title="Add 'Using Protototype AJAX &#038; JSON with J2EE and Struts' to Google Bookmarks" alt="Add 'Using Protototype AJAX &#038; JSON with J2EE and Struts' to Google Bookmarks" /></a></div>
<!-- Social Bookmarks END -->]]></content:encoded>
			<wfw:commentRss>http://www.weheartcode.com/2007/05/16/using-protototype-ajax-json-with-j2ee-and-struts/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Scraping IMDB with Ruby and Hpricot</title>
		<link>http://www.weheartcode.com/2007/04/03/scraping-imdb-with-ruby-and-hpricot/</link>
		<comments>http://www.weheartcode.com/2007/04/03/scraping-imdb-with-ruby-and-hpricot/#comments</comments>
		<pubDate>Tue, 03 Apr 2007 17:11:24 +0000</pubDate>
		<dc:creator>Tim</dc:creator>
				<category><![CDATA[ruby]]></category>
		<category><![CDATA[tutorial]]></category>

		<guid isPermaLink="false">http://www.weheartcode.com/2007/04/03/scraping-imdb-with-ruby-and-hpricot/</guid>
		<description><![CDATA[One service that cries for a nice web service interface is IMDB, however they like want $$ or something for it...the nerve!
With just a few lines of ruby we can query to our heart's content. In this post I'll go over how to create a very simple class for extracting information about movies from IMDB [...]]]></description>
			<content:encoded><![CDATA[<p>One service that cries for a nice web service interface is IMDB, however they like want $$ or something for it...the nerve!</p>
<p>With just a few lines of ruby we can query to our heart's content. In this post I'll go over how to create a very simple class for extracting information about movies from IMDB using the lovely <a href="http://code.whytheluckystiff.net/hpricot/">Hpricot</a> library.<br />
<span id="more-15"></span></p>
<h3>Prerequisites</h3>
<p>Downoad and Install Hpricot<br />
That's it!</p>
<h3>The Class</h3>
<p>So let's think of what information we want to grab.</p>
<p>I think we need the title of the movie, the rating, and all the other junk - genre,plot outline, etc.</p>
<p>So we'll create an IMDB class that takes a IMDB url as input and can then give us all that other information.</p>
<p>So the beginning of our class looks like this</p>
<div class="syntax_hilite">
<div id="ruby-49">
<div class="ruby"><span style="color:#9966CC; font-weight:bold;">class</span> IMDB<br />
<span style="color:#CC0066; font-weight:bold;">require</span> 'hpricot'<br />
<span style="color:#CC0066; font-weight:bold;">require</span> 'open-uri'</p>
<p><span style="color:#9966CC; font-weight:bold;">def</span> initialize<span style="color:#006600; font-weight:bold;">&#40;</span>url<span style="color:#006600; font-weight:bold;">&#41;</span><br />
&nbsp; @url = url;<br />
&nbsp; @hp = Hpricot<span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#CC0066; font-weight:bold;">open</span><span style="color:#006600; font-weight:bold;">&#40;</span>@url<span style="color:#006600; font-weight:bold;">&#41;</span><span style="color:#006600; font-weight:bold;">&#41;</span><br />
<span style="color:#9966CC; font-weight:bold;">end</span><br />
<span style="color:#9966CC; font-weight:bold;">end</span></div>
</div>
</div>
<p></p>
<h3>The Title</h3>
<p>Now let's build our first method to grab the title. So I'll pull up my favorite movie, Lost In Translation, and take a look at the source code.</p>
<p>Here's the bit I'm looking for</p>
<div class="syntax_hilite">
<div id="html-50">
<div class="html"><span style="color: #009900;"><a href="http://december.com/html/4/element/meta.html"><span style="color: #000000; font-weight: bold;">&lt;meta</span></a> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">"title"</span> <span style="color: #000066;">content</span>=<span style="color: #ff0000;">"Lost in Translation (2003)"</span><span style="color: #000000; font-weight: bold;">&gt;</span></a></span></div>
</div>
</div>
<p></p>
<p>So we need to search for a meta tag that has a name attribute of title and extract the contents of the 'content' attribute. Hpricot <a href="http://code.whytheluckystiff.net/hpricot/wiki/HpricotXpathSearch">uses the XPath query language</a> or a <a href="http://code.whytheluckystiff.net/hpricot/wiki/HpricotCssSearch">CSS selector based</a> query language to allow us to quickly get to the data we want. Since this has a condition in it, we'll use XPath ,the first step in getting this data is determining what sort of XPath query we need to write.</p>
<p>Here's what we have for our title method</p>
<div class="syntax_hilite">
<div id="ruby-51">
<div class="ruby"><span style="color:#9966CC; font-weight:bold;">def</span>&nbsp; title<br />
&nbsp; &nbsp;@title = @hp.<span style="color:#9900CC;">at</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">"meta[@name='title']"</span><span style="color:#006600; font-weight:bold;">&#41;</span><span style="color:#006600; font-weight:bold;">&#91;</span>'content'<span style="color:#006600; font-weight:bold;">&#93;</span><br />
<span style="color:#9966CC; font-weight:bold;">end</span></div>
</div>
</div>
<p>
We use our @hp instance variable which is a Hpricot object, and tell it to return the first element with a tag of meta and an attribute that matches title, then give us the value of the content attribute.</p>
<h3>The Ranking</h3>
<p>Looking at the source for the rating, I see it's in a div named rating. So we'll simply search for that div, then use a regular expression to extract the number value out of it!</p>
<p>Here's the html</p>
<div class="syntax_hilite">
<div id="html-52">
<div class="html"><span style="color: #009900;"><a href="http://december.com/html/4/element/div.html"><span style="color: #000000; font-weight: bold;">&lt;div</span></a> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">"general rating"</span><span style="color: #000000; font-weight: bold;">&gt;</span></a></span><br />
<span style="color: #009900;"><a href="http://december.com/html/4/element/div.html"><span style="color: #000000; font-weight: bold;">&lt;div</span></a> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">"starbar static"</span><span style="color: #000000; font-weight: bold;">&gt;</span></a></span><span style="color: #009900;"><a href="http://december.com/html/4/element/div.html"><span style="color: #000000; font-weight: bold;">&lt;div</span></a> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">"outer"</span><span style="color: #000000; font-weight: bold;">&gt;</span></a></span><span style="color: #009900;"><a href="http://december.com/html/4/element/div.html"><span style="color: #000000; font-weight: bold;">&lt;div</span></a> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">"inner"</span> <span style="color: #000066;">style</span>=<span style="color: #ff0000;">"width: 158px"</span><span style="color: #000000; font-weight: bold;">&gt;</span></a></span><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/div&gt;</span></span><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/div&gt;</span></span><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/div&gt;</span></span></p>
<p><span style="color: #009900;"><a href="http://december.com/html/4/element/b.html"><span style="color: #000000; font-weight: bold;">&lt;b&gt;</span></a></span>User Rating:<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/b&gt;</span></span> <br />
<span style="color: #009900;"><a href="http://december.com/html/4/element/b.html"><span style="color: #000000; font-weight: bold;">&lt;b&gt;</span></a></span>7.9/10<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/b&gt;</span></span> <br />
&nbsp; <span style="color: #009900;"><a href="http://december.com/html/4/element/small.html"><span style="color: #000000; font-weight: bold;">&lt;small&gt;</span></a></span>(<span style="color: #009900;"><a href="http://december.com/html/4/element/a.html"><span style="color: #000000; font-weight: bold;">&lt;a</span></a> <span style="color: #000066;">href</span>=<span style="color: #ff0000;">"ratings"</span><span style="color: #000000; font-weight: bold;">&gt;</span></a></span>74,513 votes<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/a&gt;</span></span>)<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/small&gt;</span></span><br />
<span style="color: #009900;"><a href="http://december.com/html/4/element/div.html"><span style="color: #000000; font-weight: bold;">&lt;div</span></a> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">"bottom"</span><span style="color: #000000; font-weight: bold;">&gt;</span></a></span></p>
<p><span style="color: #009900;"><a href="http://december.com/html/4/element/a.html"><span style="color: #000000; font-weight: bold;">&lt;a</span></a> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">"tn15more"</span> <span style="color: #000066;">href</span>=<span style="color: #ff0000;">"ratings"</span><span style="color: #000000; font-weight: bold;">&gt;</span></a></span>more<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/a&gt;</span></span></p>
<p><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/div&gt;</span></span></div>
</div>
</div>
<p></p>
<div class="syntax_hilite">
<div id="ruby-53">
<div class="ruby"><span style="color:#9966CC; font-weight:bold;">def</span> rating<br />
&nbsp; &nbsp; rating_text = <span style="color:#006600; font-weight:bold;">&#40;</span>@hp/<span style="color:#996600;">"div.rating/b"</span><span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">inner_text</span><br />
&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">if</span> rating_text =~ /<span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#006600; font-weight:bold;">&#91;</span>\d\.<span style="color:#006600; font-weight:bold;">&#93;</span>+<span style="color:#006600; font-weight:bold;">&#41;</span>\/<span style="color:#006666;">10</span>/<br />
&nbsp; &nbsp; &nbsp; @rating = $<span style="color:#006666;">1</span><br />
&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
&nbsp; &nbsp; @rating<br />
<span style="color:#9966CC; font-weight:bold;">end</span></div>
</div>
</div>
<p>
Looking closer we have the CSS query of "div.rating/b", in english that says find a bold tag in a d iv tag with the class name rating. The "/" operator we're  using on @hp is a shortcut for the search method, it returns an Hprcot::Element, on the element it returns we call inner_text which returns the text of that element stripped of all html tags.</p>
<p>I then run the text through a regular expression to extract the rating out of 10 points.</p>
<h3>The Rest</h3>
<p>The rest of the main information about the movie is contained in these div's with class name info, as seen in the html here</p>
<div class="syntax_hilite">
<div id="html-54">
<div class="html"><span style="color: #009900;"><a href="http://december.com/html/4/element/div.html"><span style="color: #000000; font-weight: bold;">&lt;div</span></a> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">"info"</span><span style="color: #000000; font-weight: bold;">&gt;</span></a></span><br />
<span style="color: #009900;"><a href="http://december.com/html/4/element/h5.html"><span style="color: #000000; font-weight: bold;">&lt;h5&gt;</span></a></span>Release Date:<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/h5&gt;</span></span> <br />
3 October 2003 (USA)<br />
&nbsp;<span style="color: #009900;"><a href="http://december.com/html/4/element/a.html"><span style="color: #000000; font-weight: bold;">&lt;a</span></a> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">"tn15more inline"</span> <span style="color: #000066;">href</span>=<span style="color: #ff0000;">"/rg/title-tease/releasedates/title/tt0335266/releaseinfo"</span><span style="color: #000000; font-weight: bold;">&gt;</span></a></span>more<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/a&gt;</span></span></p>
<p>&nbsp;<span style="color: #009900;"><a href="http://december.com/html/4/element/a.html"><span style="color: #000000; font-weight: bold;">&lt;a</span></a> <span style="color: #000066;">style</span>=<span style="color: #ff0000;">"margin-left: 1em"</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">"tn15more inline"</span> <span style="color: #000066;">href</span>=<span style="color: #ff0000;">"/rg/title-tease/trailers/title/tt0335266/trailers-screenplay-E19136-10-2"</span><span style="color: #000000; font-weight: bold;">&gt;</span></a></span>view trailer<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/a&gt;</span></span></p>
<p><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/div&gt;</span></span></p>
<p><span style="color: #009900;"><a href="http://december.com/html/4/element/div.html"><span style="color: #000000; font-weight: bold;">&lt;div</span></a> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">"info"</span><span style="color: #000000; font-weight: bold;">&gt;</span></a></span><br />
<span style="color: #009900;"><a href="http://december.com/html/4/element/h5.html"><span style="color: #000000; font-weight: bold;">&lt;h5&gt;</span></a></span>Genre:<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/h5&gt;</span></span><br />
<span style="color: #009900;"><a href="http://december.com/html/4/element/a.html"><span style="color: #000000; font-weight: bold;">&lt;a</span></a> <span style="color: #000066;">href</span>=<span style="color: #ff0000;">"/Sections/Genres/Comedy/"</span><span style="color: #000000; font-weight: bold;">&gt;</span></a></span>Comedy<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/a&gt;</span></span> / <span style="color: #009900;"><a href="http://december.com/html/4/element/a.html"><span style="color: #000000; font-weight: bold;">&lt;a</span></a> <span style="color: #000066;">href</span>=<span style="color: #ff0000;">"/Sections/Genres/Drama/"</span><span style="color: #000000; font-weight: bold;">&gt;</span></a></span>Drama<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/a&gt;</span></span> / <span style="color: #009900;"><a href="http://december.com/html/4/element/a.html"><span style="color: #000000; font-weight: bold;">&lt;a</span></a> <span style="color: #000066;">href</span>=<span style="color: #ff0000;">"/Sections/Genres/Romance/"</span><span style="color: #000000; font-weight: bold;">&gt;</span></a></span>Romance<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/a&gt;</span></span> <span style="color: #009900;"><a href="http://december.com/html/4/element/a.html"><span style="color: #000000; font-weight: bold;">&lt;a</span></a> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">"tn15more inline"</span> <span style="color: #000066;">href</span>=<span style="color: #ff0000;">"/rg/title-tease/keywords/title/tt0335266/keywords"</span><span style="color: #000000; font-weight: bold;">&gt;</span></a></span>more<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/a&gt;</span></span></p>
<p><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/div&gt;</span></span></p>
<p><span style="color: #009900;"><a href="http://december.com/html/4/element/div.html"><span style="color: #000000; font-weight: bold;">&lt;div</span></a> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">"info"</span><span style="color: #000000; font-weight: bold;">&gt;</span></a></span><br />
<span style="color: #009900;"><a href="http://december.com/html/4/element/h5.html"><span style="color: #000000; font-weight: bold;">&lt;h5&gt;</span></a></span>Tagline:<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/h5&gt;</span></span><br />
Everyone wants to be found. <span style="color: #009900;"><a href="http://december.com/html/4/element/a.html"><span style="color: #000000; font-weight: bold;">&lt;a</span></a> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">"tn15more inline"</span> <span style="color: #000066;">href</span>=<span style="color: #ff0000;">"/rg/title-tease/taglines/title/tt0335266/taglines"</span><span style="color: #000000; font-weight: bold;">&gt;</span></a></span>more<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/a&gt;</span></span><br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/div&gt;</span></span></p>
<p><span style="color: #009900;"><a href="http://december.com/html/4/element/div.html"><span style="color: #000000; font-weight: bold;">&lt;div</span></a> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">"info"</span><span style="color: #000000; font-weight: bold;">&gt;</span></a></span><br />
<span style="color: #009900;"><a href="http://december.com/html/4/element/h5.html"><span style="color: #000000; font-weight: bold;">&lt;h5&gt;</span></a></span>Plot Outline:<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/h5&gt;</span></span> <br />
A movie star with a sense of emptiness, and a neglected newlywed meet up as strangers in Tokyo, Japan and form an unlikely bond. <span style="color: #009900;"><a href="http://december.com/html/4/element/a.html"><span style="color: #000000; font-weight: bold;">&lt;a</span></a> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">"tn15more inline"</span> <span style="color: #000066;">href</span>=<span style="color: #ff0000;">"/rg/title-tease/plotsummary/title/tt0335266/plotsummary"</span><span style="color: #000000; font-weight: bold;">&gt;</span></a></span>more<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/a&gt;</span></span><br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/div&gt;</span></span></p>
<p><span style="color: #009900;"><a href="http://december.com/html/4/element/div.html"><span style="color: #000000; font-weight: bold;">&lt;div</span></a> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">"info"</span><span style="color: #000000; font-weight: bold;">&gt;</span></a></span><br />
<span style="color: #009900;"><a href="http://december.com/html/4/element/h5.html"><span style="color: #000000; font-weight: bold;">&lt;h5&gt;</span></a></span>Plot Keywords:<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/h5&gt;</span></span></p>
<p><span style="color: #009900;"><a href="http://december.com/html/4/element/a.html"><span style="color: #000000; font-weight: bold;">&lt;a</span></a> <span style="color: #000066;">href</span>=<span style="color: #ff0000;">"/keyword/lyrical/"</span><span style="color: #000000; font-weight: bold;">&gt;</span></a></span>Lyrical<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/a&gt;</span></span><br />
&nbsp;/ <br />
<span style="color: #009900;"><a href="http://december.com/html/4/element/a.html"><span style="color: #000000; font-weight: bold;">&lt;a</span></a> <span style="color: #000066;">href</span>=<span style="color: #ff0000;">"/keyword/reflection/"</span><span style="color: #000000; font-weight: bold;">&gt;</span></a></span>Reflection<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/a&gt;</span></span><br />
&nbsp;/ <br />
<span style="color: #009900;"><a href="http://december.com/html/4/element/a.html"><span style="color: #000000; font-weight: bold;">&lt;a</span></a> <span style="color: #000066;">href</span>=<span style="color: #ff0000;">"/keyword/psychological-drama/"</span><span style="color: #000000; font-weight: bold;">&gt;</span></a></span>Psychological<span style="color: #ddbb00;">&amp;#160;</span>Drama<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/a&gt;</span></span><br />
&nbsp;/ </p>
<p><span style="color: #009900;"><a href="http://december.com/html/4/element/a.html"><span style="color: #000000; font-weight: bold;">&lt;a</span></a> <span style="color: #000066;">href</span>=<span style="color: #ff0000;">"/keyword/loneliness/"</span><span style="color: #000000; font-weight: bold;">&gt;</span></a></span>Loneliness<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/a&gt;</span></span><br />
&nbsp;/ <br />
<span style="color: #009900;"><a href="http://december.com/html/4/element/a.html"><span style="color: #000000; font-weight: bold;">&lt;a</span></a> <span style="color: #000066;">href</span>=<span style="color: #ff0000;">"/keyword/advertising/"</span><span style="color: #000000; font-weight: bold;">&gt;</span></a></span>Advertising<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/a&gt;</span></span></p>
<p><span style="color: #009900;"><a href="http://december.com/html/4/element/a.html"><span style="color: #000000; font-weight: bold;">&lt;a</span></a> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">"tn15more inline"</span> <span style="color: #000066;">href</span>=<span style="color: #ff0000;">"/rg/title-tease/keywords/title/tt0335266/keywords"</span><span style="color: #000000; font-weight: bold;">&gt;</span></a></span>more<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/a&gt;</span></span></p>
<p><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/div&gt;</span></span></p>
<p><span style="color: #009900;"><a href="http://december.com/html/4/element/div.html"><span style="color: #000000; font-weight: bold;">&lt;div</span></a> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">"info"</span><span style="color: #000000; font-weight: bold;">&gt;</span></a></span><br />
<span style="color: #009900;"><a href="http://december.com/html/4/element/h5.html"><span style="color: #000000; font-weight: bold;">&lt;h5&gt;</span></a></span>Awards:<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/h5&gt;</span></span> <br />
Won Oscar.<br />
&nbsp;Another 67 wins<br />
<span style="color: #ddbb00;">&amp;amp;</span></p>
<p>50 nominations<br />
<span style="color: #009900;"><a href="http://december.com/html/4/element/a.html"><span style="color: #000000; font-weight: bold;">&lt;a</span></a> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">"tn15more inline"</span> <span style="color: #000066;">href</span>=<span style="color: #ff0000;">"/rg/title-tease/awards/title/tt0335266/awards"</span><span style="color: #000000; font-weight: bold;">&gt;</span></a></span>more<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/a&gt;</span></span><br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/div&gt;</span></span></div>
</div>
</div>
<p></p>
<p>We could extract each piece in it's own separate method, but I'm lazy so I think I'll just create one method called extrainfo that returns a hash of all the extra information back.</p>
<div class="syntax_hilite">
<div id="ruby-55">
<div class="ruby"><span style="color:#9966CC; font-weight:bold;">def</span> extrainfo<br />
&nbsp;<span style="color:#9966CC; font-weight:bold;">if</span> @extrainfo == <span style="color:#0000FF; font-weight:bold;">nil</span> <span style="color:#008000; font-style:italic;">#don't do it twice</span><br />
&nbsp; &nbsp; @extrainfo = <span style="color:#006600; font-weight:bold;">&#123;</span><span style="color:#006600; font-weight:bold;">&#125;</span> <span style="color:#008000; font-style:italic;">#init our hash</span><br />
&nbsp; &nbsp; <span style="color:#006600; font-weight:bold;">&#40;</span>@hp/<span style="color:#996600;">"div.info"</span><span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">each</span> <span style="color:#9966CC; font-weight:bold;">do</span> |inf| <span style="color:#008000; font-style:italic;">#go through each info div</span><br />
&nbsp; &nbsp; &nbsp; title = inf/<span style="color:#996600;">"h5"</span> <span style="color:#008000; font-style:italic;">#the type of infobox is stored in h5</span><br />
&nbsp; &nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">if</span> title.<span style="color:#9900CC;">any</span>? <span style="color:#008000; font-style:italic;">#if we found one , we got data</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; body = inf.<span style="color:#9900CC;">inner_text</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; body = body.<span style="color:#CC0066; font-weight:bold;">gsub</span><span style="color:#006600; font-weight:bold;">&#40;</span>/\n/,''<span style="color:#006600; font-weight:bold;">&#41;</span> <span style="color:#008000; font-style:italic;">#remove newlines</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">if</span> body =~ /\:<span style="color:#006600; font-weight:bold;">&#40;</span>.+<span style="color:#006600; font-weight:bold;">&#41;</span>/ <span style="color:#008000; font-style:italic;">#extract body from our text</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; body = $<span style="color:#006666;">1</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; @extrainfo<span style="color:#006600; font-weight:bold;">&#91;</span>title.<span style="color:#9900CC;">inner_text</span>.<span style="color:#CC0066; font-weight:bold;">gsub</span><span style="color:#006600; font-weight:bold;">&#40;</span>/<span style="color:#006600; font-weight:bold;">&#91;</span>:\s<span style="color:#006600; font-weight:bold;">&#93;</span>/,''<span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">downcase</span><span style="color:#006600; font-weight:bold;">&#93;</span> = body <span style="color:#008000; font-style:italic;">#store the body</span><br />
&nbsp; &nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
&nbsp; &nbsp; @extrainfo<br />
<span style="color:#9966CC; font-weight:bold;">end</span></div>
</div>
</div>
<p></p>
<p>So our first query "div.info" is a CSS based query, it searches for all div boxes with a class of info. Now, we've got to find a way to extract the title to use as a key in the hash, and the rest of the body will be the value of the hash.</p>
<p>Examining the info div's closer I see the title is always stored in an h5 tag, so what we'll do is for each info div we'll grab the first h5 tag from that div. Hpricot allows you to nest queries, so the results of our first search is also searchable, and so on. So we can search each of our inf variables for all h5 tags, once we find one we simply do a little bit of regular expression magic to separate the body from the title, then store that information in the @extrainformation hash.</p>
<h3>All Done</h3>
<p>So our finished class now looks like this:</p>
<div class="syntax_hilite">
<div id="ruby-56">
<div class="ruby"><span style="color:#9966CC; font-weight:bold;">class</span> IMDB<br />
<span style="color:#008000; font-style:italic;">#uncomment the next line if you installed hpricot from the gem</span><br />
<span style="color:#008000; font-style:italic;">#require 'rubygems'</span><br />
<span style="color:#CC0066; font-weight:bold;">require</span> 'hpricot'<br />
<span style="color:#CC0066; font-weight:bold;">require</span> 'open-uri'</p>
<p><span style="color:#9966CC; font-weight:bold;">def</span> initialize<span style="color:#006600; font-weight:bold;">&#40;</span>url<span style="color:#006600; font-weight:bold;">&#41;</span><br />
&nbsp; @url = url;<br />
&nbsp; @hp = Hpricot<span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#CC0066; font-weight:bold;">open</span><span style="color:#006600; font-weight:bold;">&#40;</span>@url<span style="color:#006600; font-weight:bold;">&#41;</span><span style="color:#006600; font-weight:bold;">&#41;</span><br />
<span style="color:#9966CC; font-weight:bold;">end</span><br />
<span style="color:#9966CC; font-weight:bold;">def</span>&nbsp; title<br />
&nbsp; &nbsp;@title = @hp.<span style="color:#9900CC;">at</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">"meta[@name='title']"</span><span style="color:#006600; font-weight:bold;">&#41;</span><span style="color:#006600; font-weight:bold;">&#91;</span>'content'<span style="color:#006600; font-weight:bold;">&#93;</span><br />
<span style="color:#9966CC; font-weight:bold;">end</span><br />
<span style="color:#9966CC; font-weight:bold;">def</span> rating<br />
&nbsp; &nbsp; rating_text = <span style="color:#006600; font-weight:bold;">&#40;</span>@hp/<span style="color:#996600;">"div.rating/b"</span><span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">inner_text</span><br />
&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">if</span> rating_text =~ /<span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#006600; font-weight:bold;">&#91;</span>\d\.<span style="color:#006600; font-weight:bold;">&#93;</span>+<span style="color:#006600; font-weight:bold;">&#41;</span>\/<span style="color:#006666;">10</span>/<br />
&nbsp; &nbsp; &nbsp; @rating = $<span style="color:#006666;">1</span><br />
&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
&nbsp; &nbsp; @rating<br />
<span style="color:#9966CC; font-weight:bold;">end</span></p>
<p><span style="color:#9966CC; font-weight:bold;">def</span> extrainfo<br />
&nbsp;<span style="color:#9966CC; font-weight:bold;">if</span> @extrainfo == <span style="color:#0000FF; font-weight:bold;">nil</span> <span style="color:#008000; font-style:italic;">#don't do it twice</span><br />
&nbsp; &nbsp; @extrainfo = <span style="color:#006600; font-weight:bold;">&#123;</span><span style="color:#006600; font-weight:bold;">&#125;</span> <span style="color:#008000; font-style:italic;">#init our hash</span><br />
&nbsp; &nbsp; <span style="color:#006600; font-weight:bold;">&#40;</span>@hp/<span style="color:#996600;">"div.info"</span><span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">each</span> <span style="color:#9966CC; font-weight:bold;">do</span> |inf| <span style="color:#008000; font-style:italic;">#go through each info div</span><br />
&nbsp; &nbsp; &nbsp; title = inf/<span style="color:#996600;">"h5"</span> <span style="color:#008000; font-style:italic;">#the type of infobox is stored in h5</span><br />
&nbsp; &nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">if</span> title.<span style="color:#9900CC;">any</span>? <span style="color:#008000; font-style:italic;">#if we found one , we got data</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; body = inf.<span style="color:#9900CC;">inner_text</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; body = body.<span style="color:#CC0066; font-weight:bold;">gsub</span><span style="color:#006600; font-weight:bold;">&#40;</span>/\n/,''<span style="color:#006600; font-weight:bold;">&#41;</span> <span style="color:#008000; font-style:italic;">#remove newlines</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">if</span> body =~ /\:<span style="color:#006600; font-weight:bold;">&#40;</span>.+<span style="color:#006600; font-weight:bold;">&#41;</span>/ <span style="color:#008000; font-style:italic;">#extract body from our text</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; body = $<span style="color:#006666;">1</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; @extrainfo<span style="color:#006600; font-weight:bold;">&#91;</span>title.<span style="color:#9900CC;">inner_text</span>.<span style="color:#CC0066; font-weight:bold;">gsub</span><span style="color:#006600; font-weight:bold;">&#40;</span>/<span style="color:#006600; font-weight:bold;">&#91;</span>:\s<span style="color:#006600; font-weight:bold;">&#93;</span>/,''<span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">downcase</span><span style="color:#006600; font-weight:bold;">&#93;</span> = body <span style="color:#008000; font-style:italic;">#store the body</span><br />
&nbsp; &nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
&nbsp; &nbsp; @extrainfo<br />
<span style="color:#9966CC; font-weight:bold;">end</span></p>
<p><span style="color:#9966CC; font-weight:bold;">def</span> reset<br />
&nbsp; @rating = <span style="color:#0000FF; font-weight:bold;">nil</span><br />
&nbsp; @extrainfo = <span style="color:#0000FF; font-weight:bold;">nil</span><br />
<span style="color:#9966CC; font-weight:bold;">end</span><br />
<span style="color:#9966CC; font-weight:bold;">end</span></div>
</div>
</div>
<p></p>
<p>You could certainly get much more advanced in your IMDB scraper class, but the above should get you started. Here's a quick test script to see how our class worked.</p>
<div class="syntax_hilite">
<div id="ruby-57">
<div class="ruby"><span style="color:#CC0066; font-weight:bold;">require</span> 'IMDB'</p>
<p>imdb = IMDB.<span style="color:#9900CC;">new</span><span style="color:#006600; font-weight:bold;">&#40;</span>'http://imdb.<span style="color:#9900CC;">com</span>/title/tt0335266/'<span style="color:#006600; font-weight:bold;">&#41;</span></p>
<p><span style="color:#CC0066; font-weight:bold;">p</span> imdb.<span style="color:#9900CC;">rating</span><br />
<span style="color:#CC0066; font-weight:bold;">p</span> imdb.<span style="color:#9900CC;">title</span><br />
<span style="color:#CC0066; font-weight:bold;">p</span> imdb.<span style="color:#9900CC;">extrainfo</span></div>
</div>
</div>
<p></p>
<p>So running this script gives us the output</p>
<div class="syntax_hilite">
<div id="code-58">
<div class="code"><span style="color:#800000;">7</span>.9<span style="color:#CC0000;">"<br />
"</span>Lost in Translation <span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#800000;">2003</span><span style="color:#006600; font-weight:bold;">&#41;</span><span style="color:#CC0000;">"<br />
{"</span>company<span style="color:#CC0000;">"=&gt;"</span>American Zoetropemore<span style="color:#CC0000;">", "</span>quotes<span style="color:#CC0000;">"=&gt;"</span>Bob:I don<span style="color:#CC0000;">'t get that close to the glass until I'</span>m on the floor.<span style="">more</span><span style="color:#CC0000;">", "</span>director<span style="color:#CC0000;">"=&gt;"</span>Sofia Coppola<span style="color:#CC0000;">", "</span>goofs<span style="color:#CC0000;">"=&gt;"</span>Continuity: The pink flowers in Charlotte<span style="color:#CC0000;">'s room disappear when she is listening to the &amp;#34;soul searching&amp;#34; tape, but reappear later in the movie.more&quot;, &quot;language&quot;=&gt;&quot;English / Japanese / German / French&quot;, &quot;usercomments&quot;=&gt;&quot;breath takingmore&quot;, &quot;moviemeter&quot;=&gt;&quot;&nbsp; 35% since last weekwhy?&quot;, &quot;mpaa&quot;=&gt;&quot; Rated R for some sexual content.&quot;, &quot;filminglocations&quot;=&gt;&quot; Japanmore&quot;, &quot;certification&quot;=&gt;&quot;Indonesia:Dewasa&nbsp; / Malaysia:18PL (re-rating) / Malaysia:(Banned) (uncut version) / Iceland:L&nbsp; / Canada:PG (British Columbia/Manitoba/Nova Scotia/Ontario) / Hungary:14&nbsp; / Argentina:13&nbsp; / Australia:PG&nbsp; / Brazil:14&nbsp; / Canada:14A (Alberta) / Canada:G (Qu&amp;#233;bec) / Chile:TE&nbsp; / Finland:K-11&nbsp; / Germany:6 (bw) / Hong Kong:IIB&nbsp; / Italy:T&nbsp; / Netherlands:AL&nbsp; / New Zealand:PG&nbsp; / Norway:A&nbsp; / Peru:PT&nbsp; / Philippines:PG-13&nbsp; / Portugal:M/12&nbsp; / Singapore:PG (edited for re-rating) / Singapore:R(A) (original rating) / South Korea:15&nbsp; / Spain:13&nbsp; / Sweden:Btl&nbsp; / Switzerland:12 (canton of the Grisons) / UK:15&nbsp; / USA:R&nbsp; / Singapore:M18 (DVD rating)&quot;, &quot;country&quot;=&gt;&quot;USA / Japan&quot;, &quot;awards&quot;=&gt;&quot; Won Oscar. Another 67 wins&amp;amp;50 nominationsmore&quot;, &quot;plotkeywords&quot;=&gt;&quot;Lyrical / Reflection / Psychological&amp;#160;Drama / Loneliness / Advertisingmore&quot;, &quot;plotoutline&quot;=&gt;&quot; A movie star with a sense of emptiness, and a neglected newlywed meet up as strangers in Tokyo, Japan and form an unlikely bond. more&quot;, &quot;soundtrack&quot;=&gt;&quot; She Gets Aroundmore&quot;, &quot;soundmix&quot;=&gt;&quot;Dolby Digital &quot;, &quot;runtime&quot;=&gt;&quot;102 min &quot;, &quot;writer(wga)&quot;=&gt;&quot;Sofia Coppola (written by)&quot;, &quot;trivia&quot;=&gt;&quot;In 1999, Bill Murray replaced his talent agency with an automated voice mailbox that can be reached with an 800 number he gives out sparingly. Sofia Coppola reportedly left hundreds of messages on Murray'</span>s mailbox before he finally called back to discuss her offer to cast him as the star.<span style="">more</span><span style="color:#CC0000;">", "</span>color<span style="color:#CC0000;">"=&gt;"</span>Color <span style="color:#CC0000;">", "</span>tagline<span style="color:#CC0000;">"=&gt;"</span>Everyone wants to be found. <span style="">more</span><span style="color:#CC0000;">", "</span>genre<span style="color:#CC0000;">"=&gt;"</span>Comedy / Drama / Romance more<span style="color:#CC0000;">", "</span>aspectratio<span style="color:#CC0000;">"=&gt;"</span><span style="color:#800000;">1</span>.<span style="color:#800000;">85</span> : <span style="color:#800000;">1</span> more<span style="color:#CC0000;">", "</span>movieconnections<span style="color:#CC0000;">"=&gt;"</span> Featured in The <span style="color:#800000;">2004</span> IFP/West Independent Spirit Awards <span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#800000;">2004</span><span style="color:#006600; font-weight:bold;">&#41;</span> <span style="color:#006600; font-weight:bold;">&#40;</span>TV<span style="color:#006600; font-weight:bold;">&#41;</span>more<span style="color:#CC0000;">", "</span>releasedate<span style="color:#CC0000;">"=&gt;"</span> <span style="color:#800000;">3</span> October <span style="color:#800000;">2003</span> <span style="color:#006600; font-weight:bold;">&#40;</span>USA<span style="color:#006600; font-weight:bold;">&#41;</span> more view trailer<span style="color:#CC0000;">"} </span></div>
</div>
</div>
<p></p>
<h3>More Information</h3>
<p><a href="http://code.whytheluckystiff.net/hpricot/wiki/AnHpricotShowcase">Hpricot Showcase</a><br/><br />
<a href="http://code.whytheluckystiff.net/doc/hpricot/">Hpricot API Documentation</a></p>
<!-- Social Bookmarks BEGIN --><div class="social_bookmark"><em>Bookmark to:</em><br /><a class="social_img" onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://del.icio.us/post?url=http://www.weheartcode.com/2007/04/03/scraping-imdb-with-ruby-and-hpricot/&amp;title=Scraping+IMDB+with+Ruby+and+Hpricot" title="Add 'Scraping IMDB with Ruby and Hpricot' to Del.icio.us"><img src="http://www.weheartcode.com/wp-content/plugins/social_bookmarks/delicious.png" title="Add 'Scraping IMDB with Ruby and Hpricot' to Del.icio.us" alt="Add 'Scraping IMDB with Ruby and Hpricot' to Del.icio.us" /></a><a class="social_img" onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://digg.com/submit?phase=2&amp;url=http://www.weheartcode.com/2007/04/03/scraping-imdb-with-ruby-and-hpricot/&amp;title=Scraping+IMDB+with+Ruby+and+Hpricot" title="Add 'Scraping IMDB with Ruby and Hpricot' to digg"><img src="http://www.weheartcode.com/wp-content/plugins/social_bookmarks/digg.png" title="Add 'Scraping IMDB with Ruby and Hpricot' to digg" alt="Add 'Scraping IMDB with Ruby and Hpricot' to digg" /></a><a class="social_img" onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://furl.net/storeIt.jsp?t=Scraping+IMDB+with+Ruby+and+Hpricot&amp;u=http://www.weheartcode.com/2007/04/03/scraping-imdb-with-ruby-and-hpricot/" title="Add 'Scraping IMDB with Ruby and Hpricot' to FURL"><img src="http://www.weheartcode.com/wp-content/plugins/social_bookmarks/furl.png" title="Add 'Scraping IMDB with Ruby and Hpricot' to FURL" alt="Add 'Scraping IMDB with Ruby and Hpricot' to FURL" /></a><a class="social_img" onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://reddit.com/submit?url=http://www.weheartcode.com/2007/04/03/scraping-imdb-with-ruby-and-hpricot/&amp;title=Scraping+IMDB+with+Ruby+and+Hpricot" title="Add 'Scraping IMDB with Ruby and Hpricot' to reddit"><img src="http://www.weheartcode.com/wp-content/plugins/social_bookmarks/reddit.png" title="Add 'Scraping IMDB with Ruby and Hpricot' to reddit" alt="Add 'Scraping IMDB with Ruby and Hpricot' to reddit" /></a><a class="social_img" onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.technorati.com/faves?add=http://www.weheartcode.com/2007/04/03/scraping-imdb-with-ruby-and-hpricot/" title="Add 'Scraping IMDB with Ruby and Hpricot' to Technorati"><img src="http://www.weheartcode.com/wp-content/plugins/social_bookmarks/technorati.png" title="Add 'Scraping IMDB with Ruby and Hpricot' to Technorati" alt="Add 'Scraping IMDB with Ruby and Hpricot' to Technorati" /></a><a class="social_img" onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.google.com/bookmarks/mark?op=edit&amp;output=popup&amp;bkmk=http://www.weheartcode.com/2007/04/03/scraping-imdb-with-ruby-and-hpricot/&amp;title=Scraping+IMDB+with+Ruby+and+Hpricot" title="Add 'Scraping IMDB with Ruby and Hpricot' to Google Bookmarks"><img src="http://www.weheartcode.com/wp-content/plugins/social_bookmarks/google.png" title="Add 'Scraping IMDB with Ruby and Hpricot' to Google Bookmarks" alt="Add 'Scraping IMDB with Ruby and Hpricot' to Google Bookmarks" /></a></div>
<!-- Social Bookmarks END -->]]></content:encoded>
			<wfw:commentRss>http://www.weheartcode.com/2007/04/03/scraping-imdb-with-ruby-and-hpricot/feed/</wfw:commentRss>
		<slash:comments>22</slash:comments>
		</item>
		<item>
		<title>Importing an MS Project Plan into Basecamp using Ruby</title>
		<link>http://www.weheartcode.com/2006/12/20/importing-an-ms-project-plan-into-basecamp-using-ruby/</link>
		<comments>http://www.weheartcode.com/2006/12/20/importing-an-ms-project-plan-into-basecamp-using-ruby/#comments</comments>
		<pubDate>Wed, 20 Dec 2006 15:18:23 +0000</pubDate>
		<dc:creator>Tim</dc:creator>
				<category><![CDATA[ruby]]></category>
		<category><![CDATA[tutorial]]></category>

		<guid isPermaLink="false">http://www.weheartcode.com/2006/12/20/importing-an-ms-project-plan-into-basecamp-using-ruby/</guid>
		<description><![CDATA[Basecamp is a web based project management tool. It's just fun to use. Microsoft Project....not so much.
That being said MS Project does a whole lot of stuff that Basecamp doesn't. Being leet web 2.0 doods we want to use Basecamp! Of course MS Project is the standard that most clients like to see, so we're [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.basecamphq.com">Basecamp</a> is a web based project management tool. It's just fun to use. Microsoft Project....not so much.<br />
That being said MS Project does a whole lot of stuff that Basecamp doesn't. Being leet web 2.0 doods we want to use Basecamp! Of course MS Project is the standard that most clients like to see, so we're kind of stuck.</p>
<p>So why not the best of both worlds, MS Project and Basecamp without having to retype everything into Basecamp!</p>
<p>With a bit of ruby and the help of the Basecamp API we can save a lot of time.<br />
<span id="more-13"></span></p>
<h3>Introduction</h3>
<p>MS Project gives us tons of different ways to organize our project, Basecamp has only a few simple ways so our mapping can't really be one to one. Basecamp offers the following concepts: Milestones, To-Do Lists (made up of items, may be linked to a milestone). </p>
<p>Here is the basic strategy I used for <strong>my</strong> project plan.</p>
<p>MS Project Milestone = Basecamp Milestone<br />
MS Project Tasks under Milestone = Basecamp to-do list  linked to milestone.</p>
<p>So our script simply loops through the project, when it hits a milestone we create a milestone, we collect all the tasks into a list until we hit the next milestone and the cycle begins again. So we end up with one whole to-do list per milestone.</p>
<p>Prerequisites:</p>
<ul>
<li><strong>Activate the Basecamp API for your project</strong> in your Account Settings (the same page where you would go to upgrade your account to pro). If you don't do this you'll see the script complain with 404 errors</li>
<li><a href="http://www.basecamphq.com/api/basecamp.rb">Download the ruby Basecamp API Wrapper</a>. Put this in the same directory as your script.
</li>
<li>Install the xml-simple gem.</li>
</ul>
<h3>Exporting from MS Project</h3>
<p>MS Project has a very nice export wizard. It allows you to export to a CSV file and specify filters and fields.</p>
<p>To access the export wizard, open up your project plan and choose File->Save As, for the 'Save as type' choose CSV (Comma delimited) (*.csv).</p>
<p>When prompted by the wizard to create or choose an export map, choose New map and click next, in the next dialog box choose Tasks as the type of data to export, uncheck 'Export includes headers', make sure our text delimiter is comma and click Next.</p>
<p>Now it's time to create our map, this is where we tell Project what columns to put in our CSV file.</p>
<p>For this script I just want the following data: [task name],[baseline finish date],[milestone].</p>
<p>So choose those three options, here's how mine looks:<br />
<img src="/export_wiz_ss.jpg"></p>
<p>Click Next, you can save the map for later if you want to do this again.</p>
<p>Another wrinkle, I like the following date format in MS Project: Tues 11/06/06 (Day MM/YY/DD). If you don't like it, no biggie you just have to figure out how to turn your preferred date format into YYYY-MM-DD later on in the script. I hope you like regex's!</p>
<h3>The Script</h3>
<p>Now it's time to write our script, so let's review what it should do:</p>
<p>Login to Basecamp<br />
Select our project<br />
Loop through our CSV<br />
Create a collection that looks like this: Milestone->Task List<br />
Insert milestones and task lists into basecamp!</p>
<p><strong>Disclaimer</strong>: I have the ruby programming skills of a 4 year old girl, I know this. I do not claim to be an expert ruby ninja, feel free to improve the script.</p>
<p>Here is the <a href="http://www.weheartcode.com/import_msproject.rb">script</a>, so place this in the same directory as your csv file and the <a href="http://www.basecamphq.com/api/basecamp.rb"> basecamp.rb</a> file from 37 Signals.</p>
<div class="syntax_hilite">
<div id="ruby-62">
<div class="ruby"><span style="color:#008000; font-style:italic;">#!/usr/bin/ruby</span></p>
<p><span style="color:#008000; font-style:italic;">#Script by weheartcode.com, modify however you like.</span><br />
<span style="color:#008000; font-style:italic;">#WARNING THIS SCRIPT CAN HOSE YOUR BASECAMP ACCOUNT</span><br />
<span style="color:#008000; font-style:italic;">#Don't be stupid, try it on a test account first</span></p>
<p><span style="color:#CC0066; font-weight:bold;">require</span> 'basecamp'</p>
<p>
<span style="color:#008000; font-style:italic;">#Fill in these variables, PLEASE TRY ON TEST ACCOUNT FIRST</span><br />
basecampurl = 'YOURBASECAMPURL' <span style="color:#008000; font-style:italic;">#Ex. weheartcode.grouphub.com</span></p>
<p>basecampuser = 'CHANGEME'<br />
basecamppass = 'CHANGEME'</p>
<p>msprojcsvfile = 'CHANGEME' <span style="color:#008000; font-style:italic;">#Ex. export.csv</span></p>
<p><span style="color:#008000; font-style:italic;">#Connect to basecamp using the Basecamp API Ruby Wrapper</span><br />
session = Basecamp.<span style="color:#9900CC;">new</span><span style="color:#006600; font-weight:bold;">&#40;</span>basecampurl,basecampuser,basecamppass<span style="color:#006600; font-weight:bold;">&#41;</span></p>
<p>
<span style="color:#008000; font-style:italic;">#Assume we're working on the first project</span><br />
project = session.<span style="color:#9900CC;">projects</span>.<span style="color:#9900CC;">first</span></p>
<p>milestones = <span style="color:#CC0066; font-weight:bold;">Array</span>.<span style="color:#9900CC;">new</span></p>
<p><span style="color:#CC0066; font-weight:bold;">puts</span> <span style="color:#996600;">"Creating data structure..."</span></p>
<p><span style="color:#008000; font-style:italic;">#Read our file line by line</span><br />
<span style="color:#CC0066; font-weight:bold;">open</span><span style="color:#006600; font-weight:bold;">&#40;</span>msprojcsvfile<span style="color:#006600; font-weight:bold;">&#41;</span><span style="color:#006600; font-weight:bold;">&#123;</span>|f|<br />
&nbsp; f.<span style="color:#9900CC;">each_line</span> <span style="color:#006600; font-weight:bold;">&#123;</span>|line|<br />
&nbsp; data = line.<span style="color:#CC0066; font-weight:bold;">split</span><span style="color:#006600; font-weight:bold;">&#40;</span>','<span style="color:#006600; font-weight:bold;">&#41;</span><br />
&nbsp; milestone = Hash.<span style="color:#9900CC;">new</span></p>
<p>&nbsp; ismile = data<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#006666;">2</span><span style="color:#006600; font-weight:bold;">&#93;</span></p>
<p>&nbsp; <span style="color:#008000; font-style:italic;">#if we just hit a milestone, create one and add it to our Array</span><br />
&nbsp; <span style="color:#9966CC; font-weight:bold;">if</span> 'Yes' == ismile.<span style="color:#9900CC;">strip</span><br />
&nbsp; &nbsp; <span style="color:#008000; font-style:italic;">#reconbobulate date for deadline</span><br />
&nbsp; &nbsp; <span style="color:#008000; font-style:italic;">#Expecting Day dd/mm/yyyy format (ex. Tues 12/25/2006)</span><br />
&nbsp; &nbsp; &nbsp;m1 = /.+\s<span style="color:#006600; font-weight:bold;">&#40;</span>\d+?<span style="color:#006600; font-weight:bold;">&#41;</span>\/<span style="color:#006600; font-weight:bold;">&#40;</span>\d+?<span style="color:#006600; font-weight:bold;">&#41;</span>\/<span style="color:#006600; font-weight:bold;">&#40;</span>\d+<span style="color:#006600; font-weight:bold;">&#41;</span>/.<span style="color:#9900CC;">match</span><span style="color:#006600; font-weight:bold;">&#40;</span>data<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#006666;">1</span><span style="color:#006600; font-weight:bold;">&#93;</span>.<span style="color:#9900CC;">strip</span><span style="color:#006600; font-weight:bold;">&#41;</span><br />
&nbsp; &nbsp; &nbsp;deadline = <span style="color:#996600;">"20"</span> + m1<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#006666;">3</span><span style="color:#006600; font-weight:bold;">&#93;</span> + <span style="color:#996600;">"-"</span> + m1<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#006666;">1</span><span style="color:#006600; font-weight:bold;">&#93;</span> + <span style="color:#996600;">"-"</span> + m1<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#006666;">2</span><span style="color:#006600; font-weight:bold;">&#93;</span></p>
<p>&nbsp; &nbsp; &nbsp; milestone<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#996600;">"title"</span><span style="color:#006600; font-weight:bold;">&#93;</span> = data<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#006666;">0</span><span style="color:#006600; font-weight:bold;">&#93;</span><br />
&nbsp; &nbsp; &nbsp; milestone<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#996600;">"deadline"</span><span style="color:#006600; font-weight:bold;">&#93;</span> = deadline<br />
&nbsp; &nbsp; &nbsp; milestone<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#996600;">"thelist"</span><span style="color:#006600; font-weight:bold;">&#93;</span> = <span style="color:#CC0066; font-weight:bold;">Array</span>.<span style="color:#9900CC;">new</span><br />
&nbsp; &nbsp; &nbsp; milestones &lt;&lt;milestone<br />
&nbsp; <span style="color:#008000; font-style:italic;">#otherwise, we just have a normal task</span><br />
&nbsp; <span style="color:#9966CC; font-weight:bold;">else</span><br />
&nbsp; &nbsp; &nbsp;<span style="color:#008000; font-style:italic;">#Add task to current milestone list array</span><br />
&nbsp; &nbsp; &nbsp;milestones.<span style="color:#9900CC;">last</span><span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#996600;">"thelist"</span><span style="color:#006600; font-weight:bold;">&#93;</span> &lt;&lt;data<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#006666;">0</span><span style="color:#006600; font-weight:bold;">&#93;</span><br />
&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
&nbsp;<span style="color:#006600; font-weight:bold;">&#125;</span><br />
<span style="color:#006600; font-weight:bold;">&#125;</span></p>
<p><span style="color:#008000; font-style:italic;">#Reverse our milestone list, so that the to-do's show up oldest first</span><br />
milestones.<span style="color:#9900CC;">reverse</span></p>
<p><span style="color:#008000; font-style:italic;">#Let's go through each milestone and add to basecamp</span><br />
milestones.<span style="color:#9900CC;">each</span><span style="color:#006600; font-weight:bold;">&#123;</span> |m|</p>
<p><span style="color:#008000; font-style:italic;">#Get a copy of our todo list</span><br />
tasklist = m<span style="color:#006600; font-weight:bold;">&#91;</span>'thelist'<span style="color:#006600; font-weight:bold;">&#93;</span></p>
<p><span style="color:#008000; font-style:italic;">#Nil out key so we dont send to basecamp API</span><br />
m<span style="color:#006600; font-weight:bold;">&#91;</span>'thelist'<span style="color:#006600; font-weight:bold;">&#93;</span> = <span style="color:#0000FF; font-weight:bold;">nil</span></p>
<p><span style="color:#008000; font-style:italic;">#Create a milestone with our project id</span><br />
<span style="color:#008000; font-style:italic;">#Uaing the data from our milestone hash</span><br />
session.<span style="color:#9900CC;">create_milestone</span><span style="color:#006600; font-weight:bold;">&#40;</span>project.<span style="color:#9900CC;">id</span>,m<span style="color:#006600; font-weight:bold;">&#41;</span></p>
<p><span style="color:#CC0066; font-weight:bold;">puts</span> <span style="color:#996600;">"Milestone created."</span></p>
<p><span style="color:#008000; font-style:italic;">#Grab an instance of the milestone we just created</span><br />
themile = session.<span style="color:#9900CC;">milestones</span><span style="color:#006600; font-weight:bold;">&#40;</span>project.<span style="color:#9900CC;">id</span><span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">last</span></p>
<p><span style="color:#008000; font-style:italic;">#create a to-do list for milestone</span><br />
tmplist = Hash.<span style="color:#9900CC;">new</span><br />
tmplist<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#996600;">"tracked"</span><span style="color:#006600; font-weight:bold;">&#93;</span> = <span style="color:#0000FF; font-weight:bold;">false</span>;</p>
<p><span style="color:#008000; font-style:italic;">#Use milestone title prefixed with M-LISt for list title</span><br />
tmplist<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#996600;">"name"</span><span style="color:#006600; font-weight:bold;">&#93;</span> = <span style="color:#996600;">"M-LIST: "</span> + m<span style="color:#006600; font-weight:bold;">&#91;</span>'title'<span style="color:#006600; font-weight:bold;">&#93;</span><br />
tmplist<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#996600;">"description"</span><span style="color:#006600; font-weight:bold;">&#93;</span> = <span style="color:#996600;">"Task list for milestone."</span><br />
tmplist<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#996600;">"milestone-id"</span><span style="color:#006600; font-weight:bold;">&#93;</span> = themile.<span style="color:#9900CC;">id</span></p>
<p>
<span style="color:#008000; font-style:italic;">#Create the list with Basecamp API</span><br />
session.<span style="color:#9900CC;">create_list</span><span style="color:#006600; font-weight:bold;">&#40;</span>project.<span style="color:#9900CC;">id</span>,tmplist<span style="color:#006600; font-weight:bold;">&#41;</span></p>
<p><span style="color:#CC0066; font-weight:bold;">puts</span> <span style="color:#996600;">"Milestone list created."</span></p>
<p>thelist = session.<span style="color:#9900CC;">lists</span><span style="color:#006600; font-weight:bold;">&#40;</span>project.<span style="color:#9900CC;">id</span>,<span style="color:#0000FF; font-weight:bold;">true</span><span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">last</span></p>
<p><span style="color:#008000; font-style:italic;">#Create items underneath our list</span><br />
tasklist.<span style="color:#9900CC;">each</span><span style="color:#006600; font-weight:bold;">&#123;</span>|task| session.<span style="color:#9900CC;">create_item</span><span style="color:#006600; font-weight:bold;">&#40;</span>thelist.<span style="color:#9900CC;">id</span>,task<span style="color:#006600; font-weight:bold;">&#41;</span><span style="color:#006600; font-weight:bold;">&#125;</span><br />
<span style="color:#006600; font-weight:bold;">&#125;</span></p>
<p><span style="color:#CC0066; font-weight:bold;">puts</span> <span style="color:#996600;">"All done!"</span></div>
</div>
</div>
<p></p>
<p>Upload the ruby script to your hosting provider (I use <a href="http://www.dreamhost.com/r.cgi?106427">dreamhost</a>) or place in the directory on your local box.</p>
<p>Make sure you have your csv file from MS project and the basecamp library from 37 signals in the same directory and the xml-simple gem installed.</p>
<p>So, we simple change the variables for the basecamp URL, username, pass, filename and run the ruby script using our favorite editor and prepare to run the script.</p>
<p><strong>For the love of god, please make sure you try this on a test account before you do it for the first time on your actual account, the results could be unexpected.</strong></p>
<div class="syntax_hilite">
<div id="code-63">
<div class="code">ruby import_basecamp.<span style="">rb</span></div>
</div>
</div>
<p></p>
<p>If all goes well you will see the script do it's thing like this.</p>
<div class="syntax_hilite">
<div id="code-64">
<div class="code">Milestone list created.<br />
<span style="">Creating</span> Item for list_id: <span style="color:#800000;">1483337</span><br />
Creating Item for list_id: <span style="color:#800000;">1483337</span><br />
Creating Item for list_id: <span style="color:#800000;">1483337</span><br />
Creating Item for list_id: <span style="color:#800000;">1483337</span><br />
.<br />
.<br />
.<br />
<span style="">All</span> done!</div>
</div>
</div>
<p></p>
<p>If you get 404 errors, please check to make sure you have the correct URL, that you have a project created in your account, and that you have <strong>activated the basecamp API</strong> in the Account tab of your basecamp account.</p>
<p>This is a very simple example, depending on how complex your MS Project Plan you may want to omit the task part all together, or modify how you name tasks/milestones. Either way it sure beats entering it all by hand.</p>
<!-- Social Bookmarks BEGIN --><div class="social_bookmark"><em>Bookmark to:</em><br /><a class="social_img" onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://del.icio.us/post?url=http://www.weheartcode.com/2006/12/20/importing-an-ms-project-plan-into-basecamp-using-ruby/&amp;title=Importing+an+MS+Project+Plan+into+Basecamp+using+Ruby" title="Add 'Importing an MS Project Plan into Basecamp using Ruby' to Del.icio.us"><img src="http://www.weheartcode.com/wp-content/plugins/social_bookmarks/delicious.png" title="Add 'Importing an MS Project Plan into Basecamp using Ruby' to Del.icio.us" alt="Add 'Importing an MS Project Plan into Basecamp using Ruby' to Del.icio.us" /></a><a class="social_img" onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://digg.com/submit?phase=2&amp;url=http://www.weheartcode.com/2006/12/20/importing-an-ms-project-plan-into-basecamp-using-ruby/&amp;title=Importing+an+MS+Project+Plan+into+Basecamp+using+Ruby" title="Add 'Importing an MS Project Plan into Basecamp using Ruby' to digg"><img src="http://www.weheartcode.com/wp-content/plugins/social_bookmarks/digg.png" title="Add 'Importing an MS Project Plan into Basecamp using Ruby' to digg" alt="Add 'Importing an MS Project Plan into Basecamp using Ruby' to digg" /></a><a class="social_img" onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://furl.net/storeIt.jsp?t=Importing+an+MS+Project+Plan+into+Basecamp+using+Ruby&amp;u=http://www.weheartcode.com/2006/12/20/importing-an-ms-project-plan-into-basecamp-using-ruby/" title="Add 'Importing an MS Project Plan into Basecamp using Ruby' to FURL"><img src="http://www.weheartcode.com/wp-content/plugins/social_bookmarks/furl.png" title="Add 'Importing an MS Project Plan into Basecamp using Ruby' to FURL" alt="Add 'Importing an MS Project Plan into Basecamp using Ruby' to FURL" /></a><a class="social_img" onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://reddit.com/submit?url=http://www.weheartcode.com/2006/12/20/importing-an-ms-project-plan-into-basecamp-using-ruby/&amp;title=Importing+an+MS+Project+Plan+into+Basecamp+using+Ruby" title="Add 'Importing an MS Project Plan into Basecamp using Ruby' to reddit"><img src="http://www.weheartcode.com/wp-content/plugins/social_bookmarks/reddit.png" title="Add 'Importing an MS Project Plan into Basecamp using Ruby' to reddit" alt="Add 'Importing an MS Project Plan into Basecamp using Ruby' to reddit" /></a><a class="social_img" onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.technorati.com/faves?add=http://www.weheartcode.com/2006/12/20/importing-an-ms-project-plan-into-basecamp-using-ruby/" title="Add 'Importing an MS Project Plan into Basecamp using Ruby' to Technorati"><img src="http://www.weheartcode.com/wp-content/plugins/social_bookmarks/technorati.png" title="Add 'Importing an MS Project Plan into Basecamp using Ruby' to Technorati" alt="Add 'Importing an MS Project Plan into Basecamp using Ruby' to Technorati" /></a><a class="social_img" onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.google.com/bookmarks/mark?op=edit&amp;output=popup&amp;bkmk=http://www.weheartcode.com/2006/12/20/importing-an-ms-project-plan-into-basecamp-using-ruby/&amp;title=Importing+an+MS+Project+Plan+into+Basecamp+using+Ruby" title="Add 'Importing an MS Project Plan into Basecamp using Ruby' to Google Bookmarks"><img src="http://www.weheartcode.com/wp-content/plugins/social_bookmarks/google.png" title="Add 'Importing an MS Project Plan into Basecamp using Ruby' to Google Bookmarks" alt="Add 'Importing an MS Project Plan into Basecamp using Ruby' to Google Bookmarks" /></a></div>
<!-- Social Bookmarks END -->]]></content:encoded>
			<wfw:commentRss>http://www.weheartcode.com/2006/12/20/importing-an-ms-project-plan-into-basecamp-using-ruby/feed/</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
		<item>
		<title>Defeating Firewalls with Putty and SSH</title>
		<link>http://www.weheartcode.com/2006/10/06/ssh-tunnel-proxy/</link>
		<comments>http://www.weheartcode.com/2006/10/06/ssh-tunnel-proxy/#comments</comments>
		<pubDate>Sat, 07 Oct 2006 01:29:55 +0000</pubDate>
		<dc:creator>Tim</dc:creator>
				<category><![CDATA[tip]]></category>
		<category><![CDATA[tutorial]]></category>

		<guid isPermaLink="false">http://www.weheartcode.com/2006/10/06/ssh-tunnel-proxy/</guid>
		<description><![CDATA[Once in a while we all get stuck behind a firewall and just have to get around it. You could use one of the many anonymizer web browsing sites which is most likely blocked or use some random proxy in Eastern Europe that features a totally leet 476 ms ping. Or if you have an [...]]]></description>
			<content:encoded><![CDATA[<p>Once in a while we all get stuck behind a firewall and just have to get around it. You could use one of the many anonymizer web browsing sites which is most likely blocked or use some random proxy in Eastern Europe that features a totally leet 476 ms ping. Or if you have an SSH account somewhere (like your webhost -- dummy) you can do some SSH tunneling voodoo to go wherever the hell you want.</p>
<p>Requirements: <a href="http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html">Putty</a>, an <a href="http://www.dreamhost.com/r.cgi?106427">SSH Account</a> like one that comes with <a href="http://www.dreamhost.com/r.cgi?106427">most web hosting plans</a>.</p>
<p><span id="more-6"></span></p>
<p>The short and sweet explanation:</p>
<blockquote><p>open up a command prompt, run putty -D 8080 yourhost.com</p>
<p>Log-in to your account at yourhost</p>
<p>Point your proxy to  localhost port 8080 (SOCKS v5)</p>
<p>You're good to go, the only catch is you must stay logged in in the putty window to use the proxy.</p></blockquote>
<p>The detailed explanation:</p>
<p>First <a href="http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html">download putty</a> if you don't already have it. You really only need putty.exe however the other tools in the putty suite are nice tools to have in your toolbox.</p>
<p>Next open up a dos prompt and navigate to whatever directory you put putty.exe in, c:\putty for me. Once you're there, type: <em>putty -D 8080 yourhost.com</em> where yourhost.com is the hostname or ip address of your SSH account. This will cause a putty window to open up, simply login like usual. <strong>Keep this window open</strong>.</p>
<p>Now open up firefox or IE and change your proxy. In Firefox go to <em>Tools->Options->Connection Settings</em> click <em>Manual proxy configuration</em> and in the box to where it says <em>SOCKS Host</em> type in <em>localhost </em>, for the port enter 8080 and select the Socks v5 radio button. If you use IE and want to configure a proxy, figure it out yourself know it all!</p>
<p>That's it,as long as you stay logged in to the SSH account you can browse the web. All traffic is now encrypted so you can head over to myspace and write another <em>omg thnx for the add XD !!!11</em> comment.</p>
<p>If you need to switch between using no proxy and using your new proxy, consider installing the <a href="https://addons.mozilla.org/firefox/125/">Switch Proxy Extension</a> for firefox, it allows you to switch proxies quickly using the status bar.</p>
<!-- Social Bookmarks BEGIN --><div class="social_bookmark"><em>Bookmark to:</em><br /><a class="social_img" onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://del.icio.us/post?url=http://www.weheartcode.com/2006/10/06/ssh-tunnel-proxy/&amp;title=Defeating+Firewalls+with+Putty+and+SSH" title="Add 'Defeating Firewalls with Putty and SSH' to Del.icio.us"><img src="http://www.weheartcode.com/wp-content/plugins/social_bookmarks/delicious.png" title="Add 'Defeating Firewalls with Putty and SSH' to Del.icio.us" alt="Add 'Defeating Firewalls with Putty and SSH' to Del.icio.us" /></a><a class="social_img" onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://digg.com/submit?phase=2&amp;url=http://www.weheartcode.com/2006/10/06/ssh-tunnel-proxy/&amp;title=Defeating+Firewalls+with+Putty+and+SSH" title="Add 'Defeating Firewalls with Putty and SSH' to digg"><img src="http://www.weheartcode.com/wp-content/plugins/social_bookmarks/digg.png" title="Add 'Defeating Firewalls with Putty and SSH' to digg" alt="Add 'Defeating Firewalls with Putty and SSH' to digg" /></a><a class="social_img" onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://furl.net/storeIt.jsp?t=Defeating+Firewalls+with+Putty+and+SSH&amp;u=http://www.weheartcode.com/2006/10/06/ssh-tunnel-proxy/" title="Add 'Defeating Firewalls with Putty and SSH' to FURL"><img src="http://www.weheartcode.com/wp-content/plugins/social_bookmarks/furl.png" title="Add 'Defeating Firewalls with Putty and SSH' to FURL" alt="Add 'Defeating Firewalls with Putty and SSH' to FURL" /></a><a class="social_img" onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://reddit.com/submit?url=http://www.weheartcode.com/2006/10/06/ssh-tunnel-proxy/&amp;title=Defeating+Firewalls+with+Putty+and+SSH" title="Add 'Defeating Firewalls with Putty and SSH' to reddit"><img src="http://www.weheartcode.com/wp-content/plugins/social_bookmarks/reddit.png" title="Add 'Defeating Firewalls with Putty and SSH' to reddit" alt="Add 'Defeating Firewalls with Putty and SSH' to reddit" /></a><a class="social_img" onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.technorati.com/faves?add=http://www.weheartcode.com/2006/10/06/ssh-tunnel-proxy/" title="Add 'Defeating Firewalls with Putty and SSH' to Technorati"><img src="http://www.weheartcode.com/wp-content/plugins/social_bookmarks/technorati.png" title="Add 'Defeating Firewalls with Putty and SSH' to Technorati" alt="Add 'Defeating Firewalls with Putty and SSH' to Technorati" /></a><a class="social_img" onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.google.com/bookmarks/mark?op=edit&amp;output=popup&amp;bkmk=http://www.weheartcode.com/2006/10/06/ssh-tunnel-proxy/&amp;title=Defeating+Firewalls+with+Putty+and+SSH" title="Add 'Defeating Firewalls with Putty and SSH' to Google Bookmarks"><img src="http://www.weheartcode.com/wp-content/plugins/social_bookmarks/google.png" title="Add 'Defeating Firewalls with Putty and SSH' to Google Bookmarks" alt="Add 'Defeating Firewalls with Putty and SSH' to Google Bookmarks" /></a></div>
<!-- Social Bookmarks END -->]]></content:encoded>
			<wfw:commentRss>http://www.weheartcode.com/2006/10/06/ssh-tunnel-proxy/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
	</channel>
</rss>
