Вот краткое описание:
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()+"@"[email protected];//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 == [email protected]).length() == 0) result[child.localName()][0].appendChild(clone);
}
}
trace(result.toXMLString());
return result;
}
С базовым xml у вас есть эта работа, но она не очень гибкая. Он должен объединить дочерние узлы для дубликатов и, возможно, должен быть рекурсивным, но у меня нет времени.
Обновление: У меня есть еще две версии для вас.Тот, который идет в дочерние узлы уровня:
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()+"@"[email protected];
if(!paths[path]) {
paths[path] = child;
result.appendChild(child.copy());
}else
for each(var clone:XML in child.*)
if(result[child.localName()][0].*.(@name == [email protected]).length() == 0) result[child.localName()][0].appendChild(clone);
else result[child.localName()][0].*.(@name == [email protected])[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 = [email protected];
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>
Узлы с одинаковыми именами были рекурсивно свернуты (например, «Все» и «Детский ребенок 3»), но, к сожалению, узел упорядочивает путь немного.
Я не думаю, что вы можете достичь этого с помощью функции фильтра, которую вы в настоящее время имеете. Теперь вы выбираете только атрибуты «name», в то время как вы должны выбирать элементы «item». Думаю, вам нужно написать функцию рекурсивного фильтра, которая отслеживает посещаемые и удаленные узлы. –