Ask Ben: Maintaining Case Of XML Attributes In Manually Created ColdFusion XML Documents

Posted January 9, 2009 at 7:39 AM by Ben Nadel

Tags: ColdFusion, Ask Ben

Just a really standard dumb "why?" question. I am querying a database and using the data to build an XML file used with some Flash component. Now for whatever reason this black-box Flash is highly case sensitive when it comes to XML. CF's default behavior breaks the component. Why is it that the CF XMLAttributes default to uppercase? Obviously it takes me about 5 seconds to do a RegEx replace when doing a ToString before saving it to file. But out of curiosity is there any voodoo magic lurking in the guts of CF to make XMLAttributes comply with my lust for lowercase markup?

Yes, there is some voodoo magic in ColdFusion to help you maintain the given case of XML attributes. The trick is to use explicit strings when settings struct values rather than attribute variables. By that, I mean that you have to use more of an array-type notation rather than a struct-type notation if you want the case of your attribute variables to carry through. Remember, ColdFusion is not case sensitive, so when you give it a variable name, the case has no meaning. To get around this with structs, use explicit strings.

I'm sure that wasn't explained well, so I'll demonstrate the issue when it comes to XML. First, I will build a ColdFusion XML document entirely with an explicit string using ColdFusion's CFXML tag:

  • <!--- Create the XML document. --->
  • <cfxml variable="xmlData">
  •  
  • <books list="recommended">
  • <book title="The Four Agreements" isbn="1878424505" />
  • <book title="Muscle" isbn="0380717638" />
  • <book title="Plainclothes Naked" isbn="0060933534" />
  • </books>
  •  
  • </cfxml>
  •  
  • <!--- Output the string. --->
  • #HtmlEditFormat( ToString( xmlData ) )#

Here, the entire ColdFusion XML document is explicit; ColdFusion doesn't have to make any guesses about case since it's all been spelled out. As such, when we run the code above, we get the following case-maintained output:

<?xml version="1.0" encoding="UTF-8"?> <books list="recommended"> <book isbn="1878424505" title="The Four Agreements"/> <book isbn="0380717638" title="Muscle"/> <book isbn="0060933534" title="Plainclothes Naked"/> </books>

Now, because your attributes are not being maintained, I know that you are not building your XML documents in this manner. From your question, what I gather is that you are setting your XML attributes using CFSet tags and the XmlAttributes node collection as in this example:

  • <!--- Create the bar-bones XML document. --->
  • <cfxml variable="xmlData">
  •  
  • <books list="recommended">
  • <book />
  • <book />
  • <book />
  • </books>
  •  
  • </cfxml>
  •  
  • <!---
  • Now that we have our bare-bones XML document, let's
  • add the book attributes manually for each book. First,
  • we need to get a collection of the target book nodes.
  • --->
  • <cfset arrBooks = XmlSearch( xmlData, "//book" ) />
  •  
  • <!--- Now, set the attributes manually. --->
  • <cfset arrBooks[ 1 ].XmlAttributes.title = "The Four Agreements" />
  • <cfset arrBooks[ 1 ].XmlAttributes.isbn = "1878424505" />
  • <cfset arrBooks[ 2 ].XmlAttributes.title = "Muscle" />
  • <cfset arrBooks[ 2 ].XmlAttributes.isbn = "0380717638" />
  • <cfset arrBooks[ 3 ].XmlAttributes.title = "Plainclothes Naked" />
  • <cfset arrBooks[ 3 ].XmlAttributes.isbn = "0060933534" />
  •  
  • <!--- Output the string. --->
  • #HtmlEditFormat( ToString( xmlData ) )#

Notice here that when we set the attributes (ex. XmlAttributes.title) we are using all lowercase labels. But, when we run the code above, we get the following output:

<?xml version="1.0" encoding="UTF-8"?> <books list="recommended"> <book ISBN="1878424505" TITLE="The Four Agreements"/> <book ISBN="0380717638" TITLE="Muscle"/> <book ISBN="0060933534" TITLE="Plainclothes Naked"/> </books>

Notice that the ISBN and TITLE XML attributes have all been converted to uppercase. This is the issue you are experiencing when you pass the XML document off to your Flash movie.

It's hard to explain exactly why this happens as I don't know how ColdFusion works under the hood; but, I rationalize it as such: when you use dot-notation, you are really just setting a variable in the context of the parent struct. Think about it like this, if you are in a regular ColdFusion page and set a variable:

  • <cfset foo = "bar" />

... this is really the same as this:

  • <cfset VARIABLES.foo = "bar" />

Variables are always scoped either explicitly or implicitly. Therefore, you can think of dot-notation as setting a variable rather than a "label". I know this is a bit of a stretch, but it's simply how I keep it clear in my mind.

But, like I said, there is a way to get around this: use explicit strings. Let's re-run the example from above, but this time, we will use array notation with explicit struct labels rather than "variable" handles:

  • <!--- Create the bar-bones XML document. --->
  • <cfxml variable="xmlData">
  •  
  • <books list="recommended">
  • <book />
  • <book />
  • <book />
  • </books>
  •  
  • </cfxml>
  •  
  • <!---
  • Now that we have our bare-bones XML document, let's
  • add the book attributes manually for each book. First,
  • we need to get a collection of the target book nodes.
  • --->
  • <cfset arrBooks = XmlSearch( xmlData, "//book" ) />
  •  
  • <!--- Now, set the attributes manually. --->
  • <cfset arrBooks[ 1 ].XmlAttributes[ "title" ] = "The Four Agreements" />
  • <cfset arrBooks[ 1 ].XmlAttributes[ "isbn" ] = "1878424505" />
  • <cfset arrBooks[ 2 ].XmlAttributes[ "title" ] = "Muscle" />
  • <cfset arrBooks[ 2 ].XmlAttributes[ "isbn" ] = "0380717638" />
  • <cfset arrBooks[ 3 ].XmlAttributes[ "title" ] = "Plainclothes Naked" />
  • <cfset arrBooks[ 3 ].XmlAttributes[ "isbn" ] = "0060933534" />
  •  
  • <!--- Output the string. --->
  • #HtmlEditFormat( ToString( xmlData ) )#

Notice that this time, instead of setting a case-insensitive variable (ex. XmlAttributes.title), we are setting explicit variable lables (ex. XmlAttributes[ "title" ]). By doing so, we are letting ColdFusion know exactly how we want to index the given value. And, we run the above code, we do get a case-maintained output:

<?xml version="1.0" encoding="UTF-8"?> <books list="recommended"> <book isbn="1878424505" title="The Four Agreements"/> <book isbn="0380717638" title="Muscle"/> <book isbn="0060933534" title="Plainclothes Naked"/> </books>

Notice that the case of the XML attributes isbn and title is the same in the output as it was in your CFSet statements. I hope that helps.



Reader Comments

Jan 9, 2009 at 8:29 AM // reply »
16 Comments

I believe this is happening because by default, XML attributes are case-insensitive (like pretty much everything else in CF), and it just happens that CF stores them in uppercase ... so when you need to retrieve them for something that is case-sensitive, you get back CF's interpretation of what you gave it.

I have been doing a bit of Flex work recently, and this question rings a faint bell with me. There may also be a way to address this from the server side, if you have access to the configuration files, but right now the particular solution escapes me.

(does research)

Okay, never mind, what I found is not quite what you were looking for. I was thinking of the setup in remoting-config.xml for Flex (wwwroot/WEB-INF/flex) ... in the ColdFusion destination, there is a property-case element that contains child elements to force CFC properties, query columns, and struct keys to lower case if you like (force-XXX-lowercase). I've set force-struct-lowercase to true so that the struct keys I use in my Flex/CF apps are all lower case, but Flash may not have the same (or any) server options.


Jan 9, 2009 at 10:06 AM // reply »
10,640 Comments

@Dave,

Thanks for the insight on the remoting stuff. I kind of like the idea of forcing things to a given case. Like, when ColdFusion returns JSON, I like that everything goes UPPERCASE. It makes it easy to make changes in one without it messing up on the other side.


Jan 9, 2009 at 5:20 PM // reply »
8 Comments

The key thing to take away from this is: 'use array notation when you want CF to retain the case of your variable names'.

A lot of people probably learned this about the same way I did ... which was working with a remote service (In my case a web service) that cares about case sensitivity.


Jan 9, 2009 at 5:26 PM // reply »
8 Comments

One more thing. Array notation is great for using struct keys that are not usually a valid variable name. Sometimes I'll build a struct where the key is a records PK.

So, these won't work:
<cfset refStruct.55873 = recordObj />
or
<cfset refStruct.E63841A8-DA2C-4F6E-A50C-17624729E0C6 = recordObj />

But, these will:
<cfset refStruct['55873'] = recordObj />
or
<cfset refStruct['E63841A8-DA2C-4F6E-A50C-17624729E0C6'] = recordObj />


Jan 9, 2009 at 5:42 PM // reply »
10,640 Comments

@Chris,

Great point. I often use structs to create ID-indexes. They are wicked fast and calling StructKeyExists() is all you need to do to see if something exists.

http://www.bennadel.com/index.cfm?dax=blog:268.view


Mar 20, 2009 at 7:33 AM // reply »
1 Comments

I need to add the attributes in the order i want, and not alphabetically. This is because the API of the program I'm sending the xml to needs the first two attributes to be always the same. Unfortunately they are not the first because CF sorts them alphabetically.

Is there a way to tell CF not to sort them?

regards
martin


Mar 20, 2009 at 8:12 AM // reply »
10,640 Comments

@Martin,

If you need to make sure all the XML stays the same, I would build your XML using CFSaveContent rather than any actual XML parsing. This way, you are just building up a string and it will be passed along as-is.


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
InVision App - Prototyping Made Beautiful With Prototyping Tools Ben Nadel's Company - Epicenter Consulting Recent Blog Comments
Feb 12, 2012 at 3:37 AM
Learning ColdFusion 8: CFImage Part III - Watermarks And Transparency
Hi Ben, Just to ask currently it is placed bottom right corner, if i need to replace the same rendered image on the bottom left side or in the bottom center, how that can be calculated. bottom ce ... read »
Feb 11, 2012 at 9:29 PM
Use jQuery's SlideDown() With Fixed-Width Elements To Prevent Jumping
I can't say how glad I am that I found your post. Thank you very much. ... read »
Feb 10, 2012 at 7:21 PM
jQuery AJAX Strips Script Tags And Inserts Them After Parent-Most Elements
Update! Instead of $(eval(options.insertAfter)).after(data['insertData']); I now use: var ajaxNode = document.createElement('span'); var parent = $(eval(options.insertAfter))[0].parentNode; ... read »
Feb 10, 2012 at 6:18 PM
jQuery AJAX Strips Script Tags And Inserts Them After Parent-Most Elements
encountered this same, what I consider, jQuery bug last week. I'm building a site in which I load some content via AJAX. This content contains Linkedin share button placeholders which Linkedin API ne ... read »
Feb 10, 2012 at 11:30 AM
Cross-Origin Resource Sharing (CORS) AJAX Requests Between jQuery And Node.js
After you understand the concepts here, this is an awesome cheatsheet for enabling CORS in just about anything http://enable-cors.org/ ... read »
JM
Feb 10, 2012 at 9:10 AM
My Safari Browser SQLite Database Hello World Example
@Amy, Here is a very good tutorial on how to use JOIN: http://www.sqltutorial.org/sqljoin-innerjoin.aspx ... read »
Feb 10, 2012 at 4:42 AM
Building A Twitter-Inspired RESTful API Architecture In ColdFusion
This is great, very useful Ben. I spotted a small typo in the api.cgm listing: <cfthrow type="Unauthroized" /> Cheers Stefan ... read »
Feb 9, 2012 at 10:35 PM
CFDirectory Filtering Uses Pipe Character For Multiple Filters (Thanks Steve Withington)
I was wondering if there would be a filter you could apply so that you got everything but what you included in the filter. As in show me all docs that are not a .pdf. ... read »