JSON/Kotlin - handling JSON objects and arrays - json

First of all, I'm very new to JSON concept so sorry if my question is silly or very simple to answer.
I want to use Oxford Dictionary API for simple app which I'm writing in Kotlin, here is the response from API as JSON:
{
"metadata": {
"provider": "Oxford University Press"
},
"results": [
{
"id": "hello",
"language": "en",
"lexicalEntries": [
{
"entries": [
{
"etymologies": [
"early 19th century: variant of earlier hollo; related to holla"
],
"homographNumber": "000",
"senses": [
{
"definitions": [
"used as a greeting or to begin a telephone conversation"
],
"examples": [
{
"text": "hello there, Katie!"
}
],
"id": "m_en_gbus0460730.012",
"short_definitions": [
"used as greeting"
],
"subsenses": [
{
"definitions": [
"used to express surprise"
],
"examples": [
{
"text": "hello, what's all this then?"
}
],
"id": "m_en_gbus0460730.017",
"regions": [
"British"
],
"short_definitions": [
"used to express surprise"
]
},
{
"definitions": [
"used as a cry to attract someone's attention"
],
"examples": [
{
"text": "‘Hello below!’ he cried"
}
],
"id": "m_en_gbus0460730.018",
"short_definitions": [
"used attract attention"
]
},
{
"definitions": [
"used informally to express sarcasm or anger"
],
"examples": [
{
"text": "Hello! Did you even get what the play was about?"
}
],
"id": "m_en_gbus0460730.019",
"short_definitions": [
"used informally to express sarcasm or anger"
]
}
]
And now, I would like to extract only "definitions" from this JSON object but as you can see it is nested within other JSON arrays, my code so far looks like this:
var resultJSON = JSONObject(result)
var JSON_results = resultJSON.getJSONArray("results")
var JSON_lexical = JSON_results.getJSONObject(0).getJSONArray("lexicalEntries")
var JSON_entries = JSON_lexical.getJSONObject(0).getJSONArray("entries")
var JSON_senses = JSON_entries.getJSONObject(0).getJSONArray("senses")
var JSON_definitions = JSON_senses.getJSONObject(0).getJSONArray("definitions")
Log.i("JSON", JSON_definitions.getString(0))
I know that there needs to be a better way of doing this but I can't find how.

Kotlin actually makes it easier to map such responses with something called "data classes". So you can simply paste the JSON response in an online JSON to Kotlin Data Class Generator e.g. https://json2kotlin.com
It churns out .kt files like this:
data class Json4Kotlin_Base (
val metadata : Metadata,
val results : List<Results>
)
and thn you can simply pass on the response JSON to the Data class mapping like this:
val json = getJson() // your json value here
val topic = Gson().fromJson(json, Json4Kotlin_Base::class.java)
In case you're looking for GSON annotations in the generated models, chose the option when you generate those.
Here's a video tutorial for step by step process about it.
https://www.youtube.com/watch?v=n46WbgNoEnE

Try as follow
val justDefinitions = mutableListOf<String>()
JSON_senses.forEach {
val definitions = it.getJSONArray("definitions")
for (i in 0 until definitions.length()) { {
justDefinitions.add(it.getString(i))
}
}

Related

Accessing list element in terraform output

I have following code in terraform state file( pasted just part of state file which I consider relevant for this question), which is result of running terraform code pasted below as well:
"mode": "managed",
"type": "azurerm_vpn_gateway",
"name": "azure_vpngw",
"provider": "provider[\"registry.terraform.io/hashicorp/azurerm\"].azure_clusters",
"instances": [
{
"schema_version": 0,
"attributes": {
"bgp_settings": [
{
"asn": 65515,
"bgp_peering_address": "",
"instance_0_bgp_peering_address": [
{
"custom_ips": [
"169.254.21.1"
],
"default_ips": [
"10.255.176.12"
],
"ip_configuration_id": "Instance0",
"tunnel_ips": [
"10.255.176.4",
"20.184.79.231"
]
Relevant terraform code:
resource "azurerm_vpn_gateway" "azure_vpngw" {
provider = azurerm.azure_clusters
name = "azure_vpngw"
location = azurerm_resource_group.azure_networking.location
resource_group_name = azurerm_resource_group.azure_networking.name
virtual_hub_id = azurerm_virtual_hub.azure_hub.id
bgp_settings {
asn = 65515
peer_weight = 50
instance_0_bgp_peering_address {
custom_ips = ["169.254.21.1"]
}
instance_1_bgp_peering_address {
custom_ips = ["169.254.22.1"]
}
}
}
And I need to accesss last element in tunnel_ips list, so 20.184.79.231.
I have been trying diff things like
azurerm_vpn_gateway.azure_vpngw.bgp_settings[0].instance_0_bgp_peering_address[0].tunnel_ips[0][1]
but it did not work. So, issue is in last part - tunnel_ips[0][1] I believe. If anybody has idea, it would be very wellcome.
Since your code is not a valid TF code, I modified it to actually be such, and this is how you can access your ip:
locals {
t = <<EOL
{
"mode": "managed",
"type": "azurerm_vpn_gateway",
"name": "azure_vpngw",
"provider": "provider[azure_clusters",
"instances": [{
"schema_version": 0,
"attributes": {
"bgp_settings": [{
"asn": 65515,
"bgp_peering_address": "",
"instance_0_bgp_peering_address": [{
"custom_ips": [
"169.254.21.1"
],
"default_ips": [
"10.255.176.12"
],
"ip_configuration_id": "Instance0",
"tunnel_ips": [
"10.255.176.4",
"20.184.79.231"
]
}]
}]
}
}]
}
EOL
v = jsondecode(local.t)
}
output "test" {
value = local.v["instances"][0]["attributes"]["bgp_settings"][0]["instance_0_bgp_peering_address"][0]["tunnel_ips"][1]
}
gives:
test = "20.184.79.231"
I figure it out. So, to fetch IP and use it in another resource definition I did:
ip_address = sort(azurerm_vpn_gateway.azure_vpngw.bgp_settings[0].instance_0_bgp_peering_address[0].tunnel_ips)[1]

API POST request in Julia

I am trying to convert some Python code to Julia. Here is the Python code:
url = "http://api.scb.se/OV0104/v1/doris/sv/ssd/START/BE/BE0101/BE0101G/BefUtvKon1749"
json = {
"query": [
{
"code": "Kon",
"selection": {
"filter": "item",
"values": [
"1",
"2"
]
}
},
{
"code": "ContentsCode",
"selection": {
"filter": "item",
"values": [
"000000LV"
]
}
}
],
"response": {
"format": "px"
}
}
r = requests.post(url=url, json=json)
Below is the Julia code, that is not working, with this error message:
syntax: { } vector syntax is discontinued around path:8
top-level scope at population_data.jl:8
using DataFrames, DataFramesMeta, HTTP, JSON3
url = "http://api.scb.se/OV0104/v1/doris/sv/ssd/START/BE/BE0101/BE0101G/BefUtvKon1749"
json = {
"query": [
{
"code": "Kon",
"selection": {
"filter": "item",
"values": [
"1",
"2",
"1+2"
]
}
},
{
"code": "ContentsCode",
"selection": {
"filter": "item",
"values": [
"000000LV"
]
}
}
],
"response": {
"format": "px"
}
}
r = HTTP.post(url, json)
My attempts to solve this are the following:
Convert the json variable to a string using """ around it.
Converting the JSON string to Julia data types, using JSON3.read()
Passing the converted JSON string to the POST request. This gives the following error:
IOError(Base.IOError("read: connection reset by peer (ECONNRESET)", -54) during request(http://api.scb.se/OV0104/v1/doris/sv/ssd/START/BE/BE0101/BE0101G/BefUtvKon1749)
None of it works, and I am not even sure that it is about the JSON format. It could be that I am passing the wrong parameters to the POST request. What should I do?
One way of solving this consists in building the parameters as native julia data structures, and use JSON to convert and use them as the body of your PUT request:
Dictionaries in julia are built using a syntax like Dict(key => value). Arrays are built using a standard syntax: [a, b, c]. The julia native data structure equivalent to your parameters would look like this:
params = Dict(
"query" => [
Dict("code" => "Kon",
"selection" => Dict(
"filter" => "item",
"values" => [
"1",
"2",
"1+2"
]),
),
Dict("code"=> "ContentsCode",
"selection" => Dict(
"filter" => "item",
"values" => [
"000000LV"
]),
),
],
"response" => Dict(
"format" => "px"
))
Then, you can use JSON.json() to build the JSON representation of it as a string and pass it to the HTTP request:
using HTTP
using JSON
url = "http://api.scb.se/OV0104/v1/doris/sv/ssd/START/BE/BE0101/BE0101G/BefUtvKon1749"
# send the request
r = HTTP.request("POST", url,
["Content-Type" => "application/json"],
JSON.json(params))
# retrieve the response body as a string
b = String(r.body)

jOOQ JSON formatting as array of objects

I have the following (simplified) jOOQ query:
val result = context.select(
jsonObject(
key("id").value(ITEM.ID),
key("title").value(ITEM.NAAM),
key("resources").value(
jsonArrayAgg(ITEM_INHOUD.RESOURCE_ID).absentOnNull()
)
)
).from(ITEM).fetch()
Now the output that I want is:
[
{
"id": "0da04cc5-f70c-4fb3-b5c7-dc645d342631",
"title": "Title1",
"resources": [
"8b0f6d5c-67fc-47ca-be77-d1735e7721ce",
"ea0316db-1cfd-46d7-8260-5c1a4e65a0cd"
]
},
{
"id": "0f7e67e6-5187-47e2-9f1d-dab08feba38b",
"title": "Title2"
}
]
result.formtJSON() gives the following output:
{
"fields": [
{
"name": "json_object",
"type": "JSON"
}
],
"records": [
[
{
"id": "0da04cc5-f70c-4fb3-b5c7-dc645d342631",
"title": "Title 1"
}
]
]
}
Disabling the headers with result.formatJSON(JSONFormat.DEFAULT_FOR_RECORDS) will get me:
[
[
{
"id": "0da04cc5-f70c-4fb3-b5c7-dc645d342631",
"title": "Title1",
"resources": [
"8b0f6d5c-67fc-47ca-be77-d1735e7721ce",
"ea0316db-1cfd-46d7-8260-5c1a4e65a0cd"
]
}
],
[
{
"id": "0f7e67e6-5187-47e2-9f1d-dab08feba38b",
"title": "Title2"
}
]
]
where I don't want the extra array.
Further customizing the JSONformatter with result.formatJSON(JSONFormat().header(false).recordFormat(JSONFormat.RecordFormat.OBJECT)) I get:
[
{
"json_object": {
"id": "0da04cc5-f70c-4fb3-b5c7-dc645d342631",
"title": "Title1",
"resources": [
"8b0f6d5c-67fc-47ca-be77-d1735e7721ce",
"ea0316db-1cfd-46d7-8260-5c1a4e65a0cd"
]
}
},
{
"json_object": {
"id": "0f7e67e6-5187-47e2-9f1d-dab08feba38b",
"title": "Title2"
}
}
]
where I don't want the object wrapped in json_object.
Is there a way to get the output I want?
Doing it with Result.formatJSON()
This is clearly a flaw in the jOOQ 3.14.0 implementation of Result.formatJSON(). In the special case where there is only one column, and that column is of type JSON or JSONB, the column name may not really matter, and thus its contents should be flattened into the object describing the row. I've created a feature request for this: https://github.com/jOOQ/jOOQ/issues/10953. It will be available in jOOQ 3.15.0 and 3.14.4. You will be able to do this:
result.formatJSON(JSONFormat().header(false).wrapSingleColumnRecords(false));
The RecordFormat is irrelevant here. This works the same way for RecordFormat.ARRAY and RecordFormat.OBJECT
Doing it directly with SQL
Of course, you can always work around this by moving all the logic into SQL. You probably simplified your query by omitting a JOIN and GROUP BY. I'm assuming this is equivalent to what you want:
JSON result = context.select(
jsonArrayAgg(jsonObject(
key("id").value(ITEM.ID),
key("title").value(ITEM.NAAM),
key("resources").value(
select(jsonArrayAgg(ITEM_INHOUD.RESOURCE_ID).absentOnNull())
.from(ITEM_INHOUD)
.where(ITEM_INHOUD.ITEM_ID.eq(ITEM.ID))
)
))
).from(ITEM).fetchSingle().value1()
Note that JSON_ARRAYAGG() aggregates empty sets into NULL, not into an empty []. If that's a problem, use COALESCE()

react native json image

I want to print out JSON images as a variable.
This is my local JSON file (JsonData.json):
{
"appetizer": [
{
"num": "appetizer1",
"name": "salad",
"condition": [ "1", "2" ],
"image": "./appetizer/salad.png"
},
{
"num": "appetizer2",
"name": "soup",
"condition": [ "2", "3" ],
"image": "./appetizer/soup.png"
},
…
],
"main": [
{
"num": "main1",
"name": "beef",
"condition": [ "1" ],
"image": "./main/beef.png"
},
{
"num": "main2",
"name": "fish",
"condition": [ "2", "3" ],
"image": "./main/fish.png"
},
…
]
}
I filtered the name when condition="2". (salad,soup,fish)
This is the code for filtering name:
const newArray1 = [...JsonData["apptizer"], ...JsonData["main"]];
const JsonResult = newArray1.filter(item => {
if(item.condition.indexOf("2") !== -1) return item.name;
});
AND I want to get the image when condition="2".
How can I get them? And How can I print out them?
Do I have to use base64? If so, Can you tell me how to use it?
I saw the explanation, but I can't understand it.
And I imported JSON file this way (I've been correctly using it):
var JsonData = require('./JsonData.json');
You can use below code:
let mainObject = JSON.parse(JSON.stringify(data))
let allKeys = Object.keys(mainObject)
let finalObject = []
allKeys.map((value, index) => {
let array = mainObject[value]
array.map((aryObject, aryIndex) => {
let condition = aryObject['condition']
if (condition.includes('2')) {
finalObject.push(aryObject)
}
})
})
alert(JSON.stringify(finalObject))
You can import data in top of screen:
import { data } from './data';
You can add below text in data.js:
export const data = {
"appetizer": [
{
"num": "appetizer1",
"name": "salad",
"condition": ["1"],
"image": "./appetizer/salad.png"
},
{
"num": "appetizer2222",
"name": "soup",
"condition": ["2", "3"],
"image": "./appetizer/soup.png"
},
],
"main": [
{
"num": "main1",
"name": "beef",
"condition": ["1"],
"image": "./main/beef.png"
},
{
"num": "main2",
"name": "fish",
"condition": ["21", "3"],
"image": "./main/fish.png"
},
]
}
You can use Object#values to get the arrays corresponding to appetizer and main and then Array#flat to extract the nested objects into a transformed array. Then use the Array#filter (which you are already using) to filter out only the required objects based on your condition and then Array#map to get the name and image values out of every filtered object into an array of objects.
Please consider following snippts
const jsonData = {"appetizer":[{"num":"appetizer1","name":"salad","condition":["1","2"],"image":"./appetizer/salad.png"},{"num":"appetizer2","name":"soup","condition":["2","3"],"image":"./appetizer/soup.png"}],"main":[{"num":"main1","name":"beef","condition":["1"],"image":"./main/beef.png"},{"num":"main2","name":"fish","condition":["2","3"],"image":"./main/fish.png"}]};
const filteredValues = Object.values(jsonData)
.flat()
.filter(o => o.condition.includes('2'))
.map(({name, image}) => ({ name, image }));
console.log(filteredValues);
The output of the above code will be an array of objects having the following structure
[{
"name": SOME_NAME,
"image": SOME_PATH
},
{
"name": SOME_NAME,
"image": SOME_PATH
},
...
]
You can use the above array to retrieve your image path and display it accordingly.
I think you shouldn't be worried about base64 as images are stored locally and path will be sufficient to display the image.
Hope this will help!!!
Side Note: You can avoid the Array#flat part as you are already doing it manually [...JsonData["apptizer"], ...JsonData["main"]] but flat will be handy in case there are more keys in jsonData that need to be considered.

How to get the the node object or array from JSON based on excel sheet data using groovy?

Lets say I have the following JSON :-
{
"book": [
{
"id": "01",
"language": "Java",
"edition": "third",
"author": "Herbert Schildt"
},
{
"id": "07",
"language": "C++",
"edition": "second",
"author": "E.Balagurusamy"
}
]
}
And, I am passing the value of author from excel sheet to check if that author is present or not. If that author is present inside JSON, then that that particular array node only and remove other from the JSON.
For Example:- I am passing "author" value as "Herbert Schildt" from excel sheet. Now this value is present inside JSON, So, I need this particular array node to be printed and rest all should be removed. Like this:-
{
"book": [
{
"id": "01",
"language": "Java",
"edition": "third",
"author": "Herbert Schildt"
}
]
}
Can it be done using groovy? I have tried with HashMap but couldn't get through.
It's quite easy using groovy:
def text = '''{
"book": [
{
"id": "01",
"language": "Java",
"edition": "third",
"author": "Herbert Schildt"
},
{
"id": "07",
"language": "C++",
"edition": "second",
"author": "E.Balagurusamy"
}
]
}
'''
def result = groovy.json.JsonOutput.toJson(
[book: new groovy.json.JsonSlurper().parseText(text).book.findAll{it.author == "Herbert Schildt"}]
)
println result
You may try this ways json search
var json = '{"book":[{"id":"01","language":"Java","edition":"third","author":"Herbert Schildt"},{"id":"07","language":"C++","edition":"second","author":"E.Balagurusamy"}]}';
var parsed = JSON.parse(json);
var result = {};
result.book = [];
var author = "Herbert Schildt";
parsed.book.map((i, j) => {
if(i.author == author) {
result.book.push(i);
}
});
console.log(result)