Accessing array in Json Data with Clojurescript - clojurescript

I am new Clojurescript and want to hack arround with clojurescript and electron based on an small json file.
I am doing something like (with transit/cljs)
(def jsondata (t/read (t/reader :json) (.readFileSync fs path_to_file "utf8")))) )
first I check if status is ok, that works fine...
(let [json_status (get jsondata "status")]
(.log js/console "JSON Glossar Status:" json_status))
now, how can I access one of the maps in the pages array, or step through the map?
{"status":"ok",
"pages":[
{
"id":1,
"name":"name1",
"image":"imagename1.png",
"children":[
{
"id":1,
"copytext":"kdjsldjsljfl"
},
{
"id":2,
"copytext":"dksdöfksöfklsöf"
}
]
},
{
"id":2,
"name":"name1",
"image":"imagename1.png",
"children":[
{
"id":4,
"copytext":"kdjsldjsljfl"
},
{
"id":5,
"copytext":"dksdöfksöfklsöf"
}
]
}
]
}

You can use aget (i.e. "array get") for nested ClojureScript / JavaScript interop.
For example, if you wanted to access the second map item in your "pages" array, you could do this:
(def my-js-object
(clj->js {:status "ok"
:pages [{:id 1
:name "foo"
:children []}
{:id 2
:name "bar"
:children []}]}))
(aget my-js-object "pages" 1)
In the above code I'm simply using clj->js to construct a notional (and incomplete) representation of your JSON; I hope this is enough to make sense.
My REPL output was:
#js {:id 2, :name "bar", :children #js []}
If you wanted to do something more complex with each page item, e.g. "map over each page hashmap and pull out the name values", then you could make use of the .- JS property accessor
(->> (.-pages my-js-object)
(map #(.-name %)))
REPL output:
("foo" "bar")

To not answer the question, you could use
js->cljs, https://cljs.github.io/api/cljs.core/js-GTclj, to turn your json into a normal Clojure data structure and use Clojures normal fns to extract the data you want.

Related

Change name of main row Rails in JSON

So i have a json:
{
"code": "Q0934X",
"name": "PIDBA",
"longlat": "POINT(23.0 33.0)",
"altitude": 33
}
And i want to change the column code to Identifier
The wished output is this
{
"Identifier": "Q0934X",
"name": "PIDBA",
"longlat": "POINT(23.0 33.0)",
"altitude": 33
}
How can i do in the shortest way? Thanks
It appears that both "the json" you have and your desired result are JSON strings. If the one you have is json_str you can write:
json = JSON.parse(json_str).tap { |h| h["Identifier"] = h.delete("code") }.to_json
puts json
#=> {"name":"PIDBA","longlat":"POINT(23.0 33.0)","altitude":33,"Identifier":"Q0934X"}
Note that Hash#delete returns the value of the key being removed.
Perhaps transform_keys is an option.
The following seems to work for me (ruby 2.6):
json = JSON.parse(json_str).transform_keys { |k| k === 'code' ? 'Identifier' : k }.to_json
But this may work for Ruby 3.0 onwards (if I've understood the docs):
json = JSON.parse(json_str).transform_keys({ 'code': 'Identifier' }).to_json

How to use Aeson to get a vector of strings inside a deep JSON object?

Let's say I want to use Aeson to parse the following JSON object:
{
"data": [
[
"data",
"more data"
],
[
"data",
"more data"
]
],
"error": {
"code": ""
}
}
I can create the records for the JSON objects, then create the instances to parse the pieces out like the documentation describes. But, I'm really only interested in the Vector Text that's inside data. Is there a more direct way to get at this than creating the records? It's not obvious how to create the Parser that gets me this directly.
It appears that there is an Aeson tutorial documenting exactly this problem: Parsing without creating extra types
In your case, data has arrays of arrays, so I'm not sure if you want a Vector (Vector Text) or flatten all of it into one array, but adapting from the documentation:
justData :: Value -> Parser (Vector (Vector Text))
justData = withObject "structure with data" $ \o -> o .: "data"
justDataFlat :: Value -> Parser (Vector Text)
justDataFlat value = fmap join (justData value)
Also note that if your structure is deeper, like this:
{
"data": {
"deep": [
"data",
"more data"
]
}
}
you can use .: more than once:
deeperData :: Value -> Parser (Vector Text)
deeperData = withObject "structure with deeper data" $ \o ->
step1 <- o .: "data"
step1 .: "deep"

transform JSON to hashmap in Ruby

I am trying to convert a json file which contain object and array to a JSON file.
Below is the JSON file
{
"localbusiness":{
"name": "toto",
"phone": "+11234567890"
},
"date":"05/02/2016",
"time":"5:00pm",
"count":"4",
"userInfo":{
"name": "John Doe",
"phone": "+10987654321",
"email":"john.doe#unknown.com",
"userId":"user1234333"
}
}
my goal is to save this is a database such as MongoId. I would like to use map to get something like:
localbusiness_name => "toto",
localbusiness_phone => "+11234567890",
date => "05/02/2016",
...
userInfo_name => "John Doe"
...
I have tried map but it's not splitting the array of local business or userInfo
def format_entry
ps = #params.map do | h |
ps.merge!(h)
##logger.info("entry #{h}")
end
##logger.info("formatting the data #{ps}")
ps
end
I do not really how to parse each entry and rebuild the name
It looks like to me you are trying to "flatten" the inner hashes into one big hash. Flatten being incorrect because you want to prepend the hash's key to the sub-hash's key. This will require looping through the hash, and then looping again through each sub hash. This code example will only work if you have 1 layer deep. if you have multiple layers, then I would suggest making two methods, or a recursive method.
#business = { # This is a hash, not a json blob, but you can take json and call JSON.parse(blob) to turn it into a hash.
"localbusiness":{
"name": "toto",
"phone": "+11234567890"
},
"date":"05/02/2016",
"time":"5:00pm",
"count":"4",
"userInfo":{
"name": "John Doe",
"phone": "+10987654321",
"email":"john.doe#unknown.com",
"userId":"user1234333"
}
}
#squashed_business = Hash.new
#business.each do |k, v|
if v.is_a? Hash
v.each do |key, value|
#squashed_business.merge! (k.to_s + "_" + key.to_s) => value
end
else
#squashed_business.merge! k => v
end
end
I noticed that you are getting "unexpected" outcomes when enumerating over a hash #params.each { |h| ... } because it gives you both a key and a value. Instead you want to do #params.each { |key, value| ... } as I did in the above code example.

JSON requests within Emacs, Phase 2: Getting a collection of items

I'm trying to get a list of sites (a list of a-lists) with the Stack Exchange API using request.el.
I'm making an Emacs major mode for Stack Exchange, so this has some nice potential payoff for you Emacs users out there. ;) (And since I tagged elisp, I'm assuming that's the lot of you.)
To do this, a fundamental necessity would be to make a request for JSON, and then view the list of returned sites. The StackExchange API supplies the /sites resource, and a request for that resource returns a collection of site objects like so:
{
"items": [
{
"site_type": "main_site",
"name": "Stack Overflow",
"logo_url": "http://cdn.sstatic.net/stackoverflow/img/logo.png",
"api_site_parameter": "stackoverflow",
"site_url": "http://stackoverflow.com",
"audience": "professional and enthusiast programmers",
"icon_url": "http://cdn.sstatic.net/stackoverflow/img/apple-touch-icon.png",
"aliases": [
"http://www.stackoverflow.com"
],
"site_state": "normal",
"styling": {
"link_color": "#0077CC",
"tag_foreground_color": "#3E6D8E",
"tag_background_color": "#E0EAF1"
},
"launch_date": 1221436800,
"favicon_url": "http://cdn.sstatic.net/stackoverflow/img/favicon.ico",
"related_sites": [
{
"name": "Stack Overflow Chat",
"site_url": "http://chat.stackoverflow.com",
"relation": "chat"
}
],
"markdown_extensions": [
"Prettify"
],
"high_resolution_icon_url": "http://cdn.sstatic.net/stackoverflow/img/apple-touch-icon#2.png"
},
{
"site_type": "main_site",
"name": "Server Fault",
"logo_url": "http://cdn.sstatic.net/serverfault/img/logo.png",
"api_site_parameter": "serverfault",
"site_url": "http://serverfault.com",
"audience": "professional system and network administrators",
"icon_url": "http://cdn.sstatic.net/serverfault/img/apple-touch-icon.png",
...
},
{
"site_type": "main_site",
"name": "Super User",
...
{
"site_type": "main_site",
"name": "Meta Stack Overflow",
...
}
...
}
I'd like to minimize the number of calls I make to the API and retrieve them all and place them in a data structure in one go for me to be able to make sense of it later on.
I'm trying to adapt one of the lovely solutions I've found here, Making JSON requests within Emacs, to fit what I need to do. It uses the request.el library, from tkf.
The example tkf gave me was able to take the most active question on a site and grab its title and tags properties using json-read, which essentially turns an object into an a-list. This attempt is based off of that solution:
(request
"https://api.stackexchange.com/2.1/sites"
:parser 'buffer-string
:success (function*
(lambda (&key data &allow-other-keys)
(let* ((items (assoc-default 'items data))
(names (mapcar (lambda (item) (assoc-default 'name item)) items))
(launches (mapcar (lambda (item) (assoc-default 'launch-date item)) items)))
(mapcar* (lambda (name launch)
(message "name:`%s` launch:`%s`" name launch))
names
launches)))))
...but seems entirely ineffective. The other examples work perfectly, so it is something wrong with my usage.
request.el can be downloaded from the MELPA package repository and, to my knowledge, requires curl to run correctly (which I have).
I suspect the problem lies in my usage (or preparation thereof) of mapcar*, where the following does work as expected:
(mapcar* (lambda (a b) (insert a) (insert b)) '(1 2 3) '(4 5 6))
I know this post is long, but I tried to provide as much information as I could.
You were almost there. This one works for me:
(request
"https://api.stackexchange.com/2.1/sites"
:parser 'json-read
:success (function*
(lambda (&key data &allow-other-keys)
(let* ((items (assoc-default 'items data))
(names (mapcar (lambda (item) (assoc-default 'name item)) items))
(launches (mapcar (lambda (item) (assoc-default 'launch_date item)) items)))
(mapcar* (lambda (name launch)
(message "name:`%s` launch:`%s`" name launch))
names
launches)))))
Two changes: 1. use json-read instead of buffer-string for parser argument. 2. use launch_date instead of launch-date as the key for alist.

clojure loop through json data

I have a problem parsing json data in a loop. Iam a clojure beginner and need some hint for looping through json data.
The data looks like this:
{"photoset" {"primary" "8455893107", "total" "2", "pages" 1, "perpage" 500, "page" 1,
"per_page" 500, "photo"
[{"id" "8455893107", "secret" "1a3236df06", "server" "8087",
"farm" 9, "title" "IMG_0137", "isprimary" "1"}
{"id" "8469482476", "secret" "4c1bf59214",
"server" "8235", "farm" 9, "title" "HippieBus", "isprimary" "0"}]
, "owner"
"93029076#N07", "id" "72157632724688181", "ownername" "clojureB5"}, "stat" "ok"}
What I want to do is loop through the two photos and build a new url with the id and farm value like http://www.flickr.com/farm/id
I know that I can get one value like this:
(-> (get-in (cheshire.core/parse-string (:body picList)) ["photoset" "photo"]) first (get "id"))
But I can I now loop through it?
You can simply use map.
(->> (get-in data ["photoset" "photo"])
(map #(str "http://www.flickr.com/" (get % "farm") "/" (get % "id"))))
It will yield the following list:
("http://www.flickr.com/9/8455893107" "http://www.flickr.com/9/8469482476")