ruslander
ruslander

Reputation: 3875

How to convert an x-www-form-urlencoded string to JSON?

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

(Decoded)

CorrelationId=1&PickedNumbers[]=1&PickedNumbers[]=2&PickedNumbers[]=3&PickedNumbers[]=4

Into JSON

var gamePlayData = {
            CorrelationId: gameId,
            PickedNumbers: ["1","2","3","4"]
        };

Upvotes: 33

Views: 76254

Answers (12)

PrototypeAlex
PrototypeAlex

Reputation: 223

You can use qs library 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' ] }

Upvotes: 15

jradelmo
jradelmo

Reputation: 126

In typescript, works for me:
Use qs.parse to transform in object ParsedQs.
Use as unknow to implicit type unknow and before force convert to string.
Use JSON.parse to convert an string to object.
It was useful to use validations with Joi.

const payload = JSON.parse(JSON.stringify(qs.parse(request.body) as unknown as string));

Payload (cURL):

--data-urlencode 'notification=123-456123' \
--data-urlencode 'test=123456' \
--data-urlencode 'ajieoajeoa=Lorem ipsum'

Result:

{
  notification: '123-456123',
  test: '123456',
  ajieoajeoa: 'Lorem ipsum'
}

Upvotes: 0

danbars
danbars

Reputation: 350

Updated answer for 2022, works both in the browser and in node. Use URLSearchParams class.

Note: The param name PickedNumbers%5B%5D will turn to be the literal string PickedNumbers[]. You don't need to encode the brackets in order to make it an array

    const paramsStr = 'CorrelationId=1&PickedNumbers%5B%5D=1&PickedNumbers%5B%5D=2&PickedNumbers%5B%5D=3&PickedNumbers%5B%5D=4';
    const params = new URLSearchParams(paramsStr);
    //access a specific param
    console.log(params.get('PickedNumbers[]')); // '4'
    console.log(params.getAll('PickedNumbers[]')); // ['1','2','3','4']
     const o = Object.fromEntries(Array.from(params.keys()).map(k => [k, params.getAll(k).length===1 ? params.get(k) : params.getAll(k)]));
    console.log(JSON.stringify(o)); //full object

Upvotes: 7

Daniel Domingues
Daniel Domingues

Reputation: 1

var jsonMessage = "{\"".concat(message.replace("&", "\",\"").replace("=", "\":\"")).concat("\"}");

Upvotes: 0

kolypto
kolypto

Reputation: 35473

A one-liner:

let s = 'a=1&b=2&c=3';

Object.fromEntries(
  s.split('&')
   .map(s => s.split('='))
   .map(pair => pair.map(decodeURIComponent)))

// -> {a: "1", b: "2", c: "3"}

and if you want repeated parameters to be represented as arrays:

let s = 'a=1&b=2&c[]=3&c[]=4&c[]=5&c[]=6';

s
  .split('&')
  .map(s => s.split('='))
  .map(pair => pair.map(decodeURIComponent))
  .reduce((memo, [key, value]) => { 
    if (!(key in memo)) { memo[key] = value; } 
    else { 
      if (!(memo[key] instanceof Array)) 
        memo[key] = [memo[key], value]; 
        else 
        memo[key].push(value); 
      } 
    return memo; 
}, {})

// -> {"a":"1","b":"2","c[]":["3","4","5","6"]}

Upvotes: 2

kuldeep chopra
kuldeep chopra

Reputation: 5

public static void Main()

{

string str ="RESULT=0&PNREF=A10AABBF8DF2&RESPMSG=Approved&AUTHCODE=668PNI&PREFPSMSG=No Rules Triggered&POSTFPSMSG=No Rules Triggered";

    var sr = str.Replace("&", "=");

    string[] sp = sr.Split('=');

    var spl = sp.Length;

    int n = 1;

    var ss = "{";

    for (var k = 0; k < spl; k++)
    {
        if (n % 2 == 0)
        {
            if (n == spl)
            {
                ss += '"' + sp[k] + '"';
            }
            else
            {
                ss += '"' + sp[k] + '"' + ",";
            }
        }
        else
        {
            ss += '"' + sp[k] + '"' + ":";
        }
        n++;
    }
    ss += "}";
    Console.WriteLine(ss);
}

Upvotes: -3

Costa Michailidis
Costa Michailidis

Reputation: 8188

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' }

Upvotes: 37

Igor G.
Igor G.

Reputation: 7019

You need the opposite of jQuery.param. One of the options is http://benalman.com/code/projects/jquery-bbq/examples/deparam/

Upvotes: 0

Elias Van Ootegem
Elias Van Ootegem

Reputation: 76433

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.

Upvotes: 16

Brian Donovan
Brian Donovan

Reputation: 8390

Here's a pure-JavaScript way to do it. JavaScript frameworks might also help you out with this. EDIT: Just for kicks, I threw in dictionary parsing, too. See the 2nd example.

function decodeFormParams(params) {
  var pairs = params.split('&'),
      result = {};

  for (var i = 0; i < pairs.length; i++) {
    var pair = pairs[i].split('='),
        key = decodeURIComponent(pair[0]),
        value = decodeURIComponent(pair[1]),
        isArray = /\[\]$/.test(key),
        dictMatch = key.match(/^(.+)\[([^\]]+)\]$/);

    if (dictMatch) {
      key = dictMatch[1];
      var subkey = dictMatch[2];

      result[key] = result[key] || {};
      result[key][subkey] = value;
    } else if (isArray) {
      key = key.substring(0, key.length-2);
      result[key] = result[key] || [];
      result[key].push(value);
    } else {
      result[key] = value;
    }
  }

  return result;
}

decodeFormParams("CorrelationId=1&PickedNumbers%5B%5D=1&PickedNumbers%5B%5D=2&PickedNumbers%5B%5D=3&PickedNumbers%5B%5D=4");
// => {"CorrelationId":"1","PickedNumbers":["1","2","3","4"]}

decodeFormParams("a%5Bb%5D=c&a%5Bd%5D=e");
// => {"a":{"b":"c","d":"e"}}

Upvotes: 3

Martin Jespersen
Martin Jespersen

Reputation: 26183

the following code should do the trick:

var str = 'CorrelationId=1&PickedNumbers%5B%5D=1&PickedNumbers%5B%5D=2&PickedNumbers%5B%5D=3&PickedNumbers%5B%5D=4';
var keyValuePairs = str.split('&');
var json = {};
for(var i=0,len = keyValuePairs.length,tmp,key,value;i <len;i++) {
    tmp = keyValuePairs[i].split('=');
    key = decodeURIComponent(tmp[0]);
    value = decodeURIComponent(tmp[1]);
    if(key.search(/\[\]$/) != -1) {
        tmp = key.replace(/\[\]$/,'');
        json[tmp] = json[tmp] || [];
        json[tmp].push(value);
    }
    else {
        json[key] = value;
    }
}

Upvotes: 6

Manse
Manse

Reputation: 38147

Try this->

// convert string to object
str = 'a=6&id=99';
var arr = str.split('&');
var obj = {};
for(var i = 0; i < arr.length; i++) {
    var bits = arr[i].split('=');
    obj[bits[0]] = bits[1];
}
//alert(obj.a);
//alert(obj.id);

// convert object back to string
str = '';
for(key in obj) {
    str += key + '=' + obj[key] + '&';
}
str = str.slice(0, str.length - 1); 
alert(str);

Or use this (JQuery) http://api.jquery.com/jQuery.param/

Upvotes: 1

Related Questions