Coldfusion - Using CFIF with JSON Data - json

I'm working with a web API, which is returning the following data (this is a cfdump of the cfhttp.filecontent);
{"id":"xxx","service1":["xxx"],"service2":["xxx"]}
I need to be able to read this and determine if a service is on the list. For example,
<cfscript>
pdata = deserializeJSON(cfhttp.FileContent);
</cfscript>
<cfif IsDefined(pdata.service1)>Do something</cfif>
However, I'm receiving an error with the above code. I've only recently started working with JSON, and so far I've had reasonable success - but I'm stuck with this!
Any pointers much appreciated!

It should be IsDefined("pdata.service1")
With isDefined() CF needs to know the name of the variable you are asking about. A name is a string, so you pass in a string.
I found it to be a little counter-intuitive at first, but JasonDean put it into perspective in the comments.

Related

ColdFusion Query Page returning JSON

So I am trying to repurpose an old Coldfusion page for an internal DBA tool to track long running queries.
The page currently does a query as a <CFQUERY name="GetLongRunners"> and then displays the data in a table format:
<table>
<tr>
<td>#GetLongRunners.spid#</td>
<td>#GetLongRunners.Database#</td>
</tr>
</table>
etc, etc
My goal is to strip out all of the display stuff, and be able to simply post to this page, and then receive JSON back with this same data. I played around with:
jsonData = SerializeJSON(#GetLongRunners#)
along with trying to be more specific with #GetLongRunners.database# and it does not seem to be working. The page shows 'jsonData = SerializeJSON(' and I get an error:
Complex object types cannot be converted to simple values.
I'm very new to ColdFusion, and am trying to encapsulate this functionality as much as I can, so I really only have to worry about posting to this page, and then I can get the raw JSON to work with in the front end.
All examples I found, built the queries in a very different way, and it seems to be outside my scope to do it this way.
I am picturing a simple way to serialize the query output as json and send it back as a JSON object. Either that, or build an array by looping through the results of the query, and then serializing that.
Any ideas?
Thanks!
If you are on CF7, try the JSONUtil.cfc. Just download the CFC and install it somewhere under the web root. Then it is ready to use.
Inside your .CFM script, run the query, create an instance of the JSONUtil, and invoke the serializeJSON() method. That is it.
<cfsetting enablecfoutputonly="true">
<cfquery name="GetLongRunners">.... your query here .... </cfquery>
<cfset util = createObject("component", "path.to.JSONUtil")>
<cfcontent type="application/json" reset="true">
<cfoutput>#util.serializeJSON(GetLongRunners)#</cfoutput>
As Henry noted, extra white space can be problem when using .cfm files in this way. Be sure to include the cfsetting at the very top of your script. It will suppress output from everything except content wrapped in <cfoutput> tags.
Truthfully I would use a CFC for this instead, but one thing at a time. If you are interested, this thread has an example of using a remote function as well as converting a query object into a more friendly format ie array of structures.
<cfsetting enablecfoutputonly="true">
<!--- logic/calculation --->
<cfset jsonData = SerializeJSON( GetLongRunners )>
<!--- lastly, output the result --->
<cfoutput>#jsonData#</cfoutput>

How to Parse JSON Returned in ColdFusion

I'm sure this is a relatively simple question, but I can't seem to find a simple answer anywhere online.
I have a few lines of JSON returned by a cfhttp POST with an image URL that I'd like to parse out and display in my ColdFusion page:
{
"href": "http://server.arcgisonline.com/arcgis/rest/directories/arcgisoutput/ESRI_StreetMap_World_2D_MapServer/_ags_map734a6ad322dd493e84499d78f027d841.png",
"width": 854,
"height": 493,
"extent": {
"xmin": -8285407.015562119,
"ymin": 4944008.4197687358,
"xmax": -8220129.7934066672,
"ymax": 4981691.8747132765,
"spatialReference": {
"wkid": 102100,
"latestWkid": 3857
}
},
"scale": 288895.27714399656
}
How can I make "href"'s value a part of a variable in ColdFusion, and/or potentially have a button linked to downloading it?
EDIT: I forgot to mention that I'm using ColdFusion MX - also known as version 6 - and hence why I cannot use the DeserializeJSON listed on Adobe's page
Converts a JSON (JavaScript Object Notation) string data
representation into CFML data, such as a CFML structure or array.
https://wikidocs.adobe.com/wiki/display/coldfusionen/DeserializeJSON
Just parsing your cfhttp result with deserializeJSON()
<cfset getResult = deserializeJSON(result_Variable.filecontent)>
and you can get the href value using "#getResult.href#"
I forgot to mention that I'm using ColdFusion MX
Ah, that makes a very big difference! (Unless otherwise stated in the tags, most people will assume a more recent version, like CF9+).
JSON support was not added until CF8. If you search, there are still some older udf/cfc's for handling JSON out there. For example:
JSONDecode at http://www.cflib.org says it works with MX6
JSONUtil.cfc works with MX7+. It might work with MX6 out of the box, or with a few modifications. This thread has a description of how to encode with JSONUtil. Decoding should be equally simple. Just create an instance and invoke deserializeJSON, ie:
<!--- not tested --->
<cfset util = createObject("component", "path.to.JSONUtil")>
<cfset result = util.deSerializeJSON(yourJSONString)>
That said, ColdFusion MX is a bit long in the tooth and no longer supported. You should seriously consider upgrading or switching to the open source Railo engine.

ColdFusion CFHTTP working with data returned from API

I am just starting to work with the Rotten Tomatoes API to retrieve movie information, and I need some help understanding how to work with the data that is returned. This is my first time working with an API such as this, so please forgive me if this sounds basic.
Using cfhttp I can successfully connect to the API and return search data, but I don't really know what format I am getting back. I thought it was JSON, but using isJSON to check it returns false. I would like to be able to call individual fields within the returned data to populate a query result set that I can output to the user.
The code I am using to make the call is simple:
<cfhttp url="#apiURL#movies.json?apikey=#apiKey#&q=#movieName#" method="get" result="httpResp" timeout="120">
<cfhttpparam type="header" name="Content-Type" value="application/json" />
</cfhttp>
<cfdump var="#httpResp#" />
And the data that is being returned:
I don't expect anyone to give me a complete walk-through of how to build my app, but if someone could give me some pointers as to the proper way to convert the data into a query result, or something else I can use, I would appreciate it.
Edit: Didn't realize the image would be so difficult to read, so here's a cut and paste of the data being returned.
{"total":2,"movies":[{"id":"11029","title":"Krull","year":1983,"mpaa_rating":"PG","runtime":120,"release_dates":{"theater":"1983-07-29","dvd":"2001-04-03"},"ratings":{"critics_rating":"Rotten","critics_score":33,"audience_rating":"Spilled","audience_score":49},"synopsis":"","posters":{"thumbnail":"http://content6.flixster.com/movie/25/86/258696_mob.jpg","profile":"http://content6.flixster.com/movie/25/86/258696_pro.jpg","detailed":"http://content6.flixster.com/movie/25/86/258696_det.jpg","original":"http://content6.flixster.com/movie/25/86/258696_ori.jpg"},"abridged_cast":[{"name":"Ken Marshall","id":"162668719","characters":["Prince Colwyn"]},{"name":"Lysette Anthony","id":"162668720","characters":["Lyssa"]},{"name":"Freddie Jones","id":"162664678","characters":["Ynyr"]},{"name":"Francesca Annis","id":"162688297","characters":["Widow of the Web"]},{"name":"Alun Armstrong","id":"770670461","characters":["Torquil"]}],"links":{"self":"http://api.rottentomatoes.com/api/public/v1.0/movies/11029.json","alternate":"http://www.rottentomatoes.com/m/krull/","cast":"http://api.rottentomatoes.com/api/public/v1.0/movies/11029/cast.json","clips":"http://api.rottentomatoes.com/api/public/v1.0/movies/11029/clips.json","reviews":"http://api.rottentomatoes.com/api/public/v1.0/movies/11029/reviews.json","similar":"http://api.rottentomatoes.com/api/public/v1.0/movies/11029/similar.json"}},{"id":"770670060","title":"Bekenntnisse des Hochstaplers Felix Krull (Confessions of Felix Krull)","year":1957,"mpaa_rating":"Unrated","runtime":107,"release_dates":{"theater":"1958-03-04"},"ratings":{"critics_score":-1,"audience_rating":"Spilled","audience_score":33},"synopsis":"","posters":{"thumbnail":"http://content7.flixster.com/movie/10/84/16/10841649_mob.jpg","profile":"http://content7.flixster.com/movie/10/84/16/10841649_pro.jpg","detailed":"http://content7.flixster.com/movie/10/84/16/10841649_det.jpg","original":"http://content7.flixster.com/movie/10/84/16/10841649_ori.jpg"},"abridged_cast":[{"name":"Horst Buchholz","id":"162718595","characters":["Felix Krull"]},{"name":"Liselotte Pulver","id":"326392065","characters":["Zaza"]},{"name":"Ingrid Andree","id":"770670669","characters":["Zouzou"]},{"name":"Susi Nicoletti","id":"770670670","characters":["Madame Houpfle"]},{"name":"Paul Dahlke","id":"573372814","characters":["Professor Kuckuck"]}],"alternate_ids":{"imdb":"0050179"},"links":{"self":"http://api.rottentomatoes.com/api/public/v1.0/movies/770670060.json","alternate":"http://www.rottentomatoes.com/m/bekenntnisse-des-hochstaplers-felix-krull-confessions-of-felix-krull/","cast":"http://api.rottentomatoes.com/api/public/v1.0/movies/770670060/cast.json","clips":"http://api.rottentomatoes.com/api/public/v1.0/movies/770670060/clips.json","reviews":"http://api.rottentomatoes.com/api/public/v1.0/movies/770670060/reviews.json","similar":"http://api.rottentomatoes.com/api/public/v1.0/movies/770670060/similar.json"}}],"links":{"self":"http://api.rottentomatoes.com/api/public/v1.0/movies.json?q=Krull&page_limit=30&page=1"},"link_template":"http://api.rottentomatoes.com/api/public/v1.0/movies.json?q={search-term}&page_limit={results-per-page}&page={page-number}"}
Edit: Thanks, Dan. That was the nudge I needed. After I understood how to get at the JSON data, I was able to find the following explanation of how to turn it into a useful query:Work with remote API JSON data in CF.
The data needs to be deserialized:
<cfset tomatoData=DeserializeJSON(httpResp.filecontent)>
<cfdump var="#tomatoData#">
It looks like the first level in has nothing but structs. So you may be able to
<cfdump var="#tomatoData.total#"> <!--- A single item --->
<cfdump var="#tomatoData.movies#"> <!--- An array --->
The filecontent looks like json. You can refer to it by using
#httpResp.filecontent#.

Convert a list to a JSON Object in erlang (mochijson)

i would really appreciate any help.
I would like to convert this list
[[{id1,1},{id2,2},{id3,3},{id4,4}],[{id1,5},{id2,6},{id3,7},{id4,8}],[...]]
to a JSON object.
Need some inspiration :)
please help.
Thank you.
Since you asked for inspiration, I can immagine two directions you can take
You can write code to hand-role your own JSON which, if your need is modest enough, can be a very light-weight and appropriate solution. It would be pretty simple Erlang to take that one data-structure and convert it to the JSON.
"[[{\"id1\":1},{\"id2\":2},{\"id3\":3},{\"id4\":4}],[{\"id1\":5},{\"id2\":6} {\"id3\":7},{\"id4\":8}]]"
You can produce a data-structure that mochiweb's mochijson:encode/1 and decode/1 can handle. I took your list and hand coded it to JSON, getting:
X = "[[{\"id1\":1},{\"id2\":2},{\"id3\":3},{\"id4\":4}],[{\"id1\":5},{\"id2\":6},{\"id3\":7},{\"id4\":8}]]".
then I used mochison:decode(X) to see what structure mochiweb uses to represent JSON (too lazy to look at the documentation).
Y = mochijson:decode(X).
{array,[{array,[{struct,[{"id1",1}]},
{struct,[{"id2",2}]},
{struct,[{"id3",3}]},
{struct,[{"id4",4}]}]},
{array,[{struct,[{"id1",5}]},
{struct,[{"id2",6}]},
{struct,[{"id3",7}]},
{struct,[{"id4",8}]}]}]}
So, if you can create this slightly more elaborate data structure then the one you are using, then you can get the JSON by using mochijson:encode/1. Here is an example imbeddied in an io:format statement so that it prints it as a string -- often you would use the io_lib:format/X depending on your application.
io:format("~s~n",[mochijson:encode(Y)]).
[[{"id1":1},{"id2":2},{"id3":3},{"id4":4}],[{"id1":5},{"id2":6},{"id3":7},{"id4":8}]]

Working with Form Arrays in ColdFusion?

I have no idea how to handle this in ColdFusion 9, I have a form being submitted (POST) with element checkboxes, called items[].
When I do a <cfdump var="#form#" /> no-problem, I get all the items shown with the proper names like items[] eg:
struct
ITEMS[] 13,14
FIELDNAMES ITEMS[]
however doing a <cfdump var="#form.items[]#" /> results in an error. How do I access the CF9 field values? Somehow loop through it?
I cannot seem to do anything with the array to get the id's out of it? Thoughts? I'm kind of stumped and ColdFusion isn't the easiest language to find examples / references on the net. ;)
Is there a correct way to deal with this? I need to get the ID's out of there so I can reference what lines were checked in the form, so I can follow up with an action.
Thanks!
There's no Form Array’s in ColdFusion. Having '[]' at the end doesn't make it an array. You can access the checkbox values from form scope like this:
FORM["ITEMS[]"]
Dot notation doesn't work 'cause of the '[]'. See: http://help.adobe.com/en_US/ColdFusion/9.0/Developing/WSc3ff6d0ea77859461172e0811cbec22c24-7fb2.html
Values from checkboxes are just comma separated values, which is a List in ColdFusion
To loop through it, use cfloop list=:
<cfoutput>
<cfloop index="i" list="#FORM['ITEMS[]']#">
#i#
</cfloop>
</cfoutput>
To convert a list to array, use ListToArray(). There are list functions like listGetAt(), but if you're doing lots of random access, it'd be smarter to convert the list into an array first.
Thoughts, I'm kindof stumped and
coldfusion isn't the easiest language
to find examples / references on the
net ;)
http://help.adobe.com/en_US/ColdFusion/9.0/Developing/index.html
http://learncf.com/tutorials
http://www.easycfm.com/
http://www.carehart.org/ugtv/
I can highly recommend Brian Kotek's "Form Utils" for cases such as this: http://www.briankotek.com/blog/index.cfm/2007/9/4/Implicit-Creation-of-Arrays-and-Structures-from-Form-Fields
I use this in every app I build, because working with arrays and structs on the form submission side is much more preferable to working with lists, imo.
See also the second answer here. It describes how to retrieve values from a field with multiple instances on a form as an array. I have to say though, I've been working in CFML for many years, and I've yet to do this myself, or see it done in any app I've worked on. I think that's just because avoiding commas is very much simpler, but if you can't or don't want to work around it that way, it is possible.
Also, note that in an ajax world, if you json encode the entire body of a post request, rather than individual form fields, it can be any arbitrary data structure, retrievable easily on the server. The snippet below shows how to get to it from ColdFusion. I'm not certain about other languages, but it's almost certainly possible.
To send a post like that using jQuery, JSON.stringify your data before passing it to jQuery, as noted here and here.
If you're building your own ajax request, the punchline would be:
xhr.send(JSON.stringify(data));
To access that data on the server side, this ColdFusion example looks first for that kind json-encoded post body, then a post with json data in the form field 'input', then in a url field with that same name. In all cases, the resulting data gets deserialized and assigned to the local var 'input', which you can then put in request scope, 'rc', or whatever your code expects.
if (Find('application/json', cgi.content_type))
{
input = ToString(GetHttpRequestData().content);
if (IsJSON(input))
input = DeserializeJSON(input);
}
else if (StructKeyExists(form, 'input') and IsJSON(form.input))
input = DeserializeJSON(form.input);
else if (StructKeyExists(url, 'input') and IsJSON(url.input))
input = DeserializeJSON(url.input);
With you list that are Id's it works fine, but if you have an array with comma's in then you're stuck.
In that case you can use the Java method getParameterValues.
<cfdump var="#getPageContext().getRequest().getParameterValues('ITEMS')#">
This will give you an standard CF array which you can use.
For ColdFusion 10+, if you use the sameformfieldsasarray setting in your Application.cfc like this:
component {
this.name = "testingzone2c";
this.sameformfieldsasarray=true;
}
You will get an actual array of form fields with the same name.
ColdFusion 10 Missing Feature - Form Fields and Arrays
I suggest that you remove the "[]" from the name since it disallows dot notation as mentioned in another answer.. When more than one form element contains the same name attribute, the browser will concatenate all of the values into a comma delimited string when submitting the form. Fortunately, ColdFusion has many functions which treat a delimited string as a list. You can use <cfloop> along with these functions to consume the list.