【问题标题】:How to convert XMLList to XML in FLEX如何在 FLEX 中将 XMLList 转换为 XML
【发布时间】:2013-03-30 10:46:37
【问题描述】:

我已经参考了以下链接,但找不到适合我的方案的解决方案。

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

【问题讨论】:

  • 我不认为你可以用你目前拥有的过滤器功能来实现这一点。您现在只选择“名称”属性,而您应该选择“项目”元素。我想您需要编写一个递归过滤器函数来跟踪访问和删除的节点。

标签: xml apache-flex xmllist


【解决方案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”),但不幸的是节点顺序有点顺序。

【讨论】:

  • 感谢您的回答。是的,它有效,这就是我想要的。
  • @Flexiflex 很高兴为您提供帮助。我还添加了递归版本
【解决方案2】:

如果您只想过滤子层,试试这个:

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

结果:

【讨论】:

    猜你喜欢
    • 2012-06-02
    • 2012-01-17
    • 2023-03-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多