carlcaroline
carlcaroline

Reputation: 65

pull data from csv file and put it into template given in golang

anyone knows how to pull data from CSV file that uploaded as multipart.file based on its column and then input the data to another CSV file (the template)?

I still can't get the right logic to do that in golang. this is the csv file look alike:

"Coorporate",,,
Address :,,,
Boulevard Street,,,
Service / Office : 021-62318113 / 021-22684901,,,
"VGA WITH GUARANTEE",Dealer,Msrp,MARGIN
VGA-1,"37,000","38,000","1,000"
VGA-2,"27,500","28,500","1,000"
CASE ,Dealer ,Msrp ,MARGIN
CASE-1 ,"430,000","480,000","50,000"
CASE-2 ,"450,000","500,000","50,000"
"MAXSUN VGA ",Dealer ,Msrp ,MARGIN
MVGA-1,"13,300,000","13,800,000","500,000"

these are the codes I've tried to read to detect the table header (the row that at least having "Msrp" column):

reader := csv.NewReader(f)
records, err := reader.ReadAll()

var rows []string
columns := []string{"Msrp", "MSRP", "msrp"}

for _, column := range columns {
    for _, columnName := range records {
        for _, cols := range columnName {
            if cols == column {
                row := strings.Join(columnName, " ")
                rows = append(rows, row)
                break
            }
        }
    }

but it just return the table header only. I need to get the value for each column and save it into a new slice (maybe?) so that later I can update the CSV template file with the value that I just pull from the CSV file uploaded

and let's say i have a struct :

type columnName struct { 
     PartName string json:"part_name" 
     Price int json:"price" 
     Msrp int json:"msrp"
}

how do i match the column name to that struct?

is there any better way to solve this problem?

anyway I'm new to golang and programming pls help me

many thanks!

Upvotes: 0

Views: 485

Answers (2)

Zach Young
Zach Young

Reputation: 11223

I cleaned up the input CSV you shared:

Coorporate,,,
Address :,,,
Boulevard Street,,,
Service / Office : 021-62318113 / 021-22684901,,,
VGA WITH GUARANTEE,Dealer,Msrp,MARGIN
VGA-1,"37,000","38,000","1,000"
VGA-2,"27,500","28,500","1,000"
CASE,Dealer,Msrp,MARGIN
CASE-1,"430,000","480,000","50,000"
CASE-2,"450,000","500,000","50,000"
MAXSUN VGA,Dealer,Msrp,MARGIN
MVGA-1,"13,300,000","13,800,000","500,000"

Looking at it in an aligned table view:

| Coorporate                                     |            |            |         |
| Address :                                      |            |            |         |
| Boulevard Street                               |            |            |         |
| Service / Office : 021-62318113 / 021-22684901 |            |            |         |
| VGA WITH GUARANTEE                             | Dealer     | Msrp       | MARGIN  |
| VGA-1                                          | 37,000     | 38,000     | 1,000   |
| VGA-2                                          | 27,500     | 28,500     | 1,000   |
| CASE                                           | Dealer     | Msrp       | MARGIN  |
| CASE-1                                         | 430,000    | 480,000    | 50,000  |
| CASE-2                                         | 450,000    | 500,000    | 50,000  |
| MAXSUN VGA                                     | Dealer     | Msrp       | MARGIN  |
| MVGA-1                                         | 13,300,000 | 13,800,000 | 500,000 |

It looks like you have a couple of rows at the top that won't end up in the final data, so I iterate over them and ignore them:

f, _ := os.Open("input.csv")
r := csv.NewReader(f)

// iterate and discard Coorporate ... Service / Office...
for i := 0; i < 4; i++ {
    _, err := r.Read()
    if doneReading(err) {
        break
    }
}

I made my struct like:

type Record struct {
    PartName string `json:"part_name"`
    Price    int    `json:"price"`
    Msrp     int    `json:"msrp"`
}

Now, I can iterate the rest of the rows and be on guard for intermediate looking headers, if I see one I just drop it by continuing to the next row, which should be real data. For the real data rows the format looks straightforward—string, string, int, int—so I can parse the 2nd and 3rd column directly as ints (checking for errors), append the results to my slice of Records, then turn it all into JSON:

Records := make([]Record, 0)
for i := 5; ; i++ {
    record, err := r.Read()
    if doneReading(err) {
        break
    }

    col3 := strings.TrimSpace(record[2])

    // discard records that look like an intermediate header
    // with "MSRP" in the 3rd colum
    if strings.ToLower(col3) == "msrp" {
        continue
    }

    col1 := strings.TrimSpace(record[0])
    col2 := strings.TrimSpace(record[1])

    price, err1 := strconv.Atoi(strings.ReplaceAll(col2, ",", ""))
    msrp, err2 := strconv.Atoi(strings.ReplaceAll(col3, ",", ""))
    if err1 != nil || err2 != nil {
        log.Printf("could not parse ints in Col2 and/or Col3 of row %d: %v\n", i, record)
    }

    Records = append(Records, Record{col1, price, msrp})
}

b, err := json.MarshalIndent(Records, "", "  ")
must(err)

fmt.Println(string(b))

and I see:

[
  {
    "part_name": "VGA-1",
    "price": 37000,
    "msrp": 38000
  },
  {
    "part_name": "VGA-2",
    "price": 27500,
    "msrp": 28500
  },
  {
    "part_name": "CASE-1",
    "price": 430000,
    "msrp": 480000
  },
  {
    "part_name": "CASE-2",
    "price": 450000,
    "msrp": 500000
  },
  {
    "part_name": "MVGA-1",
    "price": 13300000,
    "msrp": 13800000
  }
]

Bad data in one of the number columns gets logged like:

2009/11/10 23:00:00 could not parse ints in Col2 and/or Col3 of row 6: [VGA-1 37,000 38,000--AAA 1,000]

Here's a complete example, Go Playground.

Upvotes: 0

poone
poone

Reputation: 44

Looks like there might be some confusion regarding the return of reader := csv.NewReader(f) . The reader represents the entire table. If you loop through the reader ,you can print each line one by one.

like this, write a test and print out the data,you will have a clear understanding.


reader := csv.NewReader(file)

//the first line data is the titles  
titles, _ = reader.Read() 


// perform a data comparison with columns := []string{"Msrp", "MSRP", "msrp"}
// allocate a container below to store it 
//loop the row

for  {

    records, _ = reader.Read() // the records
    // the records is a var record []string 
    // you should loop that value 
    //there record[1], record[2], record[3] is your col
}

hope this can help you

Upvotes: 0

Related Questions