【コラム】
前回はXMLパースライブラリの検討をして、libxmlを採用する事にした。今回は、実際にlibxmlを組み込んで、パースを行ってみよう。
まずプロジェクトにlibxmlを加える必要がある。
ここまででプロジェクトに追加されている外部のライブラリは、フレームワーク形式のものだった。UIKit.frameworkや、Foundation.frameworkなどだ。これらのファイルは、SDKフォルダの下の、Sysytem/Library/Frameworksに入れられている。SDKフォルダは、/Developer/Platforms/iPhoneOS.platform/Developer/SDKsにある。
これに対して、libxmlのようなUNIX由来のライブラリは、別のフォルダの中にある。SDKフォルダの下の、usr/libだ。インクルードファイルは、usr/includeになる。
この中にlibxmlのためのファイルがある。iPhoneSDK2.2では、libxml2.2.dylibがインストールされている。このファイルへのシンボリックリンクであるlibxml2.dylibが用意されているので、こちらをプロジェクトに追加しよう。
プロジェクトへの追加は簡単で、libxml2.dylibファイルを、Finderからドラッグ&ドロップで追加してやればいい。または、[プロジェクト]→[プロジェクトに追加…]メニューからファイルを選択する。
インクルードパスの追加も必要である。こちらは、ターゲットの情報画面から行う。ビルドの設定項目に「ヘッダ検索パス」があるので、ここにlibxml2のためのインクルードパスを追加しよう。SDKフォルダの下の、usr/include/libxml2になる。
これで、libxmlを使う準備が整った。
今回は、パフォーマンスとメモリのフットプリントを考慮して、libxmlのSAXパーサを使う。SAXパーサでは、パースをしながらXMLの要素や属性を発見し、それをアプリケーションに通知してくれる。このために、ハンドラを登録しておく必要がある。
libxmlのSAXハンドラは、xmlSAXHandlerという構造体で定義されている。この構造体では、30ほどのハンドラが定義されている。これらを全部登録する必要はない。アプリケーションの中で、必要なものだけ使えばいいのだ。ここでは、要素の開始、要素の終わり、テキスト、を通知するハンドラを登録しよう。多くの場合、これだけでも十分だろう。
これらのハンドラは、それぞれstartElementNsSAX2Func、endElementNsSAX2Func、charactersSAXFuncという型になっている。次のような定義になっている。
List 1.
typedef void (*startElementNsSAX2Func) (
void *ctx,
const xmlChar *localname,
const xmlChar *prefix,
const xmlChar *URI,
int nb_namespaces,
const xmlChar **namespaces,
int nb_attributes,
int nb_defaulted,
const xmlChar **attributes);
typedef void (*endElementNsSAX2Func) (
void *ctx,
const xmlChar *localname,
const xmlChar *prefix,
const xmlChar *URI);
typedef void (*charactersSAXFunc) (
void *ctx,
const xmlChar *ch,
int len);
要素の開始の通知の際には、名前空間なども渡されるのが分かるだろう。
これらの第一引数に、ctxというものがあるのに注目してほしい。これは、ユーザが任意に指定できるデータとなる。Cocoaアプリでは、ここに、このXMLパーサをハンドリングするオブジェクトのアドレスを入れておくと便利だ。なぜなら、ハンドラ自体はC言語のコールバックなので、C関数となる。この中で処理をするのはなにかと不便なので、オブジェクトを使って、そちらのメソッドに処理を投げてしまうようにすればいい。
では、このlibxmlを組み込んでみよう。前回までにDownloadOperationという、フィードをダウンロードするためのクラスを作成した。これに組み込んでみる。
まずこのクラスに、SAXパーサのためのインスタンス変数を追加しよう。これは、xmlParserCtxtPtrという型になる。
List 2.
#import <Foundation/Foundation.h>
#import <libxml/tree.h>
@interface DownloadOperation : NSOperation
{
NSURLRequest* _request;
NSURLConnection* _connection;
xmlParserCtxtPtr _parserContext;
BOOL _isExecuting, _isFinished;
}
// Initialize
- (id)initWithRequest:(NSURLRequest*)request;
@end
まず、#import文でlibxml/tree.hヘッダファイルを読み込んでおく。そして、xmlParserCtxtPtr型の変数を宣言する。前回まであった、ダウンロードしたデータを保存しておくための_data変数は、ダウンロード中に逐次パースを行うため、必要なくなったので削除した。
次に、SAXハンドラを紹介しよう。
List 3.
static void startElementHandler(
void* ctx,
const xmlChar* localname,
const xmlChar* prefix,
const xmlChar* URI,
int nb_namespaces,
const xmlChar** namespaces,
int nb_attributes,
int nb_defaulted,
const xmlChar** attributes)
{
[(DownloadOperation*)ctx
startElementLocalName:localname
prefix:prefix URI:URI
nb_namespaces:nb_namespaces
namespaces:namespaces
nb_attributes:nb_attributes
nb_defaulted:nb_defaulted
attributes:attributes];
}
このように、ハンドラが呼び出された直後にDownloadOperationのメソッドを呼び出して、処理をそちらに渡すようにしている。
フィードのダウンロードを始めるときは、先にパーサを作成する。パーサの作る関数はいくつかあるが、ここではダウンロドーしたデータを逐次追加できるようにしたいので、xmlCreatePushParserCtxtを使おう。
List 4.
- (void)start
{
// ダウンロードを開始する
if (![self isCancelled]) {
// XMLパーサを作成する
_parserContext = xmlCreatePushParserCtxt(&_saxHandlerStruct, self, NULL, 0, NULL);
...
ダウンロードが始まりデータが得られたら、順次データを追加していく。これには、xmlParseChunkを使えばいい。
List 5.
- (void)connection:(NSURLConnection*)connection
didReceiveData:(NSData*)data
{
// データを追加する
xmlParseChunk(_parserContext, (const char*)[data bytes], [data length], 0);
}
これがlibxmlを組み込んだDownloadOperationクラスだ。NSXMLParserを使うものと比べて、高いパフォーマンスと、少ないメモリフットプリントを実現できているはずだ。
次回は、RSSデータを取り出して、アプリケーションを仕上げていこう。
ここまでのソースコード: RSS-2.zip
| 理研、脳・脊髄形成に必要な神経板湾曲の仕組みを解明 [20:16 5/25] |
| 京大、「慢性閉塞性肺疾患」患者の労作時呼吸困難は鍼治療が有効と実証 [20:08 5/25] |
| 120Hz SHVカメラ用イメージセンサーを使った撮像装置 - SHVフルスペック化へ [18:10 5/25] |
| 京大、視覚による物体認知は前頭前野からのトップダウン信号が重要と確認 [17:45 5/25] |
| 製品数の拡大だけでなくBCPの展開なども含めた総合力で事業の強化を図るTI [17:25 5/25] |
|
【連載】これだけは要チェック! TOEIC(R)単語帳 第108回 今回のお題は…「issue」 [20:00 5/27] キャリア |
|
TVアニメ『ペルソナ4』、新規カットを加えた再編集版を劇場でイベント上映 [20:00 5/27] ホビー |
|
[9nine]制服姿見納め? セーラー服で登場も川島海荷「4人はコスプレ」 [19:15 5/27] エンタメ |
|
「NO.6」4巻は書き下ろしドラマCD付、木乃のサイン会も [18:49 5/27] ホビー |
|
[今週の新刊]マンガ大賞3回ノミネート「アイアムアヒーロー」 カープ愛「球場ラヴァーズ」も [18:33 5/27] ホビー |
4つの診断で、自分の適性を見つめなおそう!
働くこと・挑戦し続けることへの思いを綴ったインタビュー
あなたにピッタリのアドバイスを読むことができます。
転職に必要な情報が収集できます
企業からアプローチのメッセージが届きます。