Pages

May 22, 2009

XMLListCollection Basics

Posted by Jeremy Mitchell
Depending on the characteristics of a data set, data can be modeled in a linear or hierarchical fashion.

Linear data (aka flat or list-based data) typically represents the attributes (or properties) of an individual entity (item).

In turn, multiple items can be aggregated into a list and stored in an Array. An Array provides a mechanism for storage, manipulation and retrieval of linear data within a Flex application.



Note: Arrays can also store hierarchical data (i.e. objects composed of other objects or simple xml objects) but you'll find linear data to be more common.
Other data sets represent nested levels of information (hierarchical data). ActionScript provides two native datatypes for working with hierarchical data – XML and XMLList. The contents of each can be accessed and manipulated as needed utilizing the public API (properties and methods) corresponding to the supporting ActionScript class – XML or XMLList.

XML was designed to support the transport, storage and description of hierarchical data using custom markup. The XML class contains methods and properties for working with a single, well-formed XML document.

As one might guess, an XMLList is simply a list of XML objects. Looking closely at the methods of the XML class, you’ll notice that many operations potentially result in a match against multiple XML nodes (i.e. attributes(), children(), descendants(), etc). With each matching node representing the format of a well-formed XML document, it makes sense to provide a class designed to hold one or more XML objects. That class is the XMLList class.

Note: XML and XMLList classes support E4X operations that may also return a list of XML objects (XMLList). This includes shorthand operations such as (.) or (..) used for retrieving children or descendant nodes respectively or predicate filtering.
As a Flex developer, your intent, most likely, is to eventually render some, if not all, of your data on the screen. Whether your data is linear or hierarchical in nature, Flex provides the following “data provider” components suited for the task at hand:Data provider components require a reference to the data for display. This reference is captured in the dataProvider property of the data provider component instance.

<!-- MXML -->

<List id=”myList” dataProvider=”{myArray}” />
<Tree id=”myTree” dataProvider=”{myXMLList}” />

// ActionScript

var myList:List = new List();
myList.dataProvider = myArray;

var myTree:Tree = new Tree();
myTree.dataProvider = myXMLList;
At first glance, this appears to be an acceptable use of data binding. However, using raw data objects (Array, XML and XMLList) as a data provider for a UI control is not considered a best practice.

Instead, it is recommended that collections are used in place of raw data objects for the following reasons:
  • Changes to the data stored in a collection are immediately reflected in the UI control
  • Collections provide a "view" of the underlying data that can be sorted or filtered
Therefore, an ArrayCollection should be used in place of an Array (see related blog entry) and an XMLListCollection should stand in for an XMLList object.

XMLListCollection

Similar to an ArrayCollection, XMLListCollection extends the ListCollectionView class which implements the ICollectionView and IList interfaces. 3 members of the ICollectionView interface play an integral role in the implementing class' ability to support data binding:
  • 2 methods: addEventListener() & dispatchEvent()
  • 1 event: collectionChange
When the [Bindable] metadata tag is used with a collection, Flex generates code behind the scenes required to make the collection "bindable". This code is dependent on the ability to register an event handler triggered by a event dispatched when the data object changes (aka event listener). By extending ListCollectionView which implements ICollectionView, XMLListCollection becomes an eligible participant in the data binding game.

For a more detailed look at the guts of data binding, check out Michael Labriola's presentation entitled Diving in the Data Binding Waters
To create an XMLListCollection, 3 techniques are available:

// creating an empty XMLListCollection
private var myXMLListCollection:XMLListCollection = new XMLListCollection();

// passing an existing XMLList into an XMLListCollection via the constructor
private var myXMLListCollection:XMLListCollection = new XMLListCollection(myXMLList);

// assigning an existing XMLList to the source property of an XMLListCollection
private var myXMLListCollection:XMLListCollection = new XMLListCollection();
myXMLListCollection.source = myXMLList;
After being "wrapped" by an XMLListCollection, the majority of the XMLList methods are still available including (but not limited to):

- attributes
- child
- children
- copy
- descendants
- elements

Note: E4X shorthand operations also apply to an XMLListCollection
But now your plain old hierarchical data storage container (XMLList) has been infused with new powers including data binding (as mentioned previously) and new properties / methods.

New properties:

- filterfunction
- sort

New methods:

- addAll
- addAllAt
- addEventListener
- addItem
- addItemAt
- getItemAt
- getItemIndex
- refresh (for use with filterfunction and sort properties)

Note: These are the same properties and methods employed by an ArrayCollection. Sharing the same super class (ListViewCollection), ArrayCollection and XMLListCollection behave in a very similar manner, however, it is typically the UI control that will dictate the type of collection required as a data provider. Remember, list-based UI controls (DataGrid, List, TileList and HorizontalList) require linear (or flat) data structures (ArrayCollection) while tree or menu-based controls (Tree, Menu, MenuBar, PopUpMenuButton) require hierarchical data structures (XMLListCollection).
In addition to the enhanced API provided by a collection, wrapping an XMLList inside an XMLListCollection provides 2 very powerful features:
  1. filtering
  2. sorting
A collection provides a "view" of the underlying data (Array or XMLList) that can be filtered and sorted without affecting the underlying data. It is this "view" in which UI controls are bound to. Alter the "view" using the filterfunction or sort properties along with the refresh() method and the changes are immediately reflected in your UI control.

View Sorting & Filtering an XMLListCollection Example