When working on new logic and I want to dump a variable, I often use an internal CF_DumpLite CFC/CFTag that we developed that minimizes HTML output, honors original form & query column order & case, redacts CC values and is nonce aware. If I need to view the data types, I switch it up to use the cf_dump CFTag by Alexander Kwaschny.
We occasionally need to output data from an unordered struct in an email or to the webpage and it's not optimal to use either of these developer-centric dump tools for the general public. Even though we've been manually displaying tables for years, we've tended to repeat ourselves. I wrote this UDF in an effort to avoid having to do that.
structToTable is a ColdFusion UDF that will accept a struct with key-value pairs to generate legacy-valid, email-friendly html table and text-only key-value output.
We're now using this UDF when generating email messages so that we have both HTML and TEXT versions of the data. Enjoy!
Example Usage
result = structToTable(data=CGI,
keysToRemove="SERVER_PORT", sortOrder="https,auth_user");
writeoutput(result.html);
writeoutput("\<pre\>" & result.text & "\</pre\>");
Source Code
https://gist.github.com/JamoCA/bc5c58e829e191947f2e34289fd98a5a
<cfscript> | |
/** | |
* structToTable UDF | |
* @displayname structToTable | |
* @author James Moberg http://sunstarmedia.com, @sunstarmedia | |
* @version 1 | |
* @lastUpdate 10/28/2024 15:58 | |
* @gist https://gist.github.com/JamoCA/bc5c58e829e191947f2e34289fd98a5a | |
* @blog https://dev.to/gamesover/structtotable-generate-htmltext-output-for-displayemail-1mk4 | |
* @twitter https://x.com/gamesover/status/1851046259387469955 | |
* @LinkedIn https://www.linkedin.com/posts/jamesmoberg_coldfusion-activity-7256824771630243841-gYX7 | |
* @param String data A struct with key - simple value pairs. Required. | |
* @param String tableId Table ID to use. Optional. | |
* @param String tableClass Table class name(s) to use. Optional. | |
* @param Any keysToRedact Array to string list of keys to redact. Optional. | |
* @param Any keysToRemove Array to string list of keys to remove. Optional. | |
* @param Any sortOrder Array to string list of keys to prioritize in order (if they exist). Optional. | |
* @param Boolean niceVars An option to humanize variable names. Optional. Default = true | |
*/ | |
public struct function structToTable( | |
required struct data, | |
string tableId="", | |
string tableClass="", | |
any keysToRedact="", | |
any keysToRemove="", | |
any sortOrder="", | |
boolean niceVars=true | |
) output=false hint="I accept a struct with key-value pairs to generate legacy-valid, email-friendly html table and text-only key-value output" { | |
local.data = duplicate(arguments.data); | |
local.html = ["<table"]; | |
local.text = []; | |
local.td = "<td style=""word-break:break-word;"">"; | |
local.row = 0; | |
local.sortedKeys = []; | |
string function humanizeHeader(string string) hint="Convert a camelized/dasherized/underscored string into a humanized one" { | |
arguments.string = rereplace(arguments.string, "([^[:alnum:]_-]+)", " ", "ALL").replaceAll("_", " "); | |
arguments.string = rereplace(arguments.string, "([A-Z]+)([A-Z][a-z])", "\1 \2", "ALL"); | |
return rereplace(arguments.string, "([a-z\d])([A-Z])", "\1 \2", "ALL").replaceAll("\s+", " "); | |
} | |
if (len(trim(arguments.tableId))) arrayappend(local.html, " id=""#trim(arguments.tableId)#"""); | |
if (len(trim(arguments.tableClass))) arrayappend(local.html, " tableClass=""#trim(arguments.tableClass)#"""); | |
// update Sort Order | |
local.sortOrder = (isarray(arguments.sortOrder)) ? arguments.sortOrder : (issimplevalue(arguments.sortOrder)) ? listtoarray(arguments.sortOrder) : []; | |
// Get initial keys with original key case, append to sort order if they don't exist in user-defined order | |
local.initialKeys = listtoarray(structkeylist(local.data)); | |
for(local.key in local.sortOrder){ | |
if (arrayfindnocase(local.initialKeys, local.key)){ | |
arrayappend(local.sortedKeys, local.initialKeys[arrayfindnocase(local.initialKeys, local.key)]); | |
} | |
} | |
for(local.key in local.data){ | |
if (!arrayfindnocase(local.sortedKeys, local.key)){ | |
arrayappend(local.sortedKeys, local.key); | |
} | |
} | |
// remove keys | |
local.keys = (isarray(arguments.keysToRemove)) ? arguments.keysToRemove : (issimplevalue(arguments.keysToRemove)) ? listtoarray(arguments.keysToRemove) : []; | |
for(local.key in local.keys) { | |
if (arrayfindnocase(local.sortedKeys, local.key)){ | |
arraydeleteat(local.sortedKeys, arrayfindnocase(local.sortedKeys, local.key)); | |
} | |
} | |
arrayappend(local.html, " border=""1"" cellspacing=""0"" cellpadding=""2"">"); | |
for(local.key in local.sortedKeys){ | |
local.row += 1; | |
local.rowAttributes = !(local.row mod 2) ? " style=""background-color:##e0e0e0;"" class=""odd""" : ""; | |
local.keyText = (arguments.niceVars) ? humanizeHeader(local.key) : local.key; | |
arrayappend(local.html, "<tr#local.rowAttributes#><td style=""font-weight:bold; vertical-align:top;"">#local.keyText#:</td>"); | |
local.val = local.data[local.key]; | |
if (listfindnocase(arguments.keysToRedact, local.key)){ | |
arrayappend(local.html, "#local.td#REDACTED</td>"); | |
arrayappend(local.text, "#local.keyText#: REDACTED"); | |
} else if (isnull(local.data[local.key])){ | |
arrayappend(local.html, "#local.td#NULL</td>"); | |
arrayappend(local.text, "#local.keyText#: NULL"); | |
} else if (!issimplevalue(local.data[local.key])){ | |
arrayappend(local.html, "#local.td#[Complex Object]</td>"); | |
arrayappend(local.text, "#local.keyText#: [Complex Object]"); | |
} else if (isvalid("url", local.data[local.key])){ | |
arrayappend(local.html, "#local.td#<a href=""#local.data[local.key]#"" target=""_blank"" rel=""nofollow noreferrer"">#encodeforhtml(local.data[local.key])#</a></td>"); | |
arrayappend(local.text, "#local.keyText#: #local.val#"); | |
} else { | |
arrayappend(local.html, local.td & encodeforhtml(local.val) & "</td>"); | |
arrayappend(local.text, "#local.keyText#: #local.val#"); | |
} | |
arrayappend(local.html, "</tr>"); | |
} | |
arrayappend(local.html, "</table>"); | |
return [ | |
"html": arraytolist(local.html, " ") | |
,"text": arraytolist(local.text, chr(13) & chr(10)) | |
]; | |
} | |
</cfscript> |
Top comments (0)