如何在FLEX中将XMLList转换为XML

时间:2013-04-08 11:14:15

标签: xml flex xmllist

我之前已经提到了以下链接,但找不到我的方案的解决方案。

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格式,以便我可以保留所有父节点和子节点,从而删除重复项。

2 个答案:

答案 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)

如果您只想过滤子项的图层,请尝试以下方法:

enter image description here

<?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;
        }

结果:

enter image description here