Flex Tip: Convert XML to ArrayCollection

This is one of those things that took me much longer than I thought it would have. I needed to convert a file containing XML data to an ArrayCollection. My XML file looked like this:

<rows>
	<row>
		<col1>some value</col1>
		<col2>another value</col2>
		...
	</row>
	...
</rows>

I wanted to convert this into an ArrayCollection with each row as an object (and I didn’t want to have to loop through each item in the list). Here’s the solution I’m using.

import mx.utils.ArrayUtil;
import mx.rpc.xml.SimpleXMLDecoder;
import mx.collections.ArrayCollection;
			
private function convertXmlToArrayCollection( file:String ):ArrayCollection
{
	var xml:XMLDocument = new XMLDocument( file );
			
	var decoder:SimpleXMLDecoder = new SimpleXMLDecoder();
	var data:Object = decoder.decodeXML( xml );
	var array:Array = ArrayUtil.toArray( data.rows.row );

	return new ArrayCollection( array );
}

I’m not thrilled with this approach because I’ve needed to hard code the XML structure (’rows.row’) into the function. If anyone has a better solution I’d love to see it.

Best,
Hillel

76 thoughts on “Flex Tip: Convert XML to ArrayCollection”

    1. Rahul,

      That’s really nice to hear, hoping I might save people time was why I started this blog.

      Happy coding!!
      Hillel

  1. Hi when i used your code its gives error 1069 and says that rows which is the xml file components in your file is not String value and it does not have default value

    what should i do ?

    1. Harsh,

      If you’d like to post some example code I’d be happy to take a look to see if I can figure it out.

    2. This error occurs because your xml does not use “rows” and “row” but some other tags. Change your tags to be exactly what appear in your xml, and this will work out fine. For example…

      my xml looks like this:

      so instead of “data.rows.row” I use “data.merchants.merchant”

      1. Oops! I forgot to make that code so you could see it…

            <merchants>
                        <merchant>
                                 <merch_id></merch_id>
                        </merchant>
            </merchants>
        
  2. Hi

    I’ve tried your solution but I’m getting – TypeError: Error #1034: Type Coercion failed: cannot convert Object@66ea629 to Array.

    Code snippet below:

    private function convertXmlToArrayCollection( xmlDoc:XMLDocument ):ArrayCollection
    {
    var decoder:SimpleXMLDecoder = new SimpleXMLDecoder();
    var data:Object = decoder.decodeXML( xmlDoc );
    var result:ArrayCollection = new ArrayCollection( data.StockQuotes.Stock );
    return result;
    }

    The XML structure is-

    some data
    some data

    I’m using a web service to get the data. I want to bind the data a data grid using an ArrayList.

    Thanks for your help.

  3. Hi

    Just to let you know, I’ve fixed it by using ArrayUtil.toArray –

    var result:ArrayCollection = new ArrayCollection( ArrayUtil.toArray(data.StockQuotes.Stock) );

    I’m surprised you weren’t also getting error 1034…..?

    1. Chris,

      Hmm.. that’s interesting. I know ActionScript does some fancy stuff when dealing with XML in that it will automatically convert to and from arrays depending on the number of elements. Was there a case where there was only StockQuote or Quote in your dataset. It could be I never got the error b/c all of my tags had at least two elements.

  4. Hi Hillel… Nice tip…

    To implement this function in my project… How i can refer the arraycollection returned by function for other components manipulate?

    Thanks,

    Silva Developer

    1. Silva Developer,

      I’m sorry, I’m having trouble understanding what you’re trying to accomplish. Could you please rephrase your question.

      Thanks

  5. Hi Hillel

    Sorry for taking so long to respond.

    Yes, the web service only ever returns one StockQuote with one Stock child.

    ie:

    <StockQuote>
    <Stock>
    <Element1>Element 1 data</Element1>
    <Element2>Element 2 data</Element2>
    etc…
    </Stock>
    </StockQuote>

  6. For me use the arraycollection returned of the function, how i can do this?

    For example.

    datagrid.dataprovider = ? (name of arraycollection)

    The function return an arraycollection, but how i can use this arraycollection returned with other components, referencing by name? what name? Because in the function do you not set the name of this arraycollection will have for use in other components.

    If you understanded now, show me in as code.

    Best regards,

    Silva Developer
    silva.developer@gmail.com

    1. To use the value in multiple places, you can store the value returned by the function. Here’s an example

      <?xml version="1.0" encoding="utf-8"?>
      <mx:Application 
      	xmlns:mx="http://www.adobe.com/2006/mxml"
      	verticalAlign="middle" horizontalAlign="center"
      	initialize="init()">
      		
      	<mx:Script>
      		<!&#91;CDATA&#91;
      			import mx.utils.ArrayUtil;
      			import mx.rpc.xml.SimpleXMLDecoder;
      			import mx.collections.ArrayCollection;
      			
      			&#91;Bindable&#93;
      			private var _data:ArrayCollection;
      			
      			private function init():void
      			{
      				var file = "<rows><row><col>Hello</col></row></rows>";
      				_data = convertXmlToArrayCollection( file );
      			}
      				
      			private function convertXmlToArrayCollection( file:String ):ArrayCollection
      			{
      				var xml:XMLDocument = new XMLDocument( file );
      			
      				var decoder:SimpleXMLDecoder = new SimpleXMLDecoder();
      				var data:Object = decoder.decodeXML( xml );
      				var array:Array = ArrayUtil.toArray(data.rows.row);
      			
      				return new ArrayCollection( array );
      			}
      
      		&#93;&#93;>
      	</mx:Script>
      	
      	<mx:DataGrid dataProvider="{ _data }"/>
      	<mx:DataGrid dataProvider="{ _data }"/>
      	
      </mx:Application>
      
  7. By the way, have you tried to convert ArrayCollection to Xml? I have tried to do this with SimpleXmlEncoder:

    public static function convertArrayCollectionToXml(source:ArrayCollection):XML{
    var name:QName = new QName(“books”);
    var document:XMLDocument = new XMLDocument();
    var encoder:SimpleXMLEncoder = new SimpleXMLEncoder(document);
    var data:Object = source.source;
    var xmlNode:XMLNode = encoder.encodeValue(data, name, document);
    var xml:XML = new XML(document.toString());

    return xml ;
    }

    But I don’t like the result. Doing so, I can only specify root name (), but xml children will have name and will look like this:

    This not what I want. For me will be perfect if xml will looks like:

    I can’t do this with SimpleXmlEncoder, right? I must perform such xml in some other way.

    Looking forward to your reply.
    Thank you, Christie.

    1. Christina,

      I’m sorry, I don’t have any experience using the SimpleXMLEncoder (I actually didn’t even know it existed) and am not sure how to solve your problem. I’d suggest submitting a post to the Adobe Flex forum.

      Best,
      Hillel

  8. Thank you for such fast answer 🙂 After posting my comment noticed that some text is not showing, sorry, have used tag symbols.. In any case I always can parse my array collection and create each xml child (as string).

    With pleasure will follow your blog 🙂

  9. Hi! I am doing a memory game in flex. Anyone know how store the images in array? Another problem i faced is how to compare 2 images? I got 16 images with 8 pairs of the same. Example,if image1 is clicked and image 2 is clicked,the image will flipped back because its different. However,if image1 is clicked and another image1 is clicked,both image will stay flipped open.

    Anyone can help me? i am really at wits end. Your help will be highly appreciated. Thanks

  10. Hi…

    and thanks a lot for your excellent article.But, I can’t get it to work! Yet. I guess I am not too far off, so I might just need a bit of help.

    I am populating a tree from a remote CFC call. I am getting the following XML back:

    <cfquery name="query2" …<cfquery name="query3" …

    It works fine if I bind the XML to my tree dataprovider, but I would like to turn it into an Arraycollection for easier manipulation of the tree at runtime.

    I have used your function, replacing the rows.row bit with

    var array:Array = ArrayUtil.toArray( data.categories.category );

    but when I do
    treedata=convertXmlToArrayCollection(evt.result);

    nothing happens. Any idea, is it to do with my XML structure…?

    Thanks in advance,

    Alain

    1. Alain,

      The problem may be that your using attributes (ie name=”query2″). I’m not sure how the xml decoder handles that. I’d suggest doing a ObjectUtil.toString( ) to see what the data looks like.

  11. Me again. It looks like the CFXML code I posted did not come out correctly on the post. Don’t know why… Let me know how I can post it correctly, or whether I should email it to you directly…

    Alain

  12. It doesnt work,

    My XML:

    João
    joao
    joao@teste.com.br
    (35)3822-3822
    Rua X, 99

    Blah da Silva
    blah
    blah@blah.com.br
    (35)3822-4900
    Rua B, 99

    My code to convert:

    private function xmlToArrayCollection( file:String ):ArrayCollection {

    var xml:XMLDocument = new XMLDocument( file );
    var decoder:SimpleXMLDecoder = new SimpleXMLDecoder();
    var data:Object = decoder.decodeXML( xml );
    var array:Array = ArrayUtil.toArray(data.usuarios.usuario);

    return new ArrayCollection( array );
    }

    It gives error ReferenceError: Error #1069:

  13. Ops,

    João
    joao
    joao@teste.com.br
    (35)3822-3822
    Rua X, 99

    Blah da Silva
    blah
    blah@blah.com.br
    (35)3822-4900
    Rua B, 99

    My code to convert:

    private function xmlToArrayCollection( file:String ):ArrayCollection {

    var xml:XMLDocument = new XMLDocument( file );
    var decoder:SimpleXMLDecoder = new SimpleXMLDecoder();
    var data:Object = decoder.decodeXML( xml );
    var array:Array = ArrayUtil.toArray(data.usuarios.usuario);

    return new ArrayCollection( array );
    }

    It gives error ReferenceError: Error #1069:

  14. Hello friends,
    I’m not understanding what should be given in ArrayUtil.toArray(….);
    i want the list of values stored in arraycollection, Error#1009: is displayed. but its not displaying anything. My xml file comng from webservice has huge data with many nested tags. Please help, thanx in adv.

    [Bindable]
    public var arrcoll:ArrayCollection;
    public function GetDataSetHandler(e:ResultEvent):void
    {
    var xmldoc:XMLDocument = new XMLDocument(e.result.toString());

    var decoder:SimpleXMLDecoder = new SimpleXMLDecoder();

    var resobj:Object = decoder.decodeXML(xmldoc);

    var arr:Array = ArrayUtil.toArray(data.NewDataSet.waiterlocations.locations);

    arrcoll = new ArrayCollection(arr);
    }

  15. Hello,
    I have problem retrieving individual element of xml through ArrayCollection. The details as below:

    XML gallery.xml looks like this-

    image 1
    title for Image 1

    .
    .

    .
    .

    am converting the XMl to array collection as below:

    Step1: Calling the resulthandler..code as below-

    Step2: Converting xml to Array Collection

    [Bindable]
    public var galleryData:ArrayCollection;

    protected function resultHandler(event:ResultEvent):void
    {
    galleryData=event.result.gallery.images;

    //want to use individual value of galleryData here
    }

    Now somewhere in the code I am setting text for image using label:

    My query is-in the result handler I want to set the image text by geeting each value of text value of image from galleryData which now holds xml.

    Please help!

  16. Donno why above message didin’t include code for label, well here it is

    s:Label x=”31″ y=”603″ text=”This is infor for picture4″ width=”312″ height=”39″ color=”#E1E4EB” id=”label4″

  17. Thank you Hillel, you saved a lot of time with your method. I hope that i can contact you later for other questions concerning flex!

    1. Med,

      Happy it saved you time. Although I try to support any components/posts on my blog I don’t usually provide general Flex support (if I did I’m sure I’d be spending quite a bit of my time doing it). I’d recommend posting to the Flex forums if you have any questions.

      Best,
      Hillel

  18. Do you have any ideas how to get the SimpleXMLDecoder values just in string format. Now if I give string 89.3450 it gives me 89.345 because it thinks the value is a number.

    Thanks!
    Tuomas

  19. Hi,

    Can you tell what’s the problem when the array at the end of the funtion retuns [object Object]?

    Thanks
    Doris

  20. Sure!
    I think the problem comes from my xml transformation to string, but:

    Below you’ll find the code I utilized.
    The function returns: array = [object Object],[object Object],[object Object],[object Object],[object Object],[object Object]

    Do you know why? where I am wrong?

    private function convertXmlToArrayCollection(file:String):ArrayCollection {
    var xmlStr:String = file;
    var xmlDoc:XMLDocument = new XMLDocument(xmlStr);
    var decoder:SimpleXMLDecoder = new SimpleXMLDecoder();
    var resultObject:Object = decoder.decodeXML(xmlDoc);
    var array:Array = ArrayUtil.toArray(resultObject.items.item);
    return new ArrayCollection(array);
    }

  21. Sorry for the ugliness of the post, but under code or without code tag i can’t present xml.

    This question is the form of genealogy. Where every node has the capability to expand exponentially. All nodes can have children that divide and have children of there own. How to either parse xml like this or convert it to an array collection. The simple xml of 1 child with 1 attribute is easy to do, but how do you do xml that can have different subjects who have their own children?

    If this displays right… I used ( because < these failed.

    (parent)
    (child 1)
    (name)george(/name)
    (grandchild)
    (name)frank(/name)
    (greatgrandchild)
    (name)Elmo(/name)
    (/greatgrandchild)
    (greatgrandchild)
    (name)Big Bird(/name)
    (/greatgrandchild)
    (/grandchild)
    (/child)
    (parents)
    (mother)
    (name)susie(/name)
    (dob)1824(/dob)
    (/mother)
    (/parents)
    (/parent)

    The idea is how to parse elements when you not sure how many or what they might be with multiple child nodes and they all have children of themself.

  22. Thanks again Hillel..You saved me again…use this one after AutoComplete component…

    God Bless ya..

    realy thnx..

  23. Hi Hilel

    i got this error


    1046: Type was not found or was not a compile-time constant: XMLDocument.

    1180: Call to a possibly undefined method convertXmlToArrayCollection.

    how to fix this?
    thanks

  24. Hilel,

    nevermind about my previous question, just removed and use autocomplete from flex then everything just ok 😀

    thanks

  25. Been using simpleXMLDecoder successfully for some time but have now come across a problem when using data returned from Facebook.

    Data return looks like :-

    2156783514916597080
    2156783514925485319
    10150247237985295
    4
    Wall Photos

    2156783514916480723
    2156783514925409064
    10150240208950295
    18
    Profile Pictures
    …..

    I use the follwing to ‘decode it’

    var array:Array =new Array();
    var xeml:XMLDocument = new XMLDocument(file);
    var decoder:SimpleXMLDecoder = new SimpleXMLDecoder();
    var data:Object = decoder.decodeXML(xeml);

    if(data.hasOwnProperty(“fql_query_response”))
    {
    if(data.fql_query_response.hasOwnProperty(“album”))
    {
    array = ArrayUtil.toArray(data.fql_query_response.album);
    }
    else
    {
    array= ArrayUtil.toArray(data.fql_query_response.photo);
    }
    }
    return new ArrayCollection(array);

    Only problem is the ‘aid’ value that is ‘decoded out’ is different from what was in the returned

    The aid decoded out is 2156783514916596992

    that what was in the returned file for this object was 2156783514916597080

    Any idea why ?

  26. Hi. This has also helped me a lot. But I have one problem which is that if I have no data for one of the cells, datagrid is filled with [object Object]. I’ve tried reading the arraycollection and asigning value to ” “, but as value in fact doesnt exist, it doesnt work. The structure of the xml is something like

    value

    This is converted to arraycollection as:
    arr[0][field1].type = x
    arr[0][field1].value = value
    arr[0][field2].type = x
    arr[0][field2].value———->it doesnt exists so that cell in the dataprovider of the datagrid appears like [object Object]
    Any ideas?

  27. Thank you for this. I wanted to make my helper method more customizable for different XML files, so this is my implementation:

    /**
    * Converts XML object to ArrayCollection. Use the callback to drill into the XML model to get to your collection.
    * @param xml XML object to convert
    * @param callback Optional callback function to drill into the XML model
    * function callback(data:Object):Object
    * @return The converted ArrayCollection
    **/
    public static function convertXmlToArrayCollection(xml:XML, callback:Function = null):ArrayCollection
    {
    // convert XML to XMLDocument
    var xmlStr:String = xml.toString();
    var xmlDoc:XMLDocument = new XMLDocument(xmlStr);

    // convert XMLDocument to Object
    var decoder:SimpleXMLDecoder = new SimpleXMLDecoder();
    var data:Object = decoder.decodeXML(xmlDoc);

    // drill down data using callback if provided
    if (callback != null)
    {
    data = callback(data);
    }

    // convert Object to ArrayCollection
    var array:Array = ArrayUtil.toArray(data);
    return new ArrayCollection(array);
    }

    Usage:
    var coll:ArrayCollection = convertXmlToArrayCollection(xml, function(xmlObject:Object):Object { return xmlObject.list.item; });

Leave a reply to Christina Cancel reply