Ben Nadel
On User Experience (UX) Design, JavaScript, ColdFusion, Node.js, Life, and Love.
I am the chief technical officer at InVision App, Inc - a prototyping and collaboration platform for designers, built by designers. I also rock out in JavaScript and ColdFusion 24x7.
Meanwhile on Twitter
Loading latest tweet...
Ben Nadel at Scotch On The Rocks (SOTR) 2011 (Edinburgh) with:

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

Posted by Ben Nadel

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

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.

Reply to this Comment

@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.

Reply to this Comment

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.

Reply to this Comment

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 />

Reply to this Comment

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

Reply to this Comment

@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.

Reply to this Comment

Post A Comment

?
You — Get Out Of My Dreams, Get Into My Comments
Live in the Now
Oops!
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.