15

I have the following json:

{
    "app": {
        "name": "name-of-app",
        "version" 1
    },
    "items": [
        {
            "type": "type-of-item",
            "inputs": {
                "input1": "value1"
            }
        }
    ]
}

The items[0].inputs change based on the items[0].type.

Knowing that, is there a way to keep the inputs field a string? The idea is to use the type to call the right handler passing the inputs, and in there I would parse the inputs string using the right struct.

Example:

package main

import (
    "fmt"
    "encoding/json"
)

type Configuration struct {
    App   App `json:"app"`
    Items []Item `json:"items"`
}

type App struct {
    Name    string `json:"name"`
    Version int    `json:"version"`
}

type Item struct {
    Type string `json:"type"`
    // What to put here to mantain the field a string so I can Unmarshal later?
    // Inputs string
}

var myJson = `
{
    "app": {
        "name": "name-of-app",
        "version": 1
    },
    "items": [
        {
            "type": "type-of-item",
            "inputs": {
                "input1": "value1"
            }
        }
    ]
}
`

func main() {
    data := Configuration{}
    json.Unmarshal([]byte(myJson), &data)

    fmt.Println("done!", data)
    // Loop through data.Items and use the type to define what to call, and pass inputs
    // as argument
}

Thank you in advance.

3
  • See if it's clear now @BasileStarynkevitch Commented Sep 10, 2018 at 2:49
  • No, because JSON is designed to be fully parsed. Look again on json.org and show some minimal reproducible example with Go code (that we could run on our computer) in your question. Perhaps you are using "JSON parsing" in a way that is not the common meaning of it. Commented Sep 10, 2018 at 2:50
  • @BasileStarynkevitch I added an example. Commented Sep 10, 2018 at 3:08

3 Answers 3

32

Use json.RawMessage to get the raw JSON text of the inputs field:

type Item struct {
    Type   string `json:"type"`
    Inputs json.RawMessage
}

Use it like this:

var data Configuration
if err := json.Unmarshal([]byte(myJson), &data); err != nil {
    // handle error
}

// Loop over items and unmarshal items.Inputs to Go type specific
// to each input type.    
for _, item := range data.Items {
    switch item.Type {
    case "type-of-item":
        var v struct{ Input1 string }
        if err := json.Unmarshal(item.Inputs, &v); err != nil {
            // handle error
        }
        fmt.Printf("%s has value %+v\n", item.Type, v)

    }
}

Run it on the playground.

0
5

In fairness Go would actually parse partially if you defined a partial struct. Quoting the documentation (https://blog.golang.org/json-and-go):

How does Unmarshal identify the fields in which to store the decoded data? For a given JSON key "Foo", Unmarshal will look through the destination struct's fields to find (in order of preference):

An exported field with a tag of "Foo" (see the Go spec for more on struct tags),

An exported field named "Foo", or

An exported field named "FOO" or "FoO" or some other case-insensitive match of "Foo".

What happens when the structure of the JSON data doesn't exactly match the Go type?

b := []byte(`{"Name":"Bob","Food":"Pickle"}`)
var m Message
err := json.Unmarshal(b, &m)

Unmarshal will decode only the fields that it can find in the destination type. In this case, only the Name field of m will be populated, and the Food field will be ignored. This behavior is particularly useful when you wish to pick only a few specific fields out of a large JSON blob. It also means that any unexported fields in the destination struct will be unaffected by Unmarshal.

2

Try gjson, super simple, you do not have to unmarshal the whole thing. you can take the bytes and pull a specific field out. https://github.com/tidwall/gjson

    // Get string (has string, int, bool parsing)
    someField := gjson.ParseBytes(b).Get("some_field.some_nested_field").Str
    // Other types
    v, ok := gjson.ParseBytes(b).Get("some_other_field").Value().(map[string]string)

Not the answer you're looking for? Browse other questions tagged or ask your own question.