Remove object with given property from JSON using regex - javascript

Given I have a string which represents JSON object. It might be invalid, as there might be some params which will be replaced by another system (e.g. %param%). I need to remove all objects with known propertyName equal to "true" using regex.
{
"someTopLevelProp": "value",
"arrayOfData": [
{
"firstPropIAlwaysKnow": "value",
"dontCareProp": $paramValue$,
"dontCareProp2": 2,
"flagWhichShouldIUse": true,
"somethingAtTheEnd": "value"
},
{
"absolutelyAnotherObject": %paramValue%
},
{
"firstPropIAlwaysKnow": "value",
"dontCareProp": "value",
"dontCareProp2": 2,
"flagWhichShouldIUse": false,
"somethingAtTheEnd": "value"
},
{
"firstPropIAlwaysKnow": "value",
"dontCareProp": "value",
"dontCareProp2": 2,
"flagWhichShouldIUse": true,
"somethingAtTheEnd": "value"
}
]
}
In the example above, I always have "firstPropIAlwaysKnow" which means that object can contain flag which I need. After that there might be other properties. But the most important here is "flagWhichShouldIUse" prop, which mean this object should be removed (but only in case when value equal to 'true'). As result I should receive:
{
"someTopLevelProp": "value",
"arrayOfData": [
{
"absolutelyAnotherObject": %paramValue%
},
{
"firstPropIAlwaysKnow": "value",
"dontCareProp": "value",
"dontCareProp2": 2,
"flagWhichShouldIUse": false,
"somethingAtTheEnd": "value"
}
]
}
My knowledge in regex are not strong enough, thus kindly ask for community's help.
P.S. Please do not mention that parsing JSON with regex it's crazy\incorrect\bad idea - be sure I know that.
ANSWER: now I have working regex which do that stuff. Thank you everyone who tried to help here. Maybe it will be useful for someone.
/{\s+?"firstPropIAlwaysKnow": "value"[^{}]+?(?:\{[^}]*\}[^}]+?)*[^}]+?"flagWhichShouldIUse": true[^}]+?},?/gi
Regexper

You really can't do this with just regular expressions. Something like this might work:
let filtered = jsonstring
// split into the individual 'objects'
// might need to modify this depending on formatting. You
// could use something like /},\s*{/ to split the string,
// but couldn't re-join with same formatting
.split('},{')
// filter for only the strings with the relevant property
// set to false
.filter(s => s.match(/"flagWhichShouldIUse":\s*false/) // again, may need to change
// put humpty-dumpty back together again
.join('},{');
The exact splitting method will depend heavily on the structure of your JSON, and this isn't fool-proof. It doesn't handle nesting properly. If your JSON is pretty-printed, you could use the number of tab/space characters as part of the splitter: this for instance would only split for one tab only: /\n\t},\s*{/

Related

Node.js - How can I check if a parsed json has the same structure of a class?

I'm send a complex JSON string to my server, the following is a simple example:
{
"a": 1;
"b": "test"
"c": [
{
"d":2
"e":3
},
{
"d":2
"e":3
}
]
}
Now I want check if this object has the correct structure. For example I want check if the json above has three attributes: "a" , "b" and a list of value "d" and "e" called "c". The problem is that my object is very large and I can't check every single attribute, I've not find an easy and rapid solution.
JSON schema is one popular solution. It allows you to compare your prewritten json schema against an instance/json.
If you don't want to use any third party library, you can parse your JSON to string and find if each attribute exists. But there are too many corner cases here.

Index on array keypath doesn't find any values

I want to get familiar with indexedDB to built my Firefox WebExtension.
My sample data is structured like this:
const sampleDataRaw = [
{
"ent_seq" : 1413190,
"att1" : [ {
"sub11" : "content1",
"sub12" : [ "word" ]
}, {
"sub11" : "content2"
} ],
"att2" : [ {
"sub21" : "other content",
"sub22" : [ "term" ]
} ]
}, {
"ent_seq" : 1000010,
"att2" : [ {
"sub21" : "more content"
}, {
"sub22" : "more words"
} ]
}
] // end sampleRawData
I got as far as opening/creating my database, adding this sample data and querying it by the ent_seq key using objectStore.get() and objectStore.openCursor().
The problem arises when I want to search the sub11 or sub21 fields using indexes I should have created for these like this:
objectStore.createIndex("sub11Elements", "att1.sub11", { unique: false });
objectStore.createIndex("sub21Elements", "att2.sub21", { unique: false });
When I want to search, say, fields sub11 as here:
var index = objectStore.index("sub11Elements");
index.get("content1").onsuccess = function(event) {
// I should have the first object of my data now, alas the result is undefined instead
};
It certainly does succeed, but the returned value is undefined since the get() didn't actually find anything.
I want to know why it doesn't find the entry and how to make it find it. I figured it might be because the keypath is wrong, but as stated, if I instead search by the key (ent_seq) I can successfully get the result.att1[i].sub11 values.
On mozilla's websites it's stated that keys can be of type string and array (or array within array etc) amongst others, and keypath parts are supposed to be concatenated using dots.
From searching on stackexchange I've so far found that it's not possible to have variable keys inside the keypath, but that shouldn't be the case here anyway.
Therefore, I really don't see what might be causing the search to not find the object inside the database.
It looks like the second level of objects are arrays, not properties of the first level of objects. The . accessor accesses sub properties, not indices of an array.
IDBObjectStore.prototype.get always yields success when there is no error, and is not indicative of whether a match was found.
A bit more on point 1. Look at "att1":[{"sub11" : "content1","sub12" : [ "word" ]}.... Pretend this was was an actual basic JavaScript object. Would you be able to use att1.sub11? No. Because the value of att1 is an array, not an object.

Transform parts of JSON string output to boolean

Is there any way to convert some parts of JSON string to booleans ?
My JSON string example:
{
"file_id": {
"width": "560",
"height": "270",
"esc_button": "1",
"overlay_close": "1",
"overlay_opacity": "1"
}
}
If this was my personal project, I believe I would just convert the output of booleans into true/false strings and not 1 and 0, but since it isn't I wonder if there is a way to set what properties from JSON string are booleans. In this example booleans should be: esc_button, overlay_close but not overlay_opacity...
So since this is JavaScript project, I wonder what are my options and is there any easy way to do this ? There are more settings from this JSON string, I just posted part of it. Settings change depending on click event (different file_id === different settings)
EDIT:
Just figured I could use parseInt(settings[file_id].esc_button) to get boolean, but do I really have to use that all the time ? There might be other ways that I am not aware of.
JSON is just a data format. And if the data you are consuming chose to pass the string "0", you will get the string "0", and not false.
If "0" isn't what you want in your program you need to process the data a bit.
// for example
var processData = function(jsonString) {
var data = JSON.parse(jsonString);
data.esc_button = (data.esc_button == "1");
return data;
};
JSON.parse() itself doesn't provide a way to do this. It just decodes the data as it is in the source. If you need something different, you need to translate.
Ideally you should get your data source to give you this data in a better format. If it has real boolean literal values instead, you don't have to do any translation at all.
{
"file_id": {
"width": 560,
"height": 270,
"esc_button": true,
"overlay_close": false,
"overlay_opacity": 1
}
}
If your JSON looks like that, you just parse it and your done. By removing the quotes from width and height, those are now number values that require no translation to use in other math. And by reporting true or false for boolean values, those will get parsed as boolean literals, not strings. And it all just works.
This also resolves ambiguity. In your original JSON you had "1" for true and "1" for the opacity value, which I assume is expected to be a number form zero to one. Now you can look at the raw JSON data and see the difference.
JS is a dynamic language. You can do it yourself.
if (my_object[its_property]==="1")
my_object[its_property] = true
else
my_object[its_property] = false;
Or more tersely my_object=(my_object[its_property]==="1");.

JSON with empty numeral value? (not 0)

Given a JSON such:
[
{ "id":"A", "status": 1, "rank":1, "score": },
{ "id":"B", "status": 1, "rank":1, "score": }
]
My script fails due to the empty score.
Given a JS such :
if (json[i].score) { do something } else { calculate it }
I want to keep the field empty, and not use 0. I may use "score": "", but this will imply that it's a string (empty at start), while I want score to be a numeral (empty at start). So the number I push in it stay a number, and not a string.
How to state an empty/undefined numeral ?
Note: I intuitively think it's why I sometime meet undefined.
EDIT: the question was edited to clarify the context, the need to check the existence of obj.score, where 0 would be misleading.
TL;DR: Use 0 (zero), if everyone starts with zero score. Use null, if you specifically want to say that someone's score is not set yet. Do not define the property, if it should not be placed in specific case (like object that should not even have "score" property).
Omitting the value in JSON object
Well, in JSON you are not allowed to just omit the value. It must be set to something like number (integer or float), object, list, boolean, null or string. To read more about syntax, try this resource: http://json.org/. This is the diagram taken from that site, showing you the syntax of object representations in JSON:
Most popular approaches: null, 0 (zero), undefined
The usual approach is to set null. In other cases it can be better to use 0 (zero), if applicable (eg. the field means "sum").
Another approach is just to not set the property. After deserialization you are then able to perform tests checking the existence of specific property like that:
JavaScript:
if (typeof my_object.score !== 'undefined'){
// "score" key exists in the object
}
Python:
if 'score' in my_object:
pass # "score" key exists in the object
PHP:
if (array_key_exists('score', $my_object)) {
// "score" key exists in the object
}
Less consistent approaches: false, ""
Some people also accept the value to be false in such case, but it is rather inconsistent. Similarly when it comes to empty string (""). However, both cases should be properly supported in most programming languages during deserialization.
Why not just start score at 0? Everyone will start with a score of 0 in just about anything involving score.
[
{ "id":"A", "status": 1, "rank":1, "score": 0 },
{ "id":"B", "status": 1, "rank":1, "score": 0 }
]
By definition, a numeral value is a value type, which cannot be null. Only reference types (like strings, arrays, etc.) should be initialized to null.
For the semantic of your situation, I would suggest you to use a boolean to know if weither or not there is a score to be read.
[
{ "id":"A", "status": 1, "rank":1, "empty":true },
{ "id":"B", "status": 1, "rank":1, "empty":false, "score":100}
]
Then,
if (!foo.empty) {
var score = foo.score;
}
While a null could be tested as well, it is a wrong representation of a number.

Querying/Searching for Values within JSON

For a web site I'm creating, I have to create a quote based on data provided as a JSON string from the server. I've been looking through this site (and various others) but still am unsure on the best way to query/search the data.
For example, I need to get the Area Name from the Area ID. I need to get the maximum age for an area and also the price for a given minimum/maximum age.
I also want to get an array of prices.
Is it best to create a Javascript object from the string using the eval method? Or should I be using jQuery.
Thanks for your help.
({"SkiPass":[{"Id":1,"Area":"Chamonix","Rates":[{"Id":1,"AgeMin":0,"AgeMax":2,"Price":2.5},{"Id":2,"AgeMin":3,"AgeMax":17,"Price":5.0},{"Id":3,"AgeMin":18,"AgeMax":30,"Price":6.2},{"Id":4,"AgeMin":31,"AgeMax":59,"Price":7.4}]},
{"Id":2,"Area":"Megeve","Rates":[{"Id":1,"AgeMin":0,"AgeMax":2,"Price":1},{"Id":2,"AgeMin":3,"AgeMax":17,"Price":2.0},{"Id":3,"AgeMin":18,"AgeMax":30,"Price":2.2},{"Id":4,"AgeMin":31,"AgeMax":59,"Price":4.4}]},
{"Id":3,"Area":"Verbier","Rates":[{"Id":1,"AgeMin":0,"AgeMax":2,"Price":1.5},{"Id":2,"AgeMin":3,"AgeMax":17,"Price":3.0},{"Id":3,"AgeMin":18,"AgeMax":30,"Price":4.2},{"Id":4,"AgeMin":31,"AgeMax":59,"Price":5.4}]}]})
Create a JavaScript object from the string, most definitely, but do it with legitimate JSON parsing facilities and not "eval()". You could use jQuery, but there are other solutions, such as the JSON tools available from json.org, which are small and simple.
Once it's a JavaScript object, well then your needs should guide you as to whether some query solution is necessary, or instead that it's just a simple matter of programming.
I think the best method is jLinq: http://hugoware.net/Projects/jLinq it's like doing a SQL query on JSON.
It doesn't needs jQuery.
I use it, and it's great.
Create the object from the JSON string using JSON.parse() or jQuery.parseJSON() if you are already using jQuery -- or just pass it as from the server side as JSON.
You can then iterate through the object to find the record you want. Or, you can use build your objects so that you can naturally grab data from them.
FloatLeft - as Dan points out, your task would be much easier if you could use XPath but there is no need to re-write your data in XML format. With DefiantJS (http://defiantjs.com) you can now query JSON structure with XPath expressions.
DefiantJS extends the global object JSON with the method "search", which enables XPath queries and returns an array with the matches (empty array if no matches were found). The returned array is equipped with aggregate functions as well; one of these "sortDesc".
Check out this working fiddle;
http://jsfiddle.net/hbi99/H3PR3/
var data = {
"SkiPass": [
...
{
"Id": 3,
"Area": "Verbier",
"Rates": [
{ "Id": 1, "AgeMin": 0, "AgeMax": 2, "Price": 1.5 },
{ "Id": 2, "AgeMin": 3, "AgeMax": 17, "Price": 3 },
{ "Id": 3, "AgeMin": 18, "AgeMax": 30, "Price": 4.2 },
{ "Id": 4, "AgeMin": 31, "AgeMax": 59, "Price": 5.4 }
]
}
]
},
res1 = JSON.search( data, '//SkiPass[Id=3]/Area' ),
res2 = JSON.search( data, '//*[Area and Id=3]/Rates' )
.sortDesc('AgeMax'); // <-- sorting descending by the value of "AgeMax"
document.getElementById('name').innerHTML = res1;
document.getElementById('max_age').innerHTML = res2[0].AgeMax;
document.getElementById('price').innerHTML = res2[0].Price;

Categories