4

I am attempting to abuse a reviver function with JSON.parse.

I basically want to make certain fields "null".

If I do this:

var json_data = JSON.parse(j, function(key, value) {
  if (key == "name") {        
    return value;
  } else {
    return null;    
  }    
});

The entire json_data object ends up null. In fact, no matter what I make the else, that defines the value of the json_object.

Interestingly, this works as expected:

var json_data = JSON.parse(j, function(key, value) {
  if (key == "name") {        
    return "name";
  } else {
    return value;    
  }    
});

The property "name" now has a value of "name".

JSON in question:

var j = '{"uuid":"62cfb2ec-9e43-11e1-abf2-70cd60fffe0e","count":1,"name":"Marvin","date":"2012-05-13T14:06:45+10:00"}';

Update

I just realized that the inverse of what I want to do works as well so I can nullify the name field:

var json_data = JSON.parse(j, function(key, value) {
  if (key == "name") {        
    return null;
  } else {
    return value;    
  }    
});
Walery Strauch
  • 6,792
  • 8
  • 50
  • 57
Toby Hede
  • 36,755
  • 28
  • 133
  • 162
  • Also, what do you see if you console.log -- or alert -- the value in the reviver function? I checked the [API](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/JSON/parse) and so far your code looks good... – jamesmortensen May 15 '12 at 06:50

2 Answers2

4

It has a rather interesting behavior that the entire object is included in the objects passed to the reviver.

When the entire object is passed, the key is null.

http://jsfiddle.net/sGYGM/7/

var j = '{"uuid":"62cfb2ec-9e43-11e1-abf2-70cd60fffe0e","count":1,"name":"Marvin","date":"2012-05-13T14:06:45+10:00"}';

var json_data = JSON.parse(j, function(k, v) {
    if (k === "" || k == "name") {
        return v;
    } else {
        return null;
    }
});

console.log(json_data);

As per https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/JSON/parse

The reviver is ultimately called with the empty string and the topmost value to permit transformation of the topmost value. Be certain to handle this case properly, usually by returning the provided value, or JSON.parse will return undefined.

Corbin
  • 33,060
  • 6
  • 68
  • 78
  • I'm not sure I understand why the `k === ""` is needed? What does that do exactly? – jamesmortensen May 15 '12 at 06:56
  • @jmort253 As the last call to the reviver function, the entire object is passed. In otherwords, json_data is passed as the last thing to the function. When this is the case, the key is an empty string. – Corbin May 15 '12 at 06:57
  • Now, the better question: I wonder why they chose to use an empty string (which is a valid JSON key) instead of a value like, say, `undefined`, which isn't a valid key (and would kind of make sense). – David Wolever May 15 '12 at 06:58
  • @DavidWolever Who knows. It definitely doesn't make much sense. It could have something to do though with the behavior that returning undefined makes the element be removed from the object. Maybe they were afraid if they made the key undefined and then someone returned undefined, how could they remove the entire object from itself? (Though they could of course just set the object to undefined.) – Corbin May 15 '12 at 07:06
  • @corbin, i had to pick someone as the answer, and you guys posted at nearly the same time. – Toby Hede May 15 '12 at 08:16
4

Through some experimentation, it looks like a final call is made to the function where the key is an empty string and the value is the top-level object:

> JSON.parse('{"hello": "world"}', function(k, v) { console.log(arguments); return v; })
["hello", "world"]
["", Object]

So you could use:

var json_data = JSON.parse(j, function(key, value) {
  if (key == "name" || key === "") {        
    return value;
  } else {
    return null;    
  }    
});

Now, since "" does appear to be a valid JSON key, to be 100% correct it might be better to use something like:

var json_data;
JSON.parse(j, function(key, value) {
  if (key == "name") {        
    return value;
  } else if (key === "") {
    json_data = value;
    return null;
  } else {
    return null;    
  }    
});

But that might be a little bit paranoid ;)

David Wolever
  • 148,955
  • 89
  • 346
  • 502
  • Darn… I like that edit. It made it look as if I had cited sources and stuff ;) – David Wolever May 15 '12 at 06:56
  • @David - Your console example really helps! I see what's going on, I think. One of the arrays returned has a key of "", so if it's not checked, if I understand correctly, the entire object then becomes null? – jamesmortensen May 15 '12 at 06:58
  • Yup. Like @Corbin described, the last call to the reviver has the key set to `""` and the value set to the top-level JSON object (in my example, `{hello: "world"}`). The value returned from this call is the value returned by `JSON.parse`, so if `null` is returned from here (as it would be in the OP's code)`, `JSON.parse` will also return `null`. – David Wolever May 15 '12 at 07:00