<?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>Mac / iPhone App Development &#187; RSS</title>
	<atom:link href="http://benreeves.co.uk/tag/rss/feed/" rel="self" type="application/rss+xml" />
	<link>http://benreeves.co.uk</link>
	<description>Home of a Small Time Developer</description>
	<lastBuildDate>Wed, 26 May 2010 14:24:12 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>iPhone Expat XML Parser Wrapper</title>
		<link>http://benreeves.co.uk/iphone-expat-xml-parser-wrapper/</link>
		<comments>http://benreeves.co.uk/iphone-expat-xml-parser-wrapper/#comments</comments>
		<pubDate>Mon, 24 May 2010 14:30:58 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[Atom]]></category>
		<category><![CDATA[Expat]]></category>
		<category><![CDATA[iPhone]]></category>
		<category><![CDATA[NSXMLParser]]></category>
		<category><![CDATA[objective c]]></category>
		<category><![CDATA[RSS]]></category>
		<category><![CDATA[XML]]></category>

		<guid isPermaLink="false">http://benreeves.co.uk/?p=314</guid>
		<description><![CDATA[Often in iPhone projects I&#8217;ve needed to parse XML documents from the internet. I want the data to be processed  and shown to the user as quickly as possible. If the file is large I don&#8217;t want to have to store the entire contents in memory. Using NSXMLParsers initWithURL: method the xml file is downloaded synchronously with NSURLConnection [...]]]></description>
			<content:encoded><![CDATA[<p>Often in iPhone projects I&#8217;ve needed to parse XML documents from the internet.</p>
<ul>
<li>I want the data to be processed  and shown to the user as quickly as possible.</li>
<li>If the file is large I don&#8217;t want to have to store the entire contents in memory.</li>
</ul>
<p>Using NSXMLParsers initWithURL: method the xml file is downloaded synchronously with NSURLConnection before parsing. If NSXMLParser was able to begin as soon as stream buffer began to fill, even though the overall parsing time wouldn&#8217;t be reduced significantly if the updates are immediately displayed the user perceived time decreases significantly.</p>
<p>Using the excellent <a href="http://www.robbiehanson.com/expat.html">objective c expat wrapper</a> library by <a href="http://www.robbiehanson.com/">Robbie Hanson</a> as a base iPhoneExpat uses CFNetwork &amp; CFHTTPMessage to create and feed a http stream gradually into Expat. If the server supports gzip compression <a href="http://www.zlib.net/">zlib</a> is used to decompress the stream on fly.</p>
<p>iPhone Expat offer 3 methods for initialization </p>
<pre lang="objc">
- (id)initWithContentsOfURL:(NSURL *)url;
- (id)initWithContentsOfFile:(NSString *)path;
- (id)initWithData:(NSData *)data;
</pre>
<p>The delegate messages are also a drop in replacement for NSXMLParser</p>
<pre lang="objc">@protocol ExpatXMLParserDelegate 

@optional
- (void)parserDidStartDocument:(ExpatXMLParser*)parser;
- (void)parserDidEndDocument:(ExpatXMLParser*)parser;
- (void)parser:(ExpatXMLParser*)parser didStartMappingPrefix:(NSString *)prefix toURI:(NSString *)namespaceURI;
- (void)parser:(ExpatXMLParser*)parser didEndMappingPrefix:(NSString *)prefix;
- (void)parser:(ExpatXMLParser*)parser foundComment:(NSString *)comment;
- (void)parser:(ExpatXMLParser*)parser foundProcessingInstructionWithTarget:(NSString *)target data:(NSString *)data;
- (void)parser:(ExpatXMLParser*)parser parseErrorOccurred:(NSError *)parseError;
- (BOOL)parser:(ExpatXMLParser*)parser shouldProcessAttributesForElement:(NSString *)elementName;

@required
- (void)parser:(ExpatXMLParser*)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName attributes:(NSDictionary *)attributeDict;
- (void)parser:(ExpatXMLParser*)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName;
- (void)parser:(ExpatXMLParser *)parser foundCharacters:(NSString *)string;

@end</pre>
<p>However</p>
<pre lang="objc">- (void)parser:(ExpatXMLParser *)parser foundCharacters:(NSString *)string;</pre>
<p>Will report the entire contents of a tag so you don&#8217;t need an NSMutablestring to buffer fragments in your delegate. e.g.</p>
<pre lang="objc">
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
	[buffer release];
	buffer = string;
	[buffer retain];
}
</pre>
<p>Should be good in 99% of cases to get the entire contents of a tag</p>
<p><strong>The project can be found here</strong></p>
<p><a href="http://github.com/zootreeves/iPhoneExpat">http://github.com/zootreeves/iPhoneExpat</a></p>
<p>Alternatively checkout the code using git: http://github.com/zootreeves/iPhoneExpat</p>
<p><strong>Benchmark test output:</strong></p>
<p><strong><span style="font-weight: normal;">I&#8217;ve included a test application which sequentially downloads and parses the following feeds:</span></strong></p>
<pre lang="objc">@"http://ax.itunes.apple.com/WebObjects/MZStoreServices.woa/ws/RSS/topalbums/sf=143441/limit=300/explicit=true/xml",
@"http://ax.itunes.apple.com/WebObjects/MZStoreServices.woa/ws/RSS/topalbums/sf=143441/limit=300/explicit=true/xml",
@"http://feeds.feedburner.com/DilbertDailyStrip",
@"http://designsponge.blogspot.com/atom.xml",
@"http://www.slate.com/rss/",
@"http://rssfeeds.usatoday.com/UsatodaycomBooks-TopStories",
@"http://googleblog.blogspot.com/atom.xml",
@"hhttp://api.flickr.com/services/feeds/groups_pool.gne?id=61057342@N00〈=en-us&amp;format=rss_200",
@"http://phobos.apple.com/WebObjects/MZStore.woa/wpa/MRSS/topsongs/limit=25/rss.xml",
@"http://www.readwriteweb.com/rss.xml",
@"http://rssfeeds.usatoday.com/UsatodaycomNation-TopStories",
@"http://dictionary.reference.com/wordoftheday/wotd.rss",
@"http://www.quotationspage.com/data/qotd.rss",
@"http://sports.espn.go.com/espn/rss/news"</pre>
<p><span style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; line-height: 19px; white-space: normal; font-size: 13px;">Time to reach the first element Expat: 8.611217 &#8212; NSXMLParser: 15.404100<br />
Total time for Expat: 10.902272 &#8212; NSXMLParser: 17.108309</p>
<p>Memory is also reduced by a factor of about x4 (see screenshots)<br />

<a href='http://benreeves.co.uk/iphone-expat-xml-parser-wrapper/screen-shot-2010-05-24-at-15-37-29/' title='NSXMLParser memory usage'><img width="150" height="150" src="http://benreeves.co.uk/wp-content/uploads/2010/05/Screen-shot-2010-05-24-at-15.37.29-150x150.png" class="attachment-thumbnail" alt="Record of Leaks parsing serveral XML Files" title="NSXMLParser memory usage" /></a>
<a href='http://benreeves.co.uk/iphone-expat-xml-parser-wrapper/screen-shot-2010-05-24-at-15-42-40/' title='Screen shot 2010-05-24 at 15.42.40'><img width="150" height="150" src="http://benreeves.co.uk/wp-content/uploads/2010/05/Screen-shot-2010-05-24-at-15.42.40-150x150.png" class="attachment-thumbnail" alt="Screen shot 2010-05-24 at 15.42.40" title="Screen shot 2010-05-24 at 15.42.40" /></a>
</p>
<p><strong>Further Considerations</strong></p>
<ul>
<li>It would be great if http requests were persistent, however after setting kCFStreamPropertyHTTPAttemptPersistentConnection to true using <a href="http://www.tuffcode.com/">httpscoop</a> I will still able to intercept &#8220;connection close&#8221; messages between requests to the same server. I think I must be doing something wrong here.</li>
<li>It would be preferable if as many objects as possible were released manually rather than using an autorelease pool. For example the delegate methods that pass an elementName it is common for the client to use this string to determine their current tag, but rare that they actually want to retain it. The code could be altered so these strings are not placed in a pool and are released immediately after the delegate message is sent. Not only can the overhead of collection be avoided but CFStringCreateWithCharactersNoCopy can be used as well.</li>
<li>With UTF8 creating CFStrings with the [NSString stringwithutf8string:] was no problem. However when I configured Expat to use UTF-16 characters internally I found that CFStringCreateWithCharacters would often return garbage. The problem is I was passing in UINT16_MAX as the buffer length hoping that the CFString would be terminated at null, however it doesn&#8217;t work that way and I had to change everything to calculate the buffer size using UniCharStrlen(buffer) before hand.</li>
<li> FTP (CFFTPStream) and file streams could easily be supported.</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://benreeves.co.uk/iphone-expat-xml-parser-wrapper/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

