I have been doing some exploration with ColdFusion's XML capabilities and I came up against something very interesting. It seems that the XmlRoot node is passed by reference but any other nodes below that are passed by value. Here is a demo of this in action:
<!--- Create a blank ColdFusion XML document for actresses. ---> <cfset xmlActresses = XmlNew() /> <!--- Create a new XML node that we will use as the XML root. All other nodes in the document will live under this node. ---> <cfset xmlRoot = XmlElemNew( xmlActresses, "", "actresses" ) /> <!--- Set the new root element as the root node of our actresses DOM. ---> <cfset xmlActresses.xmlRoot = xmlRoot /> <!--- Create a new actress node element. ---> <cfset xmlActress = XmlElemNew( xmlActresses, "", "actress" ) /> <!--- Set some of the actress properties. ---> <cfset xmlActress.XmlAttributes.Name = "Maria Bello" /> <cfset xmlActress.XmlAttributes.HowSexy = "Too Sexy" /> <!--- Append the actress node to the child nodes of the root (Actresses). Notice here that we are using the xmlRoot that was generated above and the xmlActress node that we just created for Maria Bello. ---> <cfset ArrayAppend( xmlRoot.XmlChildren, xmlActress ) /> <!--- Now that we have added the new Actress node to the XML DOM, let's try to update some of its values without going back into the XML document path. ---> <cfset xmlActress.XmlAttributes.BirthDay = "18 April, 1967" /> <cfset xmlActress.XmlAttributes.Hair = "Blonde" /> <!--- Now, let's add some attributes, but this time, instead of referencing our Actress xml node, let's go back through the XML DOM. ---> <cfset xmlActresses.Actresses.Actress.XmlAttributes.Eyes = "Brown" /> <cfset xmlActresses.Actresses.Actress.XmlAttributes.Smile = "Sly" /> <!--- Now, let's dump out our actress node. ---> <cfdump var="#xmlActress#" label="xmlActress Node" /> <!--- Let's dump out our actresses XML DOM. If the nodes are passed by reference when using ArrayAppend(), then the CFDump above should be reflected in the CFDump below. ---> <cfdump var="#xmlActresses#" labe="xmlActressed DOM" />
Notice that when I append the XML node, xmlActress, to the xmlActresses document, I am using the existing node reference, xmlRoot. Also notice that the node being appended is the existing node reference to xmlActress. Since both of these nodes are valid references, it should work fine.
But now, look at what I do after that - I update the xmlActress node properties, adding the two attributes Birthday and Hair. Then, I update the "same" xml node, but this time, I go though the XML DOM, xmlActresses. If the node, xmlActress, was added by reference, then all of these CFSet tags should affect the same element.
Here is a CFDump of the xmlActress node by itself:
And, here is a CFDump of the resultant xmlActresses XML DOM:
Notice that BOTH CFDumps contain the original attributes, Name and HowSexy. These were added prior to any child node appending. Also notice that only the xmlActress has BirthDay and Hair attributes which were set directly into the Xml node reference after it was appended to the xmlActresses DOM.
So clearly, when it comes to XmlAttributes, the XML Nodes are appended by value. But what about the XmlChildren? If you look at the above code, our xmlRoot reference was able to update the resultant document. This means that xmlRoot was somehow set by reference, not by value. Perhaps, ArrayAppend() will work via references for the child nodes as well:
<!--- Now, let's try to create a child node of the actress node. This node will hold a list of all the related movies. ---> <cfset xmlMovies = XmlElemNew( xmlActresses, "", "movies" ) /> <!--- Add this movie to the existing xmlActress node reference that we created above. ---> <cfset ArrayAppend( xmlActress.XmlChildren, xmlMovies ) /> <!--- Now, let's dump out our actress node. ---> <cfdump var="#xmlActress#" label="xmlActress Node" /> <!--- Let's dump out our actresses XML DOM. If the nodes are passed by reference when using ArrayAppend(), then the CFDump above should be reflected in the CFDump below. ---> <cfdump var="#xmlActresses#" labe="xmlActressed DOM" />
Here, we are adding an xml child node, xmlMovies, to the xmlActress node. Here is the CFDump of the xmlActress node:
And, here is the CFDump of the resultant xmlActresses XML DOM:
Notice that again, the actions to update the child reference did not affect the final XML document. I wonder why xmlRoot was able to act as a reference and xmlActress was only able to act as a copy. I see that xmlRoot was set using "=" operator and the other via ArrayAppend()... but, any value that cannot be passed by reference is copied no matter what operator is used (sort of).
Want to use code from this post? Check out the license.