XMLの内容をソートするメソッドというものは存在しません。Arrayのようにデータ構造が単純ではない為、データに合う実装方法を製作者側が明示的に記述する必要があり、その頻度が高い為に一般化できないのです。
しかし、現実問題 XML でデータを扱えば、「ソート」や「ソートした上で最初の10件」等、データベース的な処理が必要になる場合が多いです。
その度に「もしかしたら良い方法があるんではなかろうか」と検索する訳ですが、何度やっても便利メソッドすら見つけられないのです。
流石に物覚えの悪い私でも「そんなモノはにぃ!」事が判ってきました。
それならば、せめてソート処理に"即した"方法をテンプレ化とは言いませんが、一般化出来ないものかと考えて見ました。
しかし、現実問題 XML でデータを扱えば、「ソート」や「ソートした上で最初の10件」等、データベース的な処理が必要になる場合が多いです。
その度に「もしかしたら良い方法があるんではなかろうか」と検索する訳ですが、何度やっても便利メソッドすら見つけられないのです。
流石に物覚えの悪い私でも「そんなモノはにぃ!」事が判ってきました。
それならば、せめてソート処理に"即した"方法をテンプレ化とは言いませんが、一般化出来ないものかと考えて見ました。
ソート
今まで何度かやってきた事を簡単に説明すると、- 「 XMLList → Array 」変換。
- Array.sort や Array.map 等でソート等の処理をした配列にする。
- 「 Array → XMLList 」変換。
更に「先頭から何件」という条件が付く場合、上記の2番目と3番目の間に、
- Array.length 切り詰め。
コード例
XML 変数 honge は 属性 date と属性 length を持った child タグを多数保持しているとします。
var honge:XML =<items>
<child date="12345678" length="80">全自動冷蔵庫</child>
<child date="12334458" length="8000">V6ツインカムターボ搭載炊飯ジャー</child>
<child date="12345850" length="200">ジャイロ式オートアシスト付アイロン</child>
<child date="12548855" length="255">核磁気共鳴チョコレート</child>
<child date="13568943" length="0">寒冷地仕様扇風機</child>
<child date="12357807" length="2000">完全防水(2000気圧)目覚まし時計</child>
<child date="13457678" length="160">エアバック装備チェスト</child>
<child date="12346678" length="1970">イギリス製フードプロセッサ(1970年製)</child>
<child date="15680976" length="46">コピープロテクト対応オーディオカセットテープ(46分)</child>
<child date="12548855" length="255">1UPきのこの里</child>
</items>;
- 「 XMLList → Array 」変換。
/** * XML 変数 honge から、childタグを列挙。 */ var childList:XMLList = honge.child; /** * 各要素を配列 ary へ。 */ var ary:Array = new Array(); for each(var child:XML in childList) { ary.push(child); } - Array.sort や Array.map 等でソート等の処理をした配列にする。
Array.sort については、こちらを参照。ary.sort(function (a:XML,b:XML):int { // date属性が小さい順にソート var dateA:Number = Number(a.@date); var dateB:Number = Number(b.@date); if ( dateA > dateB ) return 1; if ( dateA < dateB ) return -1; // date属性が同じ場合は、length属性の大きい順に。 var lengthA:Number = Number(a.@length); var lengthB:Number = Number(b.@length); if ( lengthA > lengthB ) return -1; if ( lengthA < lengthB ) return 1; // 属性が全て同じ場合は、中のテキスト長の短い順に。 var strlenA:int = String(a).length; var strlenB:int = String(b).length; if ( strlenA > strlenB ) return 1; if ( strlenA < strlenB ) return -1; // 全て同じ場合は、順序が変わらない。 return 0; });
- 先頭から5件。
ary.length = 5;
後ろから5件の場合。しかし、この場合は、ソート条件を見直すべき。
ary.reverse(); ary.length = 5; ary.reverse();
- 「 Array → XMLList 」変換。
この記述に関する詳細はこちら。var newHonge:XML = <items/>; newHonge.appendChild( new XMLList( ary.map( function (child:XML, index:int, arr:Array):String { return child.toXMLString(); } ).join("") ) );
先頭5件での実行結果。
<items>
<child date="12334458" length="8000">V6ツインカムターボ搭載炊飯ジャー</child>
<child date="12345678" length="80">全自動冷蔵庫</child>
<child date="12345850" length="200">ジャイロ式オートアシスト付アイロン</child>
<child date="12346678" length="1970">イギリス製フードプロセッサ(1970年製)</child>
<child date="12357807" length="2000">完全防水(2000気圧)目覚まし時計</child>
</items>
後ろから5件での実行結果。
<items>
<child date="12548855" length="255">1UPきのこの里</child>
<child date="12548855" length="255">核磁気共鳴チョコレート</child>
<child date="13457678" length="160">エアバック装備チェスト</child>
<child date="13568943" length="0">寒冷地仕様扇風機</child>
<child date="15680976" length="46">コピープロテクト対応オーディオカセットテープ(46分)</child>
</items>
この例にて、もしも honge に以下のような childタグ があると・・・
<child delete="1"/>
属性への単純アクセスなので、E4X(ECMAScript for XML) による XML のフィルタリングとは違い、存在しない属性へのアクセスは null が返ってくるだけのようです。 したがって、上記のノードは「date="0" length="0"」(sort内関数で、Numberキャストされている為)という扱いで処理が進みます。
まと・・・め?
- 「 XMLList → Array 」変換。
- Array.sort や Array.map 等でソート等の処理をした配列にする。
- 必要件数で Array.length 切り詰め。
- 「 Array → XMLList 」変換。
これで、バッチ・・り・・・だと、思うよ?タブン。 ←詰めが弱気な草食系

コメントする