Question

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 ((child.@x.length() == 1) && (child.@y.length() == 1) && (child.@width.length() == 1) && (child.@height.length() == 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.

Was it helpful?

Solution

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

OTHER TIPS

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top