views:

160

answers:

2

I'm in a situation where I have a xml document which is going to be updated in the following way: The deepest child within the document which surrounds a certain x,y position (depending on it's x, y, width and height attributes) is going to get a new child element. If multiple childs exist with the same depth, the bottom one is updated.

My first step was to find this deepest child, this already caused problems, but I managed to solve this with the following recursion:

//returns the deepest element which surrounds the given position
     private static function getDeepestElementAtPos(curElement:XML, depth:uint, targetX:uint, targetY:uint, totParentX:uint = 0, totParentY:uint = 0):Object
     {
      var deepestElement:Object = new Object();
      deepestElement["xml"] = curElement;
      deepestElement["depth"] = depth;

      var posDeeperChild:Object;
      for each (var child:XML in curElement.children())
      {
       if (posInsideNode(child, totParentX, totParentY, targetX, targetY))
       {
        posDeeperChild = getDeepestElementAtPos(child, depth + 1, targetX, targetY, totParentX + Number(child.@x), totParentY + Number(child.@y));
        if (posDeeperChild["depth"] > depth) deepestElement = posDeeperChild;
       }
      }

      return deepestElement;
     }

     //returns whether the given position is inside the node
     private static function posInsideNode(child:XML, offsetX:uint, offsetY:uint, targetX:uint, targetY:uint):Boolean
     {
      //if all required properties are given for an element with content
      if (([email protected]() == 1) && ([email protected]() == 1) && ([email protected]() == 1) && ([email protected]() == 1))
      {
       //if the new object is inside this child
       if ((Number(child.@x) + offsetX <= targetX) && (Number(child.@x) + offsetX + Number(child.@width) >= targetX) && (Number(child.@y) + offsetY <= targetY) && (Number(child.@y) + offsetY + Number(child.@height) >= targetY))
       {
        return true;
       }
      }
      return false;
     }

Now, the next step is to update the complete code with the updated child, as you can see here:

//creates a new object at the given location, if existing elements are at the same location this will become a sub-element
     public static function addNewObject(type:String, x:uint, y:uint):void
     {
      //get page code
      var pageCode:XML = pageCodes[curPageId];

      //get deepest element at this position
      var deepestElement:XML = getDeepestElementAtPos(pageCode, 0, x, y)["xml"];

      //define the new element
      var newElement:XML = <newElement>tmp</newElement>;

      //if it has to be added to the main tree
      if (deepestElement == pageCode)
      {
       pageCode.appendChild(newElement);
      } 
      else
      {
       //add the element to the child found earlier
       deepestElement.appendChild(newElement);

       //update the element in page code
       // ! this is where I am stuck !
      }
     }

The newElement is just temporarily for experimental purposes. I did manage to update the code if the deepest child is the main tree (so there are no matching childs). However, when there are matching childs, or childs within childs, I have no idea how to update the main tree with the updated deepest child.

The following does not work:

pageCode.insertChildAfter(deepestElement, newElement);

Because, apparently, this only works if deepestElement is a direct child of the pageCode and not a child of a child (or even futher down).

So, the question: how do I update pageCode to contain the updated deepestElement child, even if that child is a child of a child and so on?

Thanks in advance, all help is greatly appreciated.

A: 

You probably have to get the parentNode of the deepestElement and work on that node. First removing the old version of the node and then inserting the updated one. Another choice which is probably more efficient is just update the attributes and/or the value of the deepestElement without having to replace it.

for example:

var parent:XMLNode = oldDeepestElement.parentNode;
oldDeepestElement.removeNode();
parent.appendChild(newDeepestElement);

I haven't tried the code but something like this should work. In any case, as I said I would first consider changing the attributes of the node and not the node itself if this is possible.

Julio Garcia
I don't see why that would work. What if the parent node has another parent node? It could have have 100 parent nodes.
Tom
To elaborate, you're only taking 1 parent node into consideration. Even though it's possible that the child's parent has a parent too.
Tom
Maybe I missinterpreted your question, what I mean is that to work on a node, that is for example to replace it by something else, you usually locate the parent node of the one you want to change and act on it. It doesn't matter if you have 1 or 1000 parents recursively because each node has one and only inmediate parent.
Julio Garcia
A: 

I figured out that the returned node is of course actually only a reference. Meaning that if I give it a new child, the complete page code will be updated too. This works:

//creates a new object at the given location, if existing elements are at the same location this will become a sub-element
     public static function addNewObject(type:String, x:uint, y:uint):void
     {
      //get page code
      var pageCode:XML = pageCodes[curPageId];

      //get deepest element at this position
      var deepestElement:XML = getDeepestElementAtPos(pageCode, 0, x, y)["xml"];

      //define the new element
      var newElement:XML = <newElement>tmp</newElement>;

      //add the new element to the code
      deepestElement.appendChild(newElement);
     }
Tom