Home > Software engineering >  Marshal different sets of fields from a struct at runtime in Golang
Marshal different sets of fields from a struct at runtime in Golang

Time:12-15

Lets say I have a struct like this (dummy example) :

type Animal struct {
   name string
   weight int
   isLandAnimal boolean
   Family
}

type Family struct {
   name string
   type string
}

Now what I want to achieve is something like this :

var a Animal = ....
bys, err := json.Marshal(a, []string{"name", "Family.name"})

and once printed bys should look like this :

{
   "name": "Lion"
   "family" : {
      "name" : "Felines"
   }
}

So I can pass a string slice that references which fields I want to actually get marshaled in the final string.

Does something like this exists in the standard library or in a third party one?

NOTE: This is what I could do based on another SO answer: https://go.dev/play/p/XVb83zoXpmb Will this bring troubles down the road?

CodePudding user response:

You can use tags

type Animal struct {
   name string         `json:"Family"` // example
   weight int          `json:"otherthing"` // fill the reset
   // ...
}

Although in your example, I would write a custom mapping function, i.e. first unmarshal it to the corresponding type, then have another type for printing, in which you map the values as you see fit.

Something like

func (a *Animal) print() { 
    showAnimal := DisplayAnimal{name: a.Family.Name}
    // add the rest and print it or w/ever you need
}

CodePudding user response:

What you're looking for is struct field annotations for json.Marshal. Basically go expects you to explicitly define the mapping from a struct to your export object, in this case json.

You need to ensure that the fields in your struct are exported, or basically start with a capital letter.

Next you can add a annotation to the end of the field to tell go what to look for when unmarshalling, or how to marshal that specific field into the file type format you're looking for.

For example:

This struct with exported members and annotations:

type Cookie struct {
   Name         string `json:"name"`
   Ingredients  int    `json:"ingredients"`
   MilkDunkTime int    `json:"milk_dunk_time"`
}

would export into this json:

{
   "name": "",
   "ingredients: 0,
   "milk_dunk_time:" 0
}

I've provided a playground link for your example above with some minor tweaks.


CodePudding user response:

You can annotate the fields which let you specify how it should show up in json and if it needs to be omitted when empty. https://pkg.go.dev/encoding/json#Marshal

Here is a working code. https://pkg.go.dev/encoding/json#Marshal

package main

import (
    "encoding/json"
    "fmt"
)

type Animal struct {
    Name         string `json:"name,omitempty"`
    Weight       int    `json:"weight,omitempty"`
    IsLandAnimal bool   `json:"IsLandAnimal,omitempty"`
    Family       Family `json:"Family,omitempty"`
}

type Family struct {
    Name       string `json:"Name,omitempty"`
    Familytype string `json:"Familytype,omitempty"`
}

func main() {
    a := Animal{Family: Family{Name: "Felines"}, Name: "Lion"}
    bys, _ := json.Marshal(a)
    fmt.Println(string(bys))
}
  • Related