Sublime Forum

JSON Flattener

#1

Hello, I’m looking for but have not found a package which will flatten (prettified or raw) JSON to a simple dot notation string for each value. JSFiddle does this but of course, I want this in ST. Perhaps my searching has been missing the magic package?

example
this:
{ "components": { "main": { "samsungce.washerDelayEnd": { "remainingTime": { "value": 0, "unit": "min", "timestamp": "2022-08-19T12:22:47.069Z" }, "minimumReservableTime": { "value": 22, "unit": "min", "timestamp": "2022-09-07T23:30:12.529Z" } } } } }

into this:
{ "components.main.samsungce.washerDelayEnd.remainingTime.value": 0, "components.main.samsungce.washerDelayEnd.remainingTime.unit": "min", "components.main.samsungce.washerDelayEnd.remainingTime.timestamp": "2022-08-19T12:22:47.069Z", "components.main.samsungce.washerDelayEnd.minimumReservableTime.value": 22, "components.main.samsungce.washerDelayEnd.minimumReservableTime.unit": "min", "components.main.samsungce.washerDelayEnd.minimumReservableTime.timestamp": "2022-09-07T23:30:12.529Z" }

Thanks

0 Likes

#2

Well, no replies is a bummer, but I did find a kludgy way.

I installed Node then added into ST a JavaScript build system like:

{
"cmd": ["node","$file"],
"selector": "source.js"

}

Then in a new .js file paste in the the JSON to be flattened. At the bottom below that I added the JS:

const flattenJSON = (obj = {}, res = {}, extraKey = '') => {
for (key in obj) {
    if (typeof obj[key] !== 'object') {
        res[extraKey + key] = obj[key];
    }
    else {
        flattenJSON(obj[key], res, `${extraKey}${key}.`);
    };
};
return res;

};
console.log(flattenJSON(obj)); (I dont know why this wasnt in the code block)

Ctl-B “builds” it and the console shows the flattened JSON. Not the most elegant but it does work

0 Likes

#3

A naive implementation:

flatten_json_command.py

from typing import Any, Dict, Optional, Union
import json
import sublime
import sublime_plugin


def flatten_dict(data: Dict[Any, Any], *, sep: str = ".", prefix: str = "") -> Dict[str, Any]:
    result: Dict[str, Any] = {}
    for key, value in data.items():
        key = f"{prefix}{key}"
        if isinstance(value, dict):
            result.update(flatten_dict(value, sep=sep, prefix=f"{key}{sep}"))
        else:
            result[key] = value
    return result


class FlattenJsonCommand(sublime_plugin.TextCommand):
    def run(
        self,
        edit: sublime.Edit,
        *,
        ensure_ascii: bool = False,
        pretty: Optional[Union[int, str]] = "\t",
        sep: str = ".",
    ) -> None:
        if len(sel := self.view.sel()) != 1:
            sublime.error_message("Please select only one region.")
            return

        if (region := sel[0]).empty():
            region = sublime.Region(0, self.view.size())

        text = self.view.substr(region)
        try:
            data = sublime.decode_value(text)
        except ValueError as e:
            sublime.error_message(f"Invalid JSON: {e}")
            return

        if not isinstance(data, dict):
            return

        flattened = flatten_dict(data, sep=sep)
        json_args = self._json_dump_args(pretty=pretty, ensure_ascii=ensure_ascii)
        self.view.replace(edit, region, json.dumps(flattened, **json_args))

    def _json_dump_args(
        self,
        *,
        ensure_ascii: bool = False,
        pretty: Optional[Union[int, str]] = "\t",
    ) -> Dict[str, Any]:
        args: Dict[str, Any] = {
            "ensure_ascii": ensure_ascii,
            "indent": pretty,
        }
        if pretty is None:
            args["separators"] = (",", ":")
        return args
0 Likes

#4

Can you tell me how to implement this?

0 Likes

#5

Just put flatten_json_command.py as Packages/User/flatten_json_command.py and assign a keybinding for it such as

{ "keys": ["alt+q"], "command": "flatten_json" },

And use that keybinding.

0 Likes

#6

Got it. I was trying to make it behave like the build system method. This is much better - thanks!

0 Likes

#7

btw, if you want a minified result, you can use

{ "keys": ["alt+q"], "command": "flatten_json", "args": {"pretty": null} },
0 Likes