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

Posted November 9, 2009 at 10:02 AM by Ben Nadel

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:

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




Reader Comments

Nov 10, 2009 at 2:32 AM // reply »
12 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 »
11,246 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 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 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 »
May 23, 2013 at 4:26 PM
ColdFusion QueryAppend( qOne, qTwo )
@Heather, Glad people are still getting value out of this! ... read »
May 23, 2013 at 3:49 PM
Strange Interaction Between DeserializeJson(), ArrayContains(), And Database Values In ColdFusion
@WebManWalking, I meant the code at the bottom (not the video). I did try to experiment with an intermediary variable, like: value = users.id[ i ]; arrayContains( userIDs, value ); ... but t ... read »
May 23, 2013 at 11:06 AM
Strange Interaction Between DeserializeJson(), ArrayContains(), And Database Values In ColdFusion
@Ben, Are you talking about As Number: YES As String: YES As Java: YES? If so, that's with 3 different ways of referencing the constant 1, not users.id[1]. Query object references(*) are what seem ... read »
InVision App - Prototyping Made Beautiful With Prototyping Tools