JSON Structure/Syntax - json

Could anyone give me a clue what is wrong with the JSON syntax listed below. According to JsonLint the error is/begins in front of the word "csv". I cannot see the error in the syntax but it must be there. If someone could just tell me the principle behind my error please.
{
"lists": {
"csv": "function(head, req) {
var row,
first = true;
// output HTTP headers
start({
headers: {
'Content-Type': 'text/csv'
},
});
// iterate through the result set
while (row = getRow()) {
// get the doc (include_docs=true)
var doc = row.doc;
// if this is the first row
if (first) {
// output column headers
send(Object.keys(doc).join(',') + 'n');
first = false;
}
// build up a line of output
var line = '';
// iterate through each row
for (var i in doc) {
// comma separator
if (line.length > 0) {
line += ',';
}
// output the value, ensuring values that themselves
// contain commas are enclosed in double quotes
var val = doc[i];
if (typeof val == 'string' && val.indexOf(',') > -1) {
line += '" ' + val.replace(/"/g, ' "" ') + ' "';
} else {
line += val;
}
}
line += 'n';
// send the line
send(line);
}
}
"
}
}
EDIT:
Full code(CouchDB view/list):
{
"_id": "_design/comptno",
"_rev": "2-4531ba9fd5bcd6b7fbc5bc8555f0bfe3",
"views": {
"list_example": {
"map": "function(doc) {\r\n if (doc.compartment.number) {\r\n emit(doc.compartment.number, null);\r\n }\r\n};"
},
"list_example2": {
"map": "function(doc) {\r\n if (doc.compartment.number) {\r\n emit(doc.compartment.number, null);\r\n }\r\n};"
}
},
"lists":{"csv":"function(head, req) { var row, first = true; // output HTTP headers start({ headers: { 'Content-Type': 'text/csv' }, }); // iterate through the result set while (row = getRow()) { // get the doc (include_docs=true) var doc = row.doc; // if this is the first row if (first) { // output column headers send(Object.keys(doc).join(',') + 'n'); first = false; } // build up a line of output var line = ''; // iterate through each row for (var i in doc) { // comma separator if (line.length > 0) { line += ','; } // output the value, ensuring values that themselves // contain commas are enclosed in double quotes var val = doc[i]; if (typeof val == 'string' && val.indexOf(',') > -1) { line += '"' + val.replace(/"/g, '""') + '"'; } else { line += val; } } line += 'n'; // send the line send(line); }}"},
"language": "javascript"
}

Here corrected without multilines:
{
"lists": {
"csv": [
"function(head, req) {",
"var row,",
"first = true;",
"",
"// output HTTP headers",
"start({",
"headers: {",
"'Content-Type': 'text/csv'",
"},",
"});",
"",
"// iterate through the result set",
"while (row = getRow()) {",
"// get the doc (include_docs=true)",
"var doc = row.doc;",
"// if this is the first row",
"if (first) {",
"// output column headers",
"send(Object.keys(doc).join(',') + 'n');",
"first = false;",
"}",
"// build up a line of output",
"var line = '';",
"// iterate through each row",
"for (var i in doc) {",
"// comma separator",
"if (line.length > 0) {",
"line += ',';",
"}",
"// output the value, ensuring values that themselves",
"// contain commas are enclosed in double quotes",
"var val = doc[i];",
"if (typeof val == 'string' && val.indexOf(',') > -1) {",
"line += '\" ' + val.replace(/\"/g, ' \"\" ') + ' ';",
"} else {",
"line += val;",
"}",
"}",
"line += 'n';",
"// send the line",
"send(line);",
"}",
"}",
""
]
}
}

Related

UrlFetchApp.fetch(url) fails

I have a bit of GAS code that is failing when executing UrlFetchApp.fetch(url) - I think.
Are there limits to the character length of a url when used in UrlFetchApp.fetch(url). My function is failing and I suspect that it has something to do with the length of the url. It is over 100 chars.
The code below refers...
function uploadToDrive(url, folderid, filename, fileDesc) {
var msg = '';
try {
var response = UrlFetchApp.fetch(url);
} catch(err) {
};
if (response.getResponseCode() === 200) {
var folder = DriveApp.getRootFolder();
if (folderid) {
folder = DriveApp.getFolderById(folderid);
}
var blob = response.getBlob();
var file = folder.createFile(blob);
file.setName(filename);
file.setDescription(fileDesc);
var headers = response.getHeaders();
var content_length = NaN;
for (var key in headers) {
if (key.toLowerCase() == 'Content-Length'.toLowerCase()) {
content_length = parseInt(headers[key], 10);
break;
}
}
var blob_length = blob.getBytes().length;
msg += 'Saved "' + filename + '" (' + blob_length + ' bytes)';
if (!isNaN(content_length)) {
if (blob_length < content_length) {
msg += ' WARNING: truncated from ' + content_length + ' bytes.';
} else if (blob_length > content_length) {
msg += ' WARNING: size is greater than expected ' + content_length + ' bytes from Content-Length header.';
}
}
msg += '\nto folder "' + folder.getName() + '".\n';
}
else {
msg += 'Response code: ' + response.getResponseCode() + '\n';
}
return file.getUrl();
}
That link generates a response code 404, but you set the response variable only if the fetch method is successful in your try block. Try validating the response variable before assuming it has properties and methods to access:
function fetching() {
var url = "<some url resource>";
try {
var response = UrlFetchApp.fetch(url);
} catch (err) {
// why catch the error if you aren't going to do anything with it?
Logger.log(err);
} finally {
if (response && response.getResponseCode() === 200) {
Logger.log("Should be 200, got " + response.getResponseCode());
} else {
Logger.log("Fetching Failed: Exception thrown, no response.");
}
}
}
However, I would go farther and guarantee a response from UrlFetchApp.fetch. This is done with the "muteHttpExceptions" paramater set to true.
function fetching() {
//dns exception
//var = "googqdoiqijwdle.com"
//200
var url = "google.com";
//404
//var url = "https://www.jotform.com/uploads/Administrator_System_sysadmin/92960977977584/4480552280228238115/BoE%20Test%20File.docx"
try {
var response = UrlFetchApp.fetch(url, {
muteHttpExceptions: true
});
} catch (err) {
Logger.log(err);
}
if (response) {
response.getResponseCode() === 200 ?
Logger.log("Should be 200, got " + response.getResponseCode()) :
Logger.log("Anything but 200, got " + response.getResponseCode());
}
}
Hope this helped!
Docs: Google Developers

Convert a JSON object to a particular CSV format

I want to convert this
{
"Name A":{
"Name B":{
"Name C":"Value C",
"Name D":"Value D",
"Name E":"Value E"
}
}
}
to this
Name A,,,
,Name B,,
,, Name C,Value C
,, Name D,Value D
,,Name E,Value E
It will look like this when opened in excel
I'm attempting to achieve this by running a small script, but before that I wanted to check if there is any node package or tool that can achieve this easily. Any clues?
Might be you can try with this npm module csvjson.
The link is here:- https://www.npmjs.com/package/csvjson
I solved this by writing my own script. I had to tweak a little to fit my necessity according to the format of the data. It is not the most elegant solution. It was quick dirty solution I got working. Still it's a good reference if anyone wants to try writing their own script to convert JSON to CSV
var fs = require('fs');
var file = 'templateEn.json';
var content = fs.readFileSync(file, { encoding: 'binary' });
var obj = JSON.parse(content);
var jsonString = ""
var lineEnd = "\r\n";
var firstLevelKeys = Object.keys(obj);
jsonString += firstLevelKeys[0] + ",,,,," + lineEnd;
var secondLevelKeys = Object.keys(obj["en"]);
secondLevelKeys.forEach(key => {
jsonString += ',' + key +',,,,'+ lineEnd
var thirdLevelKeys = Object.keys(obj["en"][key]);
thirdLevelKeys.forEach(key2=>{
if (typeof obj["en"][key][key2] === "string"){
jsonString += ",," + key2 + ',"' + obj["en"][key][key2]+'",,'+ lineEnd;
}
else if (typeof obj["en"][key][key2] === "object"){
var fourthLevelKeys = Object.keys(obj["en"][key][key2]);
jsonString += ',,' + key2 + ',,,' + lineEnd
fourthLevelKeys.forEach(key3 => {
if (typeof obj["en"][key][key2][key3] === "string") {
jsonString += ",,," + key3 + ',"' + obj["en"][key][key2][key3] + '",' + lineEnd;
}
else if (typeof obj["en"][key][key2][key3] === "object") {
var fifthLevelKeys = Object.keys(obj["en"][key][key2][key3]);
jsonString += ',,,' + key3 + ',,' + lineEnd
fifthLevelKeys.forEach(key4 => {
if (typeof obj["en"][key][key2][key3][key4] === "string") {
jsonString += ",,,," + key4 + ',"' + obj["en"][key][key2][key3][key4] + '"' + lineEnd;
}
})
}
})
}
});
});
fs.writeFileSync("generated.csv", jsonString, "utf8");

Flattening JSON but keep original properties

I am trying to flatten properties (i.e. objects, array) of a JSON object, but keep the original properties the same, and turn non-scalar properties into strings.
(I'm doing this because when I use the flat npm package, arrays/objects are flattened, but object keys are surrounded by '' , like in 'task_status.0.data' and do not get stored into AzureTables). If there is a way to fix that and de-string that, it would be an ok solution as well...)
Here's an example you could run on jsfiddle.net
var obj1 = {
"studentId": "abc",
"task_status": [
{
"status":"Current",
"date":516760078
},
{
"status":"Late",
"date":1516414446
}
],
"student_plan": "n"
}
FlattenJson = function(obj){
keys = Object.keys(obj);
var newObj = {};
for(var i=0; i<keys.length; i++){
var theType = typeof(obj[keys[i]]);
console.log(theType);
if(theType === 'array' || theType === 'object'){
console.log(JSON.stringify(obj[keys[i]]));
newObj[keys[i]] = "\"" + JSON.stringify(obj[keys[i]]) + "\"";
}
newObj[keys[i]] = obj[keys[i]];
}
return newObj;
}
var newObj1 = FlattenJson(obj1);
console.log(newObj1, obj1);
However, the newobj1 contains the same original array, instead of a string. How would I fix this?
UPDATED: Thanks to this you have a solution.
var obj1 = {
"studentId": "abc",
"task_status": [
{
"status":"Current",
"date":516760078
},
{
"status":"Late",
"date":1516414446
}
],
"student_plan": "n"
}
function customToString (obj) {
var str = '{';
for (var prop in obj) {
if (obj.hasOwnProperty(prop)) {
str += prop + ':"' + obj[prop] + '",';
}
}
return str.replace(/.$/,'') + '}';
}
var flattenObject = function(ob) {
var toReturn = {};
for (var i in ob) {
if (!ob.hasOwnProperty(i)) continue;
if ((typeof ob[i]) == 'object') {
var flatObject = flattenObject(ob[i]);
for (var x in flatObject) {
if (!flatObject.hasOwnProperty(x)) continue;
toReturn[i + '.' + x] = flatObject[x];
}
} else {
toReturn[i] = ob[i];
}
}
return toReturn;
};
var newObj1 = flattenObject(obj1);
console.log(newObj1, obj1);
document.write(customToString(newObj1));

how to convert the json to csv

I am new to this and working with json recently. I need to convert json to csv.
I have a json file with the following data. How do i convert to csv file.
[
{
"name":"Search&Navigator",
"region":"F&R",
"checkins":[[2000,100],[2001,200],[2002,300],[2003,275],[2004,222],[2005,280],[2006,281],[2007,400],[2008,55],[2009,300]],
"teamsize":[[2000,10],[2001,7],[2002,7],[2003,12],[2004,5],[2005,3],[2006,10],[2007,12],[2008,12],[2009,10]],
"Checkintimes":[[2000,40],[2001,50],[2002,60],[2003,50],[2004,40],[2005,30],[2006,30],[2007,35],[2008,30],[2009,30]]
},
{
"name":"Cobalt",
"region":"Legal",
"checkins":[[2000,121],[2001,339],[2002,124],[2003,255],[2004,325],[2005,460],[2006,177],[2007,221],[2008,122],[2009,120]],
"teamsize":[[2000,12],[2001,12],[2002,12],[2003,12],[20041,2],[2005,12],[2006,11],[2007,3],[2008,7],[2009,7]],
"Checkintimes":[[2000,20],[2001,40],[2002,60],[2003,50],[2004,40],[2005,30],[2006,35],[2007,30],[2008,30],[2009,30]]
}
]
Any links to similar requirement would be fine to start with.
Here is a fiddle I used in the past for this:
http://jsfiddle.net/sturtevant/vUnF9/
The relevant function:
function JSON2CSV(objArray) {
var array = typeof objArray != 'object' ? JSON.parse(objArray) : objArray;
var str = '';
var line = '';
if ($("#labels").is(':checked')) {
var head = array[0];
if ($("#quote").is(':checked')) {
for (var index in array[0]) {
var value = index + "";
line += '"' + value.replace(/"/g, '""') + '",';
}
} else {
for (var index in array[0]) {
line += index + ',';
}
}
line = line.slice(0, -1);
str += line + '\r\n';
}
for (var i = 0; i < array.length; i++) {
var line = '';
if ($("#quote").is(':checked')) {
for (var index in array[i]) {
var value = array[i][index] + "";
line += '"' + value.replace(/"/g, '""') + '",';
}
} else {
for (var index in array[i]) {
line += array[i][index] + ',';
}
}
line = line.slice(0, -1);
str += line + '\r\n';
}
return str;
}
Of course, depending on how you want the conversion to be structured, you could write your own.
I hope this helps.
Miller (mlr) is particularly suitable to parse json and convert it to CSV, TSV DKVP (Key-pair value)
https://miller.readthedocs.io/en/latest/file-formats/
Here is the command that will generate the desired output
mlr --ijson --ocsv cat myfile.json

What is the right way to compare as3 objects using hamcrest

I'm trying to compare two objects to see if they are the same using hamcrest for flex-unit, but when the object has sub objects, it just throws an error:
Error: Expected: (An array containing <[object Object]>
but: an array containing <[object Object]> was <[object Object]>
I want it to do an assertThat(..., hasProperties(...)); on the sub object.
Is there a way to get that or should i create a custom matcher?
EDIT
An example of the object structure i want to test:
var expected:Object = {
number:1.3,
array:[{
prop1:"val1", prop2:"val2"
}]
anObject:{
propA:1, propB:2
},
}
var objectUnderTest:Object = {
number:1.3,
array:[{
prop1:"val1", prop2:"val2"
}]
anObject:{
propA:1, propB:2
},
}
assertThat("should be the same", objectUnderTest, hasProperties(expected));
since the expected and objectUnderTest have the same structure, the test should pass, but is returning the error:
Error: Expected: (An array containing <[object Object]>
but: an array containing <[object Object]> was <[object Object]>
Also, if there is a way to compare two JSON strings will be fine too.
EDIT2
This is my final version after djib help:
package com
{
public function assertEqualsObjects(message:String, object1:Object, object2:Object):Boolean
{
// we have to run it both ways (1-2, 2-1)
return (compare(object1, object2, message + ": object") && compare(object2, object1, message + ": extra"));
}
}
import org.flexunit.asserts.fail;
function compare(object1:Object, object2:Object, parent:String):Boolean
{
var count:int = 0;
for (var s:String in object1)
{
count ++;
if (!object2.hasOwnProperty(s))
{
fail(parent + "." + s + " expected: " + object1[s] + " but was: undefined");
return false;
}
if (!compare(object1[s], object2[s], parent + "." + s))
{
fail(parent + "." + s + " expected: " + object1[s] + " but was: " + object2[s]);
return false;
}
}
if (count == 0 && object1 != object2) // if object has no properties, compare their actual values
{
fail(parent + " expected: " + object1 + " but was: " + object2);
return false;
}
return true;
}
I've put this code together. Recursion is the key ^^
// our two objects to compare ...
var obj1 = {
number:1.3,
array:[{prop1:"val1", prop2:"val2"}],
anObject:{propA:1, propB:2}
};
var obj2 = {
number:1.3,
array:[{prop1:"val1", prop2:"val2"}],
anObject:{propA:1, propB:2}
};
trace(isSame(obj1, obj2)); // -> true
function isSame(object1:Object, object2:Object):Boolean
{
// we have to run it both ways (1-2, 2-1)
return (compare(object1, object2) && compare(object2, object1));
}
function compare(object1:Object, object2:Object):Boolean
{
var count:int = 0;
for (var s:String in object1)
{
count ++;
if (object2[s] == undefined)
return false;
if (!compare(object1[s], object2[s]))
return false;
}
if (count == 0 && object1 != object2) // if object has no properties, compare their actual values
return false;
return true;
}