XMLを使ってみる(その6)

やっぱり便利だったE4X

そのうちやるであろうことのためにE4Xを勉強していたのですが、突発的にやることになった仕事でデータ形式XMLで使うことにして、そこでE4Xを実践で使ってみました。そしたら思いの外便利で、XML処理周りでは全く困ることなく仕事を完了させることができました。
とりあえず、ここまでの記事で大まかな使い方は網羅していると思うので、後は小ネタ的なものをポツポツと気づくたびに載せていきたいと思います。

子ノードもまとめてピックアップ

E4Xでは、XMLのノードをドットシンタックスでまとめてXMLListにして取得できるのですが、ドットを二つ並べると、子ノードの中も同名ノードを再帰的にピックアップしてフラットな感じで取得することができるようです。
以下にサンプルコードと出力結果を書いておきます。

var aXML:XML =
  <data id='123' color='blue'>
  <!-- this is a comment -->
    <number>21</number>
    <number>22</number>
    <kodomo>
      <number>23</number>
      <mago>
        <number>24</number>
      </mago>
    </kodomo>
  </data>;
trace( "--- 1 dot" );
trace( aXML.number.toXMLString() );
trace( "--- 2 dots" );
trace( aXML..number.toXMLString() );
[trace] --- 1 dot
[trace] <number>21</number>
[trace] <number>22</number>
[trace] --- 2 dots
[trace] <number>21</number>
[trace] <number>22</number>
[trace] <number>23</number>
[trace] <number>24</number>

アトリビュートの有無を判断する

あるXMLアトリビュート指定があるかどうか?という判断をしたかったのですが、この方法がなかなか分からず探し当てるまでちょっと時間を食ってしまいました。同じことで困る人がいるはず!ということで、やり方をメモしておきます。
まず、最初にやってみたコードは以下のような感じ。「colorアトリビュートを持つnumberノードのみ情報を出力したい」ということなのですが、アトリビュートが無ければ、そのアトリビュートはnullだろう、という安直な判断です。

var aXML:XML =
  <data>
    <number id="hoge" color="red">21</number>
    <number id="foo">22</number>
    <number id="bar" color="blur">23</number>
  </data>;
for( var i:int=0; i<aXML.number.length(); i++ ){
  // 駄目な比較.
  if( aXML.number[i].@color != null ){
    trace( aXML.number[i].@id +"["+aXML.number[i].@color+"]" );
  }
}

以下のようにすべてのノードが出力されてしまいます。

[trace] hoge[red]
[trace] foo[]
[trace] bar[blur]

こういう時には基本に立ち返る!ということで、@演算子でいったい何が返ってきているのかを調べてみます。

import flash.utils.*;
var aXML:XML =
  <data>
    <number id="hoge" color="red">21</number>
    <number id="foo">22</number>
    <number id="bar" color="blur">23</number>
  </data>;
trace( " @ > " + getQualifiedClassName(aXML.number[0].@color) );

上記コードを実行したら次のように出力され、XMLListが返ってくることが分かりました。

[trace]  @ > XMLList

ということは、「colorアトリビュートを持つかどうか?」という条件は「colorアトリビュートが返すXMLListが空っぽかどうか」という判断をすればいい、ということになるので、正しいループ処理は以下のようになります。

for( var i:int=0; i<aXML.number.length(); i++ ){
  // colorアトリビュートがあるノードのみ出力.
  if( aXML.number[i].@color.length() > 0  ){
    trace( aXML.number[i].@id +"["+aXML.number[i].@color+"]" );
  }
}