1

I'm trying to write a CSV file, I can have 1 to n columns. Currently my data are correctly written except that they are all written on the same column.

I would like to have something like this :

NAME|DESCRIPTION|PRODUCER
name1|desc1|false
name2|desc2|true
name3|desc3|false

Here is my code, a small piece of a switch:

    case "companies":
                var respToolCompanies entrepriseTool.CompaniesResponse
                if jsonErr := json.Unmarshal(resByt, &respToolCompanies); jsonErr != nil {
                    log.Fatalf("unmarshal: %s", jsonErr)
                }
                for _, mapping := range mappings {
                    writeHeader(csvwriter, mapping)

                    for _, company := range respToolCompanies.Companies {
                        writeDataAccordinglyToFieldType(mapping, company, csvwriter)
                    }
                    csvwriter.Flush()
                }

The writeDataAccordinglyToFieldType function:

func writeDataAccordinglyToFieldType(mapping ExportmappingsModel, entities interface{}, csvwriter *csv.Writer) {
    switch mapping.SourceColType.String {
    case "string":
        field := extractFieldValue(entities, mapping)
        writeFieldToBuffer(csvwriter, field.String())
    case "number":
        field := extractFieldValue(entities, mapping)
        valInt := field.Int()
        str := strconv.Itoa(int(valInt))
        writeFieldToBuffer(csvwriter, str)
    case "bool":
        field := extractFieldValue(entities, mapping)
        var boolVal string
        if field.Bool() {
            boolVal = "true"
        } else {
            boolVal = "false"
        }
        writeFieldToBuffer(csvwriter, boolVal)
    }
}

And where I write data:

func writeFieldToBuffer(csvwriter *csv.Writer, field string) {
    err := csvwriter.Write([]string{field})
    if err != nil {
        log.Println("Unable to write a line inside the file")
    }
}
1
  • Did Neha's answer help? If not, will you include a sample of the JSON? Also, when you say you have "n columns", what does that mean? Do you know ahead of time how many columns you need to write to CSV? The mappings var makes me think you already know which columns to expect, and what type they will be. Commented Oct 19, 2022 at 17:11

2 Answers 2

1

csv.Write will write in different column only when your string slice will have multiple elements .Currently you are writing each field one by one and using a slice that is only having one record at one time

I am not saying that you have to pass the delimiter .Rather populate the string slice all at once so that csv.Write automatically iterates over the slice and write each new element in new column. . So change your logic to change

       err := csvwriter.Write([]string{field})

to something like this :

  record := []string {"name1" ,"desc1","false"}
   if err := csvwriter.Write(record); err != nil {
          log.Fatalln("error writing record to file", err)
         }

or you can populate the whole thing using the two dimensional slice and then writeall at the end

   records := [][]string {{"name1" ,"desc1","false"},{"name2" 
   ,"desc2","false"}}
     if err := csvwriter.WriteAll(records); err != nil {
            log.Fatalln("error writing record to file", err)
           }
Sign up to request clarification or add additional context in comments.

Comments

0

First things first: Go's csv Writer writes a record, and a record is a slice of strings. Looking at the example from the csv pkg documentation:

records := [][]string{
    {"first_name", "last_name", "username"},
    {"Rob", "Pike", "rob"},
    {"Ken", "Thompson", "ken"},
    {"Robert", "Griesemer", "gri"},
}

w := csv.NewWriter(os.Stdout)

for _, record := range records {
    if err := w.Write(record); err != nil {
        log.Fatalln("error writing record to csv:", err)
    }
}

we can see that we write to a CSV file row-by-row, not column-by-column. So any solution you come up with must include a complete row when you call writer.Write(...).

That said, going between a struct and the csv Writer can be difficult. Have you looked at Gocarina's gocsv package? It would reduce (what I imagine to be) your problem down to something like the following:

import (
    "encoding/json"
    "os"

    "github.com/gocarina/gocsv"
)

type company struct {
    Name        string `json:"name"        csv:"Name"`
    Description string `json:"description" csv:"Description"`
    Producer    bool   `json:"producer"    csv:"Producer"`
    Employees   int    `json:"employees"   csv:"Employees"`
}

var blob = `[
    { "name": "Foo To You", "description": "Selling Foo since before the dinosaurs", "producer": false, "employees":  7 },
    { "name": "Bar Mfg.",   "description": "Best makers of Bar, bar none",           "producer": true,  "employees": 12 }
]`

func main() {
    var companies []company
    json.Unmarshal([]byte(blob), &companies)
    gocsv.Marshal(companies, os.Stdout)
}

to produce this CSV (marked-up as a table):

| Name       | Description                            | Producer | Employees |
|------------|----------------------------------------|----------|-----------|
| Foo To You | Selling Foo since before the dinosaurs | false    | 7         |
| Bar Mfg.   | Best makers of Bar, bar none           | true     | 12        |

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.