View Full Version : Tree / XML - how to display - don't understand
gurpal2000
08-02-2007, 10:23 PM
Hi I have an XML document which i'd like to display into a Flex Tree component.
<application>
<appid>3</appid>
<appname>Firefox</appname>
<category>Internet Browsers</category>
<pkgs>
<pkg>
<version>2.0.0.6</version>
<platforms>
<platform>Vista</platform>
<platform>XP</platform>
</platforms>
<files>
<file>firefox/win32/Firefox Setup 2.0.0.6.exe</file>
</files>
<source>http://www.mozilla-europe.org/en/products/firefox</source>
<notes></notes>
</pkg>
<pkg>
<version>2.0.0.5</version>
<platforms>
<platform>Vista</platform>
<platform>XP</platform>
</platforms>
<files>
<file>firefox/win32/Firefox Setup 2.0.0.5.exe</file>
</files>
<source>http://www.mozilla-europe.org/en/products/firefox</source>
<notes></notes>
</pkg>
<pkg>
<version>2.0.0.4</version>
<platforms>
<platform>Vista</platform>
<platform>XP</platform>
</platforms>
<files>
<file>firefox/win32/Firefox Setup 2.0.0.4.exe</file>
</files>
<source>http://www.mozilla-europe.org/en/products/firefox</source>
<notes></notes>
</pkg>
</pkgs>
</application>
What i want to display from here is a tree which looks like:
+Firefox
|------2.0.0.6
|------2.0.0.5
|------2.0.0.4
ie
+<appname>
|-------<version>
|-------<version>
|-------<version>
quite simple really. Of course there may be more <applications> in the document. I've tried various ways of creating another xmlList out of this but no avail. Also i've supplied a labelFunction() to try to display the right thing but nothing.
It seems only examples out there are where the text to display is an attribute of a really simple structure like this:
<node label="Mail Box">
<node label="Inbox">
<node label="Marketing"/>
<node label="Product Management"/>
<node label="Personal"/>
</node>
<node label="Outbox">
<node label="Professional"/>
<node label="Personal"/>
</node>
<node label="Spam"/>
<node label="Sent"/>
</node>
(http://examples.adobe.com/flex2/inproduct/sdk/explorer/explorer.html - Tree example). I still can't seem to get what i want from my XML above.
Any ideas or examples please.
Thanks
drkstr
08-03-2007, 01:54 AM
I think it's in attribute form because that's what the Tree control is expecting. You can create your own custom hierarchical data provider if you would like.
Here is a good article on creating custom formed data providers:
http://livedocs.adobe.com/flex/201/html/about_dataproviders_057_15.html
Hope this helps,
...aaron
Jim Freer
08-04-2007, 12:27 PM
I'm not sure if you wanted to reduce the tree to just the name and versions or if you would be satisfied if that was all you could get. You would need to reduce the XML to display only those. However, if you merely wanted to put the element text values in the tree labels, here is a generic way to do that with the labelFunction:
private function treeLabelFunction
( avObject :Object )
:String
{
var lvXml:XML = avObject as XML;
var lvLabel:String = lvXml.localName() + " " + lvXml.text();
return lvLabel;
} // treeLabelFunction
http://freerpad.blogspot.com/
gurpal2000
08-05-2007, 07:41 PM
I see. The "master" XML coming back is of the form i showed in my example. So I guess is there is some equivalent of an XSL transform that could be applied to get the data into something the tree can understand.
The generic labelFunction may be OK, bu then how you associate a class with the node? In Java you put classes in a model which you then apply to a tree, but you specifiy in the renderer what the label/component should be and display whatever.
Guess I need the equivalent... Thanks
drkstr
08-05-2007, 08:13 PM
Did you read the link I gave you, it tells you how to do exactly what your asking for.
Regards,
...aaron
Jim Freer
08-06-2007, 12:00 AM
You could possibly transform with what drkstr is suggesting although it might be a bit of a brainteaser. It would be interesting to see what it would look like.
The generic labelFunction may be OK, but then how do you associate a class with the node?
You can get the underlying XML element from a tree node with:
var lvXmlNode:XML = XML( myTree.selectedItem );
trace( lvXmlNode.name() + " " + lvXmlNode.text() );
From there, you can navigate with: lvXmlNode.parent(), etc.
http://freerpad.blogspot.com/
dr_zeus
08-06-2007, 06:20 PM
The XML you posted is too complicated to display correctly in a Tree component, by default. If you want to use that XML data without changing it, look into creating a custom "data descriptor" for your Tree. Data descriptors are what actually converts a data provider into branches and leaves that the Tree can understand.
Jim Freer
08-06-2007, 07:36 PM
DataDescriptor’s are what drkstr was talking about. I’m guessing it would a bit of a brainteaser. The alternatives, I can think of, are:
1. Reduce the XML to fit the tree and build logic to associate the reduced XML to the original possibly by utilizing attributes in the new XML. Or use something other object type.
2. Live with the complex tree. You could automatically expand the tree nodes of the parts of interest.
http://freerpad.blogspot.com/
dr_zeus
08-06-2007, 09:02 PM
Sorry, yes, drkstr was talking about data descriptions. From his description, it sounded like something different, but I guess I should have clicked on the link.
Anyway, regardless of the duplication of suggestions, I don't think it would be too difficult to create a data descriptor from the structure of that XML. I've seen much worse.
The application elements are branches. The children of those branches are XMLLists of pkg elements.
To properly display labels, you'll need to use a labelFunction. Here's some pseudo-code that might help:
private function myLabelFunction(item:Object):String
{
if(myTree.dataDescriptor.isBranch(item))
{
// we know it's an application element
// if we didn't know for sure, we could put the name of the element in a switch block.
return item.appname;
}
// for leaves, we know it's a pkg element
return item.version;
}
gurpal2000
08-06-2007, 10:45 PM
aaron, i have read it. It would work....
Let's put a different way: what if I wanted to create a standalone XMLCollection out of the larger XML - maybe not for a Tree. Writing a custom descriptor seems overkill to me for something "simple" in XML terms.
Is there a template or something i could use, something like this pseduo code
loop
read larger xml doc
$a = blah.blah.appname;
$b = blah.blah.blah.(appname = $a).blah.version
fill in template {
<apps>
<app name="$a" version="$b"/>
</apps>
}
end loop
is there a way to create a doc by template or build a doc manually (with not too much code!), if you get what i mean...Thanks
drkstr
08-06-2007, 11:08 PM
The only other way I can think of is to parse and filter.
public class TreeDada {
private var myXML:XML = <your_xml></your_xml>;
public function getDataCollection(): ArrayCollection {
var data:ArrayCollection = new ArrayCollection();
var node:Object;
var child:Object;
for( element:XML in myXML.elements() ) {
node = new Object();
node.label = element.appname.toString();
node.children = new ArrayCollection();
for( pkg:XML in element.pkgs.elements() ) {
child = new Object();
child.label = pkg.version.toString();
node.children.addItem(child);
}
data.addItem(node);
}
return data;
}
}
I just banged that out real quick without testing, so you might need to tweak it a bit, but the idea is the same. As you can see from the code, the data provider would be assigned to the return value of getDataCollection().
Regards,
...aaron
Jim Freer
08-07-2007, 02:31 AM
The code to reduce is really pretty trivial. You might want to add more attributes to help refer back to original.
<?xml version="1.0" encoding="utf-8"?>
<mx:Application
xmlns:mx="http://www.adobe.com/2006/mxml"
layout="absolute"
creationComplete="onCreationComplete()"
>
<mx:Tree
id="Tree1"
width="100%"
height="100%"
labelField="@label"
dataProvider="{mvXmlReduced}"
/>
<mx:Script>
<![CDATA[
private var mvXml:XML =
<applications>
<application>
....
</application>
<application>
....
</application>
</applications>;
[Bindable]
private var mvXmlReduced:XML;
private function onCreationComplete
()
:void
{
var lvXmlList:XMLList = new XMLList();
for each( var lvXml:XML in mvXml.children() )
lvXmlList += transformApplication( lvXml );
mvXmlReduced = <applications label="applications"/>;
mvXmlReduced.setChildren( lvXmlList );
callLater( expandAllTreeNodes, [Tree1] );
} // onCreationComplete
private function transformApplication
( avXml :XML )
:XML
{
var lvXml:XML = <application label={avXml.appname}/>;
var lvXmlList:XMLList = new XMLList();
for each( var lvXmlPkg:XML in avXml.pkgs.pkg )
{
lvXmlList += <version label={lvXmlPkg.version}/>;
} // for each
lvXml.setChildren( lvXmlList );
return lvXml;
} // transformApplication
private function expandAllTreeNodes
( avTree :Tree )
:void
{
avTree.selectedIndex = 0;
avTree.expandChildrenOf( avTree.selectedItem, true );
} // expandAllTreeNodes
]]>
</mx:Script>
</mx:Application>
http://freerpad.blogspot.com/
oops, sorry I didn't see the 2nd page of posting, drkstr. Well here is an alternative.
Jim Freer
08-07-2007, 07:05 PM
While trying to figure something else out, I came across this:
http://axel.cfwebtools.com/index.cfm/2007/5/1/Using-a-Data-Manager-and-Filtering-Data-In-A-Flex-Tree-even-the-nodes
Probably not the solution desired here, but might be for someone in the future.
gurpal2000
08-07-2007, 11:08 PM
The stuff you guys have come out with is truly helpful. Will give all these a go and let you what happens. Thanks!
|
vBulletin® v3.8.4, Copyright ©2000-2009, Jelsoft Enterprises Ltd.