我之前已经提到了以下链接,但找不到我的方案的解决方案。
Actionscript 3 - How can i convert from XMLList to XML?
我的xml变量如下:
private var checkXml:XML = new XML(
<universe>
<item name="cat 2">
<item name = "All"/>
<item name = "item 1"/>
<item name = "item 2"/>
</item>
<item name="cat 2">
<item name = "All"/>
<item name = "item 3"/>
<item name = "item 4"/>
<item name = "item 5"/>
<item name = "item 5"/>
</item>
<item name="cat 3">
<item name = "All 33"/>
<item name = "item 34"/>
<item name = "item 44"/>
</item>
</universe>);
我使用过滤器函数将上面xml中的重复值删除为:
private function filter(xmlSample:XML):XMLList
{
var seen:Object={};
return xmlSample..@name.(!seen[valueOf()]&&(seen[valueOf()]=true));
}
返回XMLList数据。当我使用它来获取XML格式时:
var thisXml:XMLList = filter(checkXml);
Alert.show(thisXml.toXMLString());
我没有得到XML格式的输出;我是这样得到的。:
cat 2
All
item 1
item 2
item 3
item 4
item 5
cat 3
All 33
item 34
item 44
如何在Flex中使用与我的XML变量“checkXml”相同的XML格式,以便我可以保留所有父节点和子节点,从而删除重复项。
答案 0 :(得分:1)
这是一个快速的建议:
function clean(xml:XML):XML{
var paths:Dictionary = new Dictionary(true);//keep track of paths
var result = new XML("<"+xml.localName()+" />");//make new xml
for each(var child:XML in xml.*){//travers 1st level
var path:String = child.parent().localName()+"/"+child.localName()+"@"+child.@name;//get a path (I formatted it like)
if(!paths[path]) {//if it's a new node
paths[path] = child;//store it in the dictionary
result.appendChild(child.copy());//add it to the result
}else {//otherwise copy children
for each(var clone:XML in child.*)//check for duplicates, otherwise insert, NOTE this does not merge child nodes yet :(
if(result[child.localName()][0].*.(@name == clone.@name).length() == 0) result[child.localName()][0].appendChild(clone);
}
}
trace(result.toXMLString());
return result;
}
使用基本的xml,你可以完成这项任务,但它不是很灵活。 它应该合并子节点的重复项,也许应该是递归的,但我没有时间atm。
<强>更新强> 我还有两个版本供你使用。进入子节点的一个级别:
function clean(xml:XML):XML{
var paths:Dictionary = new Dictionary(true);//keep track of
var result = new XML("<"+xml.localName()+" />");
for each(var child:XML in xml.*){
var path:String = child.parent().localName()+"/"+child.localName()+"@"+child.@name;
if(!paths[path]) {
paths[path] = child;
result.appendChild(child.copy());
}else
for each(var clone:XML in child.*)
if(result[child.localName()][0].*.(@name == clone.@name).length() == 0) result[child.localName()][0].appendChild(clone);
else result[child.localName()][0].*.(@name == clone.@name)[0].appendChild(clone.*);
}
return result;
}
所以像这样的xml:
var data:XML = <universe>
<item name="cat 2">
<item name = "All">
<item name="item child 1" />
<item name="item child 3">
<item name="item grandchild 1" />
</item>
</item>
<item name = "item 1">
<item name = "item child 1" />
</item>
<item name = "item 2"/>
</item>
<item name="cat 2">
<item name = "All">
<item name="item child 2" />
<item name="item child 3">
<item name="item grandchild 2" />
</item>
</item>
<item name = "item 3"/>
<item name = "item 4"/>
<item name = "item 5"/>
<item name = "item 5"/>
</item>
<item name="cat 3">
<item name = "All 33"/>
<item name = "item 34"/>
<item name = "item 44"/>
</item>
</universe>;
产生如下输出:
<universe>
<item name="cat 2">
<item name="All">
<item name="item child 1"/>
<item name="item child 3">
<item name="item grandchild 1"/>
</item>
<item name="item child 2"/>
<item name="item child 3">
<item name="item grandchild 2"/>
</item>
</item>
<item name="item 1">
<item name="item child 1"/>
</item>
<item name="item 2"/>
<item name="item 3"/>
<item name="item 4"/>
<item name="item 5"/>
</item>
<item name="cat 3">
<item name="All 33"/>
<item name="item 34"/>
<item name="item 44"/>
</item>
</universe>
请注意,根节点中的属性(如果有)将丢失。 可能最好的选择仍然是使用递归,如下所示:
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;
}
我不确定这是否是最干净/最优雅的解决方案,但它确实有效:
trace(cleanNodes(data.*));
产生
<universe>
<item name="cat 2">
<item name="item 2"/>
<item name="item 3"/>
<item name="item 4"/>
<item name="item 5"/>
<item name="All">
<item name="item child 1"/>
<item name="item child 2"/>
<item name="item child 3">
<item name="item grandchild 1"/>
<item name="item grandchild 2"/>
</item>
</item>
<item name="item 1">
<item name="item child 1"/>
</item>
</item>
<item name="cat 3">
<item name="All 33"/>
<item name="item 34"/>
<item name="item 44"/>
</item>
</universe>
注意具有相同名称的节点以递归方式折叠(如“All”和“item child 3”),但不幸的是节点按顺序排序。
答案 1 :(得分:0)
如果您只想过滤子项的图层,请尝试以下方法:
<?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.controls.Alert;
import mx.events.FlexEvent;
private var checkXml:XML = new XML(
<universe>
<item name="cat 2">
<item name = "All"/>
<item name = "item 1"/>
<item name = "item 2"/>
</item>
<item name="cat 2">
<item name = "All"/>
<item name = "item 3"/>
<item name = "item 4"/>
<item name = "item 5"/>
<item name = "item 5"/>
</item>
<item name="cat 3">
<item name = "All 33"/>
<item name = "item 34"/>
<item name = "item 44"/>
</item>
</universe>);
private function filter(xmlSample:XML):XMLList
{
var seen:Object={};
return xmlSample.item.item.(!seen[@name.valueOf()]&&(seen[@name.valueOf()]=true));
}
protected function init(event:FlexEvent):void
{
var thisXml:XMLList = filter(checkXml);
Alert.show(thisXml.toXMLString());
}
]]>
</fx:Script>
</s:Application>
修改强>
如果要过滤分隔的两个级别的项目,可以改为使用此功能:
private function filter(xmlSample:XML):XMLList
{
var seen:Object={};
var seen_child:Object={};
return xmlSample.item.(!seen[@name.valueOf()]&&(seen[@name.valueOf()]=true)).item.(!seen_child[@name.valueOf()]&&(seen_child[@name.valueOf()]=true));
}
在这种情况下,过滤器会擦除第二个节点“cat 2”以及其余节点中子节点之间的所有重复项。
<强> EDIT2 强>
如果您想过滤两个图层并且不想丢失二维结构,请执行以下操作:
private function filter(xmlSample:XML):XMLList
{
var seen:Object={};
var firstLevel:XMLList = xmlSample.item.(!seen[@name.valueOf()]&&(seen[@name.valueOf()]=true));
var secondLevel:XMLListCollection = new XMLListCollection();
var seen_child:Object={};
for each (var xmlItem:XML in firstLevel)
{
var tempXMLList:XMLList = xmlItem.item.(!seen_child[@name.valueOf()]&&(seen_child[@name.valueOf()]=true));
xmlItem.setChildren(tempXMLList);
secondLevel.addItem(xmlItem);
}
return secondLevel.source;
}
结果: