Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Golang V1.21.0 Failed to write data, excel file open error #1651

Closed
jamiesun opened this issue Sep 6, 2023 · 2 comments
Closed

Golang V1.21.0 Failed to write data, excel file open error #1651

jamiesun opened this issue Sep 6, 2023 · 2 comments
Labels
duplicate This issue or pull request already exists

Comments

@jamiesun
Copy link

jamiesun commented Sep 6, 2023

Description

This function below executes without problems under all versions of Golang v1.20, it can write data and open files without errors.

But under Golang V1.21.0, it does not report any error, but the Excel file written cannot be opened with error:

Code:

func WriteToFile[T any](sheet string, records []T, filepath string) error {
	xlsx := excelize.NewFile()
	index, err := xlsx.NewSheet(sheet)
	if err != nil {
		return err
	}

	err = xlsx.SetColWidth(sheet, "A", "AN", 18)
	if err != nil {
		log.Error(err)
	}

	err = xlsx.SetRowHeight(sheet, 1, 20)
	if err != nil {
		log.Error(err)
	}
	for i, t := range records {
		log.ErrorIf(xlsx.SetRowHeight(sheet, i+2, 20))
		WriteRow(t, i, xlsx, sheet)
	}

	xlsx.SetActiveSheet(index)
	return xlsx.SaveAs(filepath)
}

var COLNAMES = map[int]string{0: "A", 1: "B", 2: "C", 3: "D", 4: "E", 5: "F", 6: "G", 7: "H", 8: "I", 9: "J", 10: "K", 11: "L", 12: "M",
	13: "N", 14: "O", 15: "P", 16: "Q", 17: "R", 18: "S", 19: "T", 20: "U", 21: "V", 22: "W", 23: "X", 24: "Y",
	25: "Z", 26: "AA", 27: "AB", 28: "AC", 29: "AD", 30: "AE", 31: "AF", 32: "AG", 33: "AH", 34: "AI", 35: "AJ",
	36: "AK", 37: "AL", 38: "AM", 39: "AN",
}

func WriteRow[T any](t T, i int, xlsx *excelize.File, sheet string) {
	count := 0
	writeStructFields(reflect.ValueOf(t), i, xlsx, sheet, &count)
}

func writeStructFields(t reflect.Value, i int, xlsx *excelize.File, sheet string, count *int) {
	// Make sure we're working with the value (de-reference if it's a pointer)
	if t.Kind() == reflect.Ptr {
		t = t.Elem()
	}

	d := t.Type()

	for j := 0; j < t.NumField(); j++ {
		fieldValue := t.Field(j)
		fieldType := d.Field(j)

		// Handle embedded BaseModel or other embedded structs
		if fieldType.Anonymous && fieldValue.Kind() == reflect.Struct {
			writeStructFields(fieldValue, i, xlsx, sheet, count)
			continue
		}

		column := COLNAMES[*count]

		xtag := fieldType.Tag.Get("xlsx")
		if xtag == "" || xtag == "-" {
			continue
		}

		if i == 0 {
			log.ErrorIf(xlsx.SetCellValue(sheet, fmt.Sprintf("%s%d", COLNAMES[*count], i+1), xtag))
		}

		// Setting the content based on type
		ctype := fieldType.Type.String()

		// Now using fieldValue instead of reflect.ValueOf(t).Elem().Field(j) for setting values
		switch ctype {
		case "string":
			log.ErrorIf(xlsx.SetCellValue(sheet, fmt.Sprintf("%s%d", column, i+2), fieldValue.String()))
		case "int", "int32", "int64":
			log.ErrorIf(xlsx.SetCellValue(sheet, fmt.Sprintf("%s%d", column, i+2), fmt.Sprintf("%d", fieldValue.Int())))
		case "bool":
			log.ErrorIf(xlsx.SetCellValue(sheet, fmt.Sprintf("%s%d", column, i+2), fmt.Sprintf("%v", fieldValue.Bool())))
		case "float32", "float64":
			log.ErrorIf(xlsx.SetCellValue(sheet, fmt.Sprintf("%s%d", column, i+2), fmt.Sprintf("%f", fieldValue.Float())))
		case "time.Time":
			log.ErrorIf(xlsx.SetCellValue(sheet, fmt.Sprintf("%s%d", column, i+2), fieldValue.Interface().(time.Time).Format(time.DateTime)))
		case "timeutil.LocalTime":
			log.ErrorIf(xlsx.SetCellValue(sheet, fmt.Sprintf("%s%d", column, i+2), time.Time(fieldValue.Interface().(timeutil.LocalTime)).Format(time.DateTime)))
		case "decimal.Decimal":
			log.ErrorIf(xlsx.SetCellValue(sheet, fmt.Sprintf("%s%d", column, i+2), fieldValue.Interface().(decimal.Decimal).StringFixed(2)))
		default:
			log.ErrorIf(xlsx.SetCellValue(sheet, fmt.Sprintf("%s%d", column, i+2), fieldValue.String()))
		}

		*count++
	}
}

Describe the results you received:

修复结果到 > 商品信息1.xml

在文件“/Users/wangjuntao/Downloads/商品信息.xlsx”中检测到错误> 已修复的部件: 有 XML 错误的 /xl/worksheets/sheet1.xml。 Xml parsing error 行 2,列 369。已修复的部件: 有 XML 错误的 /xl/worksheets/sheet2.xml。 Xml parsing error 行 2,列 1751。

Excelize version or commit ID:

github.com/xuri/excelize/v2

Environment details (OS, Microsoft Excel™ version, physical, etc.):

macos m1

@xuri
Copy link
Member

xuri commented Sep 6, 2023

Thanks for your issue. If you are reporting a new issue, make sure that we do not have any duplicates already exist. If it does not work with Go 1.21.0, please reference the (pinned) issues #1465, #1595, #1603, #1608, #1614, #1619, #1620, #1621, #1623, #1633, #1637, #1641, #1642 and #1648. There are some incompatible changes in the Go 1.21.0 encoding/xml library. I have given feedback to the Go team and created a patch for it (golang/go#61881), and the Go team has added golang/go#62051 to the Go 1.21.1 milestone, and it will be released on Wednesday, September 6. I suggest using the Go 1.20.7 and previous Go released version or waiting for the Go 1.21.1 releases. I have added notice on the README and documentation website for this, and I've closed this. If you have any questions, please let me know, and reopen this anytime.

谢谢你的反馈,在您创建新的问题之前,请确保不存在任何重复的问题。请参考(置顶)问题 #1465#1595#1603#1603#1614#1619#1620#1621#1623#1633#1637#1641, #1642#1648。Go 1.21.0 对 encoding/xml 标准库做了不兼容的更改,我已将该问题反馈至 Go 团队,并提交了修复补丁 golang/go#61881,将在下一个版本 Go 1.21.1 中修复。目前建议使用 Go 1.20.7 以及更早版本,或等待 2023年9月6日 Go 语言 1.21.1 版本发布。我已经为此在自述文档文档网站上添加了通知,因此我将关闭此问题。如果您有任何问题,请告诉我,并可随时重新打开。

@jtyoui
Copy link

jtyoui commented Nov 29, 2023

@jamiesun Go version update to V1.21.4 Ok

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
duplicate This issue or pull request already exists
Projects
None yet
Development

No branches or pull requests

3 participants