Wednesday, May 28, 2008

Grouping XML data using GroupingCollection

I was under the impression this doesn't require any sample as it should be very easy to write one. But frequent questions on the forums have resulted in this post.

There is not much to describe so :

<mx:XML id="inputData" >
 <Tulokset>
 <Tulos id="xxx" group="xx" />
 <Tulos id="xxx" group="xx" />
 <Tulos id="xxx" group="xx" />
 </Tulokset>
</mx:XML> 
 
<mx:AdvancedDataGrid creationComplete="gc.refresh()">
 <mx:dataProvider>
  <mx:GroupingCollection source="{inputData.Tulos}" id="gc">
   <mx:Grouping>
    <mx:GroupingField name="@group" />
   </mx:Grouping>
  </mx:GroupingCollection>
 </mx:dataProvider>
 <mx:columns>
  <mx:AdvancedDataGridColumn dataField="@id" />
 </mx:columns>
</mx:AdvancedDataGrid>

The source is here.

Update: The below example shows how to use grouping when the data is in child nodes instead of attributes. This is a bit tricky because GroupingCollection is derived from HierarchicalData which treats child nodes as children by default. This leads to problems when we try to display the data after grouping. The trick is to make use of the childrenField property and point it to something like "undefined".

<mx:XML id="inputData" >
 <Tulokset>
  <Tulos>
     <id>xx1</id>
     <group>xxx</group>
  </Tulos>
  <Tulos>
     <id>xx2</id>
     <group>xxx</group>
  </Tulos>
  <Tulos>
     <id>xx3</id>
     <group>xxx</group>
  </Tulos>
 </Tulokset>
</mx:XML> 
 
<mx:AdvancedDataGrid creationComplete="gc.refresh()">
 <mx:dataProvider>
  <mx:GroupingCollection source="{inputData.Tulos}" id="gc" childrenField="undefined">
   <mx:Grouping>
    <mx:GroupingField name="group"  />
   </mx:Grouping>
  </mx:GroupingCollection>
 </mx:dataProvider>
 <mx:columns>
  <mx:AdvancedDataGridColumn dataField="id" />
 </mx:columns>
</mx:AdvancedDataGrid>

The source is here.

Please note that childrenField is also helpful when we are trying to display XML data with data and children as child nodes. Use it to point to the proper node name which contains the children. In the following example we need to set childrenField="details" to work properly.


<mx:XML id="special">
<rows>
<row>
  <name>A</name>
  <fund>100</fund>
  <details>
   <row>
   <name>a</name>
   <fund>20</fund>
   </row>
   <row>
   <name>b</name>
   <fund>80</fund>
   </row>
  </details>
</row>
<row>
  <name>C</name>
  <fund>200</fund>
  <details>
   <row>
   <name>a</name>
   <fund>80</fund>
   </row>
   <row>
   <name>b</name>
   <fund>80</fund>
   </row>
   <row>
   <name>c</name>
   <fund>40</fund>
   </row>
  </details>
</row>
</rows> 
</mx:XML>

<mx:AdvancedDataGrid >
   <mx:dataProvider>
       <mx:HierarchicalData source="{special.row}" childrenField="details" >
       </mx:HierarchicalData>
   </mx:dataProvider>
 <mx:columns>
  <mx:AdvancedDataGridColumn dataField="name" />
  <mx:AdvancedDataGridColumn dataField="fund" />
 </mx:columns>
</mx:AdvancedDataGrid>

33 comments:

Yevhen said...

Hi,
Can you post a sample for nested grouping? I mean when Tulos has inner tags.

Sreenivas said...

I have updated the post with a sample.

Yevhen said...

Thanks, but I've got even more complicated task :) Suppose, we have the following XML:

[data]
[user id="1" name="Joshua"]
[account account_id="101" account_name="name101" /]
[account account_id="102" account_name="name102" /]
[account account_id="103" account_name="name103" /]
[/user]
[user id="2" name="Kristin"]
[account account_id="201" account_name="name201" /]
[account account_id="202" account_name="name202" /]
[/user]
[user id="3" name="Donna"]
[/user]
[user id="4" name="Jack"]
[account account_id="401" account_name="name401" /]
[/user]
[/data]

I need to group it by user, but fill the column with values of the attribute "account_name". Output column of advanced data grid should look like:

Joshua
|->name101
|->name102
|->name103
Kristin
|->name201
|->name202
Donna
Jack
|->name401

Is there any way to do this?

Simo MoX said...

Hello,
how i can read a grouped data provider subjecting to a drag drop action in an advanced data grid?

Sreenivas said...

The traversal is very similar to traversing hierarchical data. You can take a look at ADG.updateDropData to see how ADG finds the parent item to add the dropped item.

Simo MoX said...

It's seems not so clear.
There's no other way to access to the modified datas on an advanced datagrid with grouping function applied?

Sreenivas said...

May be you should pose your question with a sample which would help me in understanding it better.

Simo MoX said...

problem solved! maybe..i've not used grouping collection but i converted the data model in a ordinated array, and on the datagrid i used a hierarchicaldata function on the data model. So i can update the dataprovider on each change during the operation of drag / drop on the grid, and access to the modified datas.

sparcspread said...

Your "childrenField" hack just saved me DAYS of work! Thank you so much!

Grouping on XML collections with a child node as the grouping term is a common use case. It shouldn't be as hard as it is - hope Adobe takes notice.

Once again - many thanks!
-Noah

Blugger said...

first of all, thank you for this post.

a question: is there a way to have the grouped element/item to be displayed in the grid, spanning across the grid. (e.g. the <name>A</name> in your example).

I have an ADG where its dataProvider is pointing to an ArrayCollection with nested ArrayCollection as the childrenField value. Right now, i can group the items with the "parent-children" relationship ... but i couldn't figure out how to render the parent node across the grid (i.e. columnspan=0). I've used AdvancedDataGridRendererProvider for the parent column, but it's not working as expected (the parent column is the only column displayed).

hope you can understand my problem and question. I can provide example if needed.

thank you in advance!
-tn

Sreenivas said...

An example would help me in taking a look at it for possible fixes faster !

Blugger said...

Please see the file below for an example of the ADG that I'm trying to create.

http://dl-client.getdropbox.com/u/14140/ADGExample.mxml

The ADG is missing the title for the books (I could've added it as a column, but i want it to be displayed on its own row ... and at the to level, i.e. depth=1).

Please let me know if you can't view the file from the URL above.

thanks!

Blugger said...

sorry, in my previous comment, i meant to say that the ADG was missing the author's firstName (not title). (the books are grouped by the author's firstName).

Sreenivas said...

Here is a solution

Exported FB project

Blugger said...

Thank you so much for the solution ... it is how i wanted the grid to be (with slight modification to remove the lastName and City columns and set Columnspan=0 on the firstName column).

looking forward to more of your posts/blogging!

sheetal said...

[Project]
[Task taskId="1" startDate="Sat Oct 25 18:39:49 GMT+0530 2008"
endDate="Sat Oct 25 18:39:49 GMT+0530 2008" effort="1 hr"
resources="Anand" relation="Predecessor " deliverable="No "
taskDescription="one" relatedTask="none" group="p0001"]
[Task taskId="2" startDate="Sat Oct 25 18:39:49 GMT+0530 2008"
endDate="Sat Oct 25 18:39:49 GMT+0530 2008" effort="2 hrs"
resources="Anand" relation="Predecessor " deliverable="No "
taskDescription="one" relatedTask="none" group="p0001"]
[Task taskId="3" startDate="Sat Oct 25 18:39:49 GMT+0530 2008"
endDate="Sat Oct 25 18:39:49 GMT+0530 2008" effort="3 hrs"
resources="Anand" relation="Predecessor " deliverable="No "
taskDescription="one" relatedTask="none" group="p0001"]

[Task taskId="4" startDate="Sat Oct 25 18:39:49 GMT+0530 2008"
endDate="Sat Oct 25 18:39:49 GMT+0530 2008" effort="1 hr"
resources="Anand" relation="Predecessor " deliverable="No "
taskDescription="one" relatedTask="none" group="p0002"]

[Project]
This is my XML and i want to add child to the existing child for ex.element with taskId '1'.This will be at 3rd level.Can u please help me with this.

Sreenivas said...

Use HierarchicalData to wrap the input data.

Use HierarchicalCollection to fetch the collection for the requried parent.

Use addChild to add the child.

Madhav said...

Hi Sreenivas,

Is it impossible to show two (or more) level of summary reports in AdvancedDataGrid ?

Following is the report structure I am trying to display in ADG:

_______| S |
P | R | |
_______|____|_
P1 | N |1000
-----------
| E | 200
-----------
| W | 450
-----------
| S |1250
--------------
P2 | N |1100
-----------
| E | 500
-----------
| W | 350
-----------
| S |1750
--------------


So, basically, its two summary levels (product and sales) on rows and single level summary. i.e., sales amount on column.

Another thing is that when the report is collapsed on the product level, then at total sales figure should be displayed.

Sreenivas said...

I am unable to get what you want from the textual image. Can you please provide a clearer picture. May be using summary-product, summary-sales etc as text lables help me understand your requirement.

Madhav said...

Here is the report which I am trying to implement.

http://docs.google.com/Doc?id=dcr9sgrp_2hnf33fd9

Sreenivas said...

Currently ADG doesn't support merging of cells along the rows as shown in the figure.

The nearest you can come to this would be to group along products and show the North/East/West/South as children. You can display summary at the group level if you like.

u901220 said...
This comment has been removed by the author.
u901220 said...
This comment has been removed by the author.
u901220 said...

First of all, many thanks for all those good examples. I really learn a lot from your blog.

I got a question regarding advancedDataGrid. Here is my sample application. http://www.irislin.net/itemrenderer/reliability.html

The application works fine except that I have an overall rating for each vehicle. Is there any way to achieve that? You can find my source codes in http://www.irislin.net/itemrenderer/src.zip

Sreenivas said...

I am unable to understand what do you want. Can you explain a little more ?

Surender said...

Hi Sreenivas,
One thing I have found is when XML is your source to GroupingCollection you wont be able to calculate Summary.
It will return 0 as summary.I have sent u one XML. In that iam not able to calculate summary.It returns 0 and if u put Itemrenderer on first column it will be ignored.This is not the case when we convert XML to ArrayCollection by Looping.Can u put some light on it.Iam facing this major issue.

Thanks in advance.

Surender Dahiya

Sreenivas said...

The solution is actually mentioned in the above post itself.

Set childrenField="undefined" to get it to work !

Surender said...
This comment has been removed by the author.
buffy said...

Thank you Sreenivas for this article! It was very informative.

However, I am still having difficulty getting nested data to display.

My data:

transactions
transaction
method A method
agent 100 agent
details
transaction
method a method
agent 20 agent
transaction
transaction
method b method
agent 80 agent
transaction
details
transaction
transaction
method C method
agent 200 agent
details
transaction
method a method
agent 80 agent
transaction
details
transaction
transactions

I get this data with an HTTPService:

mx:HTTPService id="detailSrv"
url="data/xactions.xml"
result="detailResultSuccess( event )"
fault="xmlResultFailure( event )"
mx:HTTPService

In detailResultSuccess, I point to the data this way:

input = new HierarchicalData(event.result.transactions.transaction);

input.childrenField = "detail";
detaildg.dataProvider = input;
detaildg.validateNow();

The AdvancedDataGrid has the following attributes:

mx:AdvancedDataGrid
id="detaildg" width="100%"
height="100%" enabled="true"
displayItemsExpanded="true"
showHeaders="true"

The result is that the top level only is displayed. I do have a folder icon on the first datum indicating that the Hierarchical data does recognize that there are children but I don't see any.

What the heck am I doing wrong? I have read everything that I can find but cannot find where my error is.

Thank you so much for your input!

buffy said...

Sorry, had a typo: 'detail' should have been 'details' in the following code snippet:

input = new HierarchicalData(event.result.transactions.transaction);
input.childrenField = "details";
detaildg.dataProvider = input;
detaildg.validateNow();


However, that does not fix the problem. Just wanted to be clear.

Thank you!

hpeter said...

If the data source is XML data with data and children as child nodes, how to take advantage of grouping collection asynchonous refresh method that does not exist for hierarchical data class (the class more appropirate for this type of structure XML data)
Can group collection be used to this ype of data with children?

Sreenivas said...

GroupingCollection derives from HierarchicalData. I think it can work with the kind of XML data you are describing.

Bish said...

If you make changes to/update your bindable XML object, then you have to recall gc.refresh - over an hour on this little chestnut!

// Update the xml
xmlCities = XML(event.result);

// Refresh the GroupingCollection gc.refresh();