My First ColdFusion XML / XSLT Example

Posted September 6, 2007 at 2:05 PM by Ben Nadel

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:

  • <!--- 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!


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 »
11,246 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 »
11,246 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 »
11,246 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 »
11,246 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 »
11,246 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 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
Ben Nadel's Company - Epicenter Consulting Recent Blog Comments
May 24, 2013 at 5:39 PM
Ask Ben: Manually Enforcing Basic HTTP Authorization In ColdFusion
@Adam Oops! My mistake! I hadn't gotten that far in my testing - I'm still baby stepping my way through the process. ... read »
May 24, 2013 at 5:13 PM
Ask Ben: Manually Enforcing Basic HTTP Authorization In ColdFusion
Hi Jason, Thanks for checking up on that, but I still stand firm on my position. :) There are actually two listLast()'s in use, and you're right that the one using a space as a delimiter is fine. ... read »
May 24, 2013 at 4:45 PM
Ask Ben: Manually Enforcing Basic HTTP Authorization In ColdFusion
@Ben I have been lurking your site for quite some time, and haven't stepped up to comment until today. Thanks for all the great info - keep it up! @Adam I believe you are mistaken... as the commen ... read »
May 24, 2013 at 11:21 AM
Strange Interaction Between DeserializeJson(), ArrayContains(), And Database Values In ColdFusion
@WebManWalking, Ha ha, let's us never speak of justifying "##" notation again :P ... read »
May 24, 2013 at 11:18 AM
Strange Interaction Between DeserializeJson(), ArrayContains(), And Database Values In ColdFusion
@Ben, Ah, so it was indeed how I vaguely remembered it to be: A direct assignment value = users.id[ i ] causes value to retain the sticky datatype of the query column. Although unnecessary in ... read »
May 24, 2013 at 9:11 AM
Preventing Links In Standalone iPhone Applications From Opening In Mobile Safari
@Brandon, Hi, No, I haven't been able to do that. I have just kept it as it is. ... read »
May 23, 2013 at 9:52 PM
Preventing Links In Standalone iPhone Applications From Opening In Mobile Safari
@Muhmmadibn Did you figure out a solution to launching PDFs? I am running into the same issues myself. There is no way to close the PDF or go back once you launch it. Thanks in advance! ... read »
May 23, 2013 at 6:06 PM
The Girl Who Broke My Heart, And Made Me A Better Person
Good day,ladies and gentle men, my name is Dr AMADI the great spell caster in Africa, i have help so many people for different kind of problems,who say there is no solution to problems on earth, that ... read »
InVision App - Prototyping Made Beautiful With Prototyping Tools