Ranging over nested array from JSON data

Hello there,

I’m struggling a bit with some nested range and I can’t find where I’m doing a mistake.
Any idea what’s wrong with my code?

I am using JSON data (Store in the Data folder of my site) to generate a list of HTML tables.

The JSON looks like that:

[{
    "GroupName": "Alloys",
    "ModifierGroups": [{
        "Cost": [{
            "Add": "mod_alloys_cost_add.dds",
            "Mult": "mod_alloys_cost_mult.dds"
        }],
        "Produces": [{
            "Add": "mod_alloys_produces_add.dds",
            "Mult": "mod_alloys_produces_mult.dds"
        }],
        "Upkeep": [{
            "Add": "mod_alloys_upkeep_add.dds",
            "Mult": "mod_alloys_upkeep_mult.dds"
        }]
        }]
},
{
    "GroupName": "Astral Threads",
    "ModifierGroups": [{
        "Cost": [{
            "Add": "mod_astral_threads_cost_add.dds",
            "Mult": "mod_astral_threads_cost_mult.dds"
        }],
        "Produces": [{
            "Add": "mod_astral_threads_produces_add.dds",
            "Mult": "mod_astral_threads_produces_mult.dds"
        }],
        "Upkeep": [{
            "Add": "mod_astral_threads_upkeep_add.dds",
            "Mult": "mod_astral_threads_upkeep_mult.dds"
        }]
        }]
}]

For each objects in the first array, a new table should be created with the following characteristics:

  • :white_check_mark: The GroupName key should be displayed as the table header
  • For each object in the ModifierGroups array, a new line should be added to the table with this characteristics:
    • :white_check_mark: In a first column, the key should be displayed
    • :x: In a second column, each key/pair value of the nested array should be used to display a picture with the src property being the value and the alt property being the key.

Even if the example JSON doesn’t show that, each key can be different in the tables so they need to be retrieved dynamically. For example, the Cost , Produces and Upkeep keys can have other name and be in different number (Which is not an issue as this part of my code works).
The same thing is true for the keys on the nested array. Add and Mult could have other names and be in different number.

If my explanation is not clear, here’s how the end result should look:

<table>
    <tbody><tr>
        <th colspan="2">Alloys</th>
    </tr>
        <tr>
          <td>Cost</td>  
          <td><img src="mod_alloys_cost_add.dds" alt="Add">
          <img src="mod_alloys_cost_mult.dds" alt="Mult"></td>
        </tr>
        <tr>
          <td>Produces</td>
            <td><img src="mod_alloys_produces_add.dds" alt="Add">
          <img src="mod_alloys_produces_mult.dds" alt="Mult"></td>
        </tr>
        <tr>
          <td>Upkeep</td>
            <td><img src="mod_alloys_upkeep_add.dds" alt="Add">
          <img src="mod_alloys_upkeep_mult.dds" alt="Mult"></td>
        </tr>
  </tbody></table>
  <table>
    <tbody><tr>
        <th colspan="2">Astral Threads</th>
    </tr>
        <tr>
          <td>Cost</td>  
          <td><img src="mod_astral_threads_cost_add.dds" alt="Add">
          <img src="mod_astral_threads_cost_mult.dds" alt="Mult"></td>
        </tr>
        <tr>
          <td>Produces</td>
            <td><img src="mod_astral_threads_produces_add.dds" alt="Add">
          <img src="mod_astral_threads_produces_mult.dds" alt="Mult"></td>
        </tr>
        <tr>
          <td>Upkeep</td>
            <td><img src="mod_astral_threads_upkeep_add.dds" alt="Add">
          <img src="mod_astral_threads_upkeep_mult.dds" alt="Mult"></td>
        </tr>
  </tbody></table>

So far, I have this code:

{{ $modifiers := site.Data.modifiers_metadata }}

{{ range $modifiers }}
  <h2>{{ .GroupName }}</h2>
  <table>
    <tbody>
        <tr>
          <th colspan="2">{{ .GroupName }}</th>
        </tr>
      {{ range .ModifierGroups }}        
        {{ range $key, $value := . }}
          <tr>
            <td>{{ $key }}</td>
            <td>
              {{ range $k, $v := $value }}
                <img src="{{ $v }}" alt="{{ $k }}">
              {{ end }}
            </td>
          </tr>
        {{ end }}
      {{ end }}
    </tbody>
  </table>
{{ end }}

Your ModifierGroups don’t contain a GroupName. If you want to output the GroupName again, save it in a variable before ranging over ModifierGroups.

I didn’t check the rest of your code but I suspect that dot is not always what you think it is.

Looks like I made a mistake when pasting my code. I had already moved the GroupName outside of the ModifierGroups range. I have edited the above code. :slight_smile:

I didn’t check the rest of your code but I suspect that dot is not always what you think it is.

If I understand correctly, while you are looping in a range, the dot refers to the current object you are looping on (Where my cursor is in the current range). Nope?

Your data structure is nested three deep (outer, inner-a, inner-b), so you need an additional range block.

{{ $modifiers := site.Data.modifiers_metadata }}

{{ range $modifiers }}
  <h2>{{ .GroupName }}</h2>
  <table>
    <tbody>
        <tr>
          <th colspan="2">{{ .GroupName }}</th>
        </tr>
      {{ range .ModifierGroups }}
        {{ range $key, $_ := . }}
          <tr>
            <td>{{ $key }}</td>
            {{ range . }}
              {{ range $k, $v := . }}
                <td>
                  <img src="{{ $v }}" alt="{{ $k }}">
                </td>
              {{ end }}
            {{ end }}
          </tr>
        {{ end }}
      {{ end }}
    </tbody>
  </table>
{{ end }}

I was re-reading documentation about range and nested slices/maps and I was going to try to reuse the “.” instead of $value to range over the last depth but you made it even easier by providing a working solution. Thanks a lot.

Can I ask what the $_ refers in this line? Is that a special variable or simply the name you decided to give it?

{{ range $key, $_ := . }}

$_ is a valid variable name, by convention indicating that I don’t need that assignment.

Thanks for the explanation. :slight_smile:

This topic was automatically closed 2 days after the last reply. New replies are no longer allowed.