DEV Community

Masui Masanori
Masui Masanori

Posted on

2

[Go] Get values by excelize

Intro

In this time, I will try getting cell values from an Excel file.

Get page sizes

Because it seems there is probably no way to get the page size directly, I will try other ways.

Image description

Get a print area

If the file is set a print area, I can get it by "GetDefinedName".

xlsWriter.go



...
    for _, name := range xlFile.GetDefinedName() {
        log.Printf("Name: %s Refer: %s Scope: %s", name.Name, name.RefersTo, name.Scope)
        if name.Name != "_xlnm.Print_Area" {
            continue
        }
        splittedRefs := strings.Split(name.RefersTo, "!")
        // The name set for the shape does not have a sheet name
        if len(splittedRefs) > 1 {
            // $B$1:$J$53
            splittedAddresses := strings.Split(splittedRefs[1], ":")
            if len(splittedAddresses) > 1 {
                log.Printf("From: %s To: %s", splittedAddresses[0], splittedAddresses[1])
            }
        }
    }
...


Enter fullscreen mode Exit fullscreen mode

Results



...
Name: _xlnm.Print_Area Refer: 個人用月次収支!$B$1:$J$53 Scope: 個人用月 次収支
From: $B$1 To: $J$53
...


Enter fullscreen mode Exit fullscreen mode

Get last columns and rows

xlsWriter.go



...
    rows, _ := xlFile.GetRows(xlFile.GetSheetName(1))
    log.Printf("Row: %d", len(rows))

    columns, _ := xlFile.GetCols(xlFile.GetSheetName(1))
    log.Printf("Column: %d", len(columns))
...


Enter fullscreen mode Exit fullscreen mode

Results



Row: 77
Column: 10


Enter fullscreen mode Exit fullscreen mode

Get NumFmt

I can get cell values like below.

sample.xlsm

Image description

xlsWriter.go



...
    targetSheet := xlFile.GetSheetName(1)
    for i := 4; i <= 7; i++ {
        add := fmt.Sprintf("D%d", i)
        value, _ := xlFile.GetCellValue(targetSheet, add)
        log.Printf("Cell Add: %s Value: %s", add, value)
    }
...


Enter fullscreen mode Exit fullscreen mode

But those results are different from the display on the Excel file.



Cell Add: D4 Value: 0.55
Cell Add: D5 Value: 0
Cell Add: D6 Value: 0.1
Cell Add: D7 Value: 10


Enter fullscreen mode Exit fullscreen mode

To match them, I should get their number format.
In excelize, I only can get their Style IDs from cells.

xlsWriter.go



...
package main

import (
    "bytes"
    "fmt"
    "log"
    "net/http"
    "regexp"
    "strconv"
    "strings"

    "github.com/xuri/excelize/v2"
)

func SaveFileFromPath(filePath string, saveFilePath string) error {
    xlFile, err := excelize.OpenFile(filePath)
    if err != nil {
        fmt.Println(err)
        return err
    }
    defer func() {
        // Close the spreadsheet.
        if err := xlFile.Close(); err != nil {
            fmt.Println(err)
        }
    }()
    rex := regexp.MustCompile("[0-9]+.[0-9]+")
    targetSheet := xlFile.GetSheetName(1)
    for i := 4; i <= 7; i++ {
        add := fmt.Sprintf("D%d", i)
        value, _ := xlFile.GetCellValue(targetSheet, add)
        // Get format code like "0.00" if the target cell is set a number format
        numberFormatCode := getNumberFormatCode(xlFile, targetSheet, add)
        log.Println(numberFormatCode)

        if len(numberFormatCode) > 0 {
            // Get format text for Sprintf
            fmtText := getFormat(numberFormatCode, rex)
            floatValue, _ := strconv.ParseFloat(value, 64)
            log.Printf("Cell Add: %s Value: %s fmt: %s formatted: %s", add, value, fmtText, fmt.Sprintf(fmtText, floatValue))

        } else {
            log.Printf("Cell Add: %s Value: %s", add, value)
        }
    }
...
    return err
}
...
// Get number format code
func getNumberFormatCode(xlFile *excelize.File, sheetName string, address string) string {
    styleID, _ := xlFile.GetCellStyle(sheetName, address)
    // Get Number Format ID by Style ID
    numFmtID := xlFile.Styles.CellXfs.Xf[styleID].NumFmtID
    for _, numFmt := range xlFile.Styles.NumFmts.NumFmt {
        if numFmt.NumFmtID == *numFmtID {
            return numFmt.FormatCode
        }
    }
    return ""
}
// Get number format for fmt.Sprintf
func getFormat(numFmtCode string, rex *regexp.Regexp) string {
    fmtNumbers := rex.FindString(numFmtCode)
    splitted := strings.Split(fmtNumbers, ".")
    if len(splitted) <= 1 {
        return fmtNumbers
    }
    result := "%.[ZERO_LENGTH]f"
    return strings.Replace(result, "[ZERO_LENGTH]", strconv.Itoa(len(splitted[1])), -1)
}


Enter fullscreen mode Exit fullscreen mode

Result



Cell Add: D4 Value: 0.55
0.00_);[Red]\(0.00\)
Cell Add: D5 Value: 0 fmt: %.2f formatted: 0.00
0.0000
Cell Add: D6 Value: 0.1 fmt: %.4f formatted: 0.1000
0.0
Cell Add: D7 Value: 0.05 fmt: %.1f formatted: 0.1


Enter fullscreen mode Exit fullscreen mode

Heroku

This site is built on Heroku

Join the ranks of developers at Salesforce, Airbase, DEV, and more who deploy their mission critical applications on Heroku. Sign up today and launch your first app!

Get Started

Top comments (0)

Image of Docusign

🛠️ Bring your solution into Docusign. Reach over 1.6M customers.

Docusign is now extensible. Overcome challenges with disconnected products and inaccessible data by bringing your solutions into Docusign and publishing to 1.6M customers in the App Center.

Learn more