光学薄膜設計ソフトの設計 その37 - NSXMLDocumentその2 [考え中 - 光学薄膜設計]
こんなこと書いてないでさっさと寝るほうが体にはいい。でもちょっとずつでも書いてないとあっという間に忘れてしまってそれまでが水泡に帰す。なんて大袈裟なものでもないけど、僕の記憶力は明らかにVolatileで、リフレッシュサイクルの仕様は3日なのでやっといたほうがいい。しかもRAS onlyとかのモードはなくて、リフレッシュには実アクセスが必要。若い頃は実力で数週間あったのに今では規格ぎりぎり。
前回、XMLのファイルをパースするためのふたつのFoundationフレームワークのクラスをさらっと見た。今回そのうちの木構造を内部的に作ってしまうNSXMLDocumentについて。
読み込みがうまくいったNSXMLDocumentの中身を見る方法はいくつかある。
- nextNodeメソッドで順番にノードを処理する
- childrenメソッドなどで木構造をたどる
- elementsForName:メソッドで要素の名前を指定して直接ノードを得る
- XPathで問い合わせる
- XQueryを使う
nextNodeメソッドは基本的には出現順に子ノードを先に、兄弟ノードをその後に木構造をたどる。これは実質的にNSXMLParserを使ってイベント駆動型で処理するのと変わらない。
NSXMLNode *node = [xmldoc rootElement]; while (node = [node nextNode]) { ... }と言うような感じ。
2番目の方法は、NSXMLDonumentにchildrenメソッドを投げると子ノードがNSArrayで返されるので、さらにその子ノードを得たければその要素のひとつにchildrenを投げれば孫が得られる。これで全部のノードにアクセスできる。
NSArray *children = [rootElem children]; for (id child in children) { ... }というふうにやる。
3番目は要素の名前を直接指定してそのノードを得る。木構造の深いところにあっても名前で直接アクセスできる。
NSXMLNode *rootElem = [xmldoc rootElement]; NSArray *nodes = [rootElem elementsForName:@"lambdaPrincipal"]; if ([nodes count] > 0) { double lambda = [[[array objectAtIndex:0] objectValue] doubleValue]; }とかになる。elementsForName:メソッドでは要素がひとつしかなくてもNSArrayとして返る。
4番目はunixのpathのような、URLのような指定の仕方で、「/」で区切られた名前で要素を指定する。
NSArray *nodes = [rootElem nodesForXPath:@"./opticalCondition/implicitCondition/incidentAngle" error:&error]; if ([nodes count] > 0) { double angle = [[[array objectAtIndex:0] objectValue] doubleValue]; }みたいな感じで構造が決めうちだったり、木構造全体ではなく、あるひとつのデータの値だけを知りたい、などと言う場合はこのXPathを使うのが簡単。属性へのアクセスも
nodesForXPath:@"./incidentAngle/@unit"みたいに「@」で表すことができる。
XQueryはいわばXPathの拡張で、位置だけでなく専用の演算子などを使ってきめ細かなアクセスをしたり、さらに書き換えたりできる。特定の値を持つ要素を抽出するなどができるので、プログラムしなくてもXQueryに書けば何でもできてしまう。複雑なXMLを対象にするけど一般的なObjective-Cのオブジェクト(NSStringやNSNumberなど)にその構造を反映させるだけならXQueryが一番手っ取り早い。
でもその文法を覚えなければならないので面倒ではある。SQLやらunixのshellスクリプトなんかと混同しやすい上にわかりにくいモードがあって使い分けなければいけないらしい。20年以上unixを使ってきたのにC shellのスクリプトが書けない僕(man pageを見ても文法はわからないし書いても思った通り動いてくれないし、結局諦めて10行程度のCを書いてすましてしまう)には、その文法が全然頭に入らない。
上のいくつかの例ではNSArrayの要素の数なんかをチェックしているけど、DTDを書いてあってNSXMLDocumentValidateのフラグをつけて読み込んであればこういうチェックは不要になる。もともとDTDによるValidationはそういうためのものだし。
今回は、XMLのファイルはそれほど大きくないけど、それをもとに作るオブジェクトは複雑なのでXQueryを使うよりもXPathやelementsForName:などで個別にデータをとってきてオブジェクトを組み立てるのが簡単になる。
次回はchildrenメソッドを使って前回書いたDTD付きのダミーデータを読み込むダミープログラムを書いてみる。
コメント 0