Ask Ben: Selecting Node Attributes In XSLT Based On List Values In ColdFusion

Posted November 9, 2009 at 10:02 AM

Tags: ColdFusion, Ask Ben

Ben, do you know how to check to see if a xml attribute is in a list? I'm looking at the contains() function, but I'm not sure of the correct syntax or if there is a better way, but I cant seem to get this to work. I don't know how to reference the value of the @system as the second argument of the contains. Can I used something like 'this' (minus quotes). Also, I have yet to really find a way to use variables in the match and selects of an xsl file. I've read some things on using another namespace and then using a node-set() function (until cf handles xslt 2.0)?

As you are probably finding out, ColdFusion's current implementation of XSLT is somewhat limited. If you take the list of XSLT and XPath functions listed on the web and try to get them to work in a ColdFusion XML transformation, you'll quickly find out that many of them are not supported. One that does work however, as you mentioned, is the contains() function. As we have seen before, though, this method is case sensitive; as such, you have to make sure that the values used with this function are strictly formatted.

With the contains() function, the first argument is the source value and the second argument is the substring for which you are testing. As such, calling:

contains( 'benjamin', 'ben' )

... would return True as the string "ben" is contained within the source string, "benjamin." Notice, however, that this is not using any sense of value deliniation - it's a substring or it isn't. When doing simple tests, this is not a problem; but, when you are dealing with lists of values, you run the risk of getting a false positive. To help compensate for this, we can add our own delimiters to the list and then make sure our substring also contains those delimiters:

contains( '-benjamin-', concat( '-', 'ben', '-' ) )

This time, the contains() function call would return False since the value, "-ben-" is no longer a substring of the source value, "-benjamin-."

NOTE: XSLT and XPath have list-based functions, but they are not supported by ColdFusion's current XSLT engine.

With that in mind, let's take a look at a small example:

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

  • <!--- Create our XML data. --->
  • <cfxml variable="girls">
  •  
  • <girls>
  • <girl type="cute">
  • <name>Sarah</name>
  • </girl>
  • <girl type="athletic">
  • <name>Tricia</name>
  • </girl>
  • <girl type="hot">
  • <name>Katie</name>
  • </girl>
  • <girl type="cute">
  • <name>Libby</name>
  • </girl>
  • </girls>
  •  
  • </cfxml>
  •  
  •  
  • <!--- Create the XSL tranformation. --->
  • <cfsavecontent variable="xslt">
  •  
  • <!--- Document type declaration. --->
  • <?xml version="1.0" encoding="ISO-8859-1"?>
  •  
  • <!--- Define the transformation. --->
  • <xsl:transform
  • version="1.0"
  • xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  •  
  •  
  • <!--- Match the root girls node. --->
  • <xsl:template match="/girls">
  •  
  • <girls>
  •  
  • <!---
  • Copy each GIRL node if the TYPE attribute
  • is contained within the given list: hot or
  • athletic.
  •  
  • NOTE: We are wrapping the TYPE attribute in
  • list delimiters to cut down on the chance of
  • a substring giving us a false positive.
  • --->
  • <xsl:copy-of
  • select="./girl[ contains( '-hot-athletic-', concat( '-', @type, '-' ) ) ]"
  • />
  •  
  • </girls>
  •  
  • </xsl:template>
  •  
  • </xsl:transform>
  •  
  • </cfsavecontent>
  •  
  •  
  • <!--- Transform the document. --->
  • <cfset newGirls = xmlParse(
  • xmlTransform( girls, trim( xslt ) )
  • ) />
  •  
  • <!--- Output the new girls. --->
  • <cfdump
  • var="#newGirls#"
  • label="Hot Girls"
  • />

Here, we are creating an XML document of girl nodes and then transforming it into another XML document that contains only girls that are "hot" or "athletic". And, as you can see, the filtering of the girl nodes is done using the following contains() function call:

contains( '-hot-athletic-', concat( '-', @type, '-' ) )

Each value in our list is wrapped in a delimiter to help prevent false positive. And, when we run this code, we get the following output:

 
 
 
 
 
 
Working With Lists In ColdFusion XSLT. 
 
 
 

As you can see, this worked nicely. As a note on this, when you are in the middle of a "select" statement, the "this" reference is implied as the node currently being examined. As such, within our contains() function call, the attribute reference "@type" correctly references the attribute of the current "girl" node being collected.

I hope this points you in the right direction. You mentioned in your question the EXSL extension library. I have never heard of this, but I just did a bit of experimentation with the node-set() method and it seems very interesting. I'll probably follow up with another blog post on that topic shortly.

Download Code Snippet ZIP File

Post Comment  |  Ask Ben  |  Other Searches  |  Print Page




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

Reader Comments

Nov 10, 2009 at 2:32 AM // reply »
4 Comments

Ben!

I tried the code.working fine. very interesting.
Its cute n hot:)

Keep Rocking

Thanks,
Raghuram Reddy Gottimukkula
http://raghuramcoldfusion.blogspot.com/
Adobe Certified Coldfusion Developer
Bangalore India


Nov 10, 2009 at 7:57 AM // reply »
7,572 Comments

@Raghuram,

Thanks! The person asking the question actually brought up a library that I knew nothing about; I'll try to write up something about it today or tomorrow as a follow-up.


Post Comment  |  Ask Ben

Recent Blog Comments
Mar 19, 2010 at 7:26 PM
MySQL 3/4 - com.mysql.jdbc.Driver And allowMultiQueries=true
Thank you very much for this post. Adding allowMultiQueries="true" in context.xml didn't help until I added it to url as allowMultiQueries=true Good idea is to use prepared statements and it will he ... read »
Jim
Mar 19, 2010 at 4:49 PM
Nobody Puts Baby In The Corner!
Wow. This is like suddenly finding a support group for your secret shame. I'm not alone! I always liked this movie, even though it is extremely cheesy. I just wish Jennifer Grey hadn't gotten the ... read »
Mar 19, 2010 at 4:47 PM
Application.cfc OnRequest() Method Affects OnError() Arguments
@Jason and @Ben, I've been doing some CF9 refactoring on our systems and noticed an odd occurrence with onError as well. Found a way to work around my problem, but what I saw was... Background: Our ... read »
Jim
Mar 19, 2010 at 4:44 PM
Shoot 'Em Up Starring Clive Owen And Paul Giamatti
I actually enjoyed this movie quite a lot. It was different, certainly, but I think they were going for more of a Quentin Tarentino-"wow, that was weird"-vibe than an actual spoof. Once I realize ... read »
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 »