Getting values when parsing JSON - how to skip unavailable values?

Hi all,

I am asking a single.html page to index a JSON data file, and grab values from it.
The catch is, I can’t (ultimately) know the structure of the JSON so the templating needs to be flexible.
I want to say, get the value for the key “head”, but if it’s not there, don’t worry about it, keep going.

So if the simple.json looks like this:

{
  "ead": {
    "arrayOfTwoObjects": [
      {
        "head": "String"
      },
      {
        "head": "String"
      }
    ]
  }
}

And the template says

   {{ $data := index .Site.Data "simple" }}
          {{ if $data }}
          {{ range $key, $value := $data.ead }}
          <h2>{{ $key }}</h2>
          {{ $wantedstring :=  ( .head | default "Nope, no header here" )}}
          Header is:  {{ $wantedstring}}
          {{ end }}
          {{ end }}

I’d like it to print nothing for $wantedstring. Or a default string. Just not fail the build.

I’ve also tried {{ if }}, {{ with }}, {{ isset }}, {{ echoParam }}.

I always get the error

can't evaluate field head in type interface {}

Really baffled, any help so much appreciated.

Generally, it helps to print out the values inside the various code blocks.

$data.ead here is a map and you are iterating over each key-value pair.

In the case of your sample data:

$key: arrayOfTwoObjects
$value: [map[head:String] map[head:String]]

Note that the dot context inside this range is the same here as $value.

You are trying to access .head, but the dot context is an array. So this doesn’t work.

So range again through the array:

{{ range $value }}
  {{$wantedstring :=  ( .head | default "Nope, no header here" )}}
   Header is:   {{$wantedstring}}
{{ end }}

Hi, thank you so much for your reply. That’s a good way to access the value.

In this situation though, there are many JSON files, all with different structures, and I can’t know the structure ahead of time. So this example is supposed to be broken. Sorry, it wasn’t the best illustration.

I want to figure out how NOT to get a value if it’s not there, without failing the build.

The only thing I’ve figured out is to explicitly check if it’s an array, using

reflect.IsSlice

But ideally one wouldn’t have to predict the point of failure each time, just be returned nothing.

What is your checking logic then? As in, walk through how it would go about walking the json tree to check and what values are expected where.

While cumbersome, this does allow the build to happen.

{{ $data := index .Site.Data "simple" }}
    {{ if $data }}
      {{ range $key, $value := $data.ead }}
        {{ if not (reflect.IsSlice $value)  }}
        {{ $wantedstring :=  ( .head |  default "Nope, no header here"  )}}
        <h2>Header is:  {{ $wantedstring}}</h2>
             {{/* Continue traversing the object  */}}
        {{ else }}
        {{/* Handle the array here, if necessary  */}}
        {{ end }}
      {{ end }}
    {{ end }}