Search code examples
bashshellpathjqrecursive-datastructures

jq: recursion -> nested arrays


How can I parse this json structure with jq? It should loop over leafs (projects and groups) recursively.

My use case is: create project and groups in VCS with CLI. Group can have multiple projects, group can be empty, projects must have parent group created in advance.

Similar analogy would be:

  • group = folder
  • project = file
  • path = absolute path in format /root-groups/nested-groups-level-1/nested-groups-level-2/nested-groups-level-N

Thanks

{
   "structure":[
      {
         "name":"rootgroup1",
         "type":"group",
         "nested":[
            {
               "name":"nestedproject1",
               "type":"project"
            },
            {
               "name":"nestedgroup1",
               "type":"group",
               "nested":[
                  {
                     "name":"nestednestedproject2",
                     "type":"project"
                  }
               ]
            }
         ]
      },
      {
         "name":"rootproject1",
         "type":"project"
      },
      {
         "name":"rootgroup2",
         "type":"group",
         "nested": []
      }
   ]
}

Expected output:

"rootgroup1","group",""
"nestedproject1","project","rootgroup1"
"nestedgroup1","group","rootgroup1"
"nestednestedproject2","group","rootgroup1/nestedgroup1"
"rootproject1","project",""
"rootgroup2","group",""

Try:

jq -r '.structure[] | .. | "\(.name?) \(.type?)"'

Still not sure, how create a parent path.


Solution

  • The following implements a solution to the problem as I understand it:

    # $prefix is an array interpreted as the prefix
    def details($prefix):
      def out:
        select(has("name") and has("type")) | [.name, .type, "/" + ($prefix|join("/"))];
    
      out,
        if (.nested | (. and length>0))
        then .name as $n | .nested[] | details($prefix + [$n]) 
        else empty
        end;
      
    .structure[]
    | details([])
    | @csv
    

    Given your sample input, the output would be:

    "rootgroup1","group","/"
    "nestedproject1","project","/rootgroup1"
    "nestedgroup1","group","/rootgroup1"
    "nestednestedproject2","project","/rootgroup1/nestedgroup1"
    "rootproject1","project","/"
    "rootgroup2","group","/"
    

    This differs in some respects from the sample output, but hopefully you can take it from here.