Sunday, July 12, 2026

ColdFusion List Functions - The 5 Minute Mission

You don't have hours to spend ramping up on ColdFusion.
You need to get in. Get out and deliver. Let's do that.

Copy and paste this into a cffiddle.org session.
Yep. Remember to wrap it with <cfscript> tags. Feel free to thank me in the comments.


// ---------------------------------------------------------------------------------------
// Tutorials with a SMART Mission
// What does that look like?

// SMART: Specific, Measurable, Achievable, Revelant and Time-bound
// S: List Functions
// M: Read and digest within 5 minutes
// A: Anyone new/familiar with programing can use them immediately
// R: Use a data in a common ways anyone will mentally and emotionally connnect with
// T: Read within 3 min, Research more within seconds and Experiment with immediately.
// ---------------------------------------------------------------------------------------

// ColdFusion lists are strings separated by a delimiter (default is a comma)
fruitList = "Apples,Bananas,Blueberries,Strawberries,Grapes,Oranges,Cantaloupe,Watermelon,Kiwi,Pomegranate";
veggieList = "Spinach,Kale,Broccoli,Cauliflower,Radish,Carrot,Potato,Pepper,Corn,Onion";
meatList = "Chicken,Turkey,Fish,Beef,Pork";

missionIntroduction = "
    <p><b>ColdFusion List Functions</b>
    As a CF developer, you use these on a daily basis. Pick these up. You gonna need all 11 of 'em.</p>

    <p><b>MISSION:</b> Operation Groceries. Go help your Mama with these three lists.</p>

    <p><b>VITAL DATA</b><br>
    <b>Fruits</b> (#listLen(fruitList)#): #fruitList#<br>
    <b>Veggies</b> (#listLen(veggieList)#): #veggieList#<br>
    <b>Meat</b> (#listLen(meatList)#): #meatList#</p>

    <p><b>NEED TO KNOW</b><br><b>1-Based Indexing:</b> ColdFusion lists start at index 1.<br>
    Yes, they start at 1. What the heck? It's ColdFusion's thing.<br>
    Call it a quirk. Get used to it. Love the number 1 and like it.<br>
    Other languages have their indexes start at 0 like JavaScript, C++, Java or Python.</p>
";
writeOutput(missionIntroduction);

writeOutput("<b>EXAMPLES</b><br>");
// 1. ListLen - Count the items in the fruit list
totalFruits = ListLen(fruitList);
writeOutput("1. <b>ListLen(fruitList)</b> - Total fruits: #totalFruits#<br>");
// Output: 10

// 2. ListGetAt - Fetch a specific item by its 1-based index
thirdFruit = ListGetAt(fruitList, 3);
writeOutput("2. <b>ListGetAt(fruitList, 3)</b> - 3rd fruit: #thirdFruit#<br>");
// Output: Blueberries

// 3. ListFindNoCase - Search for an item ignoring capital letters
veggieIndexNoCase = ListFindNoCase(veggieList, "potATO");
writeOutput("3. <b>ListFindNoCase(veggieList, 'potATO')</b> - 'potATO' found at position: #veggieIndexNoCase# <em>(not case-sensitive)</em><br>");
// Output: 7

// 4. ListContains - Search for an item that *contains* a partial string
// 'flower' is part of 'Cauliflower'
partialSearchIndex = ListContains(veggieList, "flower");
writeOutput("4. <b>ListContains(veggieList, 'flower')</b> - Element containing 'flower' (Cauliflower) at position: #partialSearchIndex#<br>");
// Output: 4

// 5. ListFind - Search for an item matching exact case sensitivity
veggieIndexCase = ListFind(veggieList, "potato"); 
writeOutput("5. <b>ListFind(veggieList, 'potato')</b> - Exact match 'potato' position (0 means not found): #veggieIndexCase# <em>(case-sensitive)</em><br>");
// Output: 0 (it is capitalized as 'Potato')

// 6. ListAppend - Add meat list to the vegetable list to make a dinner list
dinnerList = ListAppend(veggieList, meatList);
writeOutput("6. <b>ListAppend(veggieList, meatList)</b> - Combined Veggie + Meat list: #dinnerList#<br>");
// both veggieList and meatList all together

// 7. ListPrepend - Add lamb list to the meat list
meatList = ListPrepend(meatList, "Lamb");
writeOutput("7. <b>ListPrepend(meatList, 'Lamb') </b> - #meatList#<br>");
// Output: Lamb is in the first index

// 8. ListFirst - Grab the very first item from the combined dinner list
firstDinnerItem = ListFirst(dinnerList);
writeOutput("8. <b>ListFirst(dinnerList)</b> - First item to cook: #firstDinnerItem#<br>");
// Output: Spinach

// 9. ListLast - Grab the very last item from the combined dinner list
lastDinnerItem = ListLast(dinnerList);
writeOutput("9. <b>ListLast(dinnerList)</b> - Last item to cook: #lastDinnerItem#<br>");
// Output: Pork

// 10. ListDeleteAt - Remove the 2nd element (Kale) from the vegetable list
shortVeggieList = ListDeleteAt(veggieList, 2);
writeOutput("10. <b>ListDeleteAt(veggieList, 2)</b> - Veggies after removing index 2: #shortVeggieList#<br>");

// 11. ListChangeDelims - Swap the commas for pipes (|) to change data formatting
pipeDelimitedMeat = ListChangeDelims(meatList, "|");
writeOutput("11. <b>ListChangeDelims(meatList, '|')</b> - Meat list with new delimiters: #pipeDelimitedMeat#<br>");

// Include any additional information that helps summarizes the above examples
additionalPoints = "<br><hr>
<p>
 <strong>Additional Points:</strong>
 <ul>
  <li><b>Strings Under the Hood:</b> ListAppend does not alter the original variable dynamically; you must assign it back to a variable (e.g., dinnerList = ListAppend(...)).</li>
  <li><b>Find vs. Contains:</b> ListFind expects an exact match of the whole list item, but ListContains matches partial substrings inside an item.  They search differently.</li>
 </ul>
 </p>";
writeOutput(additionalPoints);
Let me know if I've missed your favorite list function. Or better yet point me to another article where everyone can learn about about a nifty List function from ColdFusion.

Sunday, February 20, 2011

ColdFusion: Flatten an XML object to a Struct

On a recent ColdFusion project I had to make a PDF file respond like a traditional web page. You know, add form fields with a submit button, capture the submitted data server-side, and show the new PDF with the data submitted by the user. Even though this Adobe technology has been around a while and I knew it was possible, I had never done it before. To accomplish this, I used several tools:

  • Adobe Professional - To add form fields and JavaScript validation
  • IText - To populate form fields and flatten the PDF

So began a new coding adventure and, again, I found myself intrigued by this software challenge. I created a simple PDF, added JavaScript validation via Adobe Professional, and then began playing around with how submission works. I discovered a few differences from a traditional HTML page, but that's another post.

I set the PDF form submit options to submit form field data as XML. I quickly discovered I had to "loop through" the PDF form fields in an XML object. However, I wanted the XML data converted into a ColdFusion structure.

Q: Surely someone has already written a function like this right?
A: Nope. Or at least I didn't find anyone doing it.

Fortunately, I did find something that helped me refactor a solution. On www.cflib.org I found a flattenStruct function. It recursively traversed through a structure and created a new structure, a flatten structure.

From this, I created a new function, flattenXmlToStruct.

<cffunction name="flattenXmlToStruct" access="public" output="false" returntype="struct">
<cfargument name="xmlObject" required="true" type="xml" />
<cfargument name="delimiter" required="false" type="string" default="." />
<cfargument name="prefix" required="false" type="string" default="" />
<cfargument name="stResult" required="false" type="struct" />
<cfargument name="addPrefix" required="false" type="boolean" default="true" />

<cfset var sKey = '' />
<cfif NOT isDefined("arguments.stResult")>
 <cfset arguments.stResult = structNew()>
</cfif>

<cfloop from="1" to="#ArrayLen(arguments.xmlObject.XmlChildren)#" index="arrIndx">

 <cfset sKey = arguments.xmlObject.XmlChildren[arrIndx].XmlName>

 <cfif ArrayLen(arguments.xmlObject.XmlChildren[arrIndx].XmlChildren) EQ 0>
   <cfif arguments.addPrefix and len(arguments.prefix)>
     <cfset arguments.stResult["#arguments.prefix##arguments.delimiter##sKey#"] =
                          arguments.xmlObject.XmlChildren[arrIndx].XmlText />
   <cfelse>
     <cfset arguments.stResult[sKey] =
                          arguments.xmlObject.XmlChildren[arrIndx].XmlText />
 </cfif>

 <cfelse> <!--- Node has more children... --->
   <cfif arguments.prefix EQ "">
     <cfset currentKey = sKey>
   <cfelse>
     <cfset currentKey = "#arguments.prefix##arguments.delimiter##sKey#">
   </cfif>

   <cfset flattenXmlToStruct(arguments.xmlObject.XmlChildren[arrIndx],
                                arguments.delimiter, currentKey, arguments.stResult) />

 </cfif>
</cfloop>

<cfreturn arguments.stResult />
</cffunction>

Saturday, July 10, 2010

Syntax Highlighter Example

Here's my first attempt at using the SyntaxHighlighter from Alex Gorbatchev.

It is one of the most popular sytnax highlighters on the web today. It has been around since 2004 and is still being supported. That's a mere feat in itself.

The example you see below is v2.1 of Alex's excellent tool. If you'd like to copy the source code, it's easy to snag. Move your mouse over the snippet of code and you'll see a toolbar appear. Mouse over the icons to see what your options are: View Source and many more.

UPDATE: July 2, 2026
Whew! I haven't updated this blog post for a while, eh? Dang. Please forgive me.

I've updated the blog to use highlight.js with the atom-one-dark theme.

Why? Flash is no longer supported. Yeah, yeah, I know. I didn't want to believe it at the time.

With that... ¡Hasta la nunca, Flash! Hasta la nunca.

<script>
alert("Hello world and good " + timeOfDay() + 
      "!\nIt's gonna be good.  Really good." );

// Determine what time of day is it... in english! 
function timeOfDay(d) {
  if (d.getHours() >= 0 && d.getHours() < 12)
    return "morning";
  else if (d.getHours() >= 12 && d.getHours() < 18)
    return "afternoon";   
  else
    return "evening";     
} // end: timeOfDay
</script>