I've seen so many complicated questions in SO whether or not some complicated structure is considered to be valid JSON.
But what about something on the other end of the spectrum?
"12345"
Is the above valid JSON?
Yes, in most contexts. It is valid JSON syntax representing a JSON value.
The confusion around this comes from Douglas Crockford's RFC 4627, which originally defined the application/json internet media type in 2006. It said that:
A JSON text is a serialized object or array.
However, as Crockford explained in a post in 2013 (unfortunately deleted with rest of Google+, but archived here):
JSON is just a grammar, and the grammar includes numbers and strings. Uses of JSON must necessarily be more restrictive. RFC-4627 is one possible use, and was never intended to be the standard for JSON itself.
The example string is a valid JSON value, but it would have been incorrect to use it as the full "JSON text" body of an application/json HTTP response. However, that's no longer true: RFC-4627 was obsoleted in 2014 with the publication of RFC 7159, which lets you use any JSON value:
A JSON text is a serialized value. Note that certain previous specifications of JSON constrained a JSON text to be an object or an array.
A "standard for JSON itself" was also published in 2013, as ECMA-404, and JSON was also defined in edition 5.1 of the ECMAScript (JavaScript) specification ECMA-262. These specifications and most parsers allow any JSON value as a complete JSON text, even if it's just a simple string.
As of 2014, RFC 7159 obsoletes the older JSON RFCs, and declares that any JSON value is valid JSON text and valid application/json content - including strings. However, it also points out the incompatibility issue with older JSON implementations:
Note that certain previous specifications of JSON constrained a
JSON text to be an object or an array. Implementations that
generate only objects or arrays where a JSON text is called for
will be interoperable in the sense that all implementations will
accept these as conforming JSON texts.
Its a valid JSON string, but its not a JSON object.
See http://www.json.org/
At the time this question was written, this would not have been a valid JSON text. It would have been a valid string that could appear as part of a JSON text.
The original specification said:
A JSON text is a serialized object or array.
… meaning that the top level had to be {} or []. You couldn't dive straight in with a string.
The latest specification says:
A JSON text is a serialized value. Note that certain previous specifications of JSON constrained a JSON text to be an object or an array.
So now any value, including a string, can be a complete JSON text and "12345" is now valid.
You can simply check what JSON.parse can handle:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse#examples
This is all valid JSON:
JSON.parse('{}'); // {}
JSON.parse('true'); // true
JSON.parse('"foo"'); // "foo"
JSON.parse('[1, 5, "false"]'); // [1, 5, "false"]
JSON.parse('null'); // null
Related
This is driving me nuts and I'm hoping someone has encountered this & come up with a clean, elegant solution. When making a JSON request to the LinkedIn REST Api, the body comes back as a string with new-line characters. When I parse the string to JSON with JSON.parse it appears to create a JSON Object, but I can't access the values with dot notation using their relative keys. I have tried escaping the new line characters, a combination of JSON.stringify then parsing, etc. I cannot get this to work and it's obnoxious, though I'm sure there's a simple solution I'm overlooking. Here's the response from the LinkedIn API:
{"statusCode":200,"body":"{\n \"numConnections\": 152,\n
\"numConnectionsCapped\":
false\n}","headers":{"server":"Apache-Coyote/1.1","x-li-request-id":"myid","vary":"*","x-li-format":"json","content-type":"application/json;charset=UTF-8","date":"Tue,
10 Jan 2017 00:08:01
GMT","x-li-fabric":"prod-ltx1","transfer-encoding":"chunked","x-li-pop":"prod-ltx1","set-cookie":["lidc=\"b=TB70:g=489:u=129:i=1484006881:t=1484082637:s=AQG3LuLPqWuZiIoHGf2NqD8O7mRfdA4q\";
Expires=Tue, 10 Jan 2017 21:10:37 GMT; domain=.linkedin.com;
Path=/"],"x-li-uuid":"53NCd2VAmBSAAWKrrSoAAA=="},"request":{"uri":{"protocol":"https:","slashes":true,"auth":null,"host":"api.linkedin.com","port":443,"hostname":"api.linkedin.com","hash":null,"search":"?format=json","query":"format=json","pathname":"/v1/people/id=myid:(num-connections,num-connections-capped)","path":"/v1/people/id=myid:(num-connections,num-connections-capped)?format=json","href":"https://api.linkedin.com/v1/people/id=myid:(num-connections,num-connections-capped)?format=json"},"method":"GET","headers":{"authorization":"Bearer
mytoken"}}}
I'm trying to access the value with key "numConnections" but just can't get to the value.
Using JSON.parse(response.body) gets me this result:
{"numConnections":152,"numConnectionsCapped":false}
however I still cannot access the values associated with each key using
myObj.numConnections or any of the other notation I've tried. How can I get a valid JSON object out of this in NodeJS?
The result of parsing response.body is an object - on which you can use dot notation or bracket notation to access the values:
var parsedBody = JSON.parse(response.body);
parsedBody.numConnections //152
parsedBody['numConnections'] //152
Try
JSON.parse(JSON.stringify(response.body))
Well, this was stupid. I found that my issue was really with Express not allowing numeric values to be sent with res.send(num). For some reason there was no error in the console as a resulting and I was receiving an undefined value with the get request. Parsing the JSON was not the issue, but marked answer as valid. If anyone else is having this issue, you need to stringify numeric values when separating them from the object if you want to send them as a response in Express!
I am just trying to parse a Json document with a field Date like this:
´ death':Date('2007-03-17T04:00:00Z') using
com.mongodb.util.JSON.parse(document)
There is an exception when the value Date is encountered. Any help?
The key here is whatever has exported the data has done it wrong. Possibly someone has run something from the MongoDB shell and redirecting console output to a file. That is basically "doing it wrong".
There is a concept called MongoDB Extended JSON and has in fact been picked up in a few other areas, notably the EJSON project.What this tries to do is make sure that any exported JSON maintains "type" information to the BSON type identifier ( or other Object Type, in the purpose of EJSON ) so that a similar "extended JSON" parser can "re-construct" the object to it's intended form.
For a "date" object, the intented JSON representation is this:
{ "death": { "$date": "2007-03-17T04:00:00Z" } }
Since com.mongodb.util.JSON.parse is enabled with knowledge of the Extended JSON spec, then any such JSON contruct will result in a correct date object being constructed from the parsed data.
So what you have right now is just a "string". In fact, if it is not "quoted" like this:
´ { "death" : "Date('2007-03-17T04:00:00Z')" }
Then it is not in fact even valid JSON and would even need to be manipulated to a correct form before even a basic JSON parser would not error. At any rate, the result is just a "string" still, so you would need to make a regex match for the numerical data, then pass that to a date object construct.
Clearly the "best" thing to do here is to fix the "export" source of the data so that it is doing this date parsing to JSON in the correct extended way. Then the parser you are using will do the right thing.
I know this will sound impossible but my boss told me I MUST send a JSON over an AJAX post call with jQuery that MUST HAVE DUPLICATE KEYS. the problem is that if I write something like this:
$.post("someurl", {
"key1" : "value1",
"key2" : "value2",
"key2" : "value3",
"key2" : "value4",
"key3" : "value5"
});
, jQuery will send the request as
someurl?key1=value1&key2=value4&key3=value5
all this because Javascript overwrites properties that have the same name. The JSON object is generated dynamically and I am NOT ALLOWED to use arrays in it. Can someone tell me how could I generate the JSON object dinamicaly and with duplicate keys?
I would realy appreciate any help from you!
From what I can see, {"a": "b", "a": "c"} actually is valid JSON according to RFC 4627.
An object structure is represented as a pair of curly brackets
surrounding zero or more name/value pairs (or members). A name is a
string. A single colon comes after each name, separating the name
from the value. A single comma separates a value from a following
name. The names within an object SHOULD be unique.
...where SHOULD means:
3. SHOULD. This word, or the adjective "RECOMMENDED", mean that there
may exist valid reasons in particular circumstances to ignore a
particular item, but the full implications must be understood and
carefully weighed before choosing a different course.
So yeah, basically you can do that, it is legal, but it's also a bad idea. Different JSON decoders will probably handle this situation differently and/or in undesiderable ways. Look at what the spec requires of parsers:
A JSON parser transforms a JSON text into another representation. A
JSON parser MUST accept all texts that conform to the JSON grammar.
A JSON parser MAY accept non-JSON forms or extensions.
An implementation may set limits on the size of texts that it
accepts. An implementation may set limits on the maximum depth of
nesting. An implementation may set limits on the range of numbers.
An implementation may set limits on the length and character contents
of strings.
...but an implementation doesn't have to handle situations like this sanely. For example:
# Python 2.7
>>> import json
>>> json.JSONDecoder().decode('{"a": "b", "a": "c"}')
`{u'a': u'c'}`
# Chrome 32
> JSON.parse('{"a": "b", "a": "c"}')
Object {a: "c"}
...and other implementations may legally give you (in Python notation):
{"a": "b"}
[("a", "b"), ("a", "c")]
[("a", ["b", "c"])]
[]
42
"your JSON is bad and you should feel bad"
...or just good old nasal daemons. Literally the only illegal thing for a JSON parser to do here is raise an exception.
The last thing you want to do in your production code is to rely on weird side cases. So the last thing you want to do is exercise your right to form nominally legal but practically useless JSON. If you want to do that, you'll have to do it by hand - build your own abstract syntax trees, your own parsers, your own generators, generators for anybody who might want to consume your data...
A Javascript object with duplicate keys is not a Javascript object. In fact, it is no more than a figment of your imagination. It is totally impossible.
The only way to do this is with an array:
{
"key1" : "value1",
"key2" : ["value2", "value3", "value4"],
"key3" : "value5"
}
jQuery will convert this into key1=value1&key2%5B%5D=value2&key2%5B%5D=value3&key2%5B%5D=value4&key3=value5
This is genuinely the only way to do this.* Is there a reason why your code cannot generate valid JSON?
* Except for writing your own parser that handles invalid JSON. But that would be breathtakingly stupid.
I would do it only if the JSON parser on the other side accepts it properly, without dropping anything. If you can show it dropping stuff, then you can look for another solution (like using an array, or generating the JSON by hand, or using a URL properly. You need better test cases first for your server.
If you can't change the source at the source, then change the source into something you can at least work with...
Parse the JSON into an Array of key value pairs (not into an object of key/value pairs).
You could do this easily if you have access to the JSON string, simply replace all "," with "},{" and wrap the result in "[" and "]".
You now have a valid JSON array of key/value pairs that is javascript legal.
From JSON website:
JSON is built on two structures:
A collection of name/value pairs. In various languages, this is realized as an object, record, struct, dictionary, hash table, keyed list, or associative array.
An ordered list of values. In most languages, this is realized as an array, vector, list, or sequence.
Now I have a sample service that returns a boolean (this is in PHP, but it could be any server side language):
<?php
header('Content-Type: application/json');
echo 'true';
exit;
And when requesting this page with ajax (for example with jQuery):
$.ajax({
url: 'service.php',
dataType: 'json',
success: function (data) {
console.log(data);
console.log(typeof data);
}
});
The result would be:
-> true
-> boolean
My question is why it's allowed to return boolean as a JSON.
Doesn't it have conflict with JSON definition?
ALSO
Also I can return number or string in my service:
<?php
header('Content-Type: application/json');
echo '2013';
exit;
And the result is:
-> 2013
-> number
And for string:
<?php
header('Content-Type: application/json');
echo '"What is going on?"';
exit;
And the result is:
-> What is going on?
-> string
You are correct that a valid JSON text can only be an object or an array. I asked Douglas Crockford about this in 2009 and he confirmed it, saying "Strictly speaking, it is object|array, as in the RFC."
The JSON RFC specifies this in section 2:
A JSON text is a serialized object or array.
JSON-text = object / array
The original JSON syntax listed on json.org does not make this clear at all. It defines all of the JSON types, but it doesn't say anywhere which of these types may be used as a "JSON text" - a complete valid piece of JSON.
That's why I asked Doug about it and he referred me to the RFC. Unfortunately, he didn't follow up on my suggestion to update json.org to clarify this.
Probably because of this confusion, many JSON libraries will happily create and parse (invalid) JSON for a standalone string, number, boolean, etc. even though those aren't really valid JSON.
Some JSON parsers are more strict. For example, jsonlint.com rejects JSON texts such as 101, "abc", and true. It only accepts an object or array.
This distinction may not matter much if you're just generating JSON data for consumption in your own web app. After all, JSON.parse() is happy to parse it, and that probably holds true in all browsers.
But it is important if you ever generate JSON for other people to use. There you should follow the standard more strictly.
I would suggest following it even in your own app, partly because there's a practical benefit: By sending down an object instead of a bare string, you have a built-in place to add more information if you ever need to, in the form of additional properties in the object.
Along those lines, when I'm defining a JSON API, I never use an array at the topmost level. If what I have is an array of items of some sort, I still wrap it in an object:
{
"items": [
...
]
}
This is partly for the same reason: If I later want to add something else to the response, having the top level be an object makes that easy to do without disrupting any existing client code.
Perhaps more importantly, there's also a possible security risk with JSON arrays. (I think that risk only affects the use of eval() or the Function constructor to parse JSON, so you're safe with JSON.parse(), but I'm not 100% sure on this.)
Note, the answer from Michael Geary is outdated since rfc7158 in 2013 which does not limit JSON text to array or object anymore. The current RFC https://www.rfc-editor.org/rfc/rfc8259 says:
A JSON text is a serialized value. Note that certain previous
specifications of JSON constrained a JSON text to be an object or an
array. Implementations that generate only objects or arrays where a
JSON text is called for will be interoperable in the sense that all
implementations will accept these as conforming JSON texts.
Why is this JSON giving me parse errors? I could swear I've done this a hundred times before without issue.
[[0,0,0,new Date(1364068990245)],[0,0,0,new Date(1364068940075)]]
If that's literal JavaScript, as in this:
var myArray = [[0,0,0.......]];
Then it should be fine, your error must be coming from somewhere else.
If it's a string that you're treating as JSON, as in this:
var myArray = JSON.parse("[[0,0,0.........]]");
Then you can't have new Date (or indeed any function call) and it should be just a number that you then parse into a date.
Because the new operator isn't part of JSON. Your example is a valid fragment of a JavaScript file, but it correctly results in an error when parsed as JSON. Dates should be serialized as strings (ideally, as ISO-8601 strings that will be accepted by the Date constructor, but I suppose numbers are tolerable as well).
That's not JSON, there are no dates in the JSON format.
Ref: http://www.json.org/
Some JSON parsers have extended the standard with this way of representing a date:
"[[0,0,0,/Date(1364068990245)/],[0,0,0,/Date(1364068940075)/]]"
If the parser that you use doesn't support that, you have to transmit them as a different data type, for example numbers, and then convert them to dates after parsing the JSON:
"[[0,0,0,1364068990245],[0,0,0,1364068940075]]"