I need it because I recently made an app that saves an object containing all the user-generated data to localStorage, and encodes/decodes it with JSON.
The bizarre thing is that for some reason, Internet Explorer has poor, if not zero, support for JSON ("JSON is not defined"), and I'm not up to trying to re-create the entire function.
stringify:function(x){
y='{'
for(i in x){
reg=RegExp('\'','g')
y+=',\''+i.replace(reg,'\\\'')+'\':\''+x[i].replace(reg,'\\\'')+'\''
}
y=y.replace(',','')
y+='}'
return y
}
This was my first attempt, but I had forgotten that the object has other objects inside it, which themselves contain objects, and kept getting an error which basically stemmed from trying to call the method String.prototype.replace() of an Object.
Since I was kinda OCD with my code at the time, I actually do have the structure of the object saved in the source code:
/*
Link Engine.data: Object: {
X: Object: { [Each is a Paradigm, contains links]
link.0:{
link:[link],
title:[title],
removed:[true/false],
starred:[true/false]
},
...
},
LSPAR: [Reserved] Object: { [Paradigm list and pointer contained here]
key:[key], (this controls X)
list:{
[listitem]:[listitem],
...
}
},
#CONFIG: [Reserved] Object: { [contains miscellaneous Config data]
property:boolean/number/string,
...
}
*/
That's the basic data structure, ... represents a repeating pattern.
Edit 2019
This whole question is an abomination, but I want to at least attempt to fix the bothersome documentation I wrote for my poorly-designed data structure so that it's more coherent:
Link {
string link
string title
boolean removed
boolean starred
}
Config {
...
/* Just has a bunch of arbitrary fields; not important */
}
WArray {
string... [paradigm-name]
/* Wasteful Array; an object of the form
* { "a":"a", "b":"b", ... }
*/
}
Paradigm { /* analogous to above "X: Object: {..." nonsense */
Link... [paradigm-name].[id]
/* each key is of the form [paradigm-name].[id] and stores a Link
* e.g. the first link in the "Example" paradigm would
* be identified by the key "Example.0"
*/
}
ParadigmList {
string key /* name of selected paradigm */
WArray list /* list of paradigm names */
}
LinkEngineData {
Paradigm... [paradigm-name]
ParadigmList LSPAR
Config #CONFIG /* actual field name */
}
Hopefully now you can sort of parse what's going on. This syntax:
type... format
is meant to convey that objects of type type appear many times, like an array, except it isn't an array. As such, the fields don't have a name that is set-in-stone, hence
format: [descriptor1]text[descriptor2]text...
a format is used in place of an actual field name. This is what happens when you try to create a data structure without knowing what a data structure is. I did use the words "data" and "structure" adjacently in the original question, but it was pure coincidence. I didn't mean it like "this is the data structure I used"; I meant it like "this is the structure of my data".
Anyways, here's how I would design it today:
Link {
string url
string title
boolean starred
}
LinkGroup {
string name
Link[] links
}
Config {
... /* has whatever it needs to have */
}
Data {
int selGroup
LinkGroup[] groups
Config config
}
That is all.
If someone has the sourcecode of the actual JSON.stringify function, or knows a way to replicate it, then please put your answer.
EDIT (2013, probably)
I ended up dropping IE support and completely redesigning the app from the ground up; the new version is hosted here. And it works with IE9 out of the box!
I think this is the best replacement: http://bestiejs.github.com/json3/
It claims to be better than Crockford's JSON 2 for the following reasons (from their site):
JSON 3...
Correctly serializes primitive wrapper objects (Issue #28).
Throws a TypeError when serializing cyclic structures (JSON 2 recurses until the call stack overflows).
Utilizes feature tests to detect broken or incomplete native JSON implementations (JSON 2 only checks for the presence of the native functions). The tests are only executed once at runtime, so there is no additional performance cost when parsing or serializing values.
In contrast to JSON 2, JSON 3 does not...
Add toJSON() methods to the Boolean, Number, and String prototypes. These are not part of any standard, and are made redundant by the design of the stringify() implementation.
Add toJSON() or toISOString() methods to Date.prototype. See the note about date serialization below.
Try https://github.com/douglascrockford/JSON-js
I think you should use the json2.js library:
https://github.com/douglascrockford/JSON-js
Related
Explanation:
I want to make an Electron app [Javascript not jQuary] (or am in the process of doing so) and would like to add a function that puts one config into the "format" of another.
The big file from which I want to take the information I currently read in via "dialog.showOpenDialog" and can also access the json object.
Now to the problem:
The file I get via the dialog is 8000 lines long and contains individual information that I want to pack into a smaller document with about 3000 lines.
Important: Individual information have a different name e.g. I want "ABCD: 23" from document 1 in the other as EFG: 23.
Now my two questions:
how can I best provide the smaller file for editing?
how can I convert the individual information without going through each line separately?
bigconfig.json:
{
"EXAMPLE_CATEGORY": {
"setting1": 0,
"setting2": 1,
"setting3": 115,
"setting4": 0,
},
Smallerconfig.json
{
"EXAMPLE_CATEGORY": {
"setting7": 115,
"setting8": 0,
},
Edit: What I want to achieve is that I can create (and save) a modified file with the information I packed from the big file into the small one.
In the smaller one should be all 3000 felt
Would really appreciate help... yesterday I did a lot of research and used the search engine for several hours.
Thanks in advance
The only way your smallerConfig object will know which new keys to use is if you define them beforehand. To do this, you must create an object that links the old key names to the new key names. These links would be best defined in one place. The code below holds these links in the conversionTable.
To build the smallerConfig object, you must loop (using for...in) through the bigConfig object one line at a time. Here you will check if the key in the bigConfig object matches a key in the conversionTable (using the in operator). If a matching key is found, then we will use the key’s value in the conversionTable as the new key in the smallerConfig object. Using the bigConfig value in the creation of the smallerConfig object is easy.
let bigConfig = {
'EXAMPLE_CATEGORY': {
'setting1': 0,
'setting2': 1,
'setting3': 115,
'setting4': 0
}
};
let smallerConfig = {
'EXAMPLE_CATEGORY': {}
};
let conversionTable = {
'setting3': 'setting7',
'setting4': 'setting8'
};
// Iterate through the bigConfig object
for (let bigKey in bigConfig.EXAMPLE_CATEGORY) {
// Check for a matching key in the conversionTable
if (bigKey in conversionTable) {
smallerConfig.EXAMPLE_CATEGORY[conversionTable[bigKey]] = bigConfig.EXAMPLE_CATEGORY[bigKey];
}
}
console.log(smallerConfig);
Output will be:
{
'EXAMPLE_CATEGORY': {
'setting7': 115,
'setting8': 0
}
}
Finally:
Use JSON.parse() to convert the file contents from a string to a Javascript object.
Use JSON.stringify() to convert the Javascript object back to a string for writing to the new file.
What is the best practice to pass an array of objects throught query string in REST style?
For example, the array:
examples[] = [
{
name: "foo",
value: "1"
},
{
name: "bar",
value: "2"
}
]
I thought about it:
/items?examples[0][name]=foo&examples[0][value]=1&examples[1}[name]=bar&examples[1][value]=2
Are there other ways to do this?
Upd:
I need readable URL to show it to the user in the address field. It should display state of some filters in the table, I'm not sending it to the backend.
Since you're parsing this manually in JS, you could keep the structure you have and just write a parsing function
var items = {};
location.search.split("?")[1].split("&").map((q) => {
var [token, value] = q.split("="),
[idx, key] = /\[([0-9+])\]\[(\w+)\]/g.exec(token).slice(1, 3);
if (!items[idx]){
items[idx] = {};
}
items[idx][key] = value;
})
This will yield you something with a structure like
{
"0": {
"key1": "data"
"key2": "data:
},
"1": {
"key1": "data"
"key2": "data"
}
}
If you need it to end up an array, it would be pretty easy to convert, but keeping it as an object with numeric strings for keys will prevent an error if it's not sequential.
Also, note there's no error checking or anything here, so if you're going to have query string params that aren't in that format, you'll want to test for that and handle them differently.
You shouldn't take care about how pass data for a backend, Angular do it for you.
About your example, you probably want to update or save several item. So it's not into the url that you will pass your data but into the Request Body :
this.httpService.post(yourUrl, examples, yourHttpOptions).subscribe( (response) => {
// you manage your response data
});
REST does not care how you encode information into your identifiers. You can use any scheme you want, so long as it is consistent with the production rules defined by RFC 3986.
REST cares a little bit about how you share information about creating URI, in the sense that that information should be shared in some readily standardizable form, like an HTML form, or a URI Template.
We don't, to my knowledge, have a "readily standardizable form" that describes how to transform a json array to a query string.
But... REST does allow code on demand; embedding, for example, a bunch of java script into a resource where that javascript knows how to encode the json into the URI... that is in bounds, so long as you have the code on demand itself referenced in a readily standardizable way (like we have with HTML and script tags).
In practice? urlencode the json representation and put it onto the query string directly. That will get you through until you start to discover the real requirements that your URI design needs to support (requirements like: operators needing to be able to understand the access logs).
I have an existing "blackbox" web service. I need to append a session ID to the end of that output so that Javascript and similar clients can resume the stateful session.
Given the output below, what is the correct syntax to append or prepend an arbitrary GUID, so that it can be properly deserialized as valid JSON?
Note This data below is perfect. If I can somehow add a "removable" bit of information, using JSON.NET the string GUID, that would be ideal.
Output from REST call
"{\"sa\":[\"BHDQ9TLPeaeVuSSgXv9bsOIVFUWbOpivMKhGki7YPLzIXEyHuxRAZhDgts2sEcBQpLBuKJZCtcmSlzWZ9iK0AAA=\",\"BAhyo7T0Wq1WBLXnyN4vo1L94rWLhCCv4DqROi+p9XHO6UeS0Gw6xh1JAKOtXBU2fA432LkNqng8cUt1eAX0bqs=\",\"BGFmyTreWY5pICAcf3itoqbfhs5brOmIDLNF3V7p7slPYdCSVhwWUT5mHD6Lb5kNi\/Qy9tracNUtVgvo3f51FrI=\",\"BMV7RIwoz+LdFgD2fq7UZ7E88KFq\/03381NDYFIKYgUKxEzuXoj6hZfSB0slX5fdaL44Lf6i\/UjDzPQt2XUG8NE=\",\"BL8BnU5WvFn7vIlKi14dWsqykNf1\/nmE55YXFGwLx9Qu3VvDblULt\/U8CXPI1vD8+wMXCRnkunXqxlsFqgghf8w=\"],\"sb\":[\"BInTtgTAn\/zkmrkporhV5DvPZRq5YWm8e\/m02oq55UfY3RxIhOplJgwLjgKMHKYDthYEBcqNNNuVbbWnbtKVAqA=\",\"BJbh5y95wHGjmAPDFNqgewnBxtqVke0sloDD2S3IdrWZ95JfP77rtXZ4lTG8g9PuTLJbl4exZUnM16260WxJ9wU=\",\"BKevE9i2J8CicXHX3elCoQPEpTOmJyGOlBskIbFMFGQFhJ5TD7N1221rhhH9HY6DsfRojmefozsQYzo7Pokp+Hg=\",\"BJbVTRyh8WwCxfR7jRXnran4td7k5+vEfM+HWxeAibneSjdMRQ1Fg6QxKLu+Zu1aPdXqD8M29kABOTAiYopVuQE=\",\"BFv3alDqjo7ckdB2vuxJ15Gur1xsgATjLe9drt\/XU9AkbN+AELCv+mF1Xy8+83L2A1p8aGxF4b7dsrMed27u1j4=\"],\"sz\":\"BF1IiqMz0KmT4gZN6euJquWFt2UmVjyOEdaX0jH8uQMAPG8DBoyneT2PJ9NQTE2xBOP9TtAb1d2O+iCojFqzkvI=\"}"
The output above comes from Chrome. I'm not sure if Chrome adds additional quotes, etc but when I debug System.String on the server, I see the same thing being sent to the WCF service.
The end-usage for this will be a Chrome and Firefox plug in
Well if I am correctly understanding:
You get JSON from a blackbox service. It contains some properties and values. You want to add a new property with some GUID and send it to browser.
If this is correct, try following:
var json=<WHAT YOU GET FROM SERVICE>;
var converter = new ExpandoObjectConverter();
dynamic obj = JsonConvert.DeserializeObject<ExpandoObject>(json, converter);
obj.sid="this is the new session id"; //ADD NEW PROPERTY
var j=JsonConvert.SerializeObject(obj); //GET BACK JSON STRING WITH NEW PROPERTY
Of if you just want to add session id on client side (inside your plugin) the utilize JSON2 javascript library and use following code (as also suggested by Josh in comments):
var o = JSON.parse(<REST OUTPUT>);
o.sid = <YOUR SESSION ID>;
To convert back to JSON string.
var jsn = JSON.stringify(o);
There is no way to modify that particular response without breaking existing clients. If you can break existing clients, or if you are working with clients that you control, you could wrap the object in another object, setting two keys: GUID and data. For example:
var json = JsonConvert.SerializeObject(new {
data = foo,
GUID = bar,
});
Where bar is the GUID that you want to use, and foo is one of two things:
The JSON string from the response. This will result in the final object looking like so:
{
data: "{\"sa\":[\"BHDQ9TLPeaeVuSSgXv9bsOIVFUWbOpivMKhGki7YPLzIXEyHuxRAZhDgts2sEcBQpLBuKJZCtcmSlzWZ9iK0AAA=\",\"BAhyo7T0Wq1WBLXnyN4vo1L94rWLhCCv4DqROi+p9XHO6UeS0Gw6xh1JAKOtXBU2fA432LkNqng8cUt1eAX0bqs=\",\"BGFmyTreWY5pICAcf3itoqbfhs5brOmIDLNF3V7p7slPYdCSVhwWUT5mHD6Lb5kNi\/Qy9tracNUtVgvo3f51FrI=\",\"BMV7RIwoz+LdFgD2fq7UZ7E88KFq\/03381NDYFIKYgUKxEzuXoj6hZfSB0slX5fdaL44Lf6i\/UjDzPQt2XUG8NE=\",\"BL8BnU5WvFn7vIlKi14dWsqykNf1\/nmE55YXFGwLx9Qu3VvDblULt\/U8CXPI1vD8+wMXCRnkunXqxlsFqgghf8w=\"],\"sb\":[\"BInTtgTAn\/zkmrkporhV5DvPZRq5YWm8e\/m02oq55UfY3RxIhOplJgwLjgKMHKYDthYEBcqNNNuVbbWnbtKVAqA=\",\"BJbh5y95wHGjmAPDFNqgewnBxtqVke0sloDD2S3IdrWZ95JfP77rtXZ4lTG8g9PuTLJbl4exZUnM16260WxJ9wU=\",\"BKevE9i2J8CicXHX3elCoQPEpTOmJyGOlBskIbFMFGQFhJ5TD7N1221rhhH9HY6DsfRojmefozsQYzo7Pokp+Hg=\",\"BJbVTRyh8WwCxfR7jRXnran4td7k5+vEfM+HWxeAibneSjdMRQ1Fg6QxKLu+Zu1aPdXqD8M29kABOTAiYopVuQE=\",\"BFv3alDqjo7ckdB2vuxJ15Gur1xsgATjLe9drt\/XU9AkbN+AELCv+mF1Xy8+83L2A1p8aGxF4b7dsrMed27u1j4=\"],\"sz\":\"BF1IiqMz0KmT4gZN6euJquWFt2UmVjyOEdaX0jH8uQMAPG8DBoyneT2PJ9NQTE2xBOP9TtAb1d2O+iCojFqzkvI=\"}",
guid: "00000000-0000-0000-0000-000000000000"
}
And you would get at the data through two calls to JSON.parse (or the equivalent).
The deserialized object from the JSON response. This will result in the final object looking like so (most data removed for brevity sake):
{
data: {
sa: [],
sb: [],
sz: ""
},
guid: "00000000-0000-0000-0000-000000000000"
}
And you would access data through response.data.
Why any modification can break existing clients
Where the current response is an object, there are only a few ways to modify it:
Injecting a key into the object. This assumes that no client uses Object.keys() or in any way iterates the key set (e.g. for (k in obj)). While this may be true, this is an assumption.
Adding another object to the end: }, {. Doing so would require that the response be transformed into an array:
[{}, {}]
This would break any client that is assumes the response is an object.
Wrapping the current response in a surrounding object (as proposed above). This as well breaks any clients that assumes a certain structure for the response.
{data:{}, guid: ""}
I have a dump of a Firebase database representing our Users table stored in JSON. I want to run some data analysis on it but the issue is that it's too big to load into memory completely and manipulate with pure JavaScript (or _ and similar libraries).
Up until now I've been using the JSONStream package to deal with my data in bite-sized chunks (it calls a callback once for each user in the JSON dump).
I've now hit a roadblock though because I want to filter my user ids based on their value. The "questions" I'm trying to answer are of the form "Which users x" whereas previously I was just asking "How many users x" and didn't need to know who they were.
The data format is like this:
{
users: {
123: {
foo: 4
},
567: {
foo: 8
}
}
}
What I want to do is essentially get the user ID (123 or 567 in the above) based on the value of foo. Now, if this were a small list it would be trivial to use something like _.each to iterate over the keys and values and extract the keys I want.
Unfortunately, since it doesn't fit into memory that doesn't work. With JSONStream I can iterate over it by using var parser = JSONStream.parse('users.*'); and piping it into a function that deals with it like this:
var stream = fs.createReadStream('my.json');
stream.pipe(parser);
parser.on('data', function(user) {
// user is equal to { foo: bar } here
// so it is trivial to do my filter
// but I don't know which user ID owns the data
});
But the problem is that I don't have access to the key representing the star wildcard that I passed into JSONStream.parse. In other words, I don't know if { foo: bar} represents user 123 or user 567.
The question is twofold:
How can I get the current path from within my callback?
Is there a better way to be dealing with this JSON data that is too big to fit into memory?
I went ahead and edited JSONStream to add this functionality.
If anyone runs across this and wants to patch it similarly, you can replace line 83 which was previously
stream.queue(this.value[this.key])
with this:
var ret = {};
ret[this.key] = this.value[this.key];
stream.queue(ret);
In the code sample from the original question, rather than user being equal to { foo: bar } in the callback it will now be { uid: { foo: bar } }
Since this is a breaking change I didn't submit a pull request back to the original project but I did leave it in the issues in case they want to add a flag or option for this in the future.
I want to flatten a multi-level object and vice versa.
For example:
{
option1:value1,
option2:value2,
option3:{
key1:value31,
key2:value32
},
option4:[value40,value41,value42]
}
Would be equivalent to:
{
option1:value1,
option2:value2,
"option3.key1":value31,
"option3.key2":value32,
"option4.0":value40,
"option4.1":value41,
"option4.2":value42
}
This is for small objects, the objective of the flattened expression is to facilitate the data collection in a form and the merge with default options. For example I can have form elements like this:
<input name="option4.0" value="value40"/>
Is this a standard approach, or is there a better way? Are there libraries that already do this?
That format ({ option4.2: value42 }) won't work (because the . in the key will be parsed as a dot operator). Instead, you'll need to quote the key:
{ 'option4.2': value42 }
However, this is very non-standard. Flattening objects is typically not required - if you want to submit such an object to a server, you can use JSON to serialize it without flattening:
var stringForServer = JSON.stringify(normalObject);
If you're looking for a library to manipulate objects and arrays etc, underscore is probably your best bet:
http://underscorejs.org/
cheers!
I experimented with my idea, it works fine but has a few limitations.
The obvious ones is that a key cannot contain a dot (dots are delimiters with this technique), and keys cannot be numbers (or else the algorithm interprets it as an array index).
Another issue is that it won't work if a value is an empty object or array (e.g. option4:[]).