Last active
March 8, 2024 22:09
-
-
Save frobware/b1e94fb6a1944d9aa16197e987f9fc34 to your computer and use it in GitHub Desktop.
Sorts elements within a JSON document
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// The JSON Order Utility sorts the elements within a JSON document, | |
// ensuring a consistent order of keys in JSON objects and sorting | |
// string arrays alphabetically. It operates on a generic JSON input, | |
// dynamically handling both JSON objects (maps) and arrays, including | |
// nested structures. For JSON objects, it orders the keys | |
// alphabetically. For arrays containing solely strings, it sorts the | |
// elements in ascending alphabetical order. Otherwise, it recursively | |
// processes each element in the array or object to achieve a fully | |
// ordered structure. | |
package main | |
import ( | |
"encoding/json" | |
"fmt" | |
"io" | |
"os" | |
"sort" | |
"strings" | |
) | |
func orderJSON(input interface{}) interface{} { | |
switch val := input.(type) { | |
case map[string]interface{}: | |
orderedMap := make(map[string]interface{}, len(val)) | |
keys := make([]string, 0, len(val)) | |
for k := range val { | |
keys = append(keys, k) | |
} | |
sort.Strings(keys) | |
for _, k := range keys { | |
orderedMap[k] = orderJSON(val[k]) | |
} | |
return orderedMap | |
case []interface{}: | |
// Check if all elements are strings. | |
allStrings := true | |
for i := 0; i < len(val); i++ { | |
if _, ok := val[i].(string); !ok { | |
allStrings = false | |
break | |
} | |
} | |
// If all elements are strings, sort them. | |
if allStrings { | |
sort.Slice(val, func(i, j int) bool { | |
return val[i].(string) < val[j].(string) | |
}) | |
} else { | |
// Otherwise, recursively order each element. | |
for i, v := range val { | |
val[i] = orderJSON(v) | |
} | |
} | |
return val | |
default: | |
return input | |
} | |
} | |
func main() { | |
var inputBytes []byte | |
var err error | |
if len(os.Args) == 2 { | |
filePath := os.Args[1] | |
inputBytes, err = os.ReadFile(filePath) | |
if err != nil { | |
fmt.Fprintf(os.Stderr, "Error reading JSON file: %v\n", err) | |
os.Exit(1) | |
} | |
} else { | |
inputBytes, err = io.ReadAll(os.Stdin) | |
if err != nil { | |
fmt.Fprintf(os.Stderr, "Error reading from stdin: %v\n", err) | |
os.Exit(1) | |
} | |
} | |
inputString := strings.TrimSpace(string(inputBytes)) | |
if inputString == "" { | |
os.Exit(0) | |
} | |
var jsonObj interface{} | |
if err := json.Unmarshal([]byte(inputString), &jsonObj); err != nil { | |
fmt.Fprintf(os.Stderr, "Error unmarshalling JSON: %v\n", err) | |
os.Exit(1) | |
} | |
orderedJSON := orderJSON(jsonObj) | |
orderedJSONBytes, err := json.MarshalIndent(orderedJSON, "", " ") | |
if err != nil { | |
fmt.Fprintf(os.Stderr, "Error marshalling JSON: %v\n", err) | |
os.Exit(1) | |
} | |
if _, err := fmt.Println(string(orderedJSONBytes)); err != nil { | |
fmt.Fprintf(os.Stderr, "Error writing JSON: %v\n", err) | |
os.Exit(1) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment