0

i'm trying to load an xml file from my assets folder.

I wrote this function :

        public static function loadXML(i_fileURL:String):XML // i want to return the actual loaded xml here
    {
        var xml:XML;
        var ldr:URLLoader = new URLLoader();
        var request:URLRequest = new URLRequest(i_fileURL);
         ldr.addEventListener(Event.COMPLETE, onXMLLoad);
         ldr.load(request);
                     //how can i return the loaded xml?
    }

        public static function onXMLLoad(e:Event):void
    {
        var ldr:URLLoader = URLLoader(e.target);
        var myxml:XML = new XML(ldr.data);
        trace(myxml.toXMLString());
                   //how can i return myxml to loadXML function?

    }

Is there a different way to do this?

Thank you!

3 Answers 3

1

You can do something like a promise or future, where you return empty XML and then populate it with the actual XML when the call returns. Since you are using Flex, you have access to data binding, which should allow this approach to work just fine.

Note that you really shouldn't be using static methods for this, and your onXMLLoad member has no reason to be exposed. Here's what the updated code might look like:

package service {
    public class XMLLoader {
        //note that the existence of this variable means that you need
        //to create a new instance of the Class each time you make a call.
        protected var future:XML;
        protected var _url:String;
        public function loadXML(url:String):XML {
            _url = url;
            var request:URLRequest = new URLRequest(url);
            var loader:URLLoader = new URLLoader();
            loader.addEventListener(Event.Complete, onLoad);
            loader.addEventListener(IoErrorEvent.IO_Error, onFail);
            loader.addEventListener(SecurityErrorEvent.Security_Error, onFail);
            future = ;
            return future;
        }
        protected function onLoad(e:Event):void {
            var loader:URLLoader = e.currentTarget as URLLoader;
            var data:XML = loader.data as XML;
            if (data) {
               //you lose your original root node, because you want data
               //binding to fire on the future object you returned.
               future.setChildren(data.children());
            }
        }
        protected function onFail(e:Event):void {
            //both Security and IOerrors have a text property, but they
            //can't both be cast to the same thing.
            trace('failed to load', _url, e[text]);
        }
    }
}

One thing to be aware of with this method is that you need to keep a reference to the instance around until the data has updated, or else it could be garbage collected before it populates the future. Because of that, you're probably better off following the conventional approach of having your instance dispatch a custom event that carries the data that it was retrieving. If you want an example of that, post back and I can provide you an example.

Sign up to request clarification or add additional context in comments.

Comments

0

you can't. because xml load request is asynchronous. when you called loadXML, onXMLLoad not yet arrived. so such work impossible asynchronous return. surely you can waiting the function process while loop using, but this method not good. because to full use a cpu resource, overkill. you must next process in onXMLLoad function. It's the most appropriate. or xml variable declared as global, and using a ENTER_FRAME or TimerEvent as a way to continue to operate if the xml is not null.

Comments

0

Since the URLLoader is asynchronous, it's not safe to create a static loader function as it would be quiet easy to mix up returned data during multiple calls. Even if you attempted to accomplish what you want with the use of Event.OPEN and a vector of URLs to keep track of the which completed data should belong to each URL, asynchronousity works on a first-come, first-served basis so it wouldn't be possible to have persistent alignment of the file URL and the returned data.

I suggest that you create instances of an XMLLoader class that uses a custom XMLLoaderEvent, which will return both the xml data and the associated file URL. The following code is untested, but with possible typos aside, it should work as intended.

Use Case

var xmlLoader:XMLLoader = new XMLLoader();
xmlLoader.addEventListener(XMLLoaderEvent.COMPLETE, xmlLoadCompleteEventHandler);
xmlLoader.load("myXMLFile.xml");

function xmlLoadCompleteEventHandler(event:XMLLoaderEvent):void
{
    xmlLoader.removeEventListener(XMLLoaderEvent.COMPLETE, xmlLoadCompleteEventHandler);

    trace(event.type, event.fileURL, event.xml);
}

XMLLoader.as

package
{
    //Imports
    import flash.events.EventDispatcher;
    import flash.events.Event;
    import flash.net.URLLoader;
    import flash.net.URLRequest;

    //Class
    public class XMLLoader extends EventDispatcher
    {
        //Properties
        private var loader:URLLoader;
        private var fileURL:String;

        //Constructor
        public function XMLLoader():void
        {
            loader = new URLLoader();
            loader.addEventListener(Event.COMPLETE, loadCompleteEventHandler);
        }

        //Load
        public function load(fileURL:String):void
        {
            this.fileURL = fileURL;

            loader.load(new URLRequest(fileURL));            
        }

        //Load Complete Event Hanlder
        private function loadCompleteEventHandler(event:Event):void
        {
            loader.removeEventListener(Event.COMPLETE, loadCompleteEventHandler);

            dispatchEvent(new XMLLoaderEvent(XMLLoaderEvent.COMPLETE, fileURL, XML(loader.data)));
        }
    }
}

XMLLoaderEvent.as

package
{
    //Imports
    import flash.events.Event;

    //Class
    public class XMLLoaderEvent extends Event
    {
        //Constants
        public static const COMPLETE:String = "complete";

        //Properties
        public var xml:XML;
        public var fileURL:String;

        //Constructor
        public function XMLLoaderEvent(type:String, fileURL:String = null, xml:XML = null) 
        {
            super(type);

            this.xml = xml;
            this.fileURL = fileURL;
        }

        //Clone
        public override function clone():Event
        {
            return new XMLLoaderEvent(type, fileURL, xml);
        }

        //To String
        public override function toString():String
        {
            return formatToString("XMLLoaderEvent", "type", "fileURL", "xml");
        }
    }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.