How to parse JSON dynamically in iOS - javascript

We used a third party service and it provides a JS file.
The js file launches an http request and get a json.We parsed the json and got the content we wanted but the json format always changes.
Is there a way to parse the json but do not update our app?

It sounds awful stupid to constantly change schemas, but anyway, maybe you could try having a manifest somewhere in the cloud that translates the latest schema keywords into one your app understands?
Basically, I presume that the info in the JSON is similar (otherwise it wouldn't make sense at all) and only the keywords change. You could have a JSON you constantly update that translates the keywords used in the app into the newest one used by the webservice.
So an example would look like this. Imagine this is the format you are used to when developing the app (this is the one app expects).
{
"name" : "Henri",
"title" : "iOS Developer"
}
Now if the webservice changes it's schema and returns something like this
{
"key1" : "Henri",
"key2" : "iOS Developer"
}
You should have a manifest.json which translates it like this
{
"name" : "key1",
"title" : "key2"
}
I hope you get where I'm going with this, basically you can shift the translation to the cloud, giving you the chance to keep it up to date while app remains the same. So after loading in the translation you can access the data like this
NSString *name = [actualJSON objectForKey: [manifestJSON objectForKey: #"name"]];

The JSON home page has quite a bit of materials on the subject which should allow you to develop your own parser if you wish. There are also some ObjectiveC parsers available down at the bottom of the page.
http://www.json.org/

For this purpose we looked at Cocoa's standard key path infrastructure but weren't particularly happy with how it combines with arrays and dictionaries. In the end I ended up writing my own little key-path lookup thing, essentially like:
- (id)objectAtPath:(NSString *)path inObject:(id)object
{
// accept an input string like key1.key2.key3.index.key4.etc;
// so we'll split on the dots and use each separate component
// to navigate the object graph
NSString *components = [path componentsSeparatedByString:#"."];
for(NSString *component in components)
{
if([object isKindOfClass:[NSDictionary class]])
{
// if this is a dictionary, use this component as
// a key into the dictionary
object = [object objectForKey:component];
}
else
if([object isKindOfClass:[NSArray class]])
{
// if this is an array, use this component
// as an index into the array
NSInteger index = [component integerValue];
// treat out of bounds indices as finding nil
// rather than raising an exception
if(index < 0 || index >= [object count]) object = nil;
else object = [object objectAtIndex:index];
}
}
}
So you might call objectAtPath:#"shoes.4.typeOfLaces" inObject:jsonResult if 'jsonResult' is a dictionary to get the array 'shoes', the dictionary at index 4 in the array and then whatever value that dictionary has for the key 'typeOfLaces'.
The production code actually has some smarter navigation aids, allowing you to say things like "take whichever object in this array of dictionaries has the largest value for the key 'size'" or "take the object with type=large if it exists, otherwise take any object", but exactly what you want to do there will depend on your app and the variability of the schema.
Once you're navigating object graphs by key path, you can just grab the current key paths from a server somewhere, allowing you to change how JSON is navigated on device without submitting a new binary.
The only warning I'd add is to be careful how much functionality you put into your key paths. Apple don't allow fresh code to be downloaded so whatever you do you don't want to end up at anything that Apple could construe as a scripting language, no matter how restricted.

Related

JSON in localforage, efficient way to update property values (Binarysearch, etc.)?

I would like to come straight to the point and show you my sample data, which is around the average of 180.000 lines from a .csv file, so a lot of lines. I am reading in the .csv with papaparse. Then I am saving the data as array of objects, which looks like this:
I just used this picture as you can also see all the properties my objects have or should have. The data is from Media Transperency Data, which is open source and shows the payments between institiutions.
The array of objects is saved by using the localforage technology, which is basically an IndexedDB or WebSQL with localstorage like API. So I save the data never on a sever! Only in the client!
The Question:
So my question is now, the user can add the sourceHash and/or targetHash attributes in a client interface. So for example assume the user loaded the "Energie Steiermark Kunden GmbH" object and now adds the sourceHash -- "company" to it. So basically a tag. This is already reflected in the client and shown, however I need to get this also in the localforage and therefore rewrite the initial array of objects. So I would need to search for every object in my huge 180.000 lines array that has the name "Energie Steiermark Kunden GmbH", as there can be multiple and set the property sourceHash to "company". Then save it again in the localforage.
The first question would be how to do this most efficient? I can get the data out of localforage by using the following method and set it respectively.
Get:
localforage.getItem('data').then((value) => {
...
});
Set:
localforage.setItem('data', dataObject);
However, the question is how do I do this most efficiently? I mean if the sourceNode only starts with "E" for example we don't need to search all sourceNode's. The same goes of course for the targetNode.
Thank you in advance!
UPDATE:
Thanks for the answeres already! And how would you do it the most efficient way in Javascript? I mean is it possible to do it in few lines. If we assume I have for example the current sourceHash "company" and want to assign it to every node starting with "Energie Steiermark Kunden GmbH" that appear across all timeNode's. It could be 20151, 20152, 20153, 20154 and so on...
Localforage is only a localStorage/sessionStorage-like wrapper over the actual storage engine, and so it only offers you the key-value capabilities of localStorage. In short, there's no more efficient way to do this for arbitrary queries.
This sounds more like a case for IndexedDB, as you can define search indexes over the data, for instance for sourceNodes, and do more efficient queries that way.

recursively parse json in javascript to retrieve certain keys' values

I am new to javascript and every time i try learning it, I just end up in an immense amount of frustration and disgust ! No offense, but this is my opinion or perhaps I am too stupid to not understand how it works at all.
I have a simple requirement. I have a pretty deeply nested dictionary (which is what it is called in many backend languages) at hand. To be more specific it is the raw text of a postman collection. The collection itself could have multiple nested directories.
Now all I want to do is to be able to parse this dictionary and do something with it recursively.
For example, if I had to do the same in python I would do it as simply as :
def createRequests(self, dic):
total_reqs = 0
headers = {}
print type(dic)
keys = dic.keys()
if 'item' in keys:
print "Folder Found. Checking for Indivisual request inside current folder . . \n"
self.item_list = dic.get('item')
for each_item in self.item_list:
self.folder.append(self.createRequests(each_item))
else:
print "Found Indivisual request. Appending. . . \n"
temp_list = []
temp_list.append(dic)
self.requestList.append(temp_list)
return self.requestList
where dic would be my dictionary that I want to parse.
Is there any simple and straight forward way to do the same in Javascript?
Let's just say all I want to do is that if I have a text file that has properly formed json data in it and whose contents have been read into dataReadFromFile and then it has been converted into a JSON as :
var obj = JSON.parse(dataReadFromFile);
is there any simple and easy way to convert this JSON to dictionary or the dataReadFromFile directly into a dictionary such that I can say something like dictioanry.keys() if I wanted a list of the keys in it.
Note that the content of the file is not fixed. It may have multiple levels of nesting, which may not be known beforehand.

Setting object to url in a custom manner

I am trying to create my own sort of "state" routing and am struggling with the manipulation of the URL. I have all the working parts for saving the state as an object and such, but I need to turn that object into a URL. So for reference, here is what my object looks like :
urlObject =
[
{"module":"module1",
"customUrl":[{"mod1":["1","2"]},{"mod2":["1","2"]}]
},
{"module":"module2",
"customUrl":[{"mod3":["true","false"]},{"mod4":["5","6"]}]
}
]
So right now I am just doing a simple
$location.search(JSON.stringify(urlObject));
To toss it in the URL. It would be neat if there were some way to format that, parse the URL formatting in my own way, so like It would change to like
/module1="module1sobject/module2="module2object"
When I say module2sobject, I mean the customUrl inside that object--so in that case it would be [{"mod1":["1","2"]},{"mod2":["1","2"]}]. I'm wondering if I could get some guidance on how to begin this process of setting and getting the object out of a url like this (specifically for use in my angular controllers).

How to convert javascript array to scala List object

I have inherited some code that uses the Play! framework which has scala.html files that have javascript in them. Play! and scala are all new to me.
One of the javascript functions does a post and gets back a JSON object. It then loops through the JSON object and creates an array.
var myArray = [];
function createArray(){
$.post('/createArray', $('#arrayForm').serialize()).done(function( data ) {
var obj1 = JSON.parse(data);
$.each(obj1, function(idx, obj) {
myArray.push(obj.name);
});
});
return true;
}
It then uses this array (of strings) to create a text input field that does autocomplete using the data in the array.
I want/need to convert this text input to a select dropdown using the Play! #select but the options arg for #select wants a List object (or Map or Seq - just figured List would be easier since I already have an array of strings).
If I manually create the List object, it works fine.
#select(pForm("equipName"), options(scala.collection.immutable.List("Yes","No")))
The problem is I cannot figure out how to convert the myArray array to a List object which I can then pass to the #select options.
I have found a lot of posts that talk about converting a scala List to an array but can't find a way to go the other way. I am hoping it is an easy thing that I can't seem to figure out.
Thanks in advance for the help.
You can not do that. And more precisely - you do not want to do that.
So basically your play application run on server. In your Play application all those .scala html files are compiled to generate some functions.
Now, when a play application receives a request from a client browser, it gets mapped to some controller by by router. The controller does some processing and finally take one of these above functions ( lets say for index.scala.html we get views.html.index ) and call this function with some parameters.
These functions returns some text which is then sent to the client's browser as HTTP response with response header Content-Type:text/html; charset=utf-8 which tells the browser to treat this text as html.
Now, the browser renders the html which has embedded JavaScript and hence runs the JavaScript. So... basically your JavaScrpt code does not exist on server... for play all of it is just text.
Both of these Scala code and JavaScript code are executed at very different times, at different computers and in different environments hence you can not do whatever you are saying.

javascript array into object with same key names

I have an unusual problem to solve here. I have an array of Guids
[
"c01f8237-72c8-4fa6-9c53-1915750385aa",
"2c8a471b-c408-436c-81b1-3f3867d8ffb4",
"27a44d46-12bd-4784-ceed-57ada31b0e33"
]
This array has to be transformed into:
{
id: "c01f8237-72c8-4fa6-9c53-1915750385aa",
id: "2c8a471b-c408-436c-81b1-3f3867d8ffb4",
id: "27a44d46-12bd-4784-ceed-57ada31b0e33"
}
I know that shouldn't be done, but unfortunately cannot control the back end part. Any idea?
Thanks
The whole point of a dictionary key is that it uniquely maps to some value. Your desired output attempts to duplicate a key and therefore is neither possible nor does it make sense.
If you're passing this to a backend (as you suggest), then of course you can manually build a string to pass over the wire that duplicates keys in the payload, but you won't be able to actually do it in JavaScript first. You'll have to manually build the string.
Also note that you can call this format whatever you want, but you can't call it JSON and you can't use JSON libraries to build it (because it's not JSON). If your API expects a custom format, then you need to write code to build that custom format.
If all you want is a string just do something like
var str = '{' + idArray.map(function(id) {
return "id: "+id
}).join(',\n')+'}';
I have no idea what mime type you would put on that though since its not valid JSON.

Categories

Resources