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

Tags: , ,

75 responses to “Flex Tip: Convert XML to ArrayCollection”

  1. Rafael Biz says :

    It doesnt work!

  2. Hillel says :

    Rafael,

    Do you want to post your code and I’ll see if I can figure out why it isn’t working for you.

  3. Rahul says :

    I love you ;) for this article..saved me a lot of time. Thanks

    • Hillel says :

      Rahul,

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

      Happy coding!!
      Hillel

  4. harsh says :

    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 ?

    • Hillel says :

      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.

    • Regina Wiley says :

      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”

      • Regina Wiley says :

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

            <merchants>
                        <merchant>
                                 <merch_id></merch_id>
                        </merchant>
            </merchants>
        
  5. Chris says :

    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.

  6. Chris says :

    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…..?

    • Hillel says :

      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.

  7. Silva Developer says :

    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

    • Hillel says :

      Silva Developer,

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

      Thanks

  8. Chris says :

    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>

  9. Silva Developer says :

    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

    • Hillel says :

      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>
      		<![CDATA[
      			import mx.utils.ArrayUtil;
      			import mx.rpc.xml.SimpleXMLDecoder;
      			import mx.collections.ArrayCollection;
      			
      			[Bindable]
      			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 );
      			}
      
      		]]>
      	</mx:Script>
      	
      	<mx:DataGrid dataProvider="{ _data }"/>
      	<mx:DataGrid dataProvider="{ _data }"/>
      	
      </mx:Application>
      
  10. Silva Developer says :

    Great… Very good!

    One more thing…

    If i want use in my mxml file:

    &lt mx:XML id=”_dpStartPositions” source=”positions.xml” format=”e4x” /&gt

    And not string var file: = ” Hello “;

    How was have do?

    Thanks,

    Silva Developer
    silva.developer@gmail.com

  11. Christina says :

    Hi, Hillel!

    Thanks for the tip :) It is very helpful for me.

  12. Christina says :

    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.

    • Hillel says :

      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

  13. Christina says :

    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 :)

  14. Bula says :

    Cheers’O mate. Worked perfect. Reminds me a bit of Generic List’s CovertAll method in .Net.

  15. Bula says :

    Christina, nice reversal solution.

  16. Shaylee says :

    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

  17. Emilio says :

    Thanks for your article!
    Your sample saves me a lot :)

  18. БaйaчaБeбe says :

    Отлично! Хотелось бы побольше таких же интересных постов

  19. ali drongo says :

    thanks! quick and easy solution worked straight away :)

  20. Alain Levy says :

    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

    • Hillel says :

      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.

  21. Alain Levy says :

    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

  22. Cleiton says :

    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:

  23. Cleiton says :

    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:

  24. Haneef says :

    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);
    }

  25. Akshay says :

    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!

  26. Akshay says :

    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″

  27. Med says :

    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!

    • Hillel says :

      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

  28. Tuomas says :

    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

  29. Савва says :

    Какие положительные результаты :)

  30. SD says :

    Thanks.
    It helped a lot.

  31. doris says :

    Hi,

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

    Thanks
    Doris

  32. doris says :

    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);
    }

  33. ahmed says :

    thank you very much
    you save my time

  34. priti says :

    Hi its very good post.Thanks a lot.

  35. mingster says :

    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.

  36. krishna says :

    thanks brother ur code saved a lot time for me. i am expecting more codes like this form you.

  37. uvo says :

    thanks, your approach was the solution!

  38. Vinit Srivastva says :

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

    God Bless ya..

    realy thnx..

  39. jack says :

    you, sir, are a life saver!

  40. ghprod says :

    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

  41. ghprod says :

    Hilel,

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

    thanks

  42. Ken says :

    thank you for blog (even today it works)

  43. J says :

    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 ?

  44. John says :

    Thanks! This saved a lot of time – the hardest thing for me in Flex is constantly converting XML to the various data types I need.

  45. maria says :

    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?

  46. maria says :

    Thats right. I’ve eventually used labelfunction. Thanks

  47. Trish Rempel says :

    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; });

  48. MADANI says :

    Merci beaucoup very nice post.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

Join 83 other followers

%d bloggers like this: