JAVAC.JP
HOSHI TETSUYA 星鉄矢
2005/07/26
hossy@javac.jp
http://www.javac.jp
Google
WWW を検索 WWW.JAVAC.JP を検索

2-2 XMLのロードとDataStorageへの保持

基本的なXMLのロード及びDataStorageの構造に関しては、Flash講座 - ActionScript 2.0の基礎とGraphの概念の『(4-1)XML通信』から『(4-3)EventDispatcher用XMLクラス(もうひとつのonLoadの仕方)』あたりを参照してください。

ModelDataStorageはArrayクラスのコレクションを用いて、以下のように作ります。
ModelDataStorage.as
---
class ModelDataStorage{
    private var pointList:Array;
    private var lineList:Array;

    function ModelDataStorage(){
        reset();
    }

    public function reset():Void{
        pointList=new Array();
        lineList=new Array();
    }

    public function getPointListLength():Number{
        return pointList.length;
    }

    public function getLineListLength():Number{
        return lineList.length;
    }

    public function addPoint(id:String,x:Number,y:Number,z:Number):Void{
        var o:Object=new Object();
        o.id=id;
        o.x=x;
        o.y=y;
        o.z=z;
        pointList.push(o);
    }

    public function setPointPosition(index:Number,x:Number,y:Number,z:Number):Void{
        pointList[index].x=x;
        pointList[index].y=y;
        pointList[index].z=z;
    }

    public function getPointId(index:Number):String{
        return String(pointList[index].id);
    }

    public function getPointPosX(index:Number):Number{
        return Number(pointList[index].x);
    }

    public function getPointPosY(index:Number):Number{
        return Number(pointList[index].y);
    }

    public function getPointPosZ(index:Number):Number{
        return Number(pointList[index].z);
    }

    public function addLine(id:String,point1:String,point2:String):Void{
        var o:Object=new Object();
        o.id=id;
        o.point1=point1;
        o.point2=point2;
        lineList.push(o);
    }

    public function getLineIndex1(index:Number):Number{
        return Number(lineList[index].index1);
    }

    public function getLineIndex2(index:Number):Number{
        return Number(lineList[index].index2);
    }

    public function addPointIndexToLineLists():Void{
        var len:Number=getLineListLength();
        for(var i:Number=0;i<len;i++){
            addPointIndexToLine(i);
        }
    }

    private function addPointIndexToLine(index:Number):Void{
        var point1:String=String(lineList[index].point1);
        var point2:String=String(lineList[index].point2);
        var pointIndex1:Number=getPointIndexFromId(point1);
        var pointIndex2:Number=getPointIndexFromId(point2);
        lineList[index].index1=pointIndex1;
        lineList[index].index2=pointIndex2;
    }

    private function getPointIndexFromId(id:String):Number{
        var ret:Number;
        for(var i:Number=0;i<pointList.length;i++){
            var targetId:String=String(pointList[i].id);
            if(id==targetId){
                ret=i;
                break;
            }
        }
        return ret;
    }
}
ここで留意しておきたいのは、XMLに記述されたIDにできるだけ頼らない設計にすることです。
XML内でIDがユニークである保障はどこにもないので(もちろんユニークにすべきではあるが。)、pointListもlineListもArrayクラスで構成し、アクセスの際にはindexナンバーでアクセスします。また、lineListに関しては、XMLから読み込んだ状態では、pointListへのアクセスがIDによるものになるので、getPointIndexFromIdメソッドでIDに対応するindexを走査し、addPointIndexToLineメソッドにてlistにindexを登録します。
このgetPointIndexFromIdメソッドにおいて改良点があるとすれば、『IDの重複をチェックする』機能を追加することが考えられます。上記のソースでは、pointListにおいてIDの重複があった場合、最初のアイテムが選択され、後のアイテムは無視されます。
また、この処理は、IDをキーにした走査を最初の1回で済ませ登録しておくことで、走査を何度も行わずに済むようにしています。
IDに頼らない設計にすべきという点は、ArrayクラスではなくObjectクラスを用いてリストを生成する場合でも同様と言えます。

XMLのロード処理にはExXMLクラスとXMLIOServiceクラスを用います。
ExXML.as
---
class ExXML extends XML{
    private var ignoreWhite:Boolean=true
    var addEventListener:Function;
    var removeEventListener:Function;
    private var dispatchEvent:Function;
}


XMLIOService.as
---
import mx.events.EventDispatcher;

class XMLIOService{
    private var loader:ExXML;
    private var handlers:Array;

    function XMLIOService(){
    }

    public function reset():Void{
        handlers=new Array();
        loader=new ExXML();
        EventDispatcher.initialize(loader);
        loader.onLoad=function(){
            var lo:Object=new Object();
            lo.target=this;
            lo.type="onLoadComplete";
            this.dispatchEvent(lo);
        };
        loader.addEventListener("onLoadComplete",this);
    }

    public function load(address:String,sendObj:Object,flag:Boolean):Void{
        var now:Date=new Date();
        var rnd:Number=now.getTime();
        var addr:String=address;
        var str:String="";
        for(var key:String in sendObj){
            var val:String=String(sendObj[key]);
            str+=key+"="+val+"&";
        }
        if(str.length>0){
            addr+="?"+str;
        }
        if(flag){
            addr+="rnd="+String(rnd)+"&";
        }
        loader.load(addr);
    }

    public function addLoadComplete(method:String,ref:Object):Void{
        var o:Object=new Object();
        o.method=method;
        o.ref=ref;
        handlers.push(o);
    }

    private function onLoadComplete():Void{
        for(var i:Number=0;i<handlers.length;i++){
            var method:String=String(handlers[i].method);
            var ref:Object=Object(handlers[i].ref);
            ref[method](loader);
        }
    }
}
留意点として、この構成は『Flash Player 7書き出し用である』ことです。
Flash Player 6以前の書き出しだと、XMLクラスはすでにXMLNodeクラスを継承しているため、更に継承を行ったExXMLクラスでは、ignoreWhiteの設定が破棄されてしまいます。

メインクラスとなるCubeControlクラスでは、以下のようにこれらのクラスを使っています。
class CubeControl{
    private var path:MovieClip;
    private var IOService:XMLIOService;
    private var dataStorage:ModelDataStorage;

    function CubeControl(path:MovieClip){
        this.path=path;
        IOService=new XMLIOService();
        dataStorage=new ModelDataStorage();
        load("xml/001.xml");
    }

    public function load(address:String):Void{
        trace("loading:"+address);
        dataStorage.reset();
        IOService.reset();
        IOService.addLoadComplete("loaded",this);
        IOService.load(address,null,false);
    }

    public function loaded(ex:ExXML):Void{
        var nodes:Array=ex.firstChild.childNodes;
        var pointList:Array;
        var lineList:Array;
        for(var i:Number=0;i<nodes.length;i++){
            var n:XMLNode=XMLNode(nodes[i]);
            if(n.nodeName=="pointlist"){
                pointList=n.childNodes;
            }else if(n.nodeName=="linelist"){
                lineList=n.childNodes;
            }else{
                trace("invalid node. :"+n.nodeName);
            }
        }
        for(var i:Number=0;i<pointList.length;i++){
            var n:XMLNode=XMLNode(pointList[i]);
            if(n.nodeName=="point"){
                var id:String=String(n.attributes.id);
                var x:Number=Number(n.attributes.x);
                var y:Number=Number(n.attributes.y);
                var z:Number=Number(n.attributes.z);
                dataStorage.addPoint(id,x,y,z);
            }else{
                trace("invalid node. :"+n.nodeName);
            }
        }
        for(var i:Number=0;i<lineList.length;i++){
            var n:XMLNode=XMLNode(lineList[i]);
            if(n.nodeName=="line"){
                var id:String=String(n.attributes.id);
                var point1:String=String(n.attributes.point1);
                var point2:String=String(n.attributes.point2);
                dataStorage.addLine(id,point1,point2);
            }else{
                trace("invalid node. :"+n.nodeName);
            }
        }
        dataStorage.addPointIndexToLineLists();
    }
}
前述のように、最後に
dataStorage.addPointIndexToLineLists();
を行うことがミソで、IDによる走査を初回1回だけで済ませます。



BACKTOPNEXT




All Contents Copyright (C) 2005 HOSHI Tetsuya
Home