12

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!

Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985
  • 7
    ["The names within an object SHOULD be unique."](http://www.ietf.org/rfc/rfc4627.txt). Ask your boss if he wants you to buy a left handed paint brush while you're at it. – Quentin Jun 12 '13 at 10:33
  • 3
    If jQuery sends the data as `someurl?key1=value1&key2=value4&key3=value5` then it isn't sending JSON. – Quentin Jun 12 '13 at 10:34
  • If the query string is the final result that needs to include multiples of the same key, then don't create it using an api that does not allow it. Just build it yourself using whatever date-structure is suitable (e.g. json+arrays). – Yoshi Jun 12 '13 at 10:55
  • 2
    Btw, do you really want to create JSON or an object? Just getting the terminology straight. [There is no such thing as a JSON object](http://benalman.com/news/2010/03/theres-no-such-thing-as-a-json/). – Felix Kling Jun 12 '13 at 11:04
  • 2
    That's one of the most stupid requirements I ever heard of, your job must be hard... – bert Jun 12 '13 at 11:10

4 Answers4

19

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...

chbrown
  • 11,865
  • 2
  • 52
  • 60
badp
  • 11,409
  • 3
  • 61
  • 89
  • 2
    This is a good answer, but overlooks the fact that the question actually is not really about JSON... – lonesomeday Nov 12 '13 at 10:51
  • @lonesomeday AFAICT the query part of an URL is [basically arbitrary](http://tools.ietf.org/html/rfc3986#section-3.4) and its `key=value&key=value` structure is mainly convention, so `?a=b&a=c` would still be legal. So that transformation from JSON to URLs wouldn't be absurd or impossible, but certainly you won't get it for free with standard components. – badp Nov 12 '13 at 11:37
  • 1
    The point is that a Javascript object literal may have duplicate keys, and JSON may have duplicate keys, and a HTTP query may have duplicate keys, but a Javascript object cannot, and nothing can change that. And the question, as I interpreted it, is about Javascript objects, not JSON. – lonesomeday Nov 12 '13 at 12:53
  • 2
    @lonesomeday If you believe so then this question needs some cleanup. The whole reason why I stumbled into this question in the first place is by googling whether or not JSON objects can have duplicate keys - and the answer to that question is definitely "yes". – badp Nov 12 '13 at 13:22
3

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.

JSK NS
  • 3,346
  • 2
  • 25
  • 42
lonesomeday
  • 233,373
  • 50
  • 316
  • 318
0

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.

John Carlson
  • 321
  • 1
  • 13
0

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.

Rodney P. Barbati
  • 1,883
  • 24
  • 18
  • Editing the input before parsing it is very bug-prone. Your idea would replace `{"x":"a,b"}` with `[{"x":"a},{b"}]`. (It' still valid JSON, but now the string has a different value.) – dpercy Feb 22 '16 at 20:48