ここに簡単な提案があります:
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を使えば、それは仕事をしますが、あまり柔軟ではありません。重複の子ノードをマージする必要があり、おそらく再帰的である必要がありますが、時間の余裕がありません。
更新:
さらに 2 つのバージョンがあります。子ノードのレベルに入るもの:
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>
同じ名前のノードが再帰的に折りたたまれていることに注意してください (「すべて」と「アイテムの子 3」のように) が、残念ながらノードの順序が少し異なります。