Working with XML in ColdFusion - Struct versus XML functions

Earlier this week I worked with John Bliss on an interesting problem he had. Let me describe his issue, and the solution he came up, and what I learned from it.

John was trying to consume a web service. The web service demanded that a particular SOAP header be sent: <soap:Header> <ApiUserAuthHeader xmlns="namespace"> <UserName>xxxxx</UserName> <Password>xxxxx</Password> <UserAccessKey>xxxx</UserAccessKey> </ApiUserAuthHeader> </soap:Header>

He created the header like so:

<cfset ApiUserAuthHeader = StructNew()> <cfset ApiUserAuthHeader.UserAccessKey = "xxxxx"> <cfset ApiUserAuthHeader.Password = "xxxxx"> <cfset ApiUserAuthHeader.UserName = "xxxxx"> <cfset AddSOAPRequestHeader(MyWebservice, "namespace", "ApiUserAuthHeader", ApiUserAuthHeader)>

So far so good, right? I’ve never actually used addSOAPRequestHeader, but just looking at his code it made sense to me. The result however was off:

<soapenv:Header> <ns1:ApiUserAuthHeader xmlns:ns1="namespace"> <item xmlns:ns2=""> <key xsi:type="xsd:string">PASSWORD</key> <value xsi:type="xsd:string">xxxxx</value> </item> <item> <key xsi:type="xsd:string">USERNAME</key> <value xsi:type="xsd:string">xxxxx</value> </item> <item> <key xsi:type="xsd:string">USERACCESSKEY</key> <value xsi:type="xsd:string">xxxxx</value> </item> </ns1:ApiUserAuthHeader> </soapenv:Header>

If you compare this to what the API requires, you can see they don’t match. The first suggestion I had was to change how he worked with the structures. When you do:

<cfset s = {}> <cfset = "Ray">

to create a structure, ColdFusion will uppercase the struct key (name), to give you: s.NAME = “Ray”. I recommended he try bracket notation, essentially:

<cfset s = {}> <cfset s["name"] = "Ray">

This didn’t help either (although the resultant header did have the right case for the keys). I hashed this a bit more in my head and then I had an idea. He created the XML data pretty much the way I always did - with structure functions. Of course, ColdFusion also has native XML functions to create XML nodes/data. I never use them because the structure functions are simpler (to me!) and just plain work. In this case though switching to ‘proper’ XML manipulation functions worked perfectly for him:

<cfset doc = XmlNew()> <cfset doc.ApiUserAuthHeader = XmlElemNew(ApiUserAuthHeader, "namespace", "ApiUserAuthHeader")> <cfset doc.ApiUserAuthHeader.UserName = XmlElemNew(ApiUserAuthHeader, "UserName")> <cfset doc.ApiUserAuthHeader.UserName.XmlText = "xxxxx"> <cfset doc.ApiUserAuthHeader.UserAccessKey = XmlElemNew(ApiUserAuthHeader, "UserAccessKey")> <cfset doc.ApiUserAuthHeader.UserAccessKey.XmlText = "xxxxx"> <cfset doc.ApiUserAuthHeader.Password = XmlElemNew(ApiUserAuthHeader, "Password")> <cfset doc.ApiUserAuthHeader.Password.XmlText = "xxxxx"> <cfset AddSOAPRequestHeader(MyWebservice, "namespace", "ApiUserAuthHeader", doc)>

So I guess I don’t have much to add here, but I’d be curious if this type of problem has tripped up others?

Raymond Camden's Picture

About Raymond Camden

Raymond is a developer advocate. He focuses on JavaScript, serverless and enterprise cat demos. If you like this article, please consider visiting my Amazon Wishlist or donating via PayPal to show your support.

Lafayette, LA