如何在Flex中将平面/分层数据转换为XML格式。 以下是我的分层数据:(表格格式)
Asia India Chennai TN Category1 Product1 100
Asia India Mumbai MH Category1 Product1 100
Asia India Calcutta CT Category1 Product1 100
Asia India Calcutta CT Category2 Product2 200
EMEA UK London LN Category3 Product1 123
EMEA UK London LN Category3 Product2 455
EMEA UK Reading RN Category1 Product1 500
EMEA UK Reading RN Category1 Product2 430
I need to format/convert this to XML format so that I can populate that resulting xml as dataprovider to a Tree control.
Asia
India
Chennai
TN
Category1
Product1
100
Mumbai
MH
Category1
Product1
100
such a tree structure.
答案 0 :(得分:2)
我会制作一个简单的转换器来获得真正的XML结构。解决方案的复杂性取决于您拥有的源文本。
这是我的实施。
假设您的分层数据结构良好,并且每个元素之前都有一定数量的空格。在我的情况下,我使用4个空格作为一个级别移位。
我从文本文件中加载数据,如下所示:
Asia
India
Chennai
TN
Category1
Product1
100
Mumbai
MH
Category2
Product2
200
Category3
Product3
300
Product4
400
然后我浏览每个字符串并分析其级别。 生成的树看起来像这样:
//申请
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
minWidth="955" minHeight="600" creationComplete="init(event)">
<fx:Script>
<![CDATA[
import mx.events.FlexEvent;
private const SPACEDELIMITER:int = 4;
private var loader:URLLoader;
private var ar:Array = new Array();
[Bindable]private var data:XML = <Root/>;
private var inputStr:String;
protected function init(event:FlexEvent):void
{
loader = new URLLoader(new URLRequest("com/treexml/tree.txt"));
loader.dataFormat = URLLoaderDataFormat.TEXT;
loader.addEventListener(Event.COMPLETE, completeHandler);
}
private function completeHandler(event:Event):void
{
inputStr = URLLoader(event.target).data;
parseString();
}
private function parseString():void
{
var levels:Array = new Array();
ar = inputStr.split("\r\n");
var reg:RegExp = /[a-z0-9]/gi;
var globalShift:int = String(ar[0]).search(reg);
for (var i:int = 0; i < ar.length; i++)
{
var item:String = ar[i];
var shift:int = item.search(reg); //amount of witespaces before the text
var level:int = (shift - globalShift)/SPACEDELIMITER; //level of the node
var label:String = item.substring(shift, item.length);
levels[level] = i; //id of the last element for the given level
var node:XML = new XML();
node = <child id = {i} label = {label}/>;
if (level == 0)
data.appendChild(node);
else
data..child.(@id == levels[level - 1]).appendChild(node);
}
}
]]>
</fx:Script>
<mx:Tree width="250"
height="400"
dataProvider="{data.child}"
labelField="@label"/>
</s:Application>
的 //修改
如果您的数据未通过空格对齐,请尝试使用另一版本的parseString函数。
假设您的数据如下:
Asia India Chennai TN Category1 Product1 100
Asia India Mumbai MH Category1 Product1 100
Asia India Calcutta CT Category1 Product1 100
Asia India Calcutta CT Category2 Product2 200
EMEA UK London LN Category3 Product1 123
EMEA UK London LN Category3 Product2 455
EMEA UK Reading RN Category1 Product1 500
EMEA UK Reading RN Category1 Product2 430
功能是:
private function parseString():void
{
ar = inputStr.split("\r\n");
var map:Dictionary = new Dictionary();
var delimiter:String = "***";
var id:int = 0;
for (var i:int = 0; i < ar.length; i++)
{
if(ar[i].length){//if it's not an empty string
var itemArray:Array = ar[i].replace(/\s{2,}/g, ' ').split(" ");//collapse multiple spaces as one using RegEx
var key:String = "";
var prevkey:String = "";
for (var j:int = 0; j< itemArray.length; j++)
{
prevkey = key;
key += itemArray[j] + delimiter;
if (map[key] == null)
{
map[key] = id;
var node:XML = <child id = {id} label = {itemArray[j]}/>;
if (j == 0)
data.appendChild(node);
else
data..child.(@id == map[prevkey]).appendChild(node);
id++;
}
}
}
}
}
答案 1 :(得分:2)
这是一种使用递归函数形式this answer的效率不高的方法:
var data:String = '';//this is just to keep the data in the editor, you would dinamically load this usually
data += 'Asia India Chennai TN Category1 Product1 100\n';
data += 'Asia India Mumbai MH Category1 Product1 100\n';
data += 'Asia India Calcutta CT Category1 Product1 100\n';
data += 'Asia India Calcutta CT Category2 Product2 200\n';
data += 'EMEA UK London LN Category3 Product1 123\n';
data += 'EMEA UK London LN Category3 Product2 455\n';
data += 'EMEA UK Reading RN Category1 Product1 500\n';
data += 'EMEA UK Reading RN Category1 Product2 430\n';
trace(cleanNodes(parseTableString(data).*));
function parseTableString(str:String):XML{
var lines:Array = str.split('\n');
var xml:XML = <root />;
for(var i:int = 0; i < lines.length; i++){
//collapse multiple spaces to 1 using RegEx, then split
var nodes:Array = lines[i].replace(/\s{2,}/g, ' ').split(' ');
for(var j:int = 0 ; j < nodes.length; j++){
if(nodes[j].length){
var node:String = '<item name="'+nodes[j]+'"/>';
if(j > 0){//if the node has parents
var pre:String = '';//create enclosing tags
var post:String = '';
for(var k:int = 0 ; k < j; k++){//build up parent hierarchy
pre += '<item name="'+nodes[k]+'">';
post += '</item>';
}
node = pre+node+post;//concatenate as a full node
xml.appendChild(new XML(node));//add full node (will add duplicates)
}
}
}
}
return xml;
}
function cleanNodes(nodes:XMLList):XML{
var parent:XML = nodes.parent();
var result:XML = new XML("<"+parent.localName()+" />");//copy parent node name
for each(var a:XML in parent.attributes()) result['@'+a.name()] = parent.attribute(a.name());//and attributes
//merge duplicates at one level
var found:Dictionary = new Dictionary(true);
for each(var child:XML in nodes){
var name:String = child.@name;
if(!found[name]) {
found[name] = child;
result.appendChild(child);
}else{//merge
found[name].appendChild(child.*);
}
}
//recurse
for each(var kid:XML in result.*){//for each child node
if(kid.*.length() > 0){//if it has children
var clean:XML = cleanNodes(kid.*);//get a clean copy of each child node
delete result.*[kid.childIndex()];//remove the original
result.appendChild(clean); //add the cleaned one (replace)
}
}
return result;
}
哪个输出:
<root>
<item name="Asia">
<item name="India">
<item name="Chennai">
<item name="TN">
<item name="Category1">
<item name="Product1">
<item name="100"/>
</item>
</item>
</item>
</item>
<item name="Mumbai">
<item name="MH">
<item name="Category1">
<item name="Product1">
<item name="100"/>
</item>
</item>
</item>
</item>
<item name="Calcutta">
<item name="CT">
<item name="Category1">
<item name="Product1">
<item name="100"/>
</item>
</item>
<item name="Category2">
<item name="Product2">
<item name="200"/>
</item>
</item>
</item>
</item>
</item>
</item>
<item name="EMEA">
<item name="UK">
<item name="London">
<item name="LN">
<item name="Category3">
<item name="Product1">
<item name="123"/>
</item>
<item name="Product2">
<item name="455"/>
</item>
</item>
</item>
</item>
<item name="Reading">
<item name="RN">
<item name="Category1">
<item name="Product1">
<item name="500"/>
</item>
<item name="Product2">
<item name="430"/>
</item>
</item>
</item>
</item>
</item>
</item>
</root>
我个人认为@Anton的答案更好,因为只在需要时添加节点(而不是我创建重复的节点,然后删除它们)。我已经添加了一个RegEx来将多个空格折叠成一个答案。
答案 2 :(得分:1)
如果转换为XML的唯一原因是用作树数据提供者,那么您不需要这样做。一种更有效的方法是使用树数据描述符。这使您可以保持数据提供者的平坦,并且描述符允许您描述其结构,以便树知道哪些对象是彼此的子对象。 http://help.adobe.com/en_US/flex/using/WS2db454920e96a9e51e63e3d11c0bf69084-7b69.html