Exampple of application/x-www-form-urlencoded string
CorrelationId=1&PickedNumbers%5B%5D=1&PickedNumbers%5B%5D=2&PickedNumbers%5B%5D=3&PickedNumbers%5B%5D=4
Into JSON
var gamePlayData = {
CorrelationId: gameId,
PickedNumbers: ["1","2","3","4"]
};
This is a core module of Node.js now: https://nodejs.org/api/querystring.html#querystring_querystring_parse_str_sep_eq_options
var qs = require('querystring') var json = qs.parse('why=not&sad=salad') // { why: 'not', sad: 'salad' }
Works with encoded characters too:
var json2 = qs.parse('http%3A%2F%2Fexample.com&sad=salad') // { url: 'http://example.com', sad: 'salad' }
I've been dealing with this recently: I had to parse data that could contain objects nested up to 5 levels deep. I needed the code to be able to deal with both rather complex data, but not fail to decode a URI as simple as id=213
.
I spent quite some time on google, trying to find a (semi-)elegant solution to this problem, and this question kept showing up. Since it gets 1 view/day (give or take) I've decided to post my solution here, hope it helps someone out:
function form2Json(str)
{
"use strict";
var obj,i,pt,keys,j,ev;
if (typeof form2Json.br !== 'function')
{
form2Json.br = function(repl)
{
if (repl.indexOf(']') !== -1)
{
return repl.replace(/\](.+?)(,|$)/g,function($1,$2,$3)
{
return form2Json.br($2+'}'+$3);
});
}
return repl;
};
}
str = '{"'+(str.indexOf('%') !== -1 ? decodeURI(str) : str)+'"}';
obj = str.replace(/\=/g,'":"').replace(/&/g,'","').replace(/\[/g,'":{"');
obj = JSON.parse(obj.replace(/\](.+?)(,|$)/g,function($1,$2,$3){ return form2Json.br($2+'}'+$3);}));
pt = ('&'+str).replace(/(\[|\]|\=)/g,'"$1"').replace(/\]"+/g,']').replace(/&([^\[\=]+?)(\[|\=)/g,'"&["$1]$2');
pt = (pt + '"').replace(/^"&/,'').split('&');
for (i=0;i<pt.length;i++)
{
ev = obj;
keys = pt[i].match(/(?!:(\["))([^"]+?)(?=("\]))/g);
for (j=0;j<keys.length;j++)
{
if (!ev.hasOwnProperty(keys[j]))
{
if (keys.length > (j + 1))
{
ev[keys[j]] = {};
}
else
{
ev[keys[j]] = pt[i].split('=')[1].replace(/"/g,'');
break;
}
}
ev = ev[keys[j]];
}
}
return obj;
}
I've tested it, with data like the string below (4 levels deep):
str = "id=007&name[first]=james&name[last]=bond&name[title]=agent&personalia[occupation]=spy&personalia[strength]=women&personalia[weakness]=women&tools[weapons][close][silent]=garrot&tools[weapons][medium][silent]=pistol_supressed&tools[weapons][medium][loud]=smg&tools[weapons][far][silent]=sniper&tools[movement][slow]=foot&tools[movement][far]=DBS";
Which neatly returns an object, that, when passed through JSON.stringify
comes out like this:
{"id":"007","name":{"title":"agent","first":"james","last":"bond"},"personalia":{"weakness":"women","occupation":"spy","strength":"women"},"tools":{"movement":{"far":"DBS","slow":"foot"},"weapons":{"close":{"silent":"garrot"},"medium":{"silent":"pistol_supressed","loud":"smg"},"far":{"silent":"sniper"}}}}
It passes a JSlint check, when ignoring white space, .
and [^...]
and accepting ++
. All in all, I'd consider that to be acceptable.
You can use qs if you're using node, or browserify.
var qs = require('qs')
var encodedString = "CorrelationId=1&PickedNumbers%5B%5D=1&PickedNumbers%5B%5D=2&PickedNumbers%5B%5D=3&PickedNumbers%5B%5D=4"
console.log(qs.parse(encodedString))
// { CorrelationId: '1', PickedNumbers: [ '1', '2', '3', '4' ] }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With