2

I'm trying to parse a json file and ran into this issue. I'm pulling some data out of a query and converting it into a json, sending it to another file, and then parsing it. However some of the data is an empty string, and that breaks stuff when I try to parse it.

I am currently generating the json object like so:

<cfset person = '{
    "fname":"#ReReplace(firstName, '\t', '\\t', "all").trim()#",
    "lname":"#ReReplace(lastName, '\t', '\\t', "all").trim()#",
    "occupation":"ReReplace(lastName, '\t', '\\t', "all").trim()#"
}'>

I am currently already using replace to handle tabs in the values (don't ask, people do weird stuff) and would like to use replace to handle empty strings. I tried using Replace(firstName, '', '""', "all") but coldfusion didn't like that one bit, for pretty obvious reasons. One option would be to use an if statement before I get to the json generation, but I'm wondering if anyone knows of a quicker way using Replace?

Community
  • 1
  • 1
ConorBaumgart
  • 493
  • 1
  • 3
  • 18

1 Answers1

8

You should never create a json string by hand.

Instead, you should use either a library provided by http://json.org, or a builtin method. Recent versions of coldfusion have SerializeJSON and DeSerializeJSON, so you should be using those.

<cfset person = {}>
<cfset person.fname = firstName.trim()>
<cfset person.lname = lastName.trim()>
<cfset person.occupation = occupation.trim()>
<cfset personJSON = SerializeJSON(person)>

Doing it this way means you don't have to worry about empty strings, tabs, or even quotes.


Probably important to note though that based on your application settings, the case of your key names may change to all uppercase. In railo/lucee this is fixed by either setting global app settings, or using

<cfprocessingdirective preserveCase="true">

In ColdFusion 11+, this is fixed by using either a Server or Application level setting. Currently, these settings apply only to basic structures, not system scopes.

<cfset this.serialization.preserveCaseForStructKey = true>

For ColdFusion 10, and earlier, you must use the longhand structure syntax to preserve case:

<cfset person = {}>
<cfset person["fname"] = "John">
<cfset person["lname"] = "Smith">
<cfset person["occupation"] = "Developer">

Since you mentioned queries, ColdFusion 11 also added a new serialization option which converts query objects into a more standard, Ajax-friendly format: an array of structures. The new format can be applied either at the Application level, or on a per-use basis, ie serializeJSON(queryName, "struct"). Unfortunately, neither preserves the case of query column names. As with query.columnList, the generated key names are always upper-cased.

rrk
  • 15,677
  • 4
  • 29
  • 45
Kevin B
  • 94,570
  • 16
  • 163
  • 180
  • 3
    (Edit) Totally agreed on not rolling your own JSON. AFAIK, ACF does not have a cfprocessingdirective relating to case. Aside from using the long-hand method to preserve case, ie `structName["desiredKeyNameCase"] = "value"`, CF11 supports some new [Application level settings like this.serialization.preservecaseforstructkey](http://blog.adamcameron.me/2014/02/coldfusion-11-preservecaseforstructkey.html) (with varying degrees of success..). – Leigh Feb 19 '16 at 23:15
  • Thank you for your response. After looking my old stuff over (old legacy code) I'm going to go ahead and use SerializeJSON(). I just have a couple of quick questions if you don't mind: 1) Why is it a bad idea to create a json string by hand? Is it simply slower? 2) Is using SerializeJSON a good idea in loops? For example I'm cflooping through a few thousand rows and need to keep adding new people to the end of a JSON string, while your above code only specifies for one instance. – ConorBaumgart Feb 20 '16 at 00:12
  • 2: It would be better to create an array of structs in that case. 1: It's less error prone to let something else do it for you. Otherwise, you have to take care of all the conversions from coldfusion datatypes to strings numbers and booleans yourself, deal with quotes/tabs, and handle nesting properly. SerializeJSON allows you to skip all that and just output JSON. – Kevin B Feb 20 '16 at 00:22
  • 1
    @ConorBaumgart - RE 2: In case it is not clear, you do not use SerializeJSON on *each* structure. Instead, create and populate a CF array of structures as usual. Then call SerializeJSON() on the *array* to return the whole thing as a JSON string. – Leigh Feb 20 '16 at 03:33