Archive for the ‘RSS’ Category

ふと、RSSリーダーを作ってみたくなった。

で、XCodeで最初から作っていく過程をのせてみようと思う。
主で使っているMacが10.4のため、10.5で追加されたメソッドとかは無し

まず、XCodeで新規プロジェクトを作成。
ここでは、Cocoa Applicationをする。
#Core Data向きの要件の気もするが、まだ勉強不足のためCocoa Applicationです

次に、プロジェクト名と保存場所。
プロジェクト名:RSSReader
パス:~/RSSReader/
とした。

これで、「完了」をクリックすると、プロジェクトが作成される。
プログラミングする準備はできた。

参考文献
たのしいCocoaプログラミング[Leopard対応版]

RSSリーダーを作ってみようの2回目

GUIを考える。
Mac標準のメーラーMailを使っているので、
そのUIを参考に作ってみた。

左側に、フィード一覧。
右側上部に、記事一覧。
右側下部に、記事概要。

と、シンプルな構成。
最初は、右側下部に、WebKitを使ってページを表示しようか考えたけど、
とりあえずは、簡単にということで、NSTextView

これだけでは、大枠だけ決まっただけなので、後々カスタマイズしていこうと思う。

次回は、いよいよコーディング
RSSを解析するエンジンのプログラム。

RSSリーダーを作ってみようの3回目

実は、恥ずかしながらこのソフトを作ってみようとおもってから、
RSSについて調べ始めました。

単純に、「XMLだからなんとかなるだろう」って思ってました。。。

調べてみると、なんかバージョンというか規格がいっぱいあって、
それなりに汎用的なリーダー作るとなると、まずこのバージョンの違いを判別する機能を
組み込まなきゃということになりました。

調べた結果。
RSS 1.0 (このブログで使用しているBlogn Plusで標準で付いているRSS配信の規格)
RSS 2.0
Atom
などなどあるらしい。。。
う〜ん、よくわからん。

とりあえず、わかんない場合はググる!!ということで調べてみました。
参考にしたページをいくつかあげておきます。

RSS1.0をわかりやすく解説してくれているページ
RSS2.0の仕様を和訳してくているページ
Atomの仕様を和訳してくれているページ

また、Blogn PlusのRSS作成モジュールを公開しているページを発見。
リンクはこちら
とりあえず、インストールしてみました。
同じブログで規格違いが見比べることができて、とっても便利♪

ってことで、今回はコーディングできず、
次回は、RSS1.0 RSS2.0 Atomの判別を行う予定

参考文献
Web開発者のためのRSS & Atomフィード一回は読んでおきたいと思いました。

今回は、RSSの判別方法についてです

違いや仕様などの詳しい説明は他のサイトにありましたので、
そちらを参照してください。

まず、ルートのタグについて
RSS1.0のルートの要素は
RSS2.0のルートの要素は
Atomのルートの要素は

次に、RSS2.0のルートタグの属性値を調べてみる。
2.0
0.93

Atomについても調べてみる
0.3
1.0

これらの相違点から判別を行っていきます。
つまり、
 rdf:RDFタグが存在するならRSS1.0
 ↓
 rssタグが存在する
 ↓
 rssのversion属性の値をバージョンとするRSS2.0 ( RSS 0.92 RSS 0.93)
 ↓
 feedタグが存在する
 ↓
 feedのversion属性の値が0.3ならAtom0.3
 ↓
 feedのversion属性がないならAtom1.0

間違っている可能性が高いですが、
この方法でやってみます。

方針も決まったので、実装してみました。
判別結果は、NSLogで確認するようにしています。

  1. #define VERSIONRSS10     @"/rdf:RDF"
  2. #define VERSIONRSS20     @"/rss"
  3. #define VERSIONATOM      @"/feed"
  4.  
  5. #define RSSVERSION200 @"2.0"
  6. #define RSSVERSION092 @"0.92"
  7. #define RSSVERSION093 @"0.93"
  8.  
  9. -(void)_rssAnlyze:(NSString *)rssStr{
  10. NSString * version;
  11. NSError * error;
  12. NSArray * tmpArray; //一時配列
  13.  
  14. NSXMLDocument * xmlDoc = [ [ [ NSXMLDocument alloc ] initWithXMLString:rssStr
  15. options:NSXMLNodeOptionsNone
  16. error:&error ] autorelease ];
  17.  
  18. //バージョン判別
  19. //1.0の判別(/rdf:RDFならrss 1.0)
  20. tmpArray = [ xmlDoc nodesForXPath:VERSIONRSS10 error:&error ];
  21.  
  22. if( [ tmpArray count ] > 0 ){
  23. NSLog(@"RSS 1.0");
  24. //[ self _rssAnalyze_1_0:rssStr ];
  25. return;
  26. }
  27.  
  28. //2.0の判別(/rss version=0.92, rss version=0.93 , rss version=2.0)はこれ
  29. tmpArray = [ xmlDoc nodesForXPath:VERSIONRSS20 error:&error ];
  30.  
  31. if( [ tmpArray count ] > 0 ){
  32. BOOL ver2Flag = NO;
  33. version = [ [ [ tmpArray objectAtIndex:0 ] attributeForName:@"version" ] stringValue ];
  34. if( [ version isEqualToString:RSSVERSION092 ] ){
  35. ver2Flag = YES;
  36. }else if( [ version isEqualToString:RSSVERSION093 ] ){
  37. ver2Flag = YES;
  38. }else if( [ version isEqualToString:RSSVERSION200 ] ){
  39. ver2Flag = YES;
  40. }
  41.  
  42. if( ver2Flag ){
  43. NSLog(@"RSS 2.0");
  44. return;
  45. }
  46. }
  47.  
  48. //Atomの判別
  49. tmpArray = [ xmlDoc nodesForXPath:VERSIONATOM error:&error ];
  50. if( [ tmpArray count ] > 0 ){
  51. version = [ [ [ tmpArray objectAtIndex:0 ] attributeForName:@"version" ] stringValue ];
  52. if( [ version isEqualToString:@"0.3" ] ){
  53. NSLog(@"Atom 0.3" );
  54. return;
  55. }else if ( version == nil ){
  56. NSLog(@"Atom 1.0" );
  57. return;
  58. }
  59. }
  60.  
  61. //ここまで来たらエラーにする
  62. NSException * e = [ NSException exceptionWithName:@"UnknownFeedErr"
  63. reason:@"UnknownFeedErrReason"
  64. userInfo:nil ];
  65. [ e raise ];
  66.  
  67. return;
  68. }

XMLの解析には、NSXMLのクラスを使用。
このBlogn Plusで生成される各フィードは判別できました。

今回は、RSS1.0の解析

このページを参考にしながら作成しました。

XMLの解析はNSXMLクラスを使って行います。

1.0の解析を入れたRSSクラスのソースがこちらです。
#前回のRSS判別メソッドも入ってます。
SZRSSクラス

  1.  
  2. //———————————————————————–//
  3. //  RSSを解析するクラス                                                    //
  4. //  キーバリューコーディング準拠                                             //
  5. //———————————————————————–//
  6.  
  7. #import <Cocoa/Cocoa.h>
  8.  
  9.  
  10. @interface SZRSS : NSObject {
  11.         NSMutableString * _about;
  12.         NSMutableString * _title;
  13.         NSMutableString * _link;
  14.         NSMutableString * _description;
  15.         NSMutableString * _language;
  16.         NSMutableString * _generator;
  17.         NSMutableString * _lastDate;
  18.         NSMutableString * _xmlString;
  19.         NSMutableString * _urlString;
  20.         NSMutableArray * _itemArray;
  21.        
  22.         NSMutableDictionary * _rssDict;
  23.        
  24. }
  25.  
  26.  
  27. //——————————-//
  28. // クラスメソッド                  //
  29. //——————————//
  30. +(id)rssWithURL:(NSURL *)url;
  31.  
  32.  
  33. //——————————-//
  34. // インスタンスメソッド             //
  35. //——————————-//
  36.  
  37. //—初期化—//
  38. -(id)initWithURL:(NSURL *)url;
  39.  
  40. //—文字列情報—//
  41. //-(NSString *)description;
  42.  
  43.  
  44.  
  45.  
  46.  
  47. @end
  48.  
  49. ——————————-SZRSS.m——————————————-
  50. &#import "SZRSS.h"
  51. #import "SZXMLNode.h"
  52.  
  53. #define RSSVERSION200 @"2.0"
  54. #define RSSVERSION092 @"0.92"
  55. #define RSSVERSION093 @"0.93"
  56.  
  57.  
  58. #define VERSIONRSS10     @"/rdf:RDF"
  59. #define VERSIONRSS20     @"/rss"
  60. #define VERSIONATOM      @"/feed"
  61.  
  62. #define RSS10CHANNEL     @"rdf:RDF/channel"
  63. #define RSS10TITLE       @"rdf:RDF/channel/title"
  64. #define RSS10LINK        @"rdf:RDF/channel/link"
  65. #define RSS10DESCRIPTION @"rdf:RDF/channel/description"
  66. #define RSS10LANG        @"rdf:RDF/channel/dc:language"
  67. #define RSS10CHITEM      @"rdf:RDF/channel/items/rdf:Seq/rdf:li"
  68. #define RSS10ITEM        @"rdf:RDF/item"
  69.  
  70. #define RSS10ABOUT       @"rdf:about"
  71. #define RSS10RESOURCE    @"rdf:resource"
  72.  
  73. @interface SZRSS(PrivateMethod)
  74.  
  75. -(void)_rssAnlyze:(NSURL *)url;
  76. -(void)_rssAnalyze_1_0:(NSXMLDocument *)xmlDoc;
  77. -(void)_rssAnalyze_2_0:(NSXMLDocument *)xmlDoc;
  78. -(void)_atomAnalyze_1_0:(NSXMLDocument *)xmlDoc;
  79.  
  80. -(void)SZRSSConvertDictionary;
  81.  
  82. @end;
  83.  
  84. @implementation SZRSS
  85.  
  86.  
  87.  
  88. #pragma mark +++クラスメソッド+++
  89. //——————————-//
  90. // クラスメソッド                  //
  91. //——————————//
  92. +(id)rssWithURL:(NSURL *)url{
  93.         return [ [ [ self alloc ] initWithURL:url ] autorelease ];
  94. }
  95.  
  96.  
  97.  
  98. #pragma mark +++インスタンスメソッド+++
  99. //——————————-//
  100. // インスタンスメソッド             //
  101. //——————————-//
  102.  
  103. #pragma mark —初期化—
  104. //—初期化—//
  105. -(id)initWithURL:(NSURL *)url{
  106.         self = [super init];
  107.         if (self != nil) {
  108.                 _about        = [ [ NSMutableString string ] retain ];
  109.                 _title        = [ [ NSMutableString string ] retain ];
  110.                 _link         = [ [ NSMutableString string ] retain ];
  111.                 _description  = [ [ NSMutableString string ] retain ];
  112.                 _language     = [ [ NSMutableString string ] retain ];
  113.                 _generator    = [ [ NSMutableString string ] retain ];
  114.                 _lastDate     = [ [ NSMutableString string ] retain ];
  115.                
  116.                 _itemArray    = [ [ NSMutableArray array ] retain ];
  117.                 _rssDict      = [ [ NSMutableDictionary dictionary ] retain ];
  118.                
  119.                 _xmlString    = [ [ NSMutableString string ] retain ];
  120.                 _urlString    = [ [ NSMutableString string ] retain ];
  121.         }
  122.        
  123.         /*NSError * error;
  124.         NSString * rssStr = [ NSString stringWithContentsOfURL:url
  125.                                                                                                   encoding:NSUTF8StringEncoding
  126.                                                                                                          error:&error ];*/
  127.         /*NSStringEncoding enc;
  128.         NSString * rssStr = [ NSString stringWithContentsOfURL:url
  129.                                                                                           usedEncoding:&enc
  130.                                                                                                          error:&error ];
  131.         NSLog(@"%d", enc );*/
  132.         //NSLog(@"%@", error );
  133.         [ self _rssAnlyze:url ];
  134.         [ self SZRSSConvertDictionary ];
  135.        
  136.         return self;
  137. }
  138.  
  139.  
  140.  
  141. #pragma mark —解放時—
  142. - (void) dealloc {
  143.         [ _about release ];      
  144.         [ _title release ];
  145.         [ _link  release ];
  146.         [ _description release ];
  147.         [ _language release ];
  148.         [ _generator release ];
  149.         [ _lastDate release ];
  150.        
  151.         [ _itemArray release ];
  152.        
  153.         [ super dealloc];
  154. }
  155.  
  156.  
  157.  
  158. #pragma mark +++プライベートメソッド+++
  159.  
  160. //—————————————–//
  161. // RSSを解析して、各インスタンス変数へ代入       //
  162. //—————————————–//
  163. -(void)_rssAnlyze:(NSURL*)url{
  164.         NSString * version;
  165.         NSError * error;
  166.         NSArray * tmpArray; //一時配列
  167.        
  168.        
  169.         NSXMLDocument * xmlDoc = [ [ [ NSXMLDocument alloc ] initWithContentsOfURL:url
  170.                                                                                                                                  options:NSXMLNodeOptionsNone
  171.                                                                                                                                    error:&error ] autorelease ];
  172.         [ _xmlString setString:[ xmlDoc XMLString ] ];
  173.         [ _urlString setString:[ url absoluteString ] ];
  174.         if( xmlDoc == nil ){
  175.                 NSException * e = [ NSException exceptionWithName:@"UnknownFeedErr"
  176.                                                                                                    reason:@"UnknownFeedErrReason"
  177.                                                                                                  userInfo:nil ];
  178.                 [ e raise ];
  179.                
  180.                 return;
  181.         }
  182.        
  183.         //バージョン判別
  184.         //1.0の判別(/rdf:RDFならrss 1.0)
  185.         tmpArray = [ xmlDoc nodesForXPath:VERSIONRSS10 error:&error ];
  186.        
  187.         if( [ tmpArray count ] > 0 ){
  188.                 NSLog(@"RSS 1.0");
  189.                 [ self _rssAnalyze_1_0:xmlDoc ];
  190.                 return;
  191.         }
  192.        
  193.         //2.0の判別(/rss version=0.92, rss version=0.93 , rss version=2.0)はこれ
  194.         tmpArray = [ xmlDoc nodesForXPath:VERSIONRSS20 error:&error ];
  195.        
  196.         if( [ tmpArray count ] > 0 ){
  197.                 BOOL ver2Flag = NO;
  198.                 version = [ [ [ tmpArray objectAtIndex:0 ] attributeForName:@"version" ] stringValue ];
  199.                 if( [ version isEqualToString:RSSVERSION092 ] ){
  200.                         ver2Flag = YES;
  201.                 }else if( [ version isEqualToString:RSSVERSION093 ] ){
  202.                         ver2Flag = YES;
  203.                 }else if( [ version isEqualToString:RSSVERSION200 ] ){
  204.                         ver2Flag = YES;
  205.                 }
  206.                
  207.                 if( ver2Flag ){
  208.                         NSLog(@"RSS 2.0");
  209.                         [ self _rssAnalyze_2_0:xmlDoc ];
  210.                         return;
  211.                 }
  212.         }
  213.        
  214.         //Atomの判別
  215.        
  216.         tmpArray = [ xmlDoc nodesForXPath:VERSIONATOM error:&error ];
  217.         NSLog(@"%d", [ tmpArray count ] );
  218.         if( [ tmpArray count ] > 0 ){
  219.                 version = [ [ [ tmpArray objectAtIndex:0 ] attributeForName:@"version" ] stringValue ];
  220.                 if( [ version isEqualToString:@"0.3" ] ){
  221.                         NSLog(@"Atom 0.3" );
  222.                         [ self _atomAnalyze_1_0:xmlDoc ];
  223.                         return;
  224.                 }else if ( version == nil ){
  225.                         NSLog(@"Atom 1.0" );
  226.                         [ self _atomAnalyze_1_0:xmlDoc ];
  227.                         return;
  228.                 }
  229.         }
  230.        
  231.         //ここまで来たらエラーにする
  232.         NSException * e = [ NSException exceptionWithName:@"UnknownFeedErr"
  233.                                                                                            reason:@"UnknownFeedErrReason"
  234.                                                                                          userInfo:nil ];
  235.         [ e raise ];
  236.                
  237.         return;
  238. }
  239.  
  240.  
  241. //————————————-//
  242. //  RSS1.0解析                          //
  243. //————————————-//
  244. -(void)_rssAnalyze_1_0:(NSXMLDocument *)xmlDoc{
  245.         //RSS1.0の解析
  246.         /*NSXMLDocument * xmlDoc = [ [ [ NSXMLDocument alloc ] initWithXMLString:rssStr
  247.                                                                                                                                    options:NSXMLNodeOptionsNone
  248.                                                                                                                                          error:NULL ] autorelease ];*/
  249.        
  250.         //タグが存在しない場合は、空文字が入る
  251.         [ _about setString:[ xmlDoc valueForXPath:RSS10CHANNEL withAttributeName:RSS10ABOUT ] ];
  252.         [ _title setString:[ xmlDoc valueForXPath:RSS10TITLE ] ];
  253.         [ _link setString:[ xmlDoc valueForXPath:RSS10LINK ] ];
  254.         [ _description setString:[ xmlDoc valueForXPath:RSS10DESCRIPTION ] ];
  255.         [ _language setString:[ xmlDoc valueForXPath:RSS10LANG ] ];
  256.        
  257.         //RSS1.0ではこの項目はない
  258.         [ _generator setString:@"" ];
  259.         [ _lastDate setString:@"" ];
  260.        
  261.         //itemsを作成
  262.         NSArray * tmpChannelArray = [ xmlDoc nodesForXPath:RSS10CHITEM error:NULL ];
  263.         NSArray * tmpItemArray = [ xmlDoc nodesForXPath:RSS10ITEM error:NULL ];
  264.        
  265.        
  266.         /***カウンタ***/
  267.         int i,j;
  268.         //itemの配列を作成する
  269.         NSEnumerator * enum_channel = [ tmpChannelArray objectEnumerator ];
  270.         id obj_channel;
  271.         while( obj_channel = [ enum_channel nextObject ]){
  272.                 NSString * tmpString = [ [ obj_channel attributeForName:RSS10RESOURCE] stringValue ];
  273.                 for ( i = 0; i < [ tmpItemArray count ]; i++ ){
  274.                         NSXMLElement * tmpElement = [ tmpItemArray objectAtIndex:i ];
  275.                         NSString * tmpItemAboutString = [ [ tmpElement attributeForName:RSS10ABOUT ] stringValue ];
  276.                        
  277.                         if( [ tmpItemAboutString isEqualToString:tmpString ] ){
  278.                                 NSMutableDictionary * dict = [ NSMutableDictionary dictionary ];
  279.                                 [ dict setValue:tmpString forKey:RSS10ABOUT ];
  280.                                 //各要素を取得する
  281.                                 for (j = 0; j < [ [ tmpElement children ] count ]; j++){
  282.                                         NSString * key = [ [ [ tmpElement children ] objectAtIndex:j ] name ];
  283.                                         NSString * value = [ [ [ tmpElement children ] objectAtIndex:j ] stringValue ];
  284.                                         [ dict setValue:value forKey:key ];
  285.                                        
  286.                                 }
  287.                                
  288.                                 //辞書からTextViewに表示する属性付き文字列の作成
  289.                                 //空の属性文字列
  290.                                 NSMutableAttributedString * attrStr = [ [ [ NSMutableAttributedString alloc ] init ] autorelease ];
  291.                                
  292.                                 //タイトル部分を作成(リンク属性)
  293.                                 NSMutableDictionary * attrDict = [ NSMutableDictionary dictionary ];
  294.                                 [ attrDict setValue:[ dict valueForKey:@"link"] forKey:NSLinkAttributeName ];
  295.                                 [ attrDict setValue:[ NSFont boldSystemFontOfSize:16 ] forKey:NSFontAttributeName ];
  296.                                 [ [ NSAttributedString alloc ] initWithString:[ dict valueForKey:@"title" ] attributes:attrDict ];
  297.                                 [ attrStr appendAttributedString:[ [ NSAttributedString alloc ] initWithString:[ dict valueForKey:@"title" ] attributes:attrDict ] ];
  298.                                
  299.                                 //改行文字などを作成
  300.                                 NSString * kugiriString = [ NSString stringWithFormat:@"\n\n" ];
  301.                                 [ attrStr appendAttributedString:[ [ NSAttributedString alloc ] initWithString:kugiriString attributes:nil ] ];
  302.                                
  303.                                 //本文部分を作成
  304.                                 NSString * htmlString = [ dict valueForKey:@"content:encoded" ];
  305.                                 if( htmlString == nil ){
  306.                                         htmlString = [ dict valueForKey:@"description" ];
  307.                                 }
  308.                                 NSData * data = [ htmlString dataUsingEncoding:NSUnicodeStringEncoding ];
  309.                                 [ attrStr appendAttributedString:[ [ NSAttributedString alloc ] initWithHTML:data
  310.                                                                                                                                                                          baseURL:nil
  311.                                                                                                                                                   documentAttributes:NULL ] ];
  312.                                 [ dict setValue:attrStr forKey:@"content" ];
  313.                                
  314.                                 [ _itemArray addObject:dict ];
  315.                                 break;
  316.                         }
  317.                        
  318.                 }
  319.         }
  320. }
  321.  

このメソッド内では、NSXMLNodeのカテゴリで追加した
valueForXPath:
valueForXPath: withAttributeName:

を使用しています。

こちらのソースについては、長くなったのでこちらを参照してください。

RSSの解析を行う際に、
NSXMLNodeにカテゴリでいくつかのメソッドを追加した。
#まだまだ、実装がしょぼいので改良の余地が多分にあります。

  1.  
  2. #import "SZXMLNode.h"
  3.  
  4.  
  5. @implementation NSXMLNode (SZXMLNode)
  6.  
  7. //————————————————//
  8. // XPathで指定された箇所のstringValueを返す           //
  9. //————————————————//
  10. -(NSString *)valueForXPath:(NSString *)xPath{
  11.         NSArray * tmpArray;
  12.         NSString * tmpString;
  13.        
  14.         tmpArray = [ self nodesForXPath:xPath error:NULL ];
  15.         //タグがなければ空文字
  16.         if( [ tmpArray count ] == 0 || [ tmpArray count ] > 1 ){
  17.                 tmpString = @"";
  18.         }else{
  19.                 tmpString = [ [ tmpArray objectAtIndex:0 ] stringValue ];
  20.         }
  21.        
  22.         return tmpString;
  23. }
  24.  
  25.  
  26. //————————————————//
  27. // XPathで指定された箇所の指定した属性の値を返す           //
  28. //————————————————//
  29. -(NSString *)valueForXPath:(NSString *)xPath withAttributeName:(NSString *)name{
  30.         NSArray * tmpArray;
  31.         NSString * tmpString;
  32.        
  33.         tmpArray = [ self nodesForXPath:xPath error:NULL ];
  34.         //ここで個数なければ、空文字か
  35.         if( [ tmpArray count ] == 0 || [ tmpArray count ] > 1){
  36.                 tmpString = @"";
  37.         }else{
  38.                 tmpString = [ [ [ tmpArray objectAtIndex:0 ] attributeForName:name ] stringValue ];
  39.         }
  40.        
  41.         return tmpString;
  42. }
  43.  
  44. @end
  45.  

今回は、RSS2.0の解析

XMLの解析自体は、NSXMLクラスを使用しているので、
その流れは全く一緒。

1.0の解析用に作成したクラスにメソッドを追加した。

追加分だけ抜粋。

  1.  
  2. #define RSS20TITLE       @"rss/channel/title"
  3. #define RSS20LINK        @"rss/channel/link"
  4. #define RSS20DESCRIPTION @"rss/channel/description"
  5. #define RSS20LANG        @"rss/channel/language"
  6. #define RSS20GENERATOR   @"rss/channel/generator"
  7. #define RSS20LASTDATE    @"rss/channel/lastBuildDate"
  8. #define RSS20ITEM        @"rss/channel/item"
  9.  
  10. -(void)_rssAnalyze_2_0:(NSString *)rssStr{
  11. //RSS2.0の解析
  12. NSXMLDocument * xmlDoc = [ [ [ NSXMLDocument alloc ] initWithXMLString:rssStr
  13. options:NSXMLNodeOptionsNone
  14. error:NULL ] autorelease ];
  15.  
  16. [ _about setString:@"" ];
  17. [ _title setString:[ xmlDoc valueForXPath:RSS20TITLE ] ];
  18. [ _link setString:[ xmlDoc valueForXPath:RSS20LINK ] ];
  19. [ _description setString:[ xmlDoc valueForXPath:RSS20DESCRIPTION ] ];
  20. [ _language setString:[ xmlDoc valueForXPath:RSS20LANG ] ];
  21. [ _generator setString:[ xmlDoc valueForXPath:RSS20GENERATOR ] ];
  22.  
  23. [ _lastDate setString:[ xmlDoc valueForXPath:RSS20LASTDATE ] ];
  24.  
  25. //itemsを作成
  26. NSArray * tmpChannelArray = [ xmlDoc nodesForXPath:RSS20ITEM error:NULL ];
  27.  
  28. /***カウンタ***/
  29. int j;
  30. //itemの配列を作成する
  31. NSEnumerator * enum_channel = [ tmpChannelArray objectEnumerator ];
  32. id obj_channel;
  33. while( obj_channel = [ enum_channel nextObject ]){
  34. NSXMLElement * tmpElement = obj_channel;
  35. NSMutableDictionary * dict = [ NSMutableDictionary dictionary ];
  36. for (j = 0; j < [ [ tmpElement children ] count ]; j++){
  37. NSString * key = [ [ [ tmpElement children ] objectAtIndex:j ] name ];
  38. NSString * value = [ [ [ tmpElement children ] objectAtIndex:j ] stringValue ];
  39. [ dict setValue:value forKey:key ];
  40. }
  41.  
  42. [ _itemArray addObject:dict ];
  43. }
  44.  
  45. }
  46.  
  47.  

特に注意するところもなく、普通にXMLを読んでいけば各値を取得することができる

Atomを解析する。

最初のころは、Atom0.3と1.0を別のメソッドで書こうかと思ってたけど
よくよく見てみると、
同じメソッドで大丈夫そう。

今回もNSXMLを用いて、解析スタート。

  1. #define ATOM03TITLE       @"feed/title"
  2. #define ATOM03LINK        @"feed/link"
  3. #define ATOM03HREF        @"href"
  4. #define ATOM03DESCRIPTION @"feed/tagline"
  5. #define ATOM03LANG        @"feed/language"
  6. #define ATOM03GENERATOR   @"feed/generator"
  7. #define ATOM03LASTDATE    @"feed/modified"
  8. #define ATOM03ITEM        @"feed/entry"
  9.  
  10. -(void)_atomAnalyze_1_0:(NSString *)rssStr{
  11.   //Atom1.0の解析
  12.   //Atom0.3の解析
  13.   NSXMLDocument * xmlDoc = [ [ [ NSXMLDocument alloc ] initWithXMLString:rssStr
  14.                     options:NSXMLNodeOptionsNone
  15.          error:NULL ] autorelease ];
  16.  
  17.   [ _about setString:@"" ];
  18.   [ _title setString:[ xmlDoc valueForXPath:ATOM03TITLE ] ];
  19.   [ _link setString:[ xmlDoc valueForXPath:ATOM03LINK withAttributeName:ATOM03HREF ] ];
  20.   [ _description setString:[ xmlDoc valueForXPath:ATOM03DESCRIPTION ] ];
  21.   [ _language setString:[ xmlDoc valueForXPath:ATOM03LANG ] ];
  22.   [ _generator setString:[ xmlDoc valueForXPath:ATOM03GENERATOR ] ];
  23.   [ _lastDate setString:[ xmlDoc valueForXPath:ATOM03LASTDATE ] ];
  24.  
  25.   //itemsを作成
  26.   NSArray * tmpChannelArray = [ xmlDoc nodesForXPath:ATOM03ITEM error:NULL ];
  27.  
  28.   /***カウンタ***/
  29.   int j;
  30.   //itemの配列を作成する
  31.   NSEnumerator * enum_channel = [ tmpChannelArray objectEnumerator ];
  32.   id obj_channel;
  33.   while( obj_channel = [ enum_channel nextObject ]){
  34.     NSXMLElement * tmpElement = obj_channel;
  35.     NSMutableDictionary * dict = [ NSMutableDictionary dictionary ];
  36.     for (j = 0; j < [ [ tmpElement children ] count ]; j++){
  37.       NSString * key = [ [ [ tmpElement children ] objectAtIndex:j ] name ];
  38.       NSString * value;
  39.       //リンクの時は、属性値"href"を使用
  40.       if ( [ key isEqualToString:@"link" ] ){
  41.         value = [ [ [ [ tmpElement children ] objectAtIndex:j ] attributeForName:ATOM03HREF ] stringValue ];
  42.       //authorタグはとりあえず、名前のみ
  43.       }else if( [ key isEqualToString:@"author" ] ){
  44.         NSString * xpath = [ [ [ tmpElement children ] objectAtIndex:j ] XPath ];
  45.         value = [ xmlDoc valueForXPath:[ xpath stringByAppendingPathComponent:@"name" ] ];
  46.       }else{
  47.         value = [ [ [ tmpElement children ] objectAtIndex:j ] stringValue ];
  48.       }
  49.       [ dict setValue:value forKey:key ];
  50.     }
  51.  
  52.     [ _itemArray addObject:dict ];
  53.   }
  54. }

基本的には、これでクラスの枠組みは完成。
このままだと、各フィードのキー名が異なるので
GUI側に反映するためにキーの統一を行っていく。
(統一しないと、Cocoa Bindingが難しい。。。)