Jeffail / gabs

For parsing, creating and editing unknown or dynamic JSON in Go
MIT License
3.45k stars 202 forks source link

Load Flattened Data into Container (With arrays) #143

Open WTIGER001 opened 2 weeks ago

WTIGER001 commented 2 weeks ago

I have tried the following with flattened JSON data like

`
flattenedData := map[string]interface{}{ "foo.arr.0": "apple", "foo.arr.1": "banana", "oarr.0.id": "id1", "oarr.1.id": "id2", }

// Create a new gabs container
container := gabs.New()

// Iterate through the flattened data and set values in the container
for path, value := range flattenedData {
    container.SetP(value, path)
}

// Print the nested JSON as a string
fmt.Println(container.StringIndent("", "  "))

`

I get

{ "foo": { "arr": { "0": "apple", "1": "banana" } }, "oarr": { "0": { "id": "id1" }, "1": { "id": "id2" } } }

Instead of

{ "foo": { "arr": [ "apple", "banana"] "oarr": [ { "id": "id1" }, { "id": "id2" } ] }

Is there a known way on how I can load this flattened data back into the container? It is using my array indexes as map keys right now.

mihaitodor commented 2 weeks ago

Hey @WTIGER001 👋 Guess you can get away with something like this:

package main

import (
    "fmt"
    "slices"
    "strconv"

    "github.com/Jeffail/gabs/v2"
)

func main() {
    flattenedData := map[string]interface{}{
        "foo.arr.0": "apple",
        "foo.arr.1": "banana",
        "oarr.0.id": "id1",
        "oarr.1.id": "id2",
        "foo.bar":   "foobar",
    }

    // Create a new gabs container
    container := gabs.New()

    // Iterate through the flattened data and set values in the container
    for path, value := range flattenedData {
        segments := gabs.DotPathToSlice(path)

        isArray := false
        for loc, segment := range segments {
            if _, err := strconv.Atoi(segment); err == nil {
                isArray = true
                if _, err := container.ArrayCount(segments[:loc]...); err != nil {
                    container.Array(segments[:loc]...)
                }
                if loc > 0 {
                    if _, err := container.Set(value, slices.Replace(segments, loc, loc+1, "-")...); err != nil {
                        panic(err)
                    }
                } else {
                    if err := container.ArrayAppend(value); err != nil {
                        panic(err)
                    }
                }
            }
        }
        if !isArray {
            if _, err := container.SetP(value, path); err != nil {
                panic(err)
            }
        }
    }

    // Print the nested JSON as a string
    fmt.Println(container.StringIndent("", "  "))
}

The trouble is that it doesn't validate the input so you could get some hard to debug issues. For example, if the flattened arrays are not in the right order, then the resulting arrays will not have the expected element order. Also, it doesn't detect gaps in arrays.

WTIGER001 commented 2 weeks ago

Thanks for that. That is an interesting approach.