views:

170

answers:

2

Take this XML example:

<root>
  <grandParent GPid="1" hidden="false">
    <parent Pid="1" hidden="false">
      <child Cid="1" hidden="false"/>
      <child Cid="2" hidden="true"/>
    </parent>
    <parent Pid="2" hidden="false">
      <child Cid="3" hidden="false"/>
      <child Cid="4" hidden="false"/>
    </parent>
  </grandParent>
  <grandParent GPid="2" hidden="false">
    <parent Pid="3" hidden="false">
      <child Cid="5" hidden="true"/>
    </parent>
    <parent Pid="4" hidden="true">
      <child Cid="6" hidden="false"/>
    </parent>
  </grandParent>
  <grandParent GPid="3" hidden="true">
    <parent Pid="5" hidden="false">
      <child Cid="7" hidden="false"/>
    </parent>
  </grandParent>
</root>

I need some sort of filter to get a copy of this where all the nodes marked "hidden" are removed like so:

<root>
  <grandParent GPid="1" hidden="false">
    <parent Pid="1" hidden="false">
      <child Cid="1" hidden="false"/>
    </parent>
    <parent Pid="2" hidden="false">
      <child Cid="3" hidden="false"/>
      <child Cid="4" hidden="false"/>
    </parent>
  </grandParent>
  <grandParent GPid="2" hidden="false">
    <parent Pid="3" hidden="false"/>
  </grandParent>
</root>

I tried using something like this

var newXML:XML = XML(root.(grandParent.@hidden != "true").(grandParent.parent.@hidden != "true").(grandParent.parent.child.@hidden !=true);

But that really just gives me back the original XML (since I'm asking for the root where those conditions are met I get the root). I understand why my approach doesn't work, but I don't know where to go from here.

A: 

So here's what I was able to come up with, but I don't like having to loop. Let me know if you have a better way:

var newXML:XML = new XML(root);
var i:uint=0;
for(i=0;i<newXML.grandparent.parent.child.(@hidden == false).length();i++){
  delete newXML.grandparent.parent.child.(@hidden == false)[0];
  //always [0] since the list is shortened by 1 each iteration
}
for(i=0;i<newXML.grandparent.parent.(@hidden == false).length();i++){
  delete newXML.grandparent.parent.(@hidden == false)[0];
}
for(i=0;i<newXML.grandparent.(@hidden == false).length();i++){
  delete newXML.grandparent.(@hidden == false)[0];
}
invertedSpear
+1  A: 

You could use a recursive function like this assuming your XML is in a variable myXML. Doing it this way, you would not be tied to the name of your elements (ie. grandParent, parent, child) and you would not be restricted in the number of levels (ie. you could add a <pet> node to each <child> node.)

public function removeElements( avXml:XML, avAttributeName:String, avCondition:String) {

    var lvAttributeValue:String;
    var lvXml:XML;

    var lvXmlList:XMLList = new XMLList();
    for each( lvXml in avXml.children() ) {
        lvAttributeValue = lvXml.attribute( avAttributeName );
        if( lvAttributeValue == avCondition )
            lvXmlList += lvXml;

        avXml.setChildren( lvXmlList ); 
    }

    for each( var lvXmlChild:XML in avXml.children() ) {
        removeElements(lvXmlChild,avAttributeName,avCondition);
    } 
}


removeElements(myXML, "hidden", "false");
trace(myXML.toXMLString());

 <root hidden="false">
      <grandParent GPid="1" hidden="false">
        <parent Pid="1" hidden="false">
          <child Cid="1" hidden="false"/>
        </parent>
        <parent Pid="2" hidden="false">
          <child Cid="3" hidden="false"/>
          <child Cid="4" hidden="false"/>
        </parent>
      </grandParent>
      <grandParent GPid="2" hidden="false">
        <parent Pid="3" hidden="false"/>
      </grandParent>
    </root>
sberry2A
I see what you're doing here. Any idea if the recursive function is more or less efficient than the delete loops in my answer?
invertedSpear
The recursive function is around 30 - 50 times more efficient. Running your code 50 times with this as the intial XML http://pastebin.com/f5f2e944d takes 110ms average. Mine takes 3ms average.
sberry2A
You can improve the speed of your code to take about 20ms average by just reversing the order of your 3 for each loops (so loop on grandParent first, then parent, then child). If you don't understand why this boosts the speed let me know and I can explain. Of course the relative increase is wholly dependent on the number of grandParent and parent nodes with hidden = "true". If none of them have hidden = "true" then your code does not run any faster by reordering your for each loops.
sberry2A
I see why the reverse is so much faster, eliminating the nodes = less to children to loop through on the next round. Thanks for the explination.
invertedSpear