Building A ColdFusion XML Document From Scratch

Posted May 14, 2007 at 2:27 PM by Ben Nadel

Tags: ColdFusion

This is a basic exploration of the ColdFusion XML functions and methodologies that can be used to construct a ColdFusion XML document object model from scratch. I am doing this, not because it is ground breaking, but simply because I have never done it before and it really is something that I should know how to do. Here is my exploratory code - it uses XmlNew() to generate a new XML DOM (document object model) and then other methods and properties to flesh it out:

  • <!--- Create a new XML girl object. --->
  • <cfset xmlGirl = XmlNew() />
  •  
  • <!---
  • Create a root xml node under which every
  • other XML node for this document will reside.
  • Notice that we have to create this new root
  • node in the context of our existing XML document
  • so that the document owner is properly set.
  • --->
  • <cfset xmlRoot = XmlElemNew( xmlGirl, "", "girl" ) />
  •  
  • <!---
  • Our new xml node is now owned by the girl
  • document, but it is not yet part of the DOM. We
  • need to explicitly set the root XML node of the
  • girl to point to our newly created XML node.
  • --->
  • <cfset xmlGirl.XmlRoot = xmlRoot />
  •  
  •  
  • <!---
  • Create a node to hold information about her
  • personality (ex. smart, funny, kind). This
  • will be a child of the root node.
  • --->
  • <cfset xmlPersonality = XmlElemNew( xmlGirl, "", "personality" ) />
  •  
  • <!--- Append the personality to the root. --->
  • <cfset ArrayAppend(
  • xmlRoot.XmlChildren,
  • xmlPersonality
  • ) />
  •  
  •  
  • <!---
  • Create a node to hold information about her body
  • (ex. measurements, color, etc). This will be a
  • child of the root node.
  • --->
  • <cfset xmlBody = XmlElemNew( xmlGirl, "", "body" ) />
  •  
  • <!--- Append the body to the root. --->
  • <cfset ArrayAppend(
  • xmlRoot.XmlChildren,
  • xmlBody
  • ) />
  •  
  •  
  • <!---
  • Now, that we have the basic containers down for
  • this XML document, we are going to flesh out the
  • sub structures.
  • --->
  •  
  •  
  • <!---
  • First, we are going to create some properties for
  • the personality. These are going to consist of
  • attribute-driven data values.
  •  
  • NOTE: We cannot just use the reference to xmlPersonality
  • that we generated above. This does not actually point
  • to the XML node that we need to update.
  • --->
  • <cfset xmlRoot.Personality.XmlAttributes.Fun = true />
  • <cfset xmlRoot.Personality.XmlAttributes.Happy = true />
  • <cfset xmlRoot.Personality.XmlAttributes.Nice = true />
  • <cfset xmlRoot.Personality.XmlAttributes.Generous = false />
  • <cfset xmlRoot.Personality.XmlAttributes.Evil = false />
  •  
  •  
  • <!---
  • Next, we are going to create some properties for the
  • body. These are going to consist of attribute-
  • driven data values.
  •  
  • NOTE: We cannot just use the reference to xmlBody
  • that we generated above. This does not actually point
  • to the XML node that we need to update.
  • --->
  • <cfset xmlRoot.Body.XmlAttributes.Hair = "Blonde" />
  • <cfset xmlRoot.Body.XmlAttributes.Eyes = "Brown" />
  • <cfset xmlRoot.Body.XmlAttributes.Bust = 36 />
  • <cfset xmlRoot.Body.XmlAttributes.Waist = 24 />
  • <cfset xmlRoot.Body.XmlAttributes.Hips = 36 />
  •  
  •  
  • <!--- Dump out the resultant XML document object. --->
  • <cfdump
  • var="#xmlGirl#"
  • label="xmlGirl XML DOM"
  • />

When all is said and done, here is a CFDump of the resultant ColdFusion XML document:


 
 
 

 
Creating A ColdFusion XML Document From Scratch  
 
 
 

Then, if we call ToString() on the resultand DOM, we get:

  • <?xml version="1.0" encoding="UTF-8"?>
  • <girl xmlns="">
  •  
  • <personality
  • EVIL="false"
  • FUN="true"
  • GENEROUS="false"
  • HAPPY="true"
  • NICE="true"
  • xmlns=""
  • />
  •  
  • <body
  • BUST="36"
  • EYES="Brown"
  • HAIR="Blonde"
  • HIPS="36"
  • WAIST="24"
  • xmlns=""
  • />
  •  
  • </girl>

That was relatively easy to work with. That'll do ColdFusion... that'll do.




Reader Comments

May 14, 2007 at 3:56 PM // reply »
20 Comments

Here's an alternate method that I use a lot. I prefer this way because it helps me if I can see the tag structure.
-------------------------------------------------------------------------------

<cfsavecontent variable="xsl">
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">

<xsl:output method="xml" omit-xml-declaration="yes"/>

<xsl:strip-space elements="*"/>

<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>

</xsl:stylesheet>
</cfsavecontent>

<cfxml variable="xmlGirl>
<cfoutput>
<?xml version="1.0" encoding="UTF-8"?>
<girl>
<personality>
<evil>true</evil>
<fun>true</fun>
<generous>false</generous>
<happy>true</happy>
<nice>true</nice>
</personality>
<body>
<eyes>brown</eyes>
<hair>blonde</hair>
<hips>36</hips>
<waist>24</waist>
<bust>36</bust>
</body>
</girl>
</cfoutput>
</cfxml>

<cfcontent variable="#ToBinary(ToBase64(XMLTransform(xmlGirl,xsl)))#" type="text/xml" />


May 14, 2007 at 3:58 PM // reply »
14 Comments

Is there a reason why you are assigning things to a variable, and then putting them into your xml document?

Why do
1) xmlRoot = XmlElemNew( xmlGirl, "", "girl" )
2) xmlGirl.XmlRoot = xmlRoot

When you could just do
1) xmlGirl.XmlRoot = XmlElemNew( xmlGirl, "", "girl" )

??


May 14, 2007 at 4:07 PM // reply »
10,640 Comments

@Matt,

That's cool looking. I really do need to learn more about XSLT. My only issue (other than not know XSLT) was that I was trying to create the XML document without using tags... I agree that tags are WAYYYYY better as you can easily see the structure - but I have done that before. I have never used XmlNew() before this.

@Rich,

I like to break things up into steps because I find it is easier to follow the individual steps. You might lose some sense of the "overall" scope of the problem, but I like to attack the problems individually. For instance, in my example, I am performing 1) Node creation, and 2) Node setting in two steps and explaining them individually... you are doing both of those in a single line of code. It's just a personal preference, but I feel like breaking them apart is slightly better for teaching because it's less you need to understand per code-line.

Sorry if that didn't make any sense.


May 14, 2007 at 5:03 PM // reply »
14 Comments

I can understand that (for teaching purposes). When actually writing something to use this, it seems easier to me to just do it in one line and not have to worry about value/reference issues and remembering to assign things back to your xml object in a second line.

One other note (maybe this is more style based as well)...

Instead of:
xmlRoot.Personality.XmlAttributes.Fun = true
I tend to use:
StructInsert(xmlRoot.PersonalityXmlAttributes, "Fun", true);

This essentially does the same thing, but after spending some time troubling to troubleshoot some weird errors (I have a process that creates a custom xml "file" in memory, then uses that xml transformed with xsl to write CF files), I started doing the second instead of the first to be able to control the case of the xml attributes. Not sure why, but no matter how you type the attribute name in the first example, it always ended up with each letter capitalized (which broke my xsl, which was looking for a specific case of the attribute apparently??). The second example allowed me to control exactly how the attribute name was written out.

Hope that helps somebody else.


May 14, 2007 at 5:12 PM // reply »
10,640 Comments

@Rich,

That is good to know about the case of the tag name when using StructInsert(). I did notice that they were call coming out upper cased in my CFDumps. I figured since CF isn't case sensitive it doesn't matter... but I guess when dealing with XML, more things are case sensitive, including this XSLT that you use.

That is a really good tip to know. Thanks.


May 15, 2007 at 3:02 AM // reply »
8 Comments

Even though I love CF, I have found a really nice Java Library called JDOM to do these things, which, if you put the jar files in your server you can do things in a much nicer (and faster!) way.

check it out!

http://www.jdom.org/


May 15, 2007 at 7:30 AM // reply »
10,640 Comments

@Mark,

That's funny you mention is because my recent XML exploration was triggered by someone asking me about JDOM. I don't know anything about it, but it made me realize that I haven't done too much with XML either. I hear good stuff about this JDOM. Thanks for the link. I will check it out.


Ron
May 16, 2007 at 9:52 AM // reply »
1 Comments

A while ago I had to create an xml document using the described method. That worked very well. The only problem I had was adding a stylesheet to the xml document.
I ended up replacing the first node name, with my stylesheet and adding the first node name again.

Something like:
<cfset xmldoc = replaceNocase(xmldoc, '<rootnode>', '<?xml-stylesheet type="text/css" href="/default.css" ?>
<rootnode>, 'ONE')>

I'm sure there's a better method....... i hope?


May 17, 2007 at 6:53 PM // reply »
10,640 Comments

@Ron,

I am not sure how you get/set the style sheet node with the API. I am trying to look into it, but not coming up with much.


May 2, 2010 at 11:06 AM // reply »
4 Comments

Have there been any improvements to the treatment of XSL in CF's XML cfscript functions? It seems like such an obvious oversight.

I just finished conversion of a bunch of nasty cfset calls that built up XML to a more elegant XMLnew() scripted solution only to find that now I can't seem to jam the XSL in there before pushing to the browser. Grrr.


May 3, 2010 at 9:12 AM // reply »
10,640 Comments

@Charles,

I am not exactly sure what you mean? Are you asking me if more XSLT functionality is supported in recent versions of ColdFusion? Or, are you asking me if there is an easier way to build up XML is CFScript?


May 3, 2010 at 11:14 AM // reply »
4 Comments

@Ben,

The primary question should have been "Do newer versions of CF support the inclusion of a XSLT spreadsheet when building XML within ColdFusion cfscript?"

Ron's solution works (thanks Ron) and got me through a weekend of coding, but like many XML features in CF, and as part of your second question...

I am often finding I have to move away from the XML functions to CF functions to do things that really should be native to the XML functions themselves. Like getting the count of child nodes, existence of items in the path, etc. Constantly having to 'backtrack' my brain to reference the XML as array in code is just a little taxing at times. They could make things a little easier to reference. The last part is me just complaining though!


May 3, 2010 at 11:54 AM // reply »
10,640 Comments

@Charles,

I am sorry, I still don't fully understand your main question. You should be able to access the XmlTransform() method within your CFScript blocks the same way you do in tags. And, XML is just string values, so I can't see any reason why XSL or XML would not be viable options.

As for upgrades to XPath queries, CF8 definitely did add some more support, but I am not sure what exactly. I know you can reference indicies in child notes in the predicates:

/nodeName[ 3 ]/

I think as of CF8, count() is also supported. I did do a bit of exploration a while back:

http://www.bennadel.com/blog/1018-XPath-Support-Expanded-In-ColdFusion-8.htm

... does that help at all?


Aug 24, 2010 at 10:04 AM // reply »
3 Comments

Hi Ben,
Great article!!

I was wondering if you may have run into this issue:

I am making an xml file by looping over db content, then saving the file to the server.

The problem I am having is the content of xml file is mashed up and not in any readable format to me as well as xml validations.

for example there is a date field in my xml and it gets wrapped to the next line of the xml file and the validation is saying the data is invalid because the data starts on a new line without a opening tag.

I am using cfscript to write out my xml

xo.xmlRoot.XMLChildren[i] = XmlElemNew(xo,"url");
xo.xmlRoot.XMLChildren[i].XMLChildren[1] = XmlElemNew(xo,"loc");

.....

then a cffile to save the content to my xml file.
when viewed raw in notepad its all bunched up and crammed together.

Any help would be great

Thanks
Tim


Aug 24, 2010 at 1:36 PM // reply »
10,640 Comments

@Tim,

I typically use the CFXML to build my XML documents these days; I find it much more straight forward, especially when building a documented based on database-driven data. Of course, it only work in tag format and it sounds like you are using CFScript.

Perhaps you need to wrap the text of the given pesky XML node in a CDATA wrapper?

<![CDATA[ ... your text ... ]]>

... that might help the line breaks work better?



Post A Comment

Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.

Please review the following issues:

Author Name:


Author Email:

Author Website:

Comment:

Supported HTML tags for formatting: <strong>bold</strong>   <em>italic</em>   <code>code</code>







  • Help Wanted - Find Your Next ColdFusion Job
InVision App - Prototyping Made Beautiful With Prototyping Tools Ben Nadel's Company - Epicenter Consulting Recent Blog Comments
Feb 10, 2012 at 7:21 PM
jQuery AJAX Strips Script Tags And Inserts Them After Parent-Most Elements
Update! Instead of $(eval(options.insertAfter)).after(data['insertData']); I now use: var ajaxNode = document.createElement('span'); var parent = $(eval(options.insertAfter))[0].parentNode; ... read »
Feb 10, 2012 at 6:18 PM
jQuery AJAX Strips Script Tags And Inserts Them After Parent-Most Elements
encountered this same, what I consider, jQuery bug last week. I'm building a site in which I load some content via AJAX. This content contains Linkedin share button placeholders which Linkedin API ne ... read »
Feb 10, 2012 at 11:30 AM
Cross-Origin Resource Sharing (CORS) AJAX Requests Between jQuery And Node.js
After you understand the concepts here, this is an awesome cheatsheet for enabling CORS in just about anything http://enable-cors.org/ ... read »
JM
Feb 10, 2012 at 9:10 AM
My Safari Browser SQLite Database Hello World Example
@Amy, Here is a very good tutorial on how to use JOIN: http://www.sqltutorial.org/sqljoin-innerjoin.aspx ... read »
Feb 10, 2012 at 4:42 AM
Building A Twitter-Inspired RESTful API Architecture In ColdFusion
This is great, very useful Ben. I spotted a small typo in the api.cgm listing: <cfthrow type="Unauthroized" /> Cheers Stefan ... read »
Feb 9, 2012 at 10:35 PM
CFDirectory Filtering Uses Pipe Character For Multiple Filters (Thanks Steve Withington)
I was wondering if there would be a filter you could apply so that you got everything but what you included in the filter. As in show me all docs that are not a .pdf. ... read »
Feb 9, 2012 at 10:29 PM
Learning ColdFusion 9: Application-Specific Data Sources
@Ben, No offence, but if people were really wanting advanced features they would be using a platform like ASP.NET MVC. CFML is so structurally compromised as a tag-based scripting language that ... read »
Feb 9, 2012 at 10:03 PM
Subversion - Cleanup Failed To Process The Following Paths
@Leviaguirre, do you still have problems with this? ... read »