<?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>everburning &#187; Article</title>
	<atom:link href="http://everburning.com/news/category/article/feed/" rel="self" type="application/rss+xml" />
	<link>http://everburning.com</link>
	<description>picking at the fringes of reality</description>
	<lastBuildDate>Thu, 17 Jun 2010 04:51:46 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>Download and XML parsing with HotCocoa</title>
		<link>http://everburning.com/news/download-and-xml-parsing-with-hotcocoa/</link>
		<comments>http://everburning.com/news/download-and-xml-parsing-with-hotcocoa/#comments</comments>
		<pubDate>Mon, 08 Feb 2010 05:47:16 +0000</pubDate>
		<dc:creator>dj2</dc:creator>
				<category><![CDATA[Article]]></category>
		<category><![CDATA[Computers]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[HotCocoa]]></category>
		<category><![CDATA[MacRuby]]></category>

		<guid isPermaLink="false">http://everburning.com/?p=700</guid>
		<description><![CDATA[<p><a href="http://everburning.com/wp-content/uploads/2010/02/IMG_7535.jpg"><img src="http://everburning.com/wp-content/uploads/2010/02/IMG_7535-150x150.jpg" alt="" title="IMG_7535" width="150" height="150" class="alignleft size-thumbnail wp-image-702" /></a>I&#8217;ve been working on <a href="http://github.com/dj2/Rife">Rife</a>, a <a href="http://reader.google.com">Google Reader</a> client, over the last few days and have been digging my way through some more <a href="http://github.com/richkilmer/hotcocoa">HotCocoa</a> mappings. I figured the best way to remember some of this stuff is to write it down so, the following will look at synchronous and asynchronous downloads and writing a XML parser in HotCocoa/<a href="http://macruby.org">MacRuby</a>.</p>
<p>So, what are we creating you ask? Well, as I said, I&#8217;ve been playing with Google Reader APIs and we&#8217;re going to do a synchronous request to Google for an identifier token. Once we&#8217;ve successfully authenticated we&#8217;re going to make an asynchronous request for our unread items. We&#8217;ll then parse the resulting XML document and spit the titles out to the console.</p>
<p>As with any HotCocoa application the easiest way to get started is to have system setup the shell of our application. We&#8217;ll use the <code>hotcocoa</code> command to create our application which I&#8217;m calling <em>titles</em>.</p>
<pre><code>titania:example dj2$ hotcocoa titles</code></pre>
<p>In order to authenticate to Google we&#8217;re going to need your username and password. Since I&#8217;m going to do the output to the console for demonstration purposes I&#8217;ll use the main application window to show the fields for username and password and a save button.</p>
<div class="dean_ch" style="white-space: wrap;"><span class="kw3">require</span> <span class="st0">&#8216;rubygems&#8217;</span><br />
<span class="kw3">require</span> <span class="st0">&#8216;hotcocoa&#8217;</span></p>
<p><span class="kw1">class</span> Application<br />
&nbsp; <span class="kw1">include</span> HotCocoa<br />
&nbsp; <br />
&nbsp; <span class="kw1">def</span> start<br />
&nbsp; &nbsp; application<span class="br0">&#40;</span><span class="re3">:name</span> =&gt; <span class="st0">&quot;Titles&quot;</span><span class="br0">&#41;</span> <span class="kw1">do</span> |app|<br />
&nbsp; &nbsp; &nbsp; app.<span class="me1">delegate</span> = <span class="kw2">self</span></p>
<p>&nbsp; &nbsp; &nbsp; window<span class="br0">&#40;</span><span class="re3">:frame</span> =&gt; <span class="br0">&#91;</span><span class="nu0">100</span>, <span class="nu0">100</span>, <span class="nu0">200</span>, <span class="nu0">200</span><span class="br0">&#93;</span>, <span class="re3">:title</span> =&gt; <span class="st0">&quot;Titles&quot;</span><span class="br0">&#41;</span> <span class="kw1">do</span> |win|<br />
&nbsp; &nbsp; &nbsp; &nbsp; win.<span class="me1">center</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; win.<span class="me1">will_close</span> <span class="br0">&#123;</span> <span class="kw3">exit</span> <span class="br0">&#125;</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; win &lt;&lt; label<span class="br0">&#40;</span><span class="re3">:text</span> =&gt; <span class="st0">&quot;Username&quot;</span>, <span class="re3">:layout</span> =&gt; <span class="br0">&#123;</span>:start =&gt; <span class="kw2">false</span><span class="br0">&#125;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; win &lt;&lt; <span class="re1">@username_field</span> = text_field<span class="br0">&#40;</span><span class="re3">:layout</span> =&gt; <span class="br0">&#123;</span>:start =&gt; <span class="kw2">false</span>, <span class="re3">:expand</span> =&gt; <span class="br0">&#91;</span><span class="re3">:width</span><span class="br0">&#93;</span><span class="br0">&#125;</span><span class="br0">&#41;</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; win &lt;&lt; label<span class="br0">&#40;</span><span class="re3">:text</span> =&gt; <span class="st0">&quot;Password&quot;</span>, <span class="re3">:layout</span> =&gt; <span class="br0">&#123;</span>:start =&gt; <span class="kw2">false</span><span class="br0">&#125;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; win &lt;&lt; <span class="re1">@password_field</span> = secure_text_field<span class="br0">&#40;</span><span class="re3">:layout</span> =&gt; <span class="br0">&#123;</span>:start =&gt; <span class="kw2">false</span>, <span class="re3">:expand</span> =&gt; <span class="br0">&#91;</span><span class="re3">:width</span><span class="br0">&#93;</span><span class="br0">&#125;</span><span class="br0">&#41;</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; win &lt;&lt; save = button<span class="br0">&#40;</span><span class="re3">:title</span> =&gt; <span class="st0">&quot;save&quot;</span>, <span class="re3">:layout</span> =&gt; <span class="br0">&#123;</span>:start =&gt; <span class="kw2">true</span><span class="br0">&#125;</span><span class="br0">&#41;</span> <span class="kw1">do</span> |button|<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; button.<span class="me1">on_action</span> <span class="br0">&#123;</span> authenticate <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">end</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; <span class="re1">@username_field</span>.<span class="me1">setNextKeyView</span><span class="br0">&#40;</span>@password_field<span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="re1">@password_field</span>.<span class="me1">setNextKeyView</span><span class="br0">&#40;</span>save<span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; save.<span class="me1">setNextKeyView</span><span class="br0">&#40;</span>@username_field<span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; <span class="kw1">end</span><br />
&nbsp; &nbsp; <span class="kw1">end</span><br />
&nbsp; <span class="kw1">end</span></p>
<p>&nbsp; <span class="kw1">def</span> authenticate<br />
&nbsp; &nbsp; <span class="kw3">puts</span> <span class="st0">&quot;DO AUTH #{@username_field.to_s} #{@password_field.to_s}&quot;</span><br />
&nbsp; <span class="kw1">end</span><br />
<span class="kw1">end</span></p>
<p>Application.<span class="me1">new</span>.<span class="me1">start</span></div>
<p>If you run the application by executing <code>macrake</code> in the <em>titles</em> directory you should see the main application window. Typing something into the <em>username</em> and <em>password</em> fields and pressing <em>save</em> you should see something similar to the following in your terminal.</p>
<pre><code>DO AUTH test test</code></pre>
<p>With our framework setup let&#8217;s get to the interesting stuff. First up, authenticating so we can retrieve our identifier from Google. We&#8217;re going to make a synchronous request to retrieve the identifier and, if successful, call a method to start retrieving our reading list.</p>
<div class="dean_ch" style="white-space: wrap;"><span class="kw1">def</span> authenticate<br />
&nbsp; username = <span class="re1">@username_field</span>.<span class="me1">stringValue</span><br />
&nbsp; password = <span class="re1">@password_field</span>.<span class="me1">stringValue</span></p>
<p>&nbsp; query = <span class="st0">&quot;https://www.google.com/accounts/ClientLogin?&quot;</span> +<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st0">&quot;Email=#{CGI.escape(username)}&amp;Passwd=#{CGI.escape(password.to_s)}&quot;</span> +<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st0">&quot;&amp;source=HotCocoaExample&amp;service=reader&quot;</span></p>
<p>&nbsp; url = NSURL.<span class="me1">URLWithString</span><span class="br0">&#40;</span>query<span class="br0">&#41;</span><br />
&nbsp; request = NSMutableURLRequest.<span class="me1">requestWithURL</span><span class="br0">&#40;</span>url<span class="br0">&#41;</span><br />
&nbsp; request.<span class="me1">addValue</span><span class="br0">&#40;</span><span class="st0">&quot;HotCocoaExample&quot;</span>, forHTTPHeaderField:<span class="st0">&quot;source&quot;</span><span class="br0">&#41;</span><br />
&nbsp; request.<span class="me1">addValue</span><span class="br0">&#40;</span><span class="st0">&quot;2&quot;</span>, forHTTPHeaderField:<span class="st0">&quot;GData-Version&quot;</span><span class="br0">&#41;</span></p>
<p>&nbsp; response = Pointer.<span class="me1">new</span><span class="br0">&#40;</span><span class="st0">&quot;@&quot;</span><span class="br0">&#41;</span><br />
&nbsp; data = NSURLConnection.<span class="me1">sendSynchronousRequest</span><span class="br0">&#40;</span>request, returningResponse:response, error:<span class="kw2">nil</span><span class="br0">&#41;</span><br />
&nbsp; data = NSString.<span class="me1">alloc</span>.<span class="me1">initWithData</span><span class="br0">&#40;</span>data, encoding:NSUTF8StringEncoding<span class="br0">&#41;</span></p>
<p>&nbsp; <span class="kw1">if</span> data =~ /^SID=<span class="br0">&#40;</span>.<span class="me1">*</span><span class="br0">&#41;</span>\n/<br />
&nbsp; &nbsp; <span class="re1">@sid</span> = $<span class="nu0">1</span></p>
<p>&nbsp; &nbsp; retrieve_reading_list<br />
&nbsp; <span class="kw1">else</span><br />
&nbsp; &nbsp; <span class="kw3">raise</span> <span class="kw4">Exception</span>.<span class="me1">new</span><span class="br0">&#40;</span><span class="st0">&quot;Authentication failed with: #{data}&quot;</span><span class="br0">&#41;</span><br />
&nbsp; <span class="kw1">end</span><br />
<span class="kw1">end</span></p>
<p><span class="kw1">def</span> retrieve_reading_list<br />
&nbsp; <span class="kw3">puts</span> <span class="re1">@sid</span><br />
<span class="kw1">end</span></div>
<p>If you add the above to your application, and add <code>require 'cgi'</code>, you should be able to run the program, put in your username and password and get a long line of characters spit out on the terminal. Those characters are your Google <em>SID</em>.</p>
<p>Let&#8217;s look a bit closer at what we&#8217;re doing in the <code>authenticate</code> method. We start by grabbing the <code>stringValue</code> for the username and password fields. Then, using these values, we build the query string needed for authentication. This query string is used to build a URL object by calling <code>NSURL.URLWithString(query)</code>. With the URL in hand we can start building our request object. This is done by calling <code>NSMutableURLRequest.requestWithURL(url)</code>. I&#8217;m using the mutable version of the request as I want to add a few extra header values. These are both added with <code>addValue(value, forHTTPHeaderField:field)</code>.</p>
<p>When we execute our request the system is going to want to put our response object somewhere. In the Cocoa version the method accepts a <code>NSURLResponse **response</code> parameter. In order to handle the response we need to create a <code>Pointer</code> object which is a MacRuby object for handling these pointers to objects. We want our pointer to point to an object so we use <code>Pointer.new("@")</code>.</p>
<p>With the response setup we call <code>NSURLConnection.sendSynchronousRequest</code> and provide our request and response objects. I don&#8217;t care about the error, but if you do, you&#8217;d want to pass in something similar to our response pointer. The request will return a <code>NSData</code> object which we convert to a string using the <code>initWithData</code> initialization method of <code>NSString</code>.</p>
<p>With the string in hand we try to extract our <em>SID</em> and, if successful, execute the <code>retrieve_reading_list</code> method which just spits out the <em>SID</em>.</p>
<p>OK, cool, we&#8217;ve now got our authentication token and are ready to move onto the asynchronous request to get our reading list.</p>
<div class="dean_ch" style="white-space: wrap;"><span class="kw1">def</span> retrieve_reading_list<br />
&nbsp; query = <span class="st0">&quot;https://www.google.com/reader/atom/user/-/state/com.google/reading-list?&quot;</span> +<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st0">&quot;xt=user/-/state/com.google/read&amp;ck=#{Time.now.to_i * 1000}&amp;n=2&quot;</span></p>
<p>&nbsp; url = NSURL.<span class="me1">URLWithString</span><span class="br0">&#40;</span>query<span class="br0">&#41;</span><br />
&nbsp; request = NSMutableURLRequest.<span class="me1">requestWithURL</span><span class="br0">&#40;</span>url<span class="br0">&#41;</span><br />
&nbsp; request.<span class="me1">addValue</span><span class="br0">&#40;</span><span class="st0">&quot;HotCocoaExample&quot;</span>, forHTTPHeaderField:<span class="st0">&quot;source&quot;</span><span class="br0">&#41;</span><br />
&nbsp; request.<span class="me1">addValue</span><span class="br0">&#40;</span><span class="st0">&quot;2&quot;</span>, forHTTPHeaderField:<span class="st0">&quot;GData-Version&quot;</span><span class="br0">&#41;</span><br />
&nbsp; request.<span class="me1">addValue</span><span class="br0">&#40;</span><span class="st0">&quot;SID=#{@sid}&quot;</span>, forHTTPHeaderField:<span class="st0">&quot;Cookie&quot;</span><span class="br0">&#41;</span></p>
<p>&nbsp; NSURLConnection.<span class="me1">connectionWithRequest</span><span class="br0">&#40;</span>request, delegate:<span class="kw2">self</span><span class="br0">&#41;</span><br />
<span class="kw1">end</span></p>
<p><span class="kw1">def</span> connectionDidFinishLoading<span class="br0">&#40;</span>conn<span class="br0">&#41;</span><br />
&nbsp; <span class="kw3">puts</span> NSString.<span class="me1">alloc</span>.<span class="me1">initWithData</span><span class="br0">&#40;</span>@receivedData, encoding:NSUTF8StringEncoding<span class="br0">&#41;</span><br />
<span class="kw1">end</span></p>
<p><span class="kw1">def</span> connection<span class="br0">&#40;</span>conn, didReceiveResponse:response<span class="br0">&#41;</span><br />
&nbsp; <span class="kw1">if</span> response.<span class="me1">statusCode</span> != <span class="nu0">200</span><br />
&nbsp; &nbsp; <span class="kw3">puts</span> <span class="st0">&quot;BAD STATUS: #{response.statusCode}&quot;</span><br />
&nbsp; &nbsp; <span class="kw3">p</span> response.<span class="me1">allHeaderFields</span><br />
&nbsp; <span class="kw1">end</span><br />
<span class="kw1">end</span></p>
<p><span class="kw1">def</span> connection<span class="br0">&#40;</span>conn, didReceiveData:data<span class="br0">&#41;</span><br />
&nbsp; <span class="re1">@receivedData</span> ||= NSMutableData.<span class="me1">new</span><br />
&nbsp; <span class="re1">@receivedData</span>.<span class="me1">appendData</span><span class="br0">&#40;</span>data<span class="br0">&#41;</span><br />
<span class="kw1">end</span></div>
<p>Similar to the synchronous method we start by building our query string, <code>NSURL</code> and <code>NSMutableURLRequest</code>. We&#8217;ve added a cookie to our request object to hold the <em>SID</em> retrieved earlier from Google.</p>
<p>We fire the request by calling <code>NSURLConnection.connectionWithRequest(request, delegate:self)</code>. We specific ourselves as the delegate for the connection. There are a few delegate methods we can implement to receive data and get notified of request states. These are:</p>
<ul>
<li><code>connectionDidFinishLoading(connection)</code></li>
<li><code>connection(connection, didReceiveResponse:response)</code></li>
<li><code>connection(connection, didReceiveData:data)</code></li>
</ul>
<p>We&#8217;ll look at our implementation of each of these callbacks in turn. First, in <code>connectionDidFinishLoading(conn)</code> we&#8217;re just printing out the data retrieved. We need to convert the data, similar to what we did in the synchronous request, from a <code>NSData</code> object to a <code>NSString</code> object.</p>
<p>In <code>connection(conn, didReceiveResponse:response)</code> we&#8217;re just checking to see if we got a 200 response code from the server. In all other cases we print an error.</p>
<p>The main work is done in <code>connection(conn, didReceiveData:data)</code> where we create a <code>NSMutableData</code> object if needed and append any data received into the mutable data object.</p>
<p>Running the code at this point should dump the first two items in your reading list to the console. The data will be a big mess of XML but we&#8217;ll look at parsing that in the next step.</p>
<div class="dean_ch" style="white-space: wrap;"><span class="kw1">def</span> connectionDidFinishLoading<span class="br0">&#40;</span>conn<span class="br0">&#41;</span><br />
&nbsp; xml = HotCocoa.<span class="me1">xml_parser</span><span class="br0">&#40;</span><span class="re3">:data</span> =&gt; <span class="re1">@receivedData</span><span class="br0">&#41;</span><br />
&nbsp; <span class="re1">@receivedData</span> = <span class="kw2">nil</span></p>
<p>&nbsp; xml.<span class="me1">on_start_document</span> <span class="br0">&#123;</span> <span class="kw3">puts</span> <span class="st0">&quot;Starting Parse&quot;</span> <span class="br0">&#125;</span><br />
&nbsp; xml.<span class="me1">on_end_document</span> <span class="kw1">do</span><br />
&nbsp; &nbsp; HotCocoa.<span class="me1">notification</span><span class="br0">&#40;</span><span class="re3">:post</span> =&gt; <span class="kw2">true</span>, <span class="re3">:name</span> =&gt; <span class="st0">&quot;all_entries_loaded&quot;</span>, <span class="re3">:object</span> =&gt; <span class="kw2">nil</span>, <span class="re3">:info</span> =&gt; <span class="kw2">nil</span><span class="br0">&#41;</span><br />
&nbsp; <span class="kw1">end</span><br />
&nbsp; xml.<span class="me1">on_parse_error</span> <span class="br0">&#123;</span> |err| <span class="kw3">puts</span> <span class="st0">&quot;Parse error #{err.inspect}&quot;</span> <span class="br0">&#125;</span></p>
<p>&nbsp; xml.<span class="me1">on_cdata</span> <span class="br0">&#123;</span> |cdata| <span class="re1">@elem_text</span> += cdata.<span class="me1">to_s</span> <span class="br0">&#125;</span><br />
&nbsp; xml.<span class="me1">on_characters</span> <span class="br0">&#123;</span> |chars| <span class="re1">@elem_text</span> += chars.<span class="me1">to_s</span> <span class="br0">&#125;</span></p>
<p>&nbsp; xml.<span class="me1">on_start_element</span> <span class="kw1">do</span> |element, namespace, qualified_name, attributes|<br />
&nbsp; &nbsp; <span class="re1">@elem_text</span> = <span class="st0">&#8221;</span><br />
&nbsp; <span class="kw1">end</span></p>
<p>&nbsp; xml.<span class="me1">on_end_element</span> <span class="kw1">do</span> |element, namespace, qualified_name|<br />
&nbsp; &nbsp; <span class="kw3">puts</span> <span class="re1">@elem_text</span> <span class="kw1">if</span> element == <span class="st0">&#8216;title&#8217;</span><br />
&nbsp; <span class="kw1">end</span></p>
<p>&nbsp; xml.<span class="me1">parse</span><br />
<span class="kw1">end</span></div>
<p>We&#8217;re finally getting into some HotCocoa specific code with our XML parser. HotCocoa defines a mapping wrapper around <code>NSXMLParser</code> and provides a set of delegate methods. These delegates mean we don&#8217;t have to set our class as the delegate and create a bunch of methods. They mean we can attach our code as blocks on our XML object. All the better if you want to define a few parsers in one class.</p>
<p>We start off by creating a <code>HotCocoa.xml_parser</code>. The parser accepts <code>NSData</code> objects so we don&#8217;t need to convert our response data to a string. We then setup  eight callbacks. There are actually a bunch more callbacks that can be hooked up and you should look at the <code>xml_parser</code> mapping code to see if you need any of them. For our purposes, we only really care about eight.</p>
<p>The <code>on_start_document</code>, <code>on_end_document</code> and <code>on_parse_error</code> callbacks, as you can probably guess, get called when we start parsing, when we finish parsing and when we receive a parse error, respectively. We don&#8217;t really care about start in this example, but I put it in anyway. When we&#8217;ve completed parsing we send a notification and other application code can then listen for this notification and do anything it needs. If we wanted we could store the entries as they&#8217;re parsed and provide them to the <code>:object</code> key. This would make those entries available to anyone that receives the notification.</p>
<p>If we receive either CDATA, with <code>on_cdata</code>, or text, with <code>on_characters</code>, we append the content to our current elements text. When we receive the open tag of a new element, <code>on_start_element</code>, we dump our current element text as we&#8217;ve started a new element. We can also take a look at the elements name, attributes, namespace and qualified name, if desired.</p>
<p>Finally, in <code>on_end_element</code> we print out the current element text if the element we&#8217;re finishing has a name of <em>title</em>.</p>
<p>With all the callbacks configured we use <code>xml.parse</code> to start the parser. You should, if you run this example, see the titles and authors of the first two posts in your reading list. (The author name is also called title and I&#8217;m not bothering to check that the parent element is <em>entry</em> before spitting it out.)</p>
<p>That&#8217;s it. You can now make synchronous and asynchronous requests for content and parse any resulting XML.</p>
<p>One last thing before you go. Both of the requests we did above were <em>GET</em> requests. You can do other types of requests using the same methods as above you just need a slightly different setup for the request. You can see a <em>POST</em> request below.</p>
<div class="dean_ch" style="white-space: wrap;">request = NSMutableURLRequest.<span class="me1">requestWithURL</span><span class="br0">&#40;</span>url<span class="br0">&#41;</span><br />
request.<span class="me1">addValue</span><span class="br0">&#40;</span>SOURCE, forHTTPHeaderField:<span class="st0">&quot;source&quot;</span><span class="br0">&#41;</span><br />
request.<span class="me1">addValue</span><span class="br0">&#40;</span><span class="st0">&quot;2&quot;</span>, forHTTPHeaderField:<span class="st0">&quot;GData-Version&quot;</span><span class="br0">&#41;</span><br />
request.<span class="me1">addValue</span><span class="br0">&#40;</span><span class="st0">&quot;SID=#{@sid}&quot;</span>, forHTTPHeaderField:<span class="st0">&quot;Cookie&quot;</span><span class="br0">&#41;</span></p>
<p>body=<span class="st0">&quot;first=1&amp;second=2&amp;third=3&quot;</span></p>
<p>request.<span class="me1">setHTTPMethod</span><span class="br0">&#40;</span><span class="st0">&#8216;POST&#8217;</span><span class="br0">&#41;</span><br />
request.<span class="me1">setValue</span><span class="br0">&#40;</span><span class="st0">&#8216;application/x-www-form-urlencoded&#8217;</span>, forHTTPHeaderField:<span class="st0">&#8216;Content-Type&#8217;</span><span class="br0">&#41;</span><br />
request.<span class="me1">setValue</span><span class="br0">&#40;</span>body.<span class="me1">length</span>.<span class="me1">to_s</span>, forHTTPHeaderField:<span class="st0">&#8216;Content-Length&#8217;</span><span class="br0">&#41;</span><br />
request.<span class="me1">setHTTPBody</span><span class="br0">&#40;</span>body.<span class="me1">dataUsingEncoding</span><span class="br0">&#40;</span>NSASCIIStringEncoding<span class="br0">&#41;</span><span class="br0">&#41;</span></div>
<p>The first few lines should look familiar from creating our asynchronous request above. Since we&#8217;re going to be posting the data we use <code>setHTTPMethod('POST')</code> to setup the request method. We&#8217;ve form encoded the data so we set the appropriate <em>Content-Type</em> and set the <em>Content-Length</em>. Note, we convert the length to a string before sending to <code>setValue</code>. Finally, we set the body of the post with <code>setHTTPBody</code>. You need to convert the body string into a <code>NSData</code> object which we do with the <code>dataUsingEncoding</code> method. If you don&#8217;t convert the body to <code>NSData</code> you&#8217;ll end up sending a <code>nil</code> body with your post request.</p>

<span class="slashdigglicious">
<a href="http://slashdot.org/bookmark.pl?url=http%3A%2F%2Feverburning.com%2Fnews%2Fdownload-and-xml-parsing-with-hotcocoa%2F&amp;title=Download+and+XML+parsing+with+HotCocoa" title="Slashdot It!"><img src="http://slashdot.org/favicon.ico" height="16" width="16" alt="[Slashdot]" /></a>
<a href="http://digg.com/submit?phase=2&amp;url=http%3A%2F%2Feverburning.com%2Fnews%2Fdownload-and-xml-parsing-with-hotcocoa%2F&amp;title=Download+and+XML+parsing+with+HotCocoa" title="Digg This Story"><img src="http://digg.com/favicon.ico" width="16" height="16" alt="[Digg]" /></a>
<a href="http://reddit.com/submit?url=http%3A%2F%2Feverburning.com%2Fnews%2Fdownload-and-xml-parsing-with-hotcocoa%2F&amp;title=Download+and+XML+parsing+with+HotCocoa" title="Reddit"><img src="http://reddit.com/favicon.ico" width="16" height="16" alt="[Reddit]" /></a>
<a href="http://del.icio.us/post?url=http%3A%2F%2Feverburning.com%2Fnews%2Fdownload-and-xml-parsing-with-hotcocoa%2F&amp;title=Download+and+XML+parsing+with+HotCocoa" title="Save to del.icio.us" onclick="window.open('http://del.icio.us/post?v=4&amp;noui&amp;jump=close&amp;url=http%3A%2F%2Feverburning.com%2Fnews%2Fdownload-and-xml-parsing-with-hotcocoa%2F&amp;title=Download+and+XML+parsing+with+HotCocoa', 'delicious', 'toolbar=no,width=700,height=400'); return false;"><img src="http://images.del.icio.us/static/img/delicious.small.gif" width="16" height="16" alt="[del.icio.us]" /></a>
<a href="http://www.facebook.com/share.php?u=http%3A%2F%2Feverburning.com%2Fnews%2Fdownload-and-xml-parsing-with-hotcocoa%2F" title="Share on Facebook"><img src="http://www.facebook.com/favicon.ico" width="16" height="16" alt="[Facebook]" /></a>
<a href="http://technorati.com/faves?add=http%3A%2F%2Feverburning.com%2Fnews%2Fdownload-and-xml-parsing-with-hotcocoa%2F" title="Add to my Technorati Favorites"><img src="http://technorati.com/favicon.ico" width="16" height="16" alt="[Technorati]" /></a>
<a href="http://www.google.com/bookmarks/mark?op=edit&amp;output=popup&amp;bkmk=http%3A%2F%2Feverburning.com%2Fnews%2Fdownload-and-xml-parsing-with-hotcocoa%2F&amp;title=Download+and+XML+parsing+with+HotCocoa" title="Save to Google Bookmarks"><img src="http://www.google.com/favicon.ico" width="16" height="16" alt="[Google]" /></a>
<a href="http://www.stumbleupon.com/submit?url=http%3A%2F%2Feverburning.com%2Fnews%2Fdownload-and-xml-parsing-with-hotcocoa%2F&amp;title=Download+and+XML+parsing+with+HotCocoa" title="Stumble it!"><img src="http://www.stumbleupon.com/favicon.ico" width="16" height="16" alt="[StumbleUpon]" /></a>
</span>]]></description>
			<content:encoded><![CDATA[<p><a href="http://everburning.com/wp-content/uploads/2010/02/IMG_7535.jpg"><img src="http://everburning.com/wp-content/uploads/2010/02/IMG_7535-150x150.jpg" alt="" title="IMG_7535" width="150" height="150" class="alignleft size-thumbnail wp-image-702" /></a>I&#8217;ve been working on <a href="http://github.com/dj2/Rife">Rife</a>, a <a href="http://reader.google.com">Google Reader</a> client, over the last few days and have been digging my way through some more <a href="http://github.com/richkilmer/hotcocoa">HotCocoa</a> mappings. I figured the best way to remember some of this stuff is to write it down so, the following will look at synchronous and asynchronous downloads and writing a XML parser in HotCocoa/<a href="http://macruby.org">MacRuby</a>.</p>
<p>So, what are we creating you ask? Well, as I said, I&#8217;ve been playing with Google Reader APIs and we&#8217;re going to do a synchronous request to Google for an identifier token. Once we&#8217;ve successfully authenticated we&#8217;re going to make an asynchronous request for our unread items. We&#8217;ll then parse the resulting XML document and spit the titles out to the console.</p>
<p>As with any HotCocoa application the easiest way to get started is to have system setup the shell of our application. We&#8217;ll use the <code>hotcocoa</code> command to create our application which I&#8217;m calling <em>titles</em>.</p>
<pre><code>titania:example dj2$ hotcocoa titles</code></pre>
<p>In order to authenticate to Google we&#8217;re going to need your username and password. Since I&#8217;m going to do the output to the console for demonstration purposes I&#8217;ll use the main application window to show the fields for username and password and a save button.</p>
<div class="dean_ch" style="white-space: wrap;"><span class="kw3">require</span> <span class="st0">&#8216;rubygems&#8217;</span><br />
<span class="kw3">require</span> <span class="st0">&#8216;hotcocoa&#8217;</span></p>
<p><span class="kw1">class</span> Application<br />
&nbsp; <span class="kw1">include</span> HotCocoa<br />
&nbsp; <br />
&nbsp; <span class="kw1">def</span> start<br />
&nbsp; &nbsp; application<span class="br0">&#40;</span><span class="re3">:name</span> =&gt; <span class="st0">&quot;Titles&quot;</span><span class="br0">&#41;</span> <span class="kw1">do</span> |app|<br />
&nbsp; &nbsp; &nbsp; app.<span class="me1">delegate</span> = <span class="kw2">self</span></p>
<p>&nbsp; &nbsp; &nbsp; window<span class="br0">&#40;</span><span class="re3">:frame</span> =&gt; <span class="br0">&#91;</span><span class="nu0">100</span>, <span class="nu0">100</span>, <span class="nu0">200</span>, <span class="nu0">200</span><span class="br0">&#93;</span>, <span class="re3">:title</span> =&gt; <span class="st0">&quot;Titles&quot;</span><span class="br0">&#41;</span> <span class="kw1">do</span> |win|<br />
&nbsp; &nbsp; &nbsp; &nbsp; win.<span class="me1">center</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; win.<span class="me1">will_close</span> <span class="br0">&#123;</span> <span class="kw3">exit</span> <span class="br0">&#125;</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; win &lt;&lt; label<span class="br0">&#40;</span><span class="re3">:text</span> =&gt; <span class="st0">&quot;Username&quot;</span>, <span class="re3">:layout</span> =&gt; <span class="br0">&#123;</span>:start =&gt; <span class="kw2">false</span><span class="br0">&#125;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; win &lt;&lt; <span class="re1">@username_field</span> = text_field<span class="br0">&#40;</span><span class="re3">:layout</span> =&gt; <span class="br0">&#123;</span>:start =&gt; <span class="kw2">false</span>, <span class="re3">:expand</span> =&gt; <span class="br0">&#91;</span><span class="re3">:width</span><span class="br0">&#93;</span><span class="br0">&#125;</span><span class="br0">&#41;</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; win &lt;&lt; label<span class="br0">&#40;</span><span class="re3">:text</span> =&gt; <span class="st0">&quot;Password&quot;</span>, <span class="re3">:layout</span> =&gt; <span class="br0">&#123;</span>:start =&gt; <span class="kw2">false</span><span class="br0">&#125;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; win &lt;&lt; <span class="re1">@password_field</span> = secure_text_field<span class="br0">&#40;</span><span class="re3">:layout</span> =&gt; <span class="br0">&#123;</span>:start =&gt; <span class="kw2">false</span>, <span class="re3">:expand</span> =&gt; <span class="br0">&#91;</span><span class="re3">:width</span><span class="br0">&#93;</span><span class="br0">&#125;</span><span class="br0">&#41;</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; win &lt;&lt; save = button<span class="br0">&#40;</span><span class="re3">:title</span> =&gt; <span class="st0">&quot;save&quot;</span>, <span class="re3">:layout</span> =&gt; <span class="br0">&#123;</span>:start =&gt; <span class="kw2">true</span><span class="br0">&#125;</span><span class="br0">&#41;</span> <span class="kw1">do</span> |button|<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; button.<span class="me1">on_action</span> <span class="br0">&#123;</span> authenticate <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">end</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; <span class="re1">@username_field</span>.<span class="me1">setNextKeyView</span><span class="br0">&#40;</span>@password_field<span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="re1">@password_field</span>.<span class="me1">setNextKeyView</span><span class="br0">&#40;</span>save<span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; save.<span class="me1">setNextKeyView</span><span class="br0">&#40;</span>@username_field<span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; <span class="kw1">end</span><br />
&nbsp; &nbsp; <span class="kw1">end</span><br />
&nbsp; <span class="kw1">end</span></p>
<p>&nbsp; <span class="kw1">def</span> authenticate<br />
&nbsp; &nbsp; <span class="kw3">puts</span> <span class="st0">&quot;DO AUTH #{@username_field.to_s} #{@password_field.to_s}&quot;</span><br />
&nbsp; <span class="kw1">end</span><br />
<span class="kw1">end</span></p>
<p>Application.<span class="me1">new</span>.<span class="me1">start</span></div>
<p>If you run the application by executing <code>macrake</code> in the <em>titles</em> directory you should see the main application window. Typing something into the <em>username</em> and <em>password</em> fields and pressing <em>save</em> you should see something similar to the following in your terminal.</p>
<pre><code>DO AUTH test test</code></pre>
<p>With our framework setup let&#8217;s get to the interesting stuff. First up, authenticating so we can retrieve our identifier from Google. We&#8217;re going to make a synchronous request to retrieve the identifier and, if successful, call a method to start retrieving our reading list.</p>
<div class="dean_ch" style="white-space: wrap;"><span class="kw1">def</span> authenticate<br />
&nbsp; username = <span class="re1">@username_field</span>.<span class="me1">stringValue</span><br />
&nbsp; password = <span class="re1">@password_field</span>.<span class="me1">stringValue</span></p>
<p>&nbsp; query = <span class="st0">&quot;https://www.google.com/accounts/ClientLogin?&quot;</span> +<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st0">&quot;Email=#{CGI.escape(username)}&amp;Passwd=#{CGI.escape(password.to_s)}&quot;</span> +<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st0">&quot;&amp;source=HotCocoaExample&amp;service=reader&quot;</span></p>
<p>&nbsp; url = NSURL.<span class="me1">URLWithString</span><span class="br0">&#40;</span>query<span class="br0">&#41;</span><br />
&nbsp; request = NSMutableURLRequest.<span class="me1">requestWithURL</span><span class="br0">&#40;</span>url<span class="br0">&#41;</span><br />
&nbsp; request.<span class="me1">addValue</span><span class="br0">&#40;</span><span class="st0">&quot;HotCocoaExample&quot;</span>, forHTTPHeaderField:<span class="st0">&quot;source&quot;</span><span class="br0">&#41;</span><br />
&nbsp; request.<span class="me1">addValue</span><span class="br0">&#40;</span><span class="st0">&quot;2&quot;</span>, forHTTPHeaderField:<span class="st0">&quot;GData-Version&quot;</span><span class="br0">&#41;</span></p>
<p>&nbsp; response = Pointer.<span class="me1">new</span><span class="br0">&#40;</span><span class="st0">&quot;@&quot;</span><span class="br0">&#41;</span><br />
&nbsp; data = NSURLConnection.<span class="me1">sendSynchronousRequest</span><span class="br0">&#40;</span>request, returningResponse:response, error:<span class="kw2">nil</span><span class="br0">&#41;</span><br />
&nbsp; data = NSString.<span class="me1">alloc</span>.<span class="me1">initWithData</span><span class="br0">&#40;</span>data, encoding:NSUTF8StringEncoding<span class="br0">&#41;</span></p>
<p>&nbsp; <span class="kw1">if</span> data =~ /^SID=<span class="br0">&#40;</span>.<span class="me1">*</span><span class="br0">&#41;</span>\n/<br />
&nbsp; &nbsp; <span class="re1">@sid</span> = $<span class="nu0">1</span></p>
<p>&nbsp; &nbsp; retrieve_reading_list<br />
&nbsp; <span class="kw1">else</span><br />
&nbsp; &nbsp; <span class="kw3">raise</span> <span class="kw4">Exception</span>.<span class="me1">new</span><span class="br0">&#40;</span><span class="st0">&quot;Authentication failed with: #{data}&quot;</span><span class="br0">&#41;</span><br />
&nbsp; <span class="kw1">end</span><br />
<span class="kw1">end</span></p>
<p><span class="kw1">def</span> retrieve_reading_list<br />
&nbsp; <span class="kw3">puts</span> <span class="re1">@sid</span><br />
<span class="kw1">end</span></div>
<p>If you add the above to your application, and add <code>require 'cgi'</code>, you should be able to run the program, put in your username and password and get a long line of characters spit out on the terminal. Those characters are your Google <em>SID</em>.</p>
<p>Let&#8217;s look a bit closer at what we&#8217;re doing in the <code>authenticate</code> method. We start by grabbing the <code>stringValue</code> for the username and password fields. Then, using these values, we build the query string needed for authentication. This query string is used to build a URL object by calling <code>NSURL.URLWithString(query)</code>. With the URL in hand we can start building our request object. This is done by calling <code>NSMutableURLRequest.requestWithURL(url)</code>. I&#8217;m using the mutable version of the request as I want to add a few extra header values. These are both added with <code>addValue(value, forHTTPHeaderField:field)</code>.</p>
<p>When we execute our request the system is going to want to put our response object somewhere. In the Cocoa version the method accepts a <code>NSURLResponse **response</code> parameter. In order to handle the response we need to create a <code>Pointer</code> object which is a MacRuby object for handling these pointers to objects. We want our pointer to point to an object so we use <code>Pointer.new("@")</code>.</p>
<p>With the response setup we call <code>NSURLConnection.sendSynchronousRequest</code> and provide our request and response objects. I don&#8217;t care about the error, but if you do, you&#8217;d want to pass in something similar to our response pointer. The request will return a <code>NSData</code> object which we convert to a string using the <code>initWithData</code> initialization method of <code>NSString</code>.</p>
<p>With the string in hand we try to extract our <em>SID</em> and, if successful, execute the <code>retrieve_reading_list</code> method which just spits out the <em>SID</em>.</p>
<p>OK, cool, we&#8217;ve now got our authentication token and are ready to move onto the asynchronous request to get our reading list.</p>
<div class="dean_ch" style="white-space: wrap;"><span class="kw1">def</span> retrieve_reading_list<br />
&nbsp; query = <span class="st0">&quot;https://www.google.com/reader/atom/user/-/state/com.google/reading-list?&quot;</span> +<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st0">&quot;xt=user/-/state/com.google/read&amp;ck=#{Time.now.to_i * 1000}&amp;n=2&quot;</span></p>
<p>&nbsp; url = NSURL.<span class="me1">URLWithString</span><span class="br0">&#40;</span>query<span class="br0">&#41;</span><br />
&nbsp; request = NSMutableURLRequest.<span class="me1">requestWithURL</span><span class="br0">&#40;</span>url<span class="br0">&#41;</span><br />
&nbsp; request.<span class="me1">addValue</span><span class="br0">&#40;</span><span class="st0">&quot;HotCocoaExample&quot;</span>, forHTTPHeaderField:<span class="st0">&quot;source&quot;</span><span class="br0">&#41;</span><br />
&nbsp; request.<span class="me1">addValue</span><span class="br0">&#40;</span><span class="st0">&quot;2&quot;</span>, forHTTPHeaderField:<span class="st0">&quot;GData-Version&quot;</span><span class="br0">&#41;</span><br />
&nbsp; request.<span class="me1">addValue</span><span class="br0">&#40;</span><span class="st0">&quot;SID=#{@sid}&quot;</span>, forHTTPHeaderField:<span class="st0">&quot;Cookie&quot;</span><span class="br0">&#41;</span></p>
<p>&nbsp; NSURLConnection.<span class="me1">connectionWithRequest</span><span class="br0">&#40;</span>request, delegate:<span class="kw2">self</span><span class="br0">&#41;</span><br />
<span class="kw1">end</span></p>
<p><span class="kw1">def</span> connectionDidFinishLoading<span class="br0">&#40;</span>conn<span class="br0">&#41;</span><br />
&nbsp; <span class="kw3">puts</span> NSString.<span class="me1">alloc</span>.<span class="me1">initWithData</span><span class="br0">&#40;</span>@receivedData, encoding:NSUTF8StringEncoding<span class="br0">&#41;</span><br />
<span class="kw1">end</span></p>
<p><span class="kw1">def</span> connection<span class="br0">&#40;</span>conn, didReceiveResponse:response<span class="br0">&#41;</span><br />
&nbsp; <span class="kw1">if</span> response.<span class="me1">statusCode</span> != <span class="nu0">200</span><br />
&nbsp; &nbsp; <span class="kw3">puts</span> <span class="st0">&quot;BAD STATUS: #{response.statusCode}&quot;</span><br />
&nbsp; &nbsp; <span class="kw3">p</span> response.<span class="me1">allHeaderFields</span><br />
&nbsp; <span class="kw1">end</span><br />
<span class="kw1">end</span></p>
<p><span class="kw1">def</span> connection<span class="br0">&#40;</span>conn, didReceiveData:data<span class="br0">&#41;</span><br />
&nbsp; <span class="re1">@receivedData</span> ||= NSMutableData.<span class="me1">new</span><br />
&nbsp; <span class="re1">@receivedData</span>.<span class="me1">appendData</span><span class="br0">&#40;</span>data<span class="br0">&#41;</span><br />
<span class="kw1">end</span></div>
<p>Similar to the synchronous method we start by building our query string, <code>NSURL</code> and <code>NSMutableURLRequest</code>. We&#8217;ve added a cookie to our request object to hold the <em>SID</em> retrieved earlier from Google.</p>
<p>We fire the request by calling <code>NSURLConnection.connectionWithRequest(request, delegate:self)</code>. We specific ourselves as the delegate for the connection. There are a few delegate methods we can implement to receive data and get notified of request states. These are:</p>
<ul>
<li><code>connectionDidFinishLoading(connection)</code></li>
<li><code>connection(connection, didReceiveResponse:response)</code></li>
<li><code>connection(connection, didReceiveData:data)</code></li>
</ul>
<p>We&#8217;ll look at our implementation of each of these callbacks in turn. First, in <code>connectionDidFinishLoading(conn)</code> we&#8217;re just printing out the data retrieved. We need to convert the data, similar to what we did in the synchronous request, from a <code>NSData</code> object to a <code>NSString</code> object.</p>
<p>In <code>connection(conn, didReceiveResponse:response)</code> we&#8217;re just checking to see if we got a 200 response code from the server. In all other cases we print an error.</p>
<p>The main work is done in <code>connection(conn, didReceiveData:data)</code> where we create a <code>NSMutableData</code> object if needed and append any data received into the mutable data object.</p>
<p>Running the code at this point should dump the first two items in your reading list to the console. The data will be a big mess of XML but we&#8217;ll look at parsing that in the next step.</p>
<div class="dean_ch" style="white-space: wrap;"><span class="kw1">def</span> connectionDidFinishLoading<span class="br0">&#40;</span>conn<span class="br0">&#41;</span><br />
&nbsp; xml = HotCocoa.<span class="me1">xml_parser</span><span class="br0">&#40;</span><span class="re3">:data</span> =&gt; <span class="re1">@receivedData</span><span class="br0">&#41;</span><br />
&nbsp; <span class="re1">@receivedData</span> = <span class="kw2">nil</span></p>
<p>&nbsp; xml.<span class="me1">on_start_document</span> <span class="br0">&#123;</span> <span class="kw3">puts</span> <span class="st0">&quot;Starting Parse&quot;</span> <span class="br0">&#125;</span><br />
&nbsp; xml.<span class="me1">on_end_document</span> <span class="kw1">do</span><br />
&nbsp; &nbsp; HotCocoa.<span class="me1">notification</span><span class="br0">&#40;</span><span class="re3">:post</span> =&gt; <span class="kw2">true</span>, <span class="re3">:name</span> =&gt; <span class="st0">&quot;all_entries_loaded&quot;</span>, <span class="re3">:object</span> =&gt; <span class="kw2">nil</span>, <span class="re3">:info</span> =&gt; <span class="kw2">nil</span><span class="br0">&#41;</span><br />
&nbsp; <span class="kw1">end</span><br />
&nbsp; xml.<span class="me1">on_parse_error</span> <span class="br0">&#123;</span> |err| <span class="kw3">puts</span> <span class="st0">&quot;Parse error #{err.inspect}&quot;</span> <span class="br0">&#125;</span></p>
<p>&nbsp; xml.<span class="me1">on_cdata</span> <span class="br0">&#123;</span> |cdata| <span class="re1">@elem_text</span> += cdata.<span class="me1">to_s</span> <span class="br0">&#125;</span><br />
&nbsp; xml.<span class="me1">on_characters</span> <span class="br0">&#123;</span> |chars| <span class="re1">@elem_text</span> += chars.<span class="me1">to_s</span> <span class="br0">&#125;</span></p>
<p>&nbsp; xml.<span class="me1">on_start_element</span> <span class="kw1">do</span> |element, namespace, qualified_name, attributes|<br />
&nbsp; &nbsp; <span class="re1">@elem_text</span> = <span class="st0">&#8221;</span><br />
&nbsp; <span class="kw1">end</span></p>
<p>&nbsp; xml.<span class="me1">on_end_element</span> <span class="kw1">do</span> |element, namespace, qualified_name|<br />
&nbsp; &nbsp; <span class="kw3">puts</span> <span class="re1">@elem_text</span> <span class="kw1">if</span> element == <span class="st0">&#8216;title&#8217;</span><br />
&nbsp; <span class="kw1">end</span></p>
<p>&nbsp; xml.<span class="me1">parse</span><br />
<span class="kw1">end</span></div>
<p>We&#8217;re finally getting into some HotCocoa specific code with our XML parser. HotCocoa defines a mapping wrapper around <code>NSXMLParser</code> and provides a set of delegate methods. These delegates mean we don&#8217;t have to set our class as the delegate and create a bunch of methods. They mean we can attach our code as blocks on our XML object. All the better if you want to define a few parsers in one class.</p>
<p>We start off by creating a <code>HotCocoa.xml_parser</code>. The parser accepts <code>NSData</code> objects so we don&#8217;t need to convert our response data to a string. We then setup  eight callbacks. There are actually a bunch more callbacks that can be hooked up and you should look at the <code>xml_parser</code> mapping code to see if you need any of them. For our purposes, we only really care about eight.</p>
<p>The <code>on_start_document</code>, <code>on_end_document</code> and <code>on_parse_error</code> callbacks, as you can probably guess, get called when we start parsing, when we finish parsing and when we receive a parse error, respectively. We don&#8217;t really care about start in this example, but I put it in anyway. When we&#8217;ve completed parsing we send a notification and other application code can then listen for this notification and do anything it needs. If we wanted we could store the entries as they&#8217;re parsed and provide them to the <code>:object</code> key. This would make those entries available to anyone that receives the notification.</p>
<p>If we receive either CDATA, with <code>on_cdata</code>, or text, with <code>on_characters</code>, we append the content to our current elements text. When we receive the open tag of a new element, <code>on_start_element</code>, we dump our current element text as we&#8217;ve started a new element. We can also take a look at the elements name, attributes, namespace and qualified name, if desired.</p>
<p>Finally, in <code>on_end_element</code> we print out the current element text if the element we&#8217;re finishing has a name of <em>title</em>.</p>
<p>With all the callbacks configured we use <code>xml.parse</code> to start the parser. You should, if you run this example, see the titles and authors of the first two posts in your reading list. (The author name is also called title and I&#8217;m not bothering to check that the parent element is <em>entry</em> before spitting it out.)</p>
<p>That&#8217;s it. You can now make synchronous and asynchronous requests for content and parse any resulting XML.</p>
<p>One last thing before you go. Both of the requests we did above were <em>GET</em> requests. You can do other types of requests using the same methods as above you just need a slightly different setup for the request. You can see a <em>POST</em> request below.</p>
<div class="dean_ch" style="white-space: wrap;">request = NSMutableURLRequest.<span class="me1">requestWithURL</span><span class="br0">&#40;</span>url<span class="br0">&#41;</span><br />
request.<span class="me1">addValue</span><span class="br0">&#40;</span>SOURCE, forHTTPHeaderField:<span class="st0">&quot;source&quot;</span><span class="br0">&#41;</span><br />
request.<span class="me1">addValue</span><span class="br0">&#40;</span><span class="st0">&quot;2&quot;</span>, forHTTPHeaderField:<span class="st0">&quot;GData-Version&quot;</span><span class="br0">&#41;</span><br />
request.<span class="me1">addValue</span><span class="br0">&#40;</span><span class="st0">&quot;SID=#{@sid}&quot;</span>, forHTTPHeaderField:<span class="st0">&quot;Cookie&quot;</span><span class="br0">&#41;</span></p>
<p>body=<span class="st0">&quot;first=1&amp;second=2&amp;third=3&quot;</span></p>
<p>request.<span class="me1">setHTTPMethod</span><span class="br0">&#40;</span><span class="st0">&#8216;POST&#8217;</span><span class="br0">&#41;</span><br />
request.<span class="me1">setValue</span><span class="br0">&#40;</span><span class="st0">&#8216;application/x-www-form-urlencoded&#8217;</span>, forHTTPHeaderField:<span class="st0">&#8216;Content-Type&#8217;</span><span class="br0">&#41;</span><br />
request.<span class="me1">setValue</span><span class="br0">&#40;</span>body.<span class="me1">length</span>.<span class="me1">to_s</span>, forHTTPHeaderField:<span class="st0">&#8216;Content-Length&#8217;</span><span class="br0">&#41;</span><br />
request.<span class="me1">setHTTPBody</span><span class="br0">&#40;</span>body.<span class="me1">dataUsingEncoding</span><span class="br0">&#40;</span>NSASCIIStringEncoding<span class="br0">&#41;</span><span class="br0">&#41;</span></div>
<p>The first few lines should look familiar from creating our asynchronous request above. Since we&#8217;re going to be posting the data we use <code>setHTTPMethod('POST')</code> to setup the request method. We&#8217;ve form encoded the data so we set the appropriate <em>Content-Type</em> and set the <em>Content-Length</em>. Note, we convert the length to a string before sending to <code>setValue</code>. Finally, we set the body of the post with <code>setHTTPBody</code>. You need to convert the body string into a <code>NSData</code> object which we do with the <code>dataUsingEncoding</code> method. If you don&#8217;t convert the body to <code>NSData</code> you&#8217;ll end up sending a <code>nil</code> body with your post request.</p>

<span class="slashdigglicious">
<a href="http://slashdot.org/bookmark.pl?url=http%3A%2F%2Feverburning.com%2Fnews%2Fdownload-and-xml-parsing-with-hotcocoa%2F&amp;title=Download+and+XML+parsing+with+HotCocoa" title="Slashdot It!"><img src="http://slashdot.org/favicon.ico" height="16" width="16" alt="[Slashdot]" /></a>
<a href="http://digg.com/submit?phase=2&amp;url=http%3A%2F%2Feverburning.com%2Fnews%2Fdownload-and-xml-parsing-with-hotcocoa%2F&amp;title=Download+and+XML+parsing+with+HotCocoa" title="Digg This Story"><img src="http://digg.com/favicon.ico" width="16" height="16" alt="[Digg]" /></a>
<a href="http://reddit.com/submit?url=http%3A%2F%2Feverburning.com%2Fnews%2Fdownload-and-xml-parsing-with-hotcocoa%2F&amp;title=Download+and+XML+parsing+with+HotCocoa" title="Reddit"><img src="http://reddit.com/favicon.ico" width="16" height="16" alt="[Reddit]" /></a>
<a href="http://del.icio.us/post?url=http%3A%2F%2Feverburning.com%2Fnews%2Fdownload-and-xml-parsing-with-hotcocoa%2F&amp;title=Download+and+XML+parsing+with+HotCocoa" title="Save to del.icio.us" onclick="window.open('http://del.icio.us/post?v=4&amp;noui&amp;jump=close&amp;url=http%3A%2F%2Feverburning.com%2Fnews%2Fdownload-and-xml-parsing-with-hotcocoa%2F&amp;title=Download+and+XML+parsing+with+HotCocoa', 'delicious', 'toolbar=no,width=700,height=400'); return false;"><img src="http://images.del.icio.us/static/img/delicious.small.gif" width="16" height="16" alt="[del.icio.us]" /></a>
<a href="http://www.facebook.com/share.php?u=http%3A%2F%2Feverburning.com%2Fnews%2Fdownload-and-xml-parsing-with-hotcocoa%2F" title="Share on Facebook"><img src="http://www.facebook.com/favicon.ico" width="16" height="16" alt="[Facebook]" /></a>
<a href="http://technorati.com/faves?add=http%3A%2F%2Feverburning.com%2Fnews%2Fdownload-and-xml-parsing-with-hotcocoa%2F" title="Add to my Technorati Favorites"><img src="http://technorati.com/favicon.ico" width="16" height="16" alt="[Technorati]" /></a>
<a href="http://www.google.com/bookmarks/mark?op=edit&amp;output=popup&amp;bkmk=http%3A%2F%2Feverburning.com%2Fnews%2Fdownload-and-xml-parsing-with-hotcocoa%2F&amp;title=Download+and+XML+parsing+with+HotCocoa" title="Save to Google Bookmarks"><img src="http://www.google.com/favicon.ico" width="16" height="16" alt="[Google]" /></a>
<a href="http://www.stumbleupon.com/submit?url=http%3A%2F%2Feverburning.com%2Fnews%2Fdownload-and-xml-parsing-with-hotcocoa%2F&amp;title=Download+and+XML+parsing+with+HotCocoa" title="Stumble it!"><img src="http://www.stumbleupon.com/favicon.ico" width="16" height="16" alt="[StumbleUpon]" /></a>
</span>]]></content:encoded>
			<wfw:commentRss>http://everburning.com/news/download-and-xml-parsing-with-hotcocoa/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>A Mathematician’s Lament</title>
		<link>http://everburning.com/news/a-mathematician%e2%80%99s-lament/</link>
		<comments>http://everburning.com/news/a-mathematician%e2%80%99s-lament/#comments</comments>
		<pubDate>Thu, 13 Mar 2008 15:41:29 +0000</pubDate>
		<dc:creator>dj2</dc:creator>
				<category><![CDATA[Article]]></category>

		<guid isPermaLink="false">http://everburning.com/news/a-mathematician%e2%80%99s-lament/</guid>
		<description><![CDATA[<p>From what I&#8217;ve read so far, I&#8217;m about 5 pages in, an excellent article on the state of mathematics education.  Give it a read: <a href="http://www.maa.org/devlin/LockhartsLament.pdf">A Mathematician&#8217;s Lament</a>.</p>

<span class="slashdigglicious">
<a href="http://slashdot.org/bookmark.pl?url=http%3A%2F%2Feverburning.com%2Fnews%2Fa-mathematician%25e2%2580%2599s-lament%2F&amp;title=A+Mathematician%E2%80%99s+Lament" title="Slashdot It!"><img src="http://slashdot.org/favicon.ico" height="16" width="16" alt="[Slashdot]" /></a>
<a href="http://digg.com/submit?phase=2&amp;url=http%3A%2F%2Feverburning.com%2Fnews%2Fa-mathematician%25e2%2580%2599s-lament%2F&amp;title=A+Mathematician%E2%80%99s+Lament" title="Digg This Story"><img src="http://digg.com/favicon.ico" width="16" height="16" alt="[Digg]" /></a>
<a href="http://reddit.com/submit?url=http%3A%2F%2Feverburning.com%2Fnews%2Fa-mathematician%25e2%2580%2599s-lament%2F&amp;title=A+Mathematician%E2%80%99s+Lament" title="Reddit"><img src="http://reddit.com/favicon.ico" width="16" height="16" alt="[Reddit]" /></a>
<a href="http://del.icio.us/post?url=http%3A%2F%2Feverburning.com%2Fnews%2Fa-mathematician%25e2%2580%2599s-lament%2F&amp;title=A+Mathematician%E2%80%99s+Lament" title="Save to del.icio.us" onclick="window.open('http://del.icio.us/post?v=4&amp;noui&amp;jump=close&amp;url=http%3A%2F%2Feverburning.com%2Fnews%2Fa-mathematician%25e2%2580%2599s-lament%2F&amp;title=A+Mathematician%E2%80%99s+Lament', 'delicious', 'toolbar=no,width=700,height=400'); return false;"><img src="http://images.del.icio.us/static/img/delicious.small.gif" width="16" height="16" alt="[del.icio.us]" /></a>
<a href="http://www.facebook.com/share.php?u=http%3A%2F%2Feverburning.com%2Fnews%2Fa-mathematician%25e2%2580%2599s-lament%2F" title="Share on Facebook"><img src="http://www.facebook.com/favicon.ico" width="16" height="16" alt="[Facebook]" /></a>
<a href="http://technorati.com/faves?add=http%3A%2F%2Feverburning.com%2Fnews%2Fa-mathematician%25e2%2580%2599s-lament%2F" title="Add to my Technorati Favorites"><img src="http://technorati.com/favicon.ico" width="16" height="16" alt="[Technorati]" /></a>
<a href="http://www.google.com/bookmarks/mark?op=edit&amp;output=popup&amp;bkmk=http%3A%2F%2Feverburning.com%2Fnews%2Fa-mathematician%25e2%2580%2599s-lament%2F&amp;title=A+Mathematician%E2%80%99s+Lament" title="Save to Google Bookmarks"><img src="http://www.google.com/favicon.ico" width="16" height="16" alt="[Google]" /></a>
<a href="http://www.stumbleupon.com/submit?url=http%3A%2F%2Feverburning.com%2Fnews%2Fa-mathematician%25e2%2580%2599s-lament%2F&amp;title=A+Mathematician%E2%80%99s+Lament" title="Stumble it!"><img src="http://www.stumbleupon.com/favicon.ico" width="16" height="16" alt="[StumbleUpon]" /></a>
</span>]]></description>
			<content:encoded><![CDATA[<p>From what I&#8217;ve read so far, I&#8217;m about 5 pages in, an excellent article on the state of mathematics education.  Give it a read: <a href="http://www.maa.org/devlin/LockhartsLament.pdf">A Mathematician&#8217;s Lament</a>.</p>

<span class="slashdigglicious">
<a href="http://slashdot.org/bookmark.pl?url=http%3A%2F%2Feverburning.com%2Fnews%2Fa-mathematician%25e2%2580%2599s-lament%2F&amp;title=A+Mathematician%E2%80%99s+Lament" title="Slashdot It!"><img src="http://slashdot.org/favicon.ico" height="16" width="16" alt="[Slashdot]" /></a>
<a href="http://digg.com/submit?phase=2&amp;url=http%3A%2F%2Feverburning.com%2Fnews%2Fa-mathematician%25e2%2580%2599s-lament%2F&amp;title=A+Mathematician%E2%80%99s+Lament" title="Digg This Story"><img src="http://digg.com/favicon.ico" width="16" height="16" alt="[Digg]" /></a>
<a href="http://reddit.com/submit?url=http%3A%2F%2Feverburning.com%2Fnews%2Fa-mathematician%25e2%2580%2599s-lament%2F&amp;title=A+Mathematician%E2%80%99s+Lament" title="Reddit"><img src="http://reddit.com/favicon.ico" width="16" height="16" alt="[Reddit]" /></a>
<a href="http://del.icio.us/post?url=http%3A%2F%2Feverburning.com%2Fnews%2Fa-mathematician%25e2%2580%2599s-lament%2F&amp;title=A+Mathematician%E2%80%99s+Lament" title="Save to del.icio.us" onclick="window.open('http://del.icio.us/post?v=4&amp;noui&amp;jump=close&amp;url=http%3A%2F%2Feverburning.com%2Fnews%2Fa-mathematician%25e2%2580%2599s-lament%2F&amp;title=A+Mathematician%E2%80%99s+Lament', 'delicious', 'toolbar=no,width=700,height=400'); return false;"><img src="http://images.del.icio.us/static/img/delicious.small.gif" width="16" height="16" alt="[del.icio.us]" /></a>
<a href="http://www.facebook.com/share.php?u=http%3A%2F%2Feverburning.com%2Fnews%2Fa-mathematician%25e2%2580%2599s-lament%2F" title="Share on Facebook"><img src="http://www.facebook.com/favicon.ico" width="16" height="16" alt="[Facebook]" /></a>
<a href="http://technorati.com/faves?add=http%3A%2F%2Feverburning.com%2Fnews%2Fa-mathematician%25e2%2580%2599s-lament%2F" title="Add to my Technorati Favorites"><img src="http://technorati.com/favicon.ico" width="16" height="16" alt="[Technorati]" /></a>
<a href="http://www.google.com/bookmarks/mark?op=edit&amp;output=popup&amp;bkmk=http%3A%2F%2Feverburning.com%2Fnews%2Fa-mathematician%25e2%2580%2599s-lament%2F&amp;title=A+Mathematician%E2%80%99s+Lament" title="Save to Google Bookmarks"><img src="http://www.google.com/favicon.ico" width="16" height="16" alt="[Google]" /></a>
<a href="http://www.stumbleupon.com/submit?url=http%3A%2F%2Feverburning.com%2Fnews%2Fa-mathematician%25e2%2580%2599s-lament%2F&amp;title=A+Mathematician%E2%80%99s+Lament" title="Stumble it!"><img src="http://www.stumbleupon.com/favicon.ico" width="16" height="16" alt="[StumbleUpon]" /></a>
</span>]]></content:encoded>
			<wfw:commentRss>http://everburning.com/news/a-mathematician%e2%80%99s-lament/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Pick your poison.</title>
		<link>http://everburning.com/news/pick-your-poison/</link>
		<comments>http://everburning.com/news/pick-your-poison/#comments</comments>
		<pubDate>Fri, 12 Oct 2007 04:28:55 +0000</pubDate>
		<dc:creator>dj2</dc:creator>
				<category><![CDATA[Article]]></category>
		<category><![CDATA[Computers]]></category>

		<guid isPermaLink="false">http://everburning.com/news/pick-your-poison/</guid>
		<description><![CDATA[<p>Stumbled across, well, it showed up in my blogroll, an interesting article on the <a href="http://www.cerias.purdue.edu/weblogs/">Cerias</a> blog about problem solving and our tendency to try to cure the symptoms instead of solving underlying issues. Mostly computer stuff but nothing technical and maps to pretty much any culture.</p>
<blockquote><p>As a result, we develop fragile monocultures that have a particular set of vulnerabilities, and then we need to spend a huge amount to protect them. ~ <a href="http://www.cerias.purdue.edu/weblogs/spaf/kudos-opinions-rants/post-124/solving-some-of-the-wrong-problems/">Solving Some of the Wrong Problems</a>.</p></blockquote>

<span class="slashdigglicious">
<a href="http://slashdot.org/bookmark.pl?url=http%3A%2F%2Feverburning.com%2Fnews%2Fpick-your-poison%2F&amp;title=Pick+your+poison." title="Slashdot It!"><img src="http://slashdot.org/favicon.ico" height="16" width="16" alt="[Slashdot]" /></a>
<a href="http://digg.com/submit?phase=2&amp;url=http%3A%2F%2Feverburning.com%2Fnews%2Fpick-your-poison%2F&amp;title=Pick+your+poison." title="Digg This Story"><img src="http://digg.com/favicon.ico" width="16" height="16" alt="[Digg]" /></a>
<a href="http://reddit.com/submit?url=http%3A%2F%2Feverburning.com%2Fnews%2Fpick-your-poison%2F&amp;title=Pick+your+poison." title="Reddit"><img src="http://reddit.com/favicon.ico" width="16" height="16" alt="[Reddit]" /></a>
<a href="http://del.icio.us/post?url=http%3A%2F%2Feverburning.com%2Fnews%2Fpick-your-poison%2F&amp;title=Pick+your+poison." title="Save to del.icio.us" onclick="window.open('http://del.icio.us/post?v=4&amp;noui&amp;jump=close&amp;url=http%3A%2F%2Feverburning.com%2Fnews%2Fpick-your-poison%2F&amp;title=Pick+your+poison.', 'delicious', 'toolbar=no,width=700,height=400'); return false;"><img src="http://images.del.icio.us/static/img/delicious.small.gif" width="16" height="16" alt="[del.icio.us]" /></a>
<a href="http://www.facebook.com/share.php?u=http%3A%2F%2Feverburning.com%2Fnews%2Fpick-your-poison%2F" title="Share on Facebook"><img src="http://www.facebook.com/favicon.ico" width="16" height="16" alt="[Facebook]" /></a>
<a href="http://technorati.com/faves?add=http%3A%2F%2Feverburning.com%2Fnews%2Fpick-your-poison%2F" title="Add to my Technorati Favorites"><img src="http://technorati.com/favicon.ico" width="16" height="16" alt="[Technorati]" /></a>
<a href="http://www.google.com/bookmarks/mark?op=edit&amp;output=popup&amp;bkmk=http%3A%2F%2Feverburning.com%2Fnews%2Fpick-your-poison%2F&amp;title=Pick+your+poison." title="Save to Google Bookmarks"><img src="http://www.google.com/favicon.ico" width="16" height="16" alt="[Google]" /></a>
<a href="http://www.stumbleupon.com/submit?url=http%3A%2F%2Feverburning.com%2Fnews%2Fpick-your-poison%2F&amp;title=Pick+your+poison." title="Stumble it!"><img src="http://www.stumbleupon.com/favicon.ico" width="16" height="16" alt="[StumbleUpon]" /></a>
</span>]]></description>
			<content:encoded><![CDATA[<p>Stumbled across, well, it showed up in my blogroll, an interesting article on the <a href="http://www.cerias.purdue.edu/weblogs/">Cerias</a> blog about problem solving and our tendency to try to cure the symptoms instead of solving underlying issues. Mostly computer stuff but nothing technical and maps to pretty much any culture.</p>
<blockquote><p>As a result, we develop fragile monocultures that have a particular set of vulnerabilities, and then we need to spend a huge amount to protect them. ~ <a href="http://www.cerias.purdue.edu/weblogs/spaf/kudos-opinions-rants/post-124/solving-some-of-the-wrong-problems/">Solving Some of the Wrong Problems</a>.</p></blockquote>

<span class="slashdigglicious">
<a href="http://slashdot.org/bookmark.pl?url=http%3A%2F%2Feverburning.com%2Fnews%2Fpick-your-poison%2F&amp;title=Pick+your+poison." title="Slashdot It!"><img src="http://slashdot.org/favicon.ico" height="16" width="16" alt="[Slashdot]" /></a>
<a href="http://digg.com/submit?phase=2&amp;url=http%3A%2F%2Feverburning.com%2Fnews%2Fpick-your-poison%2F&amp;title=Pick+your+poison." title="Digg This Story"><img src="http://digg.com/favicon.ico" width="16" height="16" alt="[Digg]" /></a>
<a href="http://reddit.com/submit?url=http%3A%2F%2Feverburning.com%2Fnews%2Fpick-your-poison%2F&amp;title=Pick+your+poison." title="Reddit"><img src="http://reddit.com/favicon.ico" width="16" height="16" alt="[Reddit]" /></a>
<a href="http://del.icio.us/post?url=http%3A%2F%2Feverburning.com%2Fnews%2Fpick-your-poison%2F&amp;title=Pick+your+poison." title="Save to del.icio.us" onclick="window.open('http://del.icio.us/post?v=4&amp;noui&amp;jump=close&amp;url=http%3A%2F%2Feverburning.com%2Fnews%2Fpick-your-poison%2F&amp;title=Pick+your+poison.', 'delicious', 'toolbar=no,width=700,height=400'); return false;"><img src="http://images.del.icio.us/static/img/delicious.small.gif" width="16" height="16" alt="[del.icio.us]" /></a>
<a href="http://www.facebook.com/share.php?u=http%3A%2F%2Feverburning.com%2Fnews%2Fpick-your-poison%2F" title="Share on Facebook"><img src="http://www.facebook.com/favicon.ico" width="16" height="16" alt="[Facebook]" /></a>
<a href="http://technorati.com/faves?add=http%3A%2F%2Feverburning.com%2Fnews%2Fpick-your-poison%2F" title="Add to my Technorati Favorites"><img src="http://technorati.com/favicon.ico" width="16" height="16" alt="[Technorati]" /></a>
<a href="http://www.google.com/bookmarks/mark?op=edit&amp;output=popup&amp;bkmk=http%3A%2F%2Feverburning.com%2Fnews%2Fpick-your-poison%2F&amp;title=Pick+your+poison." title="Save to Google Bookmarks"><img src="http://www.google.com/favicon.ico" width="16" height="16" alt="[Google]" /></a>
<a href="http://www.stumbleupon.com/submit?url=http%3A%2F%2Feverburning.com%2Fnews%2Fpick-your-poison%2F&amp;title=Pick+your+poison." title="Stumble it!"><img src="http://www.stumbleupon.com/favicon.ico" width="16" height="16" alt="[StumbleUpon]" /></a>
</span>]]></content:encoded>
			<wfw:commentRss>http://everburning.com/news/pick-your-poison/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

<!-- Dynamic Page Served (once) in 0.940 seconds -->
