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 »
3 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,212 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
Feb 9, 2010 at 8:09 AM
Creating A "Remember Me" Login System In ColdFusion
@Nikos, Heck yeah! Glad you got things working smoothly. ... read »
Feb 9, 2010 at 8:05 AM
Creating A "Remember Me" Login System In ColdFusion
No probs :) anyway , Im good now :) ... read »
Feb 9, 2010 at 8:02 AM
Creating A "Remember Me" Login System In ColdFusion
@Nikos, I've seen people use the J2EE sessions, but I have not used them myself... yet. ... read »
Feb 9, 2010 at 7:57 AM
Ask Ben: Converting a Query to an Array
@Stju, Did you actually test this? I ask because there is a fatal flaw in it - you are using the same Row struct for every row. Since Structs are passed by reference, every subsequent update you ma ... read »
Feb 9, 2010 at 7:50 AM
Using jQuery's SlideUp() and SlideDown() Methods With Bottom-Positioned Elements
@Thomas, Not bad. I suppose you could do the same with Top as well as margin. ... read »
Feb 9, 2010 at 7:47 AM
Ask Ben: Creating A PDF And Attaching It To An Email Using ColdFusion
@Johan, I don't think I have one off hand. Basically, you'd just want to use the File attribute of CFDocument to save the PDF to disk. Then, you'd want to use the File attribute of CFMailParam to a ... read »
Feb 9, 2010 at 5:34 AM
Creating A "Remember Me" Login System In ColdFusion
Any change you could show how to take advantage how the J2ee session stuff in your code? http://kb2.adobe.com/cps/182/tn_18232.html ... read »
Feb 9, 2010 at 5:32 AM
Creating A "Remember Me" Login System In ColdFusion
This may help: http://bugs.farcrycms.org/browse/FC-79 Its the session variables' option being selected in the CF Admin ... read »