Javascript Parsing Key Value String to JSON - javascript

I'm currently working on trying to create a UDF to split a key value pair string based on web traffic into JSON.
I've managed to get as far as outputting a JSON object but I'd like to be able to dynamically add nested items based on the number of products purchased or viewed based on the index number of the key.
When a product is only viewed, there is always only one product in the string. Only when its a transaction is it more than one but I think it would be good to conform the structure of the json and then identify a purchase or view based on the presence of a transactionid. For example:
Item Purchased:
sessionid=12345&transactionid=555555&product1=apples&productprice1=12&product1qty=1&product2=pears&productprice2=23&product2qty=3&transactionamount=58
The output should look something like this:
[
{
"sessionid":12345,
"transactionid":555555,
"transactionamount":58
},
[
{
"productline":1,
"product":"apples",
"productprice":12,
"productqty":1
},
{
"productline":2,
"product":"pears",
"productprice":23,
"productqty":2
}
]
]
Item Viewed:
sessionid=12345&product1=apples&productprice1=12&product1qty=1&product2=pears&productprice2=23&product2qty=3
[
{
"sessionid":12345,
"transactionid":0,
"transactionamount":0
},
[
{
"productline":1,
"product":"apples",
"productprice":12,
"productqty":1
}
]
]
The result I'll be able to parse from JSON into a conformed table in a SQL table.
What I've tried so far is only parsing the string, but its not ideal to create a table in SQL because the number of purchases can vary:
var string = "sessionid=12345&transactionid=555555&product1=apples&productprice1=12&product1qty=1&product2=pears&productprice2=23&product2qty=3&transactionamount=58";
function splitstring(queryString) {
var dictionary = {};
if (queryString.indexOf('?') === 0) {
queryString = queryString.substr(1);
}
var parts = queryString.split('&');
for (var i = 0; i < parts.length; i++) {
var p = parts[i];
// Step 2: Split Key/Value pair
var keyValuePair = p.split('=');
var key = keyValuePair[0];
var value = keyValuePair[1];
dec_val = decodeURIComponent(value);
final_value = dec_val.replace(/\+/g, ' ');
dictionary[key] = final_value;
}
return (dictionary);
}
console.log(splitstring(string));
Thanks in advance!!!

Feel like this would be less clunky with better param naming conventions, but here's my take...
function parseString(string) {
var string = string || '',
params, param, output, i, l, n, v, k, pk;
params = string.split('&');
output = [{},
[]
];
for (i = 0, l = params.length; i < l; i++) {
param = params[i].split('=');
n = param[0].match(/^product.*?([0-9]+).*/);
v = decodeURIComponent(param[1] || '');
if (n && n[1]) {
k = n[1];
output[1][k] = output[1][k] || {};
output[1][k]['productline'] = k;
pk = n[0].replace(/[0-9]+/, '');
output[1][k][pk] = v;
} else {
output[0][param[0]] = v;
}
}
output[1] = output[1].filter(Boolean);
return output;
}
var string = "sessionid=12345&transactionid=555555&product1=apples&productprice1=12&product1qty=1&product2=pears&productprice2=23&product2qty=3&transactionamount=58";
console.log(parseString(string));
output:
[
{
"sessionid": "12345",
"transactionid": "555555",
"transactionamount": "58"
},
[{
"productline": "1",
"product": "1",
"productprice": "12"
}, {
"productline": "2",
"product": "3",
"productprice": "23"
}]
]

There's probably a far nicer way to do this, but I just wrote code as I thought about it
var string = "sessionid=12345&transactionid=555555&product1=apples&productprice1=12&product1qty=1&product2=pears&productprice2=23&product2qty=3&transactionamount=58";
function splitstring(queryString) {
var dictionary = {};
if (queryString.indexOf('?') === 0) {
queryString = queryString.substr(1);
}
var parts = queryString.split('&');
for (var i = 0; i < parts.length; i++) {
var p = parts[i];
// Step 2: Split Key/Value pair
var keyValuePair = p.split('=');
var key = keyValuePair[0];
var value = keyValuePair[1];
dec_val = decodeURIComponent(value);
final_value = dec_val.replace(/\+/g, ' ');
dictionary[key] = final_value;
}
return (dictionary);
}
function process(obj) {
let i = 1;
const products = [];
while(obj.hasOwnProperty(`product${i}`)) {
products.push({
[`product`]: obj[`product${i}`],
[`productprice`]: obj[`productprice${i}`],
[`productqty`]: obj[`product${i}qty`]
});
delete obj[`product${i}`];
delete obj[`productprice${i}`];
delete obj[`product${i}qty`];
++i;
}
return [obj, products];
}
console.log(process(splitstring(string)));
By the way, if this is in the browser, then splitstring can be "replaced" by
const splitstring = string => Object.fromEntries(new URLSearchParams(string).entries());
var string = "sessionid=12345&transactionid=555555&product1=apples&productprice1=12&product1qty=1&product2=pears&productprice2=23&product2qty=3&transactionamount=58";
function process(string) {
const splitstring = queryString => {
var dictionary = {};
if (queryString.indexOf('?') === 0) {
queryString = queryString.substr(1);
}
var parts = queryString.split('&');
for (var i = 0; i < parts.length; i++) {
var p = parts[i];
// Step 2: Split Key/Value pair
var keyValuePair = p.split('=');
var key = keyValuePair[0];
var value = keyValuePair[1];
dec_val = decodeURIComponent(value);
final_value = dec_val.replace(/\+/g, ' ');
dictionary[key] = final_value;
}
return (dictionary);
};
let i = 1;
const obj = splitstring(string);
const products = [];
while (obj.hasOwnProperty(`product${i}`)) {
products.push({
[`product`]: obj[`product${i}`],
[`productprice`]: obj[`productprice${i}`],
[`productqty`]: obj[`product${i}qty`]
});
delete obj[`product${i}`];
delete obj[`productprice${i}`];
delete obj[`product${i}qty`];
++i;
}
return [obj, products];
}
console.log(process(string));

Related

How can i get key of nested object = used For....in?

Here is my code. How can i get the key of the key-value pair using for loop?
var apartment = {
bedroom: {
area: 20,
bed: {
type: 'twin-bed',
price: 100
}
}
};
The desired output is as follows:
/* desired results :
* bedroom
* area
* bed
* type
* price
*/
Please help
var getKeys = function(obj) {
var keys = [];
Object.keys(obj).forEach(function(key){
keys.push(key);
if(typeof obj[key] == 'object'){
keys = keys.concat(getKeys(obj[key]));
}
})
return keys;
}
Then
var keys = getKeys(apartment);
You can use a simple Regex as follow:
var apartment = {
bedroom: {
area: 20,
bed: {
type: 'twin-bed',
price: 100
}
}
};
let result = [];
let jsonstr = JSON.stringify(apartment);
// {"bedroom":{"area":20,"bed":{"type":"twin-bed","price":100}}}
let regex = /"(\w+)":/g;
jsonstr.replace(regex, function(match,prop){
result.push(prop);
});
console.log(result);
we can easily done by using regex, convert object string and apply regex to extract the particular word
run the snippet for required output
var apartment = {
bedroom: {
area: 20,
bed: {
type: 'twin-bed',
price: 100
}
}
};
apartment = JSON.stringify(apartment);
var re = /(")\w+(")(:)/g;
var match;
do {
match = re.exec(apartment);
if (match) {
console.log(match[0]);
}
} while (match);
regex : /(")\w+(")(:)/g
only extracts key for more click here
do while loop responsible to detect multiple match in the string
You can use a recursive function :
function getKeys(source, dest) {
for (let key in source) {
if (typeof source[key] == 'object') {
dest.push(key)
getKeys(source[key], dest)
} else {
dest.push(key)
}
}
return dest
}
result = []
const apartment = {
bedroom: {
area: 20,
bed: {
type: 'twin-bed',
price: 100
}
}
}
getKeys(apartment, result) // ["bedroom", "area", "bed", "type", "price"]
var inputs = [
{a:1,b:2,c:3}, // Simple object
{a:{b:2,c:3}}, // Simple object with nesting
{a:{a:{b:2,c:3}}}, // Repeated key hiding nesting
{a:[{b:2,c:3}]}, // keys behind array
];
inputs.push(inputs); // reference cycle and array at top
function getKeys(obj) {
var all = {};
var seen = [];
checkValue(obj);
return Object.keys(all);
function checkValue(value) {
if (Array.isArray(value)) return checkArray(value);
if (value instanceof Object) return checkObject(value);
}
function checkArray(array) {
if (seen.indexOf(array) >= 0) return;
seen.push(array);
for (var i = 0, l = array.length; i < l; i++) {
checkValue(array[i]);
}
}
function checkObject(obj) {
if (seen.indexOf(obj) >= 0) return;
seen.push(obj);
var keys = Object.keys(obj);
for (var i = 0, l = keys.length; i < l; i++) {
var key = keys[i];
all[key] = true;
checkValue(obj[key]);
}
}
}
var result = inputs.map(getKeys);
console.log(result);

Serialize/Reg ex

I use serialize function to get all the values of my form.
My problem is how can i extract only the value in the generated url string of the serialize function and split it into an array.
var input = $('#addForm').serialize();
deviceBrand=itemBrand&deviceModel=itemModel&deviceSerial=itemSerial&deviceType=Desktop&deviceStatus=Available&deviceDesc=item+description //generated url string
i need string function to extract each string between "=" and "&" and put each String into an array.
Don't use serialize, use serializeArray. It creates an array of objects of the form {name: "xxx", value: "yyy" } that you can process more easily.
var input = $("#addForm").serializeArray();
var values = input.map(x => x.value);
You can also make an object with all the name: value properties:
var object = {};
input.map(x => object[x.name] = x.value);
try this code to unserialize the string,
(function($){
$.unserialize = function(serializedString){
var str = decodeURI(serializedString);
var pairs = str.split('&');
var obj = {}, p, idx, val;
for (var i=0, n=pairs.length; i < n; i++) {
p = pairs[i].split('=');
idx = p[0];
if (idx.indexOf("[]") == (idx.length - 2)) {
// Eh um vetor
var ind = idx.substring(0, idx.length-2)
if (obj[ind] === undefined) {
obj[ind] = [];
}
obj[ind].push(p[1]);
}
else {
obj[idx] = p[1];
}
}
return obj;
};
})(jQuery);

Push different object in an array with a for loop

I have an element structured like this:
Element ->
[{values: arrayOfObject, key:'name1'}, ... ,{values: arrayOfObjectN, key:'nameN'}]
arrayDiObject -> [Object1, Object2, ... , ObjectN] //N = number of lines in my CSV
Object1 -> {x,y}
I have to take data from a big string:
cityX#substanceX#cityY#substanceY#
I thought to make it this way, but it seems like it pushes always in the same array of objects. If I put oggetto = {values: arrayDateValue, key: key}; inside the d3.csv function, instead if I put outside the function it add me only empty objects.
Here is my code:
var final = new Array();
var oggetto;
var key;
function creaDati() {
var newdate;
var arrayDateValue = new Array();
var selString = aggiungiElemento().split("#");
//selString is an array with selString[0]: city, selString[1]: substance and so on..
var citySelected = "";
var substanceSelected = "";
for (var i = 0; i < selString.length - 1; i++) {
if (i % 2 === 0) {
citySelected = selString[i];
} else if (i % 2 !== 0) {
substanceSelected = selString[i];
key = citySelected + "#" + substanceSelected;
d3.csv("/CSV/" + citySelected + ".csv", function(error, dataset) {
dataset.forEach(function(d) {
arrayDateValue.push({
x: d.newdate,
y: d[substanceSelected]
});
});
});
oggetto = {
values: arrayDateValue,
key: key
};
arrayDateValue = [];
final.push(oggetto);
}
}
}
Any idea ?
First you should make the if statement for the city and then for the key, which you seem to be doing wrong since you want the pair indexes to be the keys and the not pair to be the city, and you are doing the opposite. And then you need to have the d3.csv and push the objects outside of the if statement, otherwise in your case you are just adding elements with citySelected="".
Try something like :
for(var i = 0; i < selString.length -1; i+=2){
cittySelected = selString[i];
substanceSelected = selString[i+1];
key = citySelected + "#" + substanceSelected;
d3.csv("/CSV/"+citySelected+".csv", function(error, dataset){
dataset.forEach(function(d){
arrayDateValue.push({x: d.newdate, y: d[substanceSelected]});
});
});
oggetto = {values: arrayDateValue, key: key};
arrayDateValue = [];
final.push(oggetto);
}
It's is not the best way to do it, but it is clearer that what you are following, i think.
In the if(i % 2 == 0) { citySelected = ... } and else if(i % 2 !== 0) { substanceSelected = ... } citySelected and substanceSelected will never come together.
The values should be in one statement:
if(...) { citySelected = ...; substanceSelected = ...; }
The string can be splitted into pairs
city1#substance1, city2#substance2, ...
with a regex (\w{1,}#\w{1,}#).
Empty the arrayDateValue after the if-statement.
Hint:
var str = "cityX#substanceX#cityY#substanceY#";
function createArr(str) {
var obj = {};
var result = [];
var key = "";
// '', cityX#substanceX, '', cityYsubstanceY
var pairs = str.split(/(\w{1,}#\w{1,}#)/g);
for (var i = 0; i < pairs.length; i++) {
if(i % 2 !== 0) {
key = pairs[i];
// d3 stuff to create values
obj = {
// Values created with d3 placeholder
values: [{x: "x", y: "y"}],
// Pair
key: key
};
result.push(obj);
}
// Here should be values = [];
}
return result;
}
var r = createArr(str);
console.log(r);
May be you can do like this;
var str = "cityX#substanceX#cityY#substanceY",
arr = str.split("#").reduce((p,c,i,a) => i%2 === 0 ? p.concat({city:c, key:a[i+1]}) : p,[]);
console.log(JSON.stringify(arr));
RESOLVED-
The problem is about d3.csv which is a asynchronous function, it add in the array when it finish to run all the other code.
I make an XMLHttpRequest for each csv file and it works.
Hope it helps.

How to convert an array of paths into JSON structure?

I found the question How to convert a file path into treeview?, but I'm not sure how to get the desired result in JavaScript:
I'm trying to turn an array of paths into a JSON tree:
https://jsfiddle.net/tfkdagzv/16/
But my path is being overwritten.
I'm trying to take something like this:
[
'/org/openbmc/path1',
'/org/openbmc/path2',
...
]
... and turn it into...
output = {
org: {
openbmc: {
path1: {},
path2: {}
}
}
}
I'm sure this is pretty easy, but I'm missing something.
const data = [
"/org/openbmc/examples/path0/PythonObj",
"/org/openbmc/UserManager/Group",
"/org/openbmc/HostIpmi/1",
"/org/openbmc/HostServices",
"/org/openbmc/UserManager/Users",
"/org/openbmc/records/events",
"/org/openbmc/examples/path1/SDBusObj",
"/org/openbmc/UserManager/User",
"/org/openbmc/examples/path0/SDBusObj",
"/org/openbmc/examples/path1/PythonObj",
"/org/openbmc/UserManager/Groups",
"/org/openbmc/NetworkManager/Interface"
];
const output = {};
let current;
for (const path of data) {
current = output;
for (const segment of path.split('/')) {
if (segment !== '') {
if (!(segment in current)) {
current[segment] = {};
}
current = current[segment];
}
}
}
console.log(output);
Your solution was close, you just didn't reset the current variable properly. Use this:
current = output;
instead of this:
current = output[path[0]];
This function should do :
var parsePathArray = function() {
var parsed = {};
for(var i = 0; i < paths.length; i++) {
var position = parsed;
var split = paths[i].split('/');
for(var j = 0; j < split.length; j++) {
if(split[j] !== "") {
if(typeof position[split[j]] === 'undefined')
position[split[j]] = {};
position = position[split[j]];
}
}
}
return parsed;
}
Demo
var paths = [
"/org/openbmc/UserManager/Group",
"/org/stackExchange/StackOverflow",
"/org/stackExchange/StackOverflow/Meta",
"/org/stackExchange/Programmers",
"/org/stackExchange/Philosophy",
"/org/stackExchange/Religion/Christianity",
"/org/openbmc/records/events",
"/org/stackExchange/Religion/Hinduism",
"/org/openbmc/HostServices",
"/org/openbmc/UserManager/Users",
"/org/openbmc/records/transactions",
"/org/stackExchange/Religion/Islam",
"/org/openbmc/UserManager/Groups",
"/org/openbmc/NetworkManager/Interface"
];
var parsePathArray = function() {
var parsed = {};
for(var i = 0; i < paths.length; i++) {
var position = parsed;
var split = paths[i].split('/');
for(var j = 0; j < split.length; j++) {
if(split[j] !== "") {
if(typeof position[split[j]] === 'undefined')
position[split[j]] = {};
position = position[split[j]];
}
}
}
return parsed;
}
document.body.innerHTML = '<pre>' +
JSON.stringify(parsePathArray(), null, '\t')
'</pre>';
(see also this Fiddle)
NB: The resulting arrays need to be merged
This method works for both files & directories, and by using only arrays as the data format.
The structure is based upon arrays being folders, the first element being the folder name and the second - the contents array.
Files are just regular strings inside the array (but could easily be objects containing properties)
Converts =>
[
'/home/',
'/home/user/.bashrc',
'/var/',
'/var/test.conf',
'/var/www/',
'/var/www/index.html',
'/var/www/index2.html'
]
To =>
[
['home', [
['user', [
'.bashrc'
]]
]],
['var', [
'test.conf',
['www', [
'index.html',
'index2.html'
]]
]]
]
Script:
var paths = [
'/var/',
'/var/test.conf',
'/var/www/',
'/var/www/index.html',
'/var/www/index2.html'
]
var parsed = []
for (let path of paths) {
let tree = path.split('/')
let previous = parsed
console.groupCollapsed(path)
for (let item in tree) {
const name = tree[item]
const last = item == tree.length - 1
if (name) {
if (last) {
console.log('File:', name)
previous.push(name) - 1
} else {
console.log('Folder:', name)
let i = previous.push([name, []]) - 1
previous = previous[i][1]
}
}
}
console.groupEnd(path)
}
console.warn(JSON.stringify(parsed))

Javascript Recursion for creating a JSON object

needing some advice on how to do this properly recursively.
Basically what I'm doing, is entering in a bunch of text and it returns it as JSON.
For example:
The text:
q
b
name:rawr
Returns:
[
"q",
"b",
{
"name": "rawr"
}
]
And the following input:
q
b
name:rawr:awesome
Would return (output format is not important):
[
"q",
"b",
{
"name": {
"rawr": "awesome"
}
}
]
How can I modify the following code to allow a recursive way to have objects in objects.
var jsonify = function(input){
var listItems = input, myArray = [], end = [], i, item;
var items = listItems.split('\r\n');
// Loop through all the items
for(i = 0; i < items.length; i++){
item = items[i].split(':');
// If there is a value, then split it to create an object
if(item[1] !== undefined){
var obj = {};
obj[item[0]] = item[1];
end.push(obj);
}
else{
end.push(item[0]);
}
}
// return the results
return end;
};
I don't think recursion is the right approach here, a loop could do that as well:
var itemparts = items[i].split(':');
var value = itemparts.pop();
while (itemparts.length) {
var obj = {};
obj[itemparts.pop()] = value;
value = obj;
}
end.push(value);
Of course, as recursion and loops have equivalent might, you can do the same with a recursive function:
function recurse(parts) {
if (parts.length == 1)
return parts[0];
// else
var obj = {};
obj[parts.shift()] = recurse(parts);
return obj;
}
end.push(recurse(items[i].split(':')));
Here is a solution with recursion:
var data = [];
function createJSON(input) {
var rows = input.split("\n");
for(var i = 0; i < rows.length; i++) {
data.push(createObject(rows[i].split(":")));
}
}
function createObject(array) {
if(array.length === 1) {
return array[0];
} else {
var obj = {};
obj[array[0]] = createObject(array.splice(1));
return obj;
}
}
createJSON("p\nq\nname:rawr:awesome");
console.log(data);

Categories

Resources