How can I unmarshal the following json into golang struct [closed] - json

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 years ago.
Improve this question
How can I unmarshal the following json into golang struct
{
"VM": {
"0": {
"component": "A",
"name": "hostname1",
"hostname": "hostname1",
"role": "NODE",
"this": true,
"type": "t1"
},
"1": {
"component": "B",
"name": "hostname2",
"hostname": "hostname2",
"role": "role2",
"type": "t2"
},
"2": {
"component": "C",
"name": "hostname3",
"hostname": "hostname3",
"role": "role3",
"type": "t3"
},
"n": { //this can go upto n levels
"component": "N",
"name": "hostnamen",
"hostname": "hostnamen",
"role": "rolen",
"type": "tn"
}
}
}

This is a handy online resource to get you started: https://mholt.github.io/json-to-go/
It does however get tripped up by defining specific struct fields instead of using a map - which appears the case here.
Striking a balance:
type Collection map[string][string]Component
type Component struct {
Component string `json:"component"`
Name string `json:"name"`
Hostname string `json:"hostname"`
Role string `json:"role"`
This bool `json:"this"`
Type string `json:"type"`
}
If your output always has a "VM" key at the top-level, then the Collection type could be flattened to something like:
type Collection struct {
VM map[string]Component `json:"VM"`
}
// Component def stays the same
If you're confident the component indices will always be numeric, this may work too:
type Collection struct {
VM map[int]Component `json:"VM"` // index by `int` instead of `string`
}
PlayGround example: https://play.golang.org/p/ewHnlq8h1Vc

Related

How to change the value of specific key which is multiple time duplicated in the JSON using node JS [duplicate]

This question already has answers here:
Dynamic deep setting for a JavaScript object [duplicate]
(3 answers)
How to set object property (of object property of..) given its string name in JavaScript?
(16 answers)
Dynamically updating a JavaScript object from a string path [duplicate]
(3 answers)
Accessing nested JavaScript objects and arrays by string path
(44 answers)
Closed 1 year ago.
The community reviewed whether to reopen this question 1 year ago and left it closed:
Duplicate This question has been answered, is not unique, and doesn’t differentiate itself from another question.
I'm trying to construct a function which will replace the value based on the path user given as input argument. I have a complex JSON with some duplicated key and user will give path of the element and based on that path It needs to replace the value of the particular key (which is possibly duplicated):
SampleJSON.json:
{
"product": "delivery",
"Merchant": {
"payment_method": "GPay"
},
"transactions": [
{
"amount": {
"total": "100",
"currency": "USD",
"details": {
"subtotal": "100",
"tax": "1",
"insurance": "0.1"
}
},
"description": "The payment transaction description",
"custom": "JACKSON DISPUTERS SYSTEMS",
"invoicenumber": "",
"descriptor": "null",
"itemlist": {
"items": [
{
"name": "COMPUTER",
"description": "BLACK",
"quantity": "1",
"price": "100",
"tax": "1",
"currency": "USD"
}
],
"shippingaddress": {
"recipient_name": "JACKSON DISPUTERS SYSTEMS",
"line1": "XXXX",
"line2": "XXXX",
"city": "XXXX",
"country_code": "XX",
"postal_code": "XXXX",
"phone": "XXXXXX",
"state": "XXXXXX"
}
}
}
],
"note_to_payer": "Contact us for any questions on your order."
}
User Input:
arg1: product.transactions.currency,
arg2: EUR
I just need to traverse through the above path (arg1) and replace the value of currency as AUD (arg2).
If you noticed the currency element is available in two different places in the given JSON file but I just want to replace the currency which is under the transactions array that mentioned in the arg1, and not the other one.
I just created the below code so far and It will traverse through each and every element in the given JSON but not sure how to replace the value for the given key (arg1).
const arg1 = "product.transactions.currency";
const condition = arg1.toString().split(".");
const arg2 = "EUR";
const cond = false;
function process(key,value) {
if(key === condition[condition.length-1]) //condition[condition.length-1] return currency
{
cond = true;
console.log(key + " : "+value);
}
}
function traverse(o,func) {
for (var i in o) {
func.apply(this,[i,o[i]]);
if (o[i] !== null && typeof(o[i])=="object") {
if(cond === false)
{
traverse(o[i],func);
}
}
}
}
traverse(SampleJSON, process);
The above code print the first occurrence of the "Currency" element but I just want to print the element based on the arg1 which is given by user, and want to replace that value based on arg2.
is there any npm package available to achieve this?
Any help would be highly appreciated.
You can use Lodash set method to assign a value on a specific path in an object. First, run the below command to install the package:
yarn install lodash.set
Usage
const set = require('lodash.set');
set(yourObject, 'product.transactions.currency', 'EUR');

Swift: Decode json response [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 1 year ago.
Improve this question
I have a backend response that has the format:
{
"Items": [
{
"Id": "blabla",
"Text": "blabla",
"Description": "blabla"
},
{
"Id": "blabla",
"Text": "blabla",
"Description": "blabla"
}]
}
Which will be the best Swift approach to directly decode the array?
For the moment I have a struct for the response, but I have also to take in account the "Items" key, which hasn't any business logic implication for the project.
struct SearchResult: Decodable {
let Id: String
let Text: String
let Description: String
}
Your JSON is missing a trailing ] on the end of the array.
Besides that, you just need a wrapper than gives you the Items array. This, for example, works fine:
let jsonData = """
{
"Items": [
{
"Id": "blabla",
"Text": "blabla",
"Description": "blabla"
},
{
"Id": "blabla",
"Text": "blabla",
"Description": "blabla"
}
]
}
""".data(using: .utf8)!
struct ResultWrapper: Decodable {
var Items : [SearchResult]
}
struct SearchResult: Decodable {
let Id: String
let Text: String
let Description: String
}
do {
let results = try JSONDecoder().decode(ResultWrapper.self, from: jsonData)
print(results.Items) //this is your array
} catch {
print(error)
}

Umarshalling large unstructured REST/JSON Response

I'm having a heck of a time figuring out how to unmarshal a large unstructured json response into a usable object.
Here is a sample response (trimmed to show the part I'm having trouble with)
This has been greatly trimmed as this is a very large json response. I left the struct tags off below as well for simplicity.
{
"responseStatus": "ok",
"responseHeader": {
"status": "ok",
"requestId": "blah"
},
"responseData": {
"records": [
{
"name": "blah",
"site": {
"id": 1,
"name": "west"
},
"somevar1": "someval",
"somevar2": {
"x": 2,
"y": 1
},
"entries": [
{
"model": "100",
},
{
"model": "200",
}
]
},
]
}
So records is a large list of "objects". I need to convert these to a type I defined. The "entries" list also needs to be converted to its object type.
type Record struct {
Name string
Site map[string]string
Somevar1 string
Somevar2 map[string]string
Entries []Entry
}
type Entry struct {
Model string
}
Here I can get the responseData into an object I can iterate over:
results := data["responseData"].(map[string]interface{})
devices := results["records"].([]interface{})
for _, device := range devices {
fmt.Fprintf(os.Stdout, "%T\n", device)
fmt.Fprintf(os.Stdout, "%+v\n", device)
}
Here is a sample output from 1 iteration:
map[string]interface {}
map[name:foo site:map[id:2 name:somewhere somevar1: blah somevar2:map[x:1 y:2] entries:[map[model:100] map[model:200]
This is where I'm stuck. I need to take this line above and get convert it into my type Record while also converting the Entries to []Entry.
Change the Site and Somevar2 fields to map[string]interface{} or to a proper struct, because their corresponding json contains ints, so when you use only map[string]string it will fail.
Other than that your code works https://play.golang.com/p/rTgaXhXD1V6

map[string] struct inside struct

I have a JSON file that looks like this:
{
"jailbreaks": [
{
"jailbroken": false,
"name": "",
"version": "",
"url": "",
"anleitung": [],
"ios": {
"start": "10.2.1"
},
"caveats": "",
"platforms": []
},
{
"jailbroken": true,
"name": "Yalu102",
"version": "beta 6",
"url": "https://domain-dl.tld",
"anleitung": [
{ "blog": "title", "link": "http://domain.tld/" },
{ "blog": "Test", "link": "http://google.at" }
],
"ios": {
"start": "10.2"
},
"caveats": "some text here",
"platforms": [
"Windows",
"OS X",
"Linux"
]
},
And I create the object to work with like this:
type Jailbreak struct {
Jailbroken bool `json:"jailbroken"`
Name string `json:"name"`
Version string `json:"version"`
URL string `json:"url"`
Anleitung map[string]struct {
Name string `json:"blog"`
Link string `json:"link"`
} `json:"anleitung"`
Firmwares struct {
Start string `json:"start"`
End string `json:"end"`
} `json:"ios"`
Platforms []string `json:"platforms"`
Caveats string `json:"caveats"`
}
When I want to build my go program I get an error, that the JSON file cannot be read. But as soon as I delete the map[string]struct I can compile and run the program without any error and everything works fine.
Am I messing around with something or is there an error in my JSON file?
The json provided is not valid (as the array does not have a closing ] and the top level json object lacks another closing }) so let's assume it's like:
{
"jailbreaks": [
{
"jailbroken": false,
"name": "",
"version": "",
"url": "",
"anleitung": [],
"ios": {
"start": "10.2.1",
"end": ""
},
"platforms": [],
"caveats": ""
},
{
"jailbroken": true,
"name": "Yalu102",
"version": "beta 6",
"url": "https://domain-dl.tld",
"anleitung": [
{
"blog": "title",
"link": "http://domain.tld/"
},
{
"blog": "Test",
"link": "http://google.at"
}
],
"ios": {
"start": "10.2",
"end": ""
},
"platforms": [
"Windows",
"OS X",
"Linux"
],
"caveats": "some text here"
}
]
}
The data structure Jailbreaks (first one), marshals-to/unmarshals-from this json properly:
type Jailbreaks struct {
List []Jailbreak `json:"jailbreaks"`
}
type Jailbreak struct {
Jailbroken bool `json:"jailbroken"`
Name string `json:"name"`
Version string `json:"version"`
URL string `json:"url"`
Anleitung []struct {
Name string `json:"blog"`
Link string `json:"link"`
} `json:"anleitung"`
Firmwares struct {
Start string `json:"start"`
End string `json:"end"`
} `json:"ios"`
Platforms []string `json:"platforms"`
Caveats string `json:"caveats"`
}
As you see Anleitung is declared as a slice (not a map).
Use omitempty flag for when your "anleitung" is empty in JSON to be consumed. Beware though, when that is the case, your Jailbreak struct won't have an "anleitung" field.
Change your map's json flag to to;
Anleitung map[string]struct {
Name string `json:"blog"`
Link string `json:"link"`
} `json:"anleitung,omitempty"`
Option 2;
I guess you could also use Anleitung map[string]interface{} but that is better for "holding a map of strings to arbitrary data types". In your case the data is not arbitrary but rather, empty I guess. And looks like that is just temporary.
I'd go for option 1, then I'd check if my struct contains any Anleitung data or not before accessing it.

How to define a JSON schema that requires at least one of many properties

I would like to know if I can define a JSON schema (draft 4) that requires at least one of many properties possible for an object. I already know of allOf, anyOf and oneOf but just can't figure out how to use them in the way I want.
Here are some example JSON to illustrate :
// Test Data 1 - Should pass
{
"email": "hello#example.com",
"name": "John Doe"
}
// Test Data 2 - Should pass
{
"id": 1,
"name": "Jane Doe"
}
// Test Data 3 - Should pass
{
"id": 1,
"email": "hello#example.com",
"name": "John Smith"
}
// Test Data 4 - Should fail, invalid email
{
"id": 1,
"email": "thisIsNotAnEmail",
"name": "John Smith"
}
// Test Data 5 - Should fail, missing one of required properties
{
"name": "John Doe"
}
I would like to require at least id or email (also accepting both of them) and still pass validation according to format. Using oneOf fails validation if I provide both (test 3), anyOf passes validation even if one of them is not valid (test 4)
Here is my schema :
{
"$schema": "http://json-schema.org/draft-04/schema#",
"id": "https://example.com",
"properties": {
"name": {
"type": "string"
}
},
"anyOf": [
{
"properties": {
"email": {
"type": "string",
"format": "email"
}
}
},
{
"properties": {
"id": {
"type": "integer"
}
}
}
]
}
Can you help me how to achieve correct validation for my use case ?
To require at least one of a set of properties, use required inside a series of anyOf options:
{
"type": "object",
"anyOf": [
{"required": ["id"]},
{"required": ["email"]}
// any other properties, in a similar way
],
"properties": {
// Your actual property definitions here
}
}
If any of the properties you want is present ("id", "email"), then it will pass the corresponding option in allOf.
You may use minProperties: number (and maxProperties: number if needed).
That would shorten the schema definition:
{
type: "object",
minProperties: 1,
properties: [/* your actual properties definitions */],
additionalProperties: false
}
Link to documentation: https://json-schema.org/understanding-json-schema/reference/object.html#size