My First ColdFusion XML / XSLT Example

Posted September 6, 2007 at 2:05 PM

Tags: ColdFusion

Over the past few months, I have been learning a lot about XML and especially the use of XPath in ColdFusion. As a natural extension of that, I felt it was time to look into some ColdFusion XML Transformation stuff in the form of XSLT. I don't know anything about it other than I looked at it a long time ago and thought the syntax was just silly. Part of that may have influenced by the fact that I didn't understand XPath, so I thought it was worth re-examining.

As with any new learning endeavour, I must do some sort of Hello World example to get my feet wet. In this ColdFusion XSLT demo, I am taking a small XML document containing messages and outputting them in an HTML page:

 Launch code in new window » Download code as text file »

  • <!--- Define the ColdFusion XML document object. --->
  • <cfxml variable="xmlData">
  •  
  • <messages>
  • <message id="1">
  • <text>Hello World</text>
  • </message>
  • <message id="2">
  • <text>Eating kittens is just plain wrong!</text>
  • </message>
  • <message id="3">
  • <text>Honk if you love justice!</text>
  • </message>
  • </messages>
  •  
  • </cfxml>
  •  
  •  
  • <!--- Define the XSL Transformation (XSLT). --->
  • <cfsavecontent variable="strXSLT">
  •  
  • <!--- Document type declaration. --->
  • <?xml version="1.0" encoding="ISO-8859-1"?>
  •  
  • <xsl:transform
  • version="1.0"
  • xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  •  
  • <!---
  • Bind this template to the root of the XML document
  • using the "/" match attribute.
  • --->
  • <xsl:template match="/">
  •  
  • <html>
  • <head>
  • <title>My ColdFusion XSLT Hello World</title>
  • </head>
  • <body>
  •  
  • <h1>
  • Messages
  • </h1>
  •  
  • <!--- Loop over each message node. --->
  • <xsl:for-each select="//message">
  •  
  • <p>
  • <!---
  • Output the ID of the current
  • contextual message node.
  • --->
  • <xsl:value-of
  • select="@id"
  • />:
  •  
  • <!---
  • Get the Text value of the descendent
  • TEXT node of the current contextual
  • message node.
  • --->
  • <xsl:value-of
  • select="text"
  • />
  • </p>
  •  
  • </xsl:for-each>
  •  
  • </body>
  • </html>
  •  
  • </xsl:template>
  •  
  • </xsl:transform>
  •  
  • </cfsavecontent>
  •  
  •  
  • <!--- Output the transformed XML document. --->
  • #XmlTransform(
  • xmlData,
  • Trim( strXSLT )
  • )#

A few things to notice in this example. For starters, the XML that I am passing into ColdFusion's XmlTransform() function is a full-blown ColdFusion XML document object model. According to the documentation, I could have passed in an XML string as well.

The XSLT value that I am passing in is just an XML string, but according to the documentation this could have been:

  • A string containing XSL text.
  • The name of an XSTLT file. Relative paths start at the directory containing the current CFML page.
  • The URL of an XSLT file; valid protocol identifiers include http, https, ftp, and file. Relative paths start at the directory containing the current CFML page.

You will notice that I am trimming the XSLT value as I pass it into the function. Remember, XML documents (what the XSLT document really is) cannot have white space at the beginning of them or you get that "target matching" error. However, when dealing with XmlTransform(), the error is a bit more convoluted:

A [Transformer] object cannot be created that satisfies the configuration requested. This could be due to a failure in compiling the [XSL] text. javax.xml.transform.TransformerConfigurationException: javax.xml.transform.TransformerException: org.xml.sax.SAXParseException: The processing instruction target matching "[xX][mM][lL]" is not allowed.

A bit more wordy, but same error. Trimming the XSLT XML data as you pass it in makes sure that it compiles down properly in the black box.

My XSLT Transform document contains three main parts: the base template, the node loop, and the node values. I am still learning the syntax, which feels very foreign to me, but basically, the template that matches "/" binds the template to the root node of the XML document. Then, my for-each command loops over the nodes returned by the XPath, //message, which of course selected all message nodes anywhere in the document. Within each of the loop iterations, the "context" of the loop is the current Message node; therefore, commands within the loop must be relative to the current context node. That's why my value-of commands don't need a whole lot of explanation - one gets the text value of the Text node, the other gets the text value of the attribute, ID.

Anyway, running the code above, we get the following output:

Messages

1: Hello World

2: Eating kittens is just plain wrong!

3: Honk if you love justice!

I can already see that having a good understanding of XPath is really helping me understand the XSL Transformation functionality. Not sure if I see too much of a place for this in my programming just yet, but then again, knowing this functionality will open its own doors.

Oh, and also, those last two quotes are from the TV show, The Tick :) That was a sweet show!

Download Code Snippet ZIP File

Post Comment  |  Ask Ben  |  Other Searches  |  Print Page


You Might Also Be Interested In:




Reader Comments

Sep 6, 2007 at 3:45 PM // reply »
5 Comments

Hi Ben,

Have you seen this bug in your travels with xml?

http://davequested.blogspot.com/2007_02_01_archive.html#117079695943973557


Sep 6, 2007 at 3:54 PM // reply »
7,572 Comments

@Dave,

I have posted a comment on your blog. I think I need to know more about how you are using the XML document as multiple reads should never corrupt anything??


Sep 6, 2007 at 4:40 PM // reply »
5 Comments

Hi Ben,

Just to be confusing, that "Dave" isn't me ;-)
...he is another "Dave" I know...


Sep 6, 2007 at 4:43 PM // reply »
7,572 Comments

Ok, now you confused me :) What are you talking about? You mean, that isn't your blog?


Sep 6, 2007 at 4:55 PM // reply »
5 Comments

The blog I linked to is the "other" David.
He is based in Cork, Ireland (last I heard), and he found the issue with XMLParse().

I guess when I read your blog, I thought of that "gotcha" and wondered if you had encountered it at all.

The main plan is us "David"s are going to take over the world, but don't tell anyone I told you!


Sep 6, 2007 at 5:15 PM // reply »
7,572 Comments

Ha ha. Good luck. When the revolution is over, don't forget about us little people :)


Sep 7, 2007 at 9:22 AM // reply »
42 Comments

XSLT is freakin awesome. It can be used for a lot of stuff, for example I use it as my email templates, which makes it really easy to update any email that gets sent out. A while back this saved me quite a bit of time when DOD changed to INFOCON 4 and had to change to all plain text emails. I also use XSLT for generating base DAO, gateway, and service objects. Definitely good stuff!


Sep 7, 2007 at 11:41 AM // reply »
43 Comments

XSLT is convoluted as hell, but immensely useful in a pinch. And powerful as hell.

I wrote a mini-feed reader a while back that I wanted to support RDF, RSS2 and Atom 1.0 feed formats, but I didn't want to write 3 separate parsers. I used XSLT to convert all formats into RSS2 (only the elements that were directly transferable or a reasonable approximation) and then wrote and RSS2 parser. Magic. :-)


Sep 7, 2007 at 11:44 AM // reply »
7,572 Comments

@Dustin / Rob,

Both those things sound really cool. I agree that it is convoluted, but I think in the long run it will be good to know.


Apr 4, 2009 at 7:31 AM // reply »
1 Comments

Ben,
I appreciate your example on XSLT with CF.
I'm still not sold on XSLT though. Mainly because I can't use a WYSIWYG with it, but also because I feel like XSLT does for XML the same thing that CF does for a database. And a database would do it faster.
Now, if I got hired into a company that used XML a lot, then I could see using XSLT. But even then, I could just use CF to parse it directly and skip the middleman... which bring me back to my original thought: XSLT, why do I need you?


Apr 9, 2009 at 9:35 AM // reply »
7,572 Comments

@Russ,

I think it really depends on what you want to do with it. To be honest, I very rarely use XSLT; most of the time, I just want to extract data, which ColdFusion is fantastic at. However, I have used XSLT to transform content data. If i have content that has tons of paragraphs, but I want to change P tags with a given class to some other viewlet, I find that XSLT can make this much easier that CF parsing.


Post Comment  |  Ask Ben

Recent Blog Comments
Mar 19, 2010 at 4:34 PM
An Intensive Exploration Of jQuery With Ben Nadel (Video Presentation)
Hey I guess the video is down. Is there anyway you can upload to youtube or vimeo or some other service? Greatly appreciated. ... read »
Mar 19, 2010 at 4:24 PM
ColdFusion CFPOP - My First Look
@Ben Thanks for the follow up! The root of the problem had to do with being able to trace bounced emails to specific records in a DB table. Let's say you run an email campaign and you get 1,000 bou ... read »
Mar 19, 2010 at 4:15 PM
SQL COUNT( NULLIF( .. ) ) Is Totally Awesome
Thank you Ben and Tony! Either of these work for the summary report I am working on and the info is much appreciated! I think I like Tony's a little better because I won't have to educate every ... read »
Mar 19, 2010 at 3:35 PM
ColdFusion Path Usage And Manipulation Overview
@Ben, Sorry. Clarification. expandpath worked for me in application.cfc, but not in other templates. ... read »
Mar 19, 2010 at 3:33 PM
ColdFusion Path Usage And Manipulation Overview
@Ben, Never did. Worked around it and moved on. Here is what I ended up with in onApplicationStart: // chop off "\application.cfc" application.appdir = GetCurrentTemplatePath().ReplaceFirst( "[\\\ ... read »
Mar 19, 2010 at 12:55 PM
Content Is Not Allowed In Prolog - ColdFusion XML And The Byte-Order-Mark (BOM)
Thank you! Thank you! Thank you! One more additional bit to add to this: in addition to the, "Content is not allowed in Prolog," error solved by Ben's REReplace, I was also getting, "An invalid XML ... read »
Mar 19, 2010 at 12:52 PM
Thoughts And Goals For 2010
@Ben Do bodybuilders from our generation take glucosamine supplements to strengthen joints for this type of exercise? I'm assuming in your early 30s, no? ... read »
Mar 19, 2010 at 12:46 PM
Using ColdFusion's CFLocation Tag For Inline Image SRC Attributes
@Ben, Yes, the client reads the headers and if it has a cached version of the file (same ETAG) then shuts down the request and render the cached version. ( I think it is done in the same request/co ... read »