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  |  Permalink  |  Other Searches  |  Print Page


You Might Also Be Interested In:



Learning ColdFusion 9 - ColdFusion 9 tutorials, samples, examples, demos

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 »
6,516 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 »
6,516 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 »
6,516 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 »
6,516 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 »
6,516 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
Nov 20, 2009 at 11:32 PM
Five Months Without Hungarian Notation And I'm Loving It
I've used headless camel case for years for not only ColdFusion variables, but also SQL tables and fields... pretty much everything involving code. I also subscribe to the "don't abbreviate and clea ... read »
Nov 20, 2009 at 11:00 PM
Five Months Without Hungarian Notation And I'm Loving It
@Marcel, Yeah, I always err on the side of longer but more readable variable names. As for the camel casing of CF methods and the headless camel casing of custom items, I get around this by always ... read »
Nov 20, 2009 at 10:56 PM
Five Months Without Hungarian Notation And I'm Loving It
I use the following and love it: my.namespace.MyComponents.functionMethodsOrUDF() CONSTANT_VALUES_OR_PROPERTIES One thing I always try is to CamelCaseBuiltInColdFusionFunctions() so others can tell ... read »
Nov 20, 2009 at 5:38 PM
Learning ColdFusion 8: CFImage Part I - Reading And Writing Images
Hi Ben, Great article. I've been looking around to see if ColdFusion image engine can programatically create the following "wrap around" effect: http://www.creativepro.com/article/photoshop-s-she ... read »
Nov 20, 2009 at 5:35 PM
Maintaining ColdFusion Sessions Across SMS Text Message Requests Without Cookies
@Dave: I talked to Gert he suggested: <cfhttp method="get" url="http://{some cf website}" result="stuff" addtoken="yes" /> Note the addition of cfhttp attribute addtoken. That should persist y ... read »
Nov 20, 2009 at 5:23 PM
Maintaining ColdFusion Sessions Across SMS Text Message Requests Without Cookies
@Todd, Ahh, gotcha, yeah that makes sense. ... read »
Nov 20, 2009 at 5:17 PM
Maintaining ColdFusion Sessions Across SMS Text Message Requests Without Cookies
Ben, sorry if I didn't make this clear. You can make it work like that if you want, just put <cfset session.foo = 1> (and <cfset application.foo = 1>) in your OnRequestStart() and it reve ... read »