eggPlant crashes while working with trees/xml


i run into a problem while working with xml. i try to copy child nodes from one parent to an other parent like this:

repeat with childNode = each item of (the _children of sourceNode)
	insert childNode into destNode
end repeat	

the code works fine, but if i try to put this code into a seperate function like this:

function copyChildNodes(sourceNode, destNode)
	repeat with childNode = each item of (the _children of sourceNode)
		insert childNode into destNode
	end repeat
end function

and i call this function like

do copyChildNodes(aNode, aSecondNode)

eggPlant crashes on the line

insert childNode into destNode

-> so what i am doing wrong??

But maybe i think too difficult -> is it possible to insert new nodes deeper than into the first level?
I want to create a beautiful XML structure like


but the insert command is only able to insert new nodes under the root node or do i miss something? the chapter “adding children to a tree” is very short…


Yes, you can easily insert nodes at any level of a tree. Your code was on the right track-- if you hadn’t run into that bug you probably would have got it very soon.

I’ve created a modified version of your handler that you can use. But first I thought it might be helpful to take a look at some of the ways to put together a nice multi-level tree. One way is to first construct the data in the tree using SenseTalk’s ordinary lists and property lists. For example:

// create a tree from a nested list/propertyList structure:
set book1 to {book: {
		(author: ((firstName:"Franz"), (lastName:"Kafka"))),
		(title:"The Metamorphosis")
	} } as tree
put book1 -- see what this tree looks like in XML

Here, I’ve set book1 to a property list containing a list of property lists. The first inner property list contains a property “author” whose value is another list of property lists. This sort of nesting could be carried out to any level, and is an easy way to build a tree in one shot.

Since the data is contained in ordinary lists and property lists, you can manipulate them just as you would any other list (using the insert and delete commands, for example) before turning the entire structure into a tree for rendering as XML.

Now, let’s go through the process of constructing a similar tree (for another book) one step at a time. First, create the top level tree:

set book2 to an empty tree 
set book2's _tag to "book"
// or we could have just said: set book2 to "<book>" as a tree
put book2 -- take a look at it

Next, insert some nodes at the top level within the tree:

insert "<author>" into book2
insert "<title>The Wonderful Wizard of Oz</title>" into book2
put book2 -- see what it looks like now

Note that you can also convert a tree back to an ordinary object structure. This lets you use the data in whichever form is most convenient for you at any point in your script. Displaying a tree as an object may also be useful in order to learn how to construct a tree from objects.

put "As an object:", book2 as object

Finally, let’s insert some nodes at a deeper level in the tree, using either “item” or “node” to refer to the node we want to insert into. This code adds firstName and lastName subnodes within the empty author node:

insert "<firstName>L. Frank</firstName>" into item 1 of book2
insert "<lastName>Baum</lastName>" into node "author" of book2

Now that we’ve created two book trees, let’s create a containing tree and insert both subtrees into it. First, create a new “library” tree and put book1 in directly as a child of the new tree:

set myLibrary to (_tag:"library", _children:book1) as tree
put "My Library:", myLibrary, ""

Then, put book2 in the library by using “insert” to add it, and take a look at the library as both XML and in object form:

insert book2 into myLibrary
put "My Library (bigger):", myLibrary, ""
put "My Library as an object:", myLibrary as object, ""

Finally, let’s revisit your copyChildNodes function. I’ve rewritten it as a “to” handler, since you’ll probably want to call it as a command rather than as a function. Here’s how you can use it to copy the children of one tree into another tree:

set yourLibrary to "<library>" as tree

copyChildNodes myLibrary, @yourLibrary 
put "Your Library:", yourLibrary, ""

That will copy all of the books from myLibrary into youLibrary. For this to work (and also to avoid the bug) you need to pass a reference to the tree that will receive the copies (just put “@” or “reference to” before the variable holding the destination tree).

You can also use this to copy nodes into a more deeply nested part of a tree, like this:

set bigLibrary to (_tag:"library", _children:("<fiction>", "<nonFiction>")) as a tree
put "Big Library (empty):", bigLibrary, ""

copyChildNodes yourLibrary, @node "fiction" of bigLibrary --OR: @item 1 of bigLibrary
put "Big Library (with fiction books):", bigLibrary, ""

Here’s the new copyChildNodes handler. The only real change I made was to add a check to make sure the destination was passed in by reference:

to copyChildNodes(sourceNode, destNode) 
	if destNode is not a reference then
		throw "Error", "destination must be passed by reference"
	end if
	repeat with childNode = each item of (the _children of sourceNode) 
		insert childNode into destNode 
	end repeat 
end copyChildNodes

XML trees can be complex structures, and I find working with them is often confusing. I usually end up working my way in slowly, one step at a time and displaying the result at each step in order to be sure I know which part of the structure I’m dealing with.

I’ve added the example script containing all the code presented here as an attachment so you can step through it line by line and get a better feel for what it’s doing.