"If a worker wants to do his job well, he must first sharpen his tools." - Confucius, "The Analects of Confucius. Lu Linggong"
Front page > Programming > How to Unmarshal Non-Homogenous JSON Data with a \"Code\" Field?

How to Unmarshal Non-Homogenous JSON Data with a \"Code\" Field?

Published on 2024-11-02
Browse:623

How to Unmarshal Non-Homogenous JSON Data with a \

Unmarshalling Non-Homogenous JSON Data

This inquiry centers around unmarshalling JSON data efficiently by leveraging a mechanism that allows for selective unmarshalling of specific sections or segments. The objective is to handle JSON structures where the first part serves as a "code" that determines the type of data contained in the latter part.

Imagine a scenario where you have multiple data structures:

type Range struct {
    Start int
    End   int
}

type User struct {
    ID    int
    Pass  int
}

And your JSON message has a "code" field that signals what data is in the "payload" field:

{
    "Code": 4,
    "Payload": {
        "Start": 1,
        "End": 10
    }
}
{
    "Code": 3,
    "Payload": {
        "ID": 1,
        "Pass": 1234
    }
}

You need to unmarshal the "payload" field into the appropriate data structure based on the "code" field.

Solution

The key here is to use the json.RawMessage type to delay the unmarshalling of the "payload" field until after you know its type. For example:

package main

import (
    "encoding/json"
    "fmt"
)

type Message struct {
    Code    int
    Payload json.RawMessage // Delay parsing until we know the code
}

// Unmarshall into appropriate structures based on Code
func unmarshal(m []byte) error {
    var message Message
    err := json.Unmarshal(m, &message)
    if err != nil {
        return err
    }
    switch message.Code {
    case 3:
        var user User
        if err := json.Unmarshal(message.Payload, &user); err != nil {
            return err
        }
        fmt.Printf("Unmarshalled a User: %#v\n", user)
    case 4:
        var range Range
        if err := json.Unmarshal(message.Payload, &range); err != nil {
            return err
        }
        fmt.Printf("Unmarshalled a Range: %#v\n", range)
    default:
        return fmt.Errorf("unknown code: %d", message.Code)
    }
    return nil
}

func main() {
    json1 := []byte(`{"Code": 3, "Payload": {"ID": 1, "Pass": 1234}}`)
    if err := unmarshal(json1); err != nil {
        fmt.Printf("error: %v\n", err)
    }

    json2 := []byte(`{"Code": 4, "Payload": {"Start": 1, "End": 10}}`)
    if err := unmarshal(json2); err != nil {
        fmt.Printf("error: %v\n", err)
    }
}
Latest tutorial More>

Disclaimer: All resources provided are partly from the Internet. If there is any infringement of your copyright or other rights and interests, please explain the detailed reasons and provide proof of copyright or rights and interests and then send it to the email: [email protected] We will handle it for you as soon as possible.

Copyright© 2022 湘ICP备2022001581号-3