Search code examples
jsonpathjqhierarchical-data

Nest and merge JSON based on namespaces


I've got the following JSON document:
(sorted by namespace; any namespace can appear multiple times)

[ {"namespace": "/"       , "exports": {"a": 10, "b": 11}}
, {"namespace": "/"       , "exports": {"c": 12, "d": 13}}
, {"namespace": "/bar"    , "exports": {"e": 14, "f": 15}}
, {"namespace": "/bar/baz", "exports": {"g": 16, "h": 17}}
]

that I need to convert into this JSON document:
(the risk of key collisions can be ignored)

{ "a": 10
, "b": 11
, "c": 12
, "d": 13
, "bar": { "e": 14
         , "f": 15
         , "baz": { "g": 16
                  , "h": 17}}}

Note that whilst nesting namespaces we only keep their basename e.g.,

/
/bar
/bar/baz
/bar/baz/bat

becomes:

{"bar": {"baz": {"bat": {}}}}

Members must be nested under their corresponding namespace object with the only expection of members of the root "/" namespace which become top-level properties.

I've scratched my head a few times over this problem as I'd like to get this done in one pass (ideally) but I'm open to any other suggestions.


Solution

  • Convert namespaces to paths and you can build the desired output using getpath/setpath built-ins.

    reduce .[] as {$namespace, $exports} ({};
      ($namespace | ltrimstr("/") | split("/")) as $path
      | setpath($path; getpath($path) + $exports)
    )
    

    Online demo