go-excel

repository·master·Indexed 41 days ago

https://github.com/szyhf/go-excel

A lightweight Go library for reading XLSX files and mapping rows directly into structs, maps, or slices. It treats Excel files like relational databases or configuration files, supporting custom mapping via `xlsx` struct tags, JSON encoding, and programmatic configuration through the `ExcelFiledConfiger` interface.

Tokens
6.4K
Snippets
29
Records
30
Agent score
51%

What's inside go-excel

  1. Implement custom unmarshaling for complex types

    master

    To handle complex data types (like JSON strings in a cell), implement the encoding.BinaryUnmarshaler interface on your custom type. The library will automatically use UnmarshalBinary to populate the field.

    type Temp struct {
    	Foo string
    }
    
    // UnmarshalBinary allows custom logic for cell values
    func (t *Temp) UnmarshalBinary(d []byte) error {
    	return json.Unmarshal(d, t)
    }
  2. Use the Connector and Reader API for advanced control

    master

    For more granular control (e.g., iterating through rows or selecting specific sheets), use excel.NewConnecter().

    1. Create a connector with excel.NewConnecter().
    2. Open a file with .Open(path) or binary data with .OpenBinary(data).
    3. Create a reader with .NewReader(sheetName).
    4. Iterate using .Next() and read rows into structs with .Read(&target) or use .ReadAll(&target) to load everything at once.
    conn := excel.NewConnecter()
    err := conn.Open("./testdata/simple.xlsx")
    if err != nil {
    	panic(err)
    }
    defer conn.Close()
    
    // sheetName can be: 
    // - a string (exact sheet name)
    // - an int (1-based index, e.g., 1 for the first sheet)
    // - an object implementing GetXLSXSheetName() string
    rd, err := conn.NewReader("Standard")
    if err != nil {
    	panic(err)
    }
    defer rd.Close()
    
    for rd.Next() {
    	var s Standard
    	err := rd.Read(&s)
    	if err != nil {
    		panic(err)
    	}
    	fmt.Printf("%+v\n", s)
    }
  3. Configure sheet reading with excel.Config

    master

    You can pass an excel.Config object to customize how sheets are identified and how rows are processed.

    Key configuration fields:

    • Sheet: Defines the sheet to use (string name, index, or object with GetXLSXSheetName()).
    • TitleRowIndex: The index of the row used as the title row (default is 0). Rows before this are ignored.
    • Skip: Number of rows to skip after the title row (default is 0).
    • Prefix: Auto-prefix for the sheet name.
    • Suffix: Auto-suffix for the sheet name.
    type Config struct {
    	Sheet         interface{}
    	TitleRowIndex int
    	Skip          int
    	Prefix        string
    	Suffix        string
    }
  4. Configure Excel mapping using the `xlsx` struct tag

    master

    You can map Excel columns to struct fields using the xlsx tag. The tag supports several configuration parameters in the format key(value) or column_name. Parameters are separated by a semicolon (;).

    Supported parameters:

    • column(name): Specifies the name of the Excel column.
    • default(value): Specifies a default value to use if the cell is empty.
    • split(separator): Specifies a character to split the cell value into a slice/array (e.g., split(;)).
    • encoding(type): Specifies the decoding format. Currently supports encoding(json) to unmarshal the cell content as JSON.
    • nil(value): Specifies a specific string value that should be treated as nil (skipping the scan for that field).
    • req: Marks the field as required. If the column is missing, the application will panic.
    • -: Marks the field to be ignored.
    type User struct {
    	ID       string `xlsx:"id"`                          // Maps to column "id"
    	Name     string `xlsx:"name,default(Unknown)"`      // Maps to "name", defaults to "Unknown"
    	Tags     []string `xlsx:"tags,split(;)"`            // Splits column "tags" by ";"
    	Metadata string `xlsx:"meta,encoding(json)"`       // Unmarshals column "meta" as JSON
    	Status   string `xlsx:"status,nil(N/A)"`           // If cell is "N/A", skip scanning
    	Email    string `xlsx:"email,req"`                 // Required column "email"
    	Secret   string `xlsx:"-"`                         // Ignored field
    }
  5. Quick start with UnmarshalXLSX

    master

    For simple use cases, use excel.UnmarshalXLSX to read an entire XLSX file directly into a slice of structs. By default, it assumes the sheet name matches the struct name.

    type Standard struct {
    	ID      int
    	Name    string `xlsx:"column(NameOf)"`
    	Age     int    `xlsx:"AgeOf"` 
    }
    
    func simpleUsage() {
    	var stdList []Standard
    	err := excel.UnmarshalXLSX("./testdata/simple.xlsx", &stdList)
    	if err != nil {
    		panic(err)
    	}
    }
  6. Override field configuration with GetXLSXFieldConfigs

    master

    If struct tags are insufficient or difficult to manage (e.g., due to complex escape characters), you can implement the GetXLSXFieldConfigs() map[string]FieldConfig method on your struct. This method takes precedence over struct tags.

    // Implementation detail: implement this on your struct to override tags
    // func (s *Standard) GetXLSXFieldConfigs() map[string]FieldConfig { ... }
  7. Configure the Excel Connecter with Config

    master

    The Config struct allows you to define how a sheet is identified and how rows are parsed.

    Key fields:

    • Sheet: Defines which sheet to target. It accepts:
      • string: The exact sheet name.
      • int: The 1-based index of the sheet (note: hidden sheets are included in the count).
      • An object implementing GetXLSXSheetName() string.
      • A struct (the name is inferred via reflection).
      • A slice (the element type is used to infer the name).
    • TitleRowIndex: The 0-based index of the row used as the header/title. Rows before this index are ignored. Defaults to 0.
    • Skip: The number of rows to skip immediately after the title row. Empty rows are not counted. Defaults to 0.
    • Prefix / Suffix: Strings to automatically prefix or suffix the sheet name.
    config := &excel.Config{
        Sheet:         "Sheet1",
        TitleRowIndex: 1,
        Skip:          2,
    }
  8. Use XLSX struct tags to map Excel columns

    master

    Use the xlsx tag to control how Excel cells map to your struct fields:

    • column(Name): Maps the field to a specific column name in the title row. If omitted, the field name is used as the default.
    • default(Value): Sets a default value if the cell is empty.
    • split(Separator): Splits a string cell into a slice using the provided separator (e.g., split(|)).
    • nil(Value): Specifies a value that should be treated as nil (not skipped).
    • req: Returns an error if the required column title is missing from the Excel file.
    • encoding(json): Decodes the string value using the specified encoding (currently only json is supported).
    • -: Ignores the field.
    type Standard struct {
    	ID      int      `xlsx:"ID"`                      // Uses field name as default
    	Name    string   `xlsx:"column(NameOf)"`          // Explicit column mapping
    	Age     int      `xlsx:"AgeOf"`                   // Shorthand for column(AgeOf)
    	Slice   []int    `xlsx:"split(|)"`                // Splits "1|2|3" into []int{1, 2, 3}
    	Temp    *Temp    `xlsx:"column(UnmarshalString)"`  // Uses encoding.BinaryUnmarshaler
    	TempEnc *Temp    `xlsx:"column(U);encoding(json)"` // Uses JSON unmarshaling
    	Ignored string `xlsx:"-"`                          // Field is ignored
    }
  9. Read all rows into a container using ReadAll()

    master

    The ReadAll(container interface{}) method reads all remaining rows in the worksheet and populates a slice container.

    Requirements for container:

    • It must be a pointer to a slice (e.g., *[]MyStruct or *[]map[string]string).
    • If the slice contains structs, the fields will be mapped according to the worksheet's title row.

    If the container is not a pointer to a slice, it returns ErrInvalidConatiner.

    var allRows []MyStruct
    err := rd.ReadAll(&allRows)
    if err != nil {
        // handle error
    }
  10. Use the `ExcelFiledConfiger` interface for manual configuration

    master

    If you prefer not to use struct tags, you can implement the ExcelFiledConfiger interface on your struct. This allows you to provide a map of FieldConfig objects, which takes precedence over struct tags.

    Implementing GetXLSXFieldConfigs() map[string]FieldConfig allows you to define mapping logic programmatically.

    type MyStruct struct {
    	Name string
    }
    
    // Implement ExcelFiledConfiger
    func (m *MyStruct) GetXLSXFieldConfigs() map[string]excel.FieldConfig {
    	return map[string]excel.FieldConfig{
    		"Name": {
    			ColumnName: "Full Name",
    			DefaultValue: "Anonymous",
    		},
    	}
    }
  11. Open an Excel file from binary data

    master

    If you have the Excel file content already loaded in memory as a byte slice, use OpenBinary to initialize the reader.

    err := conn.OpenBinary(xlsxData)
    if err != nil {
        // handle error
    }