Skip to content

Commit

Permalink
Merge pull request #1 from bhataprameya/Add-non-Array-flattening
Browse files Browse the repository at this point in the history
flatten only map functionality
  • Loading branch information
bhataprameya authored Feb 14, 2024
2 parents b32d060 + 3209653 commit 84f438d
Show file tree
Hide file tree
Showing 4 changed files with 733 additions and 12 deletions.
64 changes: 62 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ Flatten is a Go library that simplifies the process of converting arbitrarily ne
- Support various key styles: dotted, path-like, Rails, or underscores.
- Define custom key styles to suit your needs.
- Works with both JSON strings and Go structures.
- Ability to flatten only maps and not arrays.

## Installation

Expand Down Expand Up @@ -81,11 +82,70 @@ flat, err := gojsonflatten.Flatten(nested, "", flatten.RailsStyle, 3)
// }
```

### Flatten Go Maps without Arrays

You can also flatten Go maps while preserving arrays as it is like this::

```GO

import (
"github.com/bhataprameya/gojsonflatten"
)

nested := map[string]interface{}{
"a": "b",
"c": map[string]interface{}{
"d": "e",
"f": "g",
},
"z": []interface{}{"one", "two"},
}

flat, err := gojsonflatten.FlattenNoArray(nested, "", flatten.RailsStyle, 3)

// Output:
// {
// "a": "b",
// "c[d]": "e",
// "c[f]": "g",
// "z": []interface{}{"one", "two"}
// }
```

### Flatten JSON Strings without Arrays

You can flatten JSON strings while preserving arrays using FlattenNoArray:

```GO
import (
"github.com/bhataprameya/gojsonflatten"
)

nested := `{
"one": {
"two": [
"2a",
"2b"
]
},
"side": "value"
}`

flat, err := gojsonflatten.FlattenStringNoArray(nested, "", flatten.DotStyle, -1)

// Output:
// {
// "one.two": ["2a", "2b"],
// "side": "value"
// }

```

## Custom Key Style

You can even define a custom key style for flattening:

```go
```GO
import (
"github.com/bhataprameya/gojsonflatten"
)
Expand All @@ -105,7 +165,7 @@ flat, err := gojsonflatten.FlattenString(nested, "", doubleDash, 5)

You can even define a custom key style for flattening:

```go
```GO
import (
"github.com/bhataprameya/gojsonflatten"
)
Expand Down
44 changes: 34 additions & 10 deletions flatten.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,23 +32,43 @@ var (

// Flatten generates a flat map from a nested map with a specified depth.
func Flatten(nested map[string]interface{}, prefix string, style SeparatorStyle, depth int) (map[string]interface{}, error) {
return flattenInternal(nested, prefix, style, depth, false)
}

// FlattenString generates a flat JSON map from a nested JSON string with a specified depth.
func FlattenString(nestedString, prefix string, style SeparatorStyle, depth int) (string, error) {
return flattenStringInternal(nestedString, prefix, style, depth, false)
}

// FlattenNoArray generates a flat map from a nested map with a specified depth, preserving arrays as strings.
func FlattenNoArray(nested map[string]interface{}, prefix string, style SeparatorStyle, depth int) (map[string]interface{}, error) {
return flattenInternal(nested, prefix, style, depth, true)
}

// FlattenStringNoArray generates a flat JSON map from a nested JSON string with a specified depth, preserving arrays as strings.
func FlattenStringNoArray(nestedString, prefix string, style SeparatorStyle, depth int) (string, error) {
return flattenStringInternal(nestedString, prefix, style, depth, true)
}

// flattenInternal generates a flat map from a nested map with a specified depth, optionally preserving arrays as strings.
func flattenInternal(nested map[string]interface{}, prefix string, style SeparatorStyle, depth int, preserveArray bool) (map[string]interface{}, error) {
if depth == 0 {
return nested, nil
} else if depth > 0 {
depth++
}

flatmap := make(map[string]interface{})
err := flatten(true, flatmap, nested, prefix, style, depth)
err := flatten(true, flatmap, nested, prefix, style, depth, preserveArray)
if err != nil {
return nil, err
}

return flatmap, nil
}

// FlattenString generates a flat JSON map from a nested JSON string with a specified depth.
func FlattenString(nestedString, prefix string, style SeparatorStyle, depth int) (string, error) {
// flattenStringInternal generates a flat JSON map from a nested JSON string with a specified depth, optionally preserving arrays as strings.
func flattenStringInternal(nestedString, prefix string, style SeparatorStyle, depth int, preserveArray bool) (string, error) {
if !isJsonMap.MatchString(nestedString) {
return "", ErrNotValidJsonInput
}
Expand All @@ -59,7 +79,7 @@ func FlattenString(nestedString, prefix string, style SeparatorStyle, depth int)
return "", err
}

flatmap, err := Flatten(nested, prefix, style, depth)
flatmap, err := flattenInternal(nested, prefix, style, depth, preserveArray)
if err != nil {
return "", err
}
Expand All @@ -73,7 +93,7 @@ func FlattenString(nestedString, prefix string, style SeparatorStyle, depth int)
}

// flatten recursively processes nested structures and flattens them.
func flatten(top bool, flatMap map[string]interface{}, nested interface{}, prefix string, style SeparatorStyle, depth int) error {
func flatten(top bool, flatMap map[string]interface{}, nested interface{}, prefix string, style SeparatorStyle, depth int, keepArrays bool) error {
if depth == 0 {
// If the desired depth is reached, add the prefix and nested value to the flat map.
flatMap[prefix] = nested
Expand All @@ -85,7 +105,7 @@ func flatten(top bool, flatMap map[string]interface{}, nested interface{}, prefi
switch v.(type) {
case map[string]interface{}, []interface{}:
// If the value is a nested map or slice, continue flattening recursively.
if err := flatten(false, flatMap, v, newKey, style, depth-1); err != nil {
if err := flatten(false, flatMap, v, newKey, style, depth-1, keepArrays); err != nil {
return err
}
default:
Expand All @@ -104,10 +124,14 @@ func flatten(top bool, flatMap map[string]interface{}, nested interface{}, prefi
assign(newKey, v)
}
case []interface{}:
for i, v := range nested {
newKey := enkey(top, prefix, strconv.Itoa(i), style)
// Process and assign the index-value pair.
assign(newKey, v)
if !keepArrays {
for i, v := range nested {
newKey := enkey(top, prefix, strconv.Itoa(i), style)
// Process and assign the index-value pair.
assign(newKey, v)
}
} else {
flatMap[prefix] = nested
}
default:
return ErrNotValidInput
Expand Down
Loading

0 comments on commit 84f438d

Please sign in to comment.