As of ColdFusion MX, there are several tags and functions that make working with XML a snap. In this tutorial I am going to demonstrate how to use these tools to generate an XML document.

The first step is to write a query to get the data we want to export. We are going to export a list of books from the cfbookclub database that comes with ColdFusion.

<!--- Query the Datasource --->
<cfquery name="GetBooks" datasource="cfbookclub">
SELECT B.BookID, B.Title, B.BookDescription, B.Genre, A.FirstName, A.LastName
FROM Books B JOIN Authors A ON B.AuthorID = A.AuthorID

Now that we have our data, we want to convert it into an XML Document, and as is often the case in programming, there is more than one way to accomplish this task. ColdFusion offers two basic methods for creating XML documents and which one you choose really depends on what you like better.

The first way I will show you is to use the CFXML tag which will process the CFML between its start and end tags, then saves the output as a ColdFusion XML Document Object. This is the method I prefer to use because as you can see from the code below it is much like what we do to generate HTML output for browsers, so I find it easier to work with than the alternative.

<!--- Create an XML Document Object with CFXML --->
<cfxml variable="MyXMLDoc">
<?xml version='1.0' encoding='utf-8' ?>
   <cfloop query="GetBooks">
   <book id="#GetBooks.BookID#">
      <author>#GetBooks.FirstName# #GetBooks.LastName#</author>

<!--- Dump the XML Document Object --->
<h1>Dump from the first method (CFXML)</h1>
<cfdump var="#MyXMLDoc#">

The second way is to use xmlNew() to create a ColdFusion XML Document Object, then use XMLElemNew() to creade the necessary XML nodes. You will see from the example that each node has an XMLChildren property, which contains its child nodes. and works like a ColdFusion array, so you can use array related functions to interact with it. Each node also has an XMLAttributes property that you can interact with like you would a ColdFusion structure. Additionally, each node has a XMLText property which you can use to set the text that goes between that nodes start and end tags.

<!--- Create a ColdFusion XML Document Object --->
<cfset MyXMLDoc = xmlnew()>

<!--- set the XMLRoot to books --->
<cfset MyXMLDoc.XMLRoot = XMLElemNew(MyXMLDoc,"books")>

<cfloop query="GetBooks">
   <!--- Add book node for each query row --->
   <cfset MyXMLDoc.books.XmlChildren[currentrow] = XmlElemNew(MyXMLDoc,"book")>
   <!--- set the id attribute in the book node --->
   <cfset MyXMLDoc.books.XmlChildren[currentrow] = "#GetBooks.BookID#">
   <!--- create the child nodes for the book --->
   <cfset arrayappend(MyXMLDoc.books.XmlChildren[currentrow].xmlChildren, XmlElemNew(MyXMLDoc,"title"))>
   <cfset MyXMLDoc.books.XmlChildren[currentrow].title.XMLText="#GetBooks.Title#">
   <cfset arrayappend(MyXMLDoc.books.XmlChildren[currentrow].xmlChildren, XmlElemNew(MyXMLDoc,"description"))>
   <cfset MyXMLDoc.books.XmlChildren[currentrow].description.XMLText="#GetBooks.BookDescription#">
   <cfset arrayappend(MyXMLDoc.books.XmlChildren[currentrow].xmlChildren, XmlElemNew(MyXMLDoc,"genre"))>
   <cfset MyXMLDoc.books.XmlChildren[currentrow].genre.XMLText="#GetBooks.Genre#">
   <cfset arrayappend(MyXMLDoc.books.XmlChildren[currentrow].xmlChildren, XmlElemNew(MyXMLDoc,"author"))>
   <cfset MyXMLDoc.books.XmlChildren[currentrow].author.XMLText="#GetBooks.FirstName# #GetBooks.LastName#">

<!--- Dump the XML Document Object --->
<h1>Dump from the second method (XMLNew() & XMLElemNew())</h1>
<cfdump var="#MyXMLDoc#">

You can use the toString() function to convert the XML document object to an XML string that can be saved as a file, inserted into a database, submitted to an API, or whatever you need to do with it.

<!--- Use the toString() function to convert the XML Document Object to an XML string --->
<h1>Dump of the toString() function</h1>
<cfdump var="#toString(MyXMLDoc)#">

As you can see from the results of the cfdumps, either of these methods will result in the same output, so you can pick whichever is more comfortable for you.

Related Blog Entries

Comments (Comment Moderation is enabled. Your comment will not appear until approved.)
Bruce's Gravatar When you want to use CF to output XML that will be consumed by other technologies (Flex, ajax, etc) then you may need to ensure that the browser or flash runtime correctly recognizes the output as XML.

It's my understanding that there can be no output to the browser prior to the <?xml tag. So I use the cfprocessingdirective tag to suppress whitespace.

I also use the CFContent tag and its type and reset attributes just before outputting the XML.

Lastly you may want to use the caseSensitive attribute of the CFXML tag if the consumer of the XML needs to have the XML element names in a specific case.



# Posted By Bruce | 11/21/07 5:41 PM
Scott Bennett's Gravatar That's a good point. Whenever you are generating XML, you need to keep your audience in mind when it comes to what you do with the resulting XML string. For example, if you were using ColdFusion to generate an RSS feed or a Google sitemap or something like that, which is accessible to someone performing an HTTP request against your server, you will want to follow Bruce's advice and make sure there is no leading whitespace before the <?xml tag in the page results. If you are saving the XML to a file or using CFHTTP to post the XML string to a web service then using #toString(MyXMLDoc)# in your CFFile or CFHTTPPARAM tag will work for you.
# Posted By Scott Bennett | 11/21/07 7:57 PM
Brett Harnett's Gravatar I have used this technique to pull a string, how can I put that in a
RSS format? (using Dreamweaver)
# Posted By Brett Harnett | 3/1/10 4:09 PM
Home | Blog | Portfolio | Contact | © 2001 - 2007 The ColdFusion Guy - Scott Bennett. All rights reserved.
BlogCFC was created by Raymond Camden. This blog is running version 5.9.