CSV Display (help)

Howdy there!

I’m trying to display some CSV data. The csv data looks like this:

Pretty simple, right?

My problem is, I’m having a bad case of the Mondays on a Wednesday after spending an entire day over the ER.

I am trying to display my entire book collection (I saved one per row) and print, say, just the Genre, or just the Title, or just the image link.

So I can make a range or show a single book

<h1>{{ index $c 1 }}</h1>
<img src="{{ index $c 2 }}">

Say that with the above I print the title and the img address. I know that’s gibberish code, that’s just from the top of my head.

This is what my melted brain has so far:

{{ $url := "csv/bookslist.csv" }}
{{ $sep := "," }}

{{ $csv := getCSV $sep $url }}

{{ $r := 16 }}
{{ $c := 1 }}
{{ index ( index $csv $r ) $c }}

That’s it. But that’s for just one book, I can’t think of a way of doing a range with it (that’s what I need).

Someone put me out of my misery or push me out a window, please.

There is an example with a range at https://gohugo.io/templates/data-templates/#example-for-csv-files. I haven’t used it.

Yeah my problem with that one is that it prints the entire row, and I can’t make much with it.

I can’t use it to build the book list, with the cover images, etc because it prints the entire row.

(I am trying to do a <img src="#"> for each book on the list, that is, one per row)

I can’t say: “range first 10” so it prints the first 10 rows, and from those I get the $img for each book, or “range first 10 where” and then print some of the series.

I got the impression getCSV was for loading spreadsheets into a table element, more or less as it is in the file.

For your purpose I’d recommend converting your spreadsheet into JSON and using getJSON, which of course does exactly what you want.

Looking forward to others’ insights as well. :slight_smile:

Yes, I was thinking the same, but sometime I managed to do it: I just lost the code (wasn’t versioning back when I first started with Hugo).

Now it kills me but I know it can be done.

Shouldn’t be this hard, to display a range and have some of the info formatted into HTML

If you share a dummy CSV file similar enough to your real one, I’ll play around with this

Sure thing, here’s a dummy CSV on the one and only Microsoft One Drive


All I want to do is show a list of books and be able to: show them all, show just one or show some that match some variable (like Special for instance).

For that I wanted to show the IMG of the books, the titles, etc. Not all of the data, because some of it might be internal, but be able to pick, you know.

Its getting on my nerves not being able to do it.

So your CSV is not a typical data organization. What I mean is, you’d typically do something like this

book1,fantasy,john doe
book2,fiction,sally smith

Whereas your data organization is kinda reverse of that. But, going with how you have things now, you could do something like this

{{ $url := "csv/bookslist.csv" }}
{{ $sep := "," }}

{{ $csv := getCSV $sep $url }}

{{ range $csv }}
  {{ if in (index . 0) "Title" }}
    <h1>{{ (index . 2) }}</h1>
  {{ end }}

  {{ if in (index . 0 ) "Cover Amazon" }}
    <img src="{{ index . 2 }}">
  {{ end }}
{{ end }}
1 Like

Ohhh I see what you did there.

Part of it seems beyond my comprehension, though. Like for instance, you’re doing a range there, but only to display one book. How can I display all books?

I mean, I could just repeat the same block of code over and over again like, 40 times, but my code has enough spaghetti already :wink:

Because if I do this:

  {{ if in (index . 0) "Title" }}
    <h1>{{ . }}</h1>
  {{ end }}

I get this

[Title Mythos: A Silicon Valley Thriller Lord of the Rings]

That’s both titles one next to another in the same string.

I tried to split it with "/r" or "," but couldn’t figure out how.

If you format organize your csv properly like @zwbetz mentioned you won’t have this problem.

You are trying to loop columns instead of rows which is how the range works with csvs.

It’s probably not what you want to hear but that will most definitely solve your problems, good luck.

1 Like

My CSV is formatted “properly”.

That Hugo loops rows instead of rows AND columns is only a temporary Hugo limitation, that’s all.

I am probably misunderstanding something, but as far as I am aware, the csv spec doesn’t mention that style of layout where columns are the data, with an optional header column on the left. Csv files are all row-based in my experience: https://tools.ietf.org/html/rfc4180

That is not to say that in Excel, that is not a valid or useful way to format.

You could transform / rotate the data using python, maybe adapting this:

All right, say I format my csv like so:

Instead of my perfectly cool way of formatting it.

Still, I can’t display all book covers with their links, etc.

{{ range $i, $r := getCSV "," "csv/bookslist.csv" }}
   {{ if eq (index $r 3) "Cover Amazon" }}
   <p> {{ . }}</p>

I get something like

 [Title Genre Internal Link Cover Amazon Series Amazon Kobo Apple Barnes Blurb] 

What I’m trying to say to Hugo there is if the index is Cover Amazon then print everything in there, but it prints the titles!

It’s printing titles because you’re telling it to. If you only want to print image links, then do

{{ range $index, $row := $csv }}
  {{ if ne $index 0 }}
    <img src="{{ index $row 3}}">
  {{ end }}
{{ end }}

That “if” statement is there to ignore the first row, since it is the data headers

getCSV gives you an array of rows, each row being an array of cells. So when you do

{{ range $i, $r := $csv }}

each $r is a row. index $r 3 is column D in the row $i.

So. Building on @zwbetz and assuming proper formatting as per @RickCogley,

assuming partials/getcol.html , looking up Title, Published, Length:

{{ $csv := getCSV $sep $url }}
{{ partial "getcol.html" (dict "csv" $csv "lookups" (slice "Title" "Published" "Length")) }}
<!-- partials/getcol.html -->
{{ $csv := .csv }}
{{ $headers := index $csv 0 }} <!-- Assumes row 0 contains headers --> 
{{ $lookups := .lookups }} <!-- Column headers of interest -->
{{ $colsi := slice }} <!-- Container for actual headers found. Array of {i: 0, label: "label"} -->

{{ range $i, $e := $headers }}
  {{ if in $lookups $e }} <!-- Look for $lookups in $headers --> 
  <!-- If found append to $colsi -->
  {{ $colsi = $colsi | append (dict "i" $i "label" $e) }}
  {{ end }}
{{ end }}

{{ range $i, $row := after 1 $csv }} <!-- Range through $csv, row by row, skipping headers row --> 
  <!-- $row = i-th data row -->
  Entry #{{ add 1 $i }}: <br> <!-- Display counter -->
  {{ range $j, $f := $colsi }} <!-- Range through $colsi -->
    <!-- $colsi[$j] = $f = {i: 0, label: "label"} -->
    <!-- $colsi[$j]["label"] : $row[$colsi[$j][$i]] -->
    {{index $f "label"}}: {{ index $row (index $f "i") }}<br>
  {{ end }}
{{ end }}

Entry #1:
Title: Mythos: A Silicon Valley Thriller
Published: Friday, March 8, 2019
Length: Short Story

Entry #2:
Title: Lord of the Rings
Published: Thursday, September 6, 2012
Length: Novel


Mine was spagetti-bad:

{{ range $csv }}
    {{ if or (eq (index . 3) "Cover Amazon") (eq (index . 3) "0") }}                                                                                                                            
    {{ else }}
    <p class="book"><a href="{{ (index . 2) }}"><img src="{{ (index . 3) }}"></a></p>
    {{ end }}
{{ end }}
1 Like

That is impressive Pointyfar, gonna steal bits of that one!

1 Like