forked from p30928647/excelize
Fix potential file corrupted and change worksheet name case-insensitive
- Using sheet ID instead of sheet index when delete the cell in calculation chain - Update documentation for exported functions - Using `sheet` represent the sheet name in the function parameters
This commit is contained in:
parent
0d4c97c88a
commit
ebea684ae5
|
@ -49,7 +49,7 @@ func (f *File) deleteCalcChain(index int, axis string) {
|
|||
calc := f.calcChainReader()
|
||||
if calc != nil {
|
||||
calc.C = xlsxCalcChainCollection(calc.C).Filter(func(c xlsxCalcChainC) bool {
|
||||
return !((c.I == index && c.R == axis) || (c.I == index && axis == ""))
|
||||
return !((c.I == index && c.R == axis) || (c.I == index && axis == "") || (c.I == 0 && c.R == axis))
|
||||
})
|
||||
}
|
||||
if len(calc.C) == 0 {
|
||||
|
|
55
cell.go
55
cell.go
|
@ -170,18 +170,21 @@ func (c *xlsxC) hasValue() bool {
|
|||
}
|
||||
|
||||
// removeFormula delete formula for the cell.
|
||||
func (c *xlsxC) removeFormula(ws *xlsxWorksheet) {
|
||||
if c.F != nil && c.F.T == STCellFormulaTypeShared && c.F.Ref != "" {
|
||||
si := c.F.Si
|
||||
for r, row := range ws.SheetData.Row {
|
||||
for col, cell := range row.C {
|
||||
if cell.F != nil && cell.F.Si != nil && *cell.F.Si == *si {
|
||||
ws.SheetData.Row[r].C[col].F = nil
|
||||
func (f *File) removeFormula(c *xlsxC, ws *xlsxWorksheet, sheet string) {
|
||||
if c.F != nil && c.Vm == nil {
|
||||
f.deleteCalcChain(f.getSheetID(sheet), c.R)
|
||||
if c.F.T == STCellFormulaTypeShared && c.F.Ref != "" {
|
||||
si := c.F.Si
|
||||
for r, row := range ws.SheetData.Row {
|
||||
for col, cell := range row.C {
|
||||
if cell.F != nil && cell.F.Si != nil && *cell.F.Si == *si {
|
||||
ws.SheetData.Row[r].C[col].F = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
c.F = nil
|
||||
}
|
||||
c.F = nil
|
||||
}
|
||||
|
||||
// setCellIntFunc is a wrapper of SetCellInt.
|
||||
|
@ -281,8 +284,8 @@ func (f *File) SetCellInt(sheet, axis string, value int) error {
|
|||
defer ws.Unlock()
|
||||
cellData.S = f.prepareCellStyle(ws, col, row, cellData.S)
|
||||
cellData.T, cellData.V = setCellInt(value)
|
||||
cellData.removeFormula(ws)
|
||||
cellData.IS = nil
|
||||
f.removeFormula(cellData, ws, sheet)
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -308,8 +311,8 @@ func (f *File) SetCellBool(sheet, axis string, value bool) error {
|
|||
defer ws.Unlock()
|
||||
cellData.S = f.prepareCellStyle(ws, col, row, cellData.S)
|
||||
cellData.T, cellData.V = setCellBool(value)
|
||||
cellData.removeFormula(ws)
|
||||
cellData.IS = nil
|
||||
f.removeFormula(cellData, ws, sheet)
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -347,8 +350,8 @@ func (f *File) SetCellFloat(sheet, axis string, value float64, precision, bitSiz
|
|||
defer ws.Unlock()
|
||||
cellData.S = f.prepareCellStyle(ws, col, row, cellData.S)
|
||||
cellData.T, cellData.V = setCellFloat(value, precision, bitSize)
|
||||
cellData.removeFormula(ws)
|
||||
cellData.IS = nil
|
||||
f.removeFormula(cellData, ws, sheet)
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -374,8 +377,8 @@ func (f *File) SetCellStr(sheet, axis, value string) error {
|
|||
defer ws.Unlock()
|
||||
cellData.S = f.prepareCellStyle(ws, col, row, cellData.S)
|
||||
cellData.T, cellData.V, err = f.setCellString(value)
|
||||
cellData.removeFormula(ws)
|
||||
cellData.IS = nil
|
||||
f.removeFormula(cellData, ws, sheet)
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -474,8 +477,8 @@ func (f *File) SetCellDefault(sheet, axis, value string) error {
|
|||
defer ws.Unlock()
|
||||
cellData.S = f.prepareCellStyle(ws, col, row, cellData.S)
|
||||
cellData.T, cellData.V = setCellDefault(value)
|
||||
cellData.removeFormula(ws)
|
||||
cellData.IS = nil
|
||||
f.removeFormula(cellData, ws, sheet)
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -510,13 +513,12 @@ type FormulaOpts struct {
|
|||
}
|
||||
|
||||
// SetCellFormula provides a function to set formula on the cell is taken
|
||||
// according to the given worksheet name (case-sensitive) and cell formula
|
||||
// settings. The result of the formula cell can be calculated when the
|
||||
// worksheet is opened by the Office Excel application or can be using
|
||||
// the "CalcCellValue" function also can get the calculated cell value. If
|
||||
// the Excel application doesn't calculate the formula automatically when the
|
||||
// workbook has been opened, please call "UpdateLinkedValue" after setting
|
||||
// the cell formula functions.
|
||||
// according to the given worksheet name and cell formula settings. The result
|
||||
// of the formula cell can be calculated when the worksheet is opened by the
|
||||
// Office Excel application or can be using the "CalcCellValue" function also
|
||||
// can get the calculated cell value. If the Excel application doesn't
|
||||
// calculate the formula automatically when the workbook has been opened,
|
||||
// please call "UpdateLinkedValue" after setting the cell formula functions.
|
||||
//
|
||||
// Example 1, set normal formula "=SUM(A1,B1)" for the cell "A3" on "Sheet1":
|
||||
//
|
||||
|
@ -662,11 +664,12 @@ func (ws *xlsxWorksheet) countSharedFormula() (count int) {
|
|||
return
|
||||
}
|
||||
|
||||
// GetCellHyperLink provides a function to get cell hyperlink by given
|
||||
// worksheet name and axis. Boolean type value link will be true if the cell
|
||||
// has a hyperlink and the target is the address of the hyperlink. Otherwise,
|
||||
// the value of link will be false and the value of the target will be a blank
|
||||
// string. For example get hyperlink of Sheet1!H6:
|
||||
// GetCellHyperLink gets a cell hyperlink based on the given worksheet name and
|
||||
// cell coordinates. If the cell has a hyperlink, it will return 'true' and
|
||||
// the link address, otherwise it will return 'false' and an empty link
|
||||
// address.
|
||||
//
|
||||
// For example, get a hyperlink to a 'H6' cell on a worksheet named 'Sheet1':
|
||||
//
|
||||
// link, target, err := f.GetCellHyperLink("Sheet1", "H6")
|
||||
//
|
||||
|
@ -765,7 +768,7 @@ func (f *File) SetCellHyperLink(sheet, axis, link, linkType string, opts ...Hype
|
|||
|
||||
switch linkType {
|
||||
case "External":
|
||||
sheetPath := f.sheetMap[trimSheetName(sheet)]
|
||||
sheetPath, _ := f.getSheetXMLPath(sheet)
|
||||
sheetRels := "xl/worksheets/_rels/" + strings.TrimPrefix(sheetPath, "xl/worksheets/") + ".rels"
|
||||
rID := f.setRels(linkData.RID, sheetRels, SourceRelationshipHyperLink, link, linkType)
|
||||
linkData = xlsxHyperlink{
|
||||
|
|
12
col.go
12
col.go
|
@ -40,7 +40,15 @@ type Cols struct {
|
|||
sheetXML []byte
|
||||
}
|
||||
|
||||
// GetCols return all the columns in a sheet by given worksheet name (case-sensitive). For example:
|
||||
// GetCols gets the value of all cells by columns on the worksheet based on the
|
||||
// given worksheet name, returned as a two-dimensional array, where the value
|
||||
// of the cell is converted to the `string` type. If the cell format can be
|
||||
// applied to the value of the cell, the applied value will be used, otherwise
|
||||
// the original value will be used.
|
||||
//
|
||||
// For example, get and traverse the value of all cells by columns on a
|
||||
// worksheet named
|
||||
// 'Sheet1':
|
||||
//
|
||||
// cols, err := f.GetCols("Sheet1")
|
||||
// if err != nil {
|
||||
|
@ -196,7 +204,7 @@ func columnXMLHandler(colIterator *columnXMLIterator, xmlElement *xml.StartEleme
|
|||
// }
|
||||
//
|
||||
func (f *File) Cols(sheet string) (*Cols, error) {
|
||||
name, ok := f.sheetMap[trimSheetName(sheet)]
|
||||
name, ok := f.getSheetXMLPath(sheet)
|
||||
if !ok {
|
||||
return nil, ErrSheetNotExist{sheet}
|
||||
}
|
||||
|
|
|
@ -115,7 +115,8 @@ func (f *File) AddComment(sheet, cell, format string) error {
|
|||
drawingVML = strings.ReplaceAll(sheetRelationshipsDrawingVML, "..", "xl")
|
||||
} else {
|
||||
// Add first comment for given sheet.
|
||||
sheetRels := "xl/worksheets/_rels/" + strings.TrimPrefix(f.sheetMap[trimSheetName(sheet)], "xl/worksheets/") + ".rels"
|
||||
sheetXMLPath, _ := f.getSheetXMLPath(sheet)
|
||||
sheetRels := "xl/worksheets/_rels/" + strings.TrimPrefix(sheetXMLPath, "xl/worksheets/") + ".rels"
|
||||
rID := f.addRels(sheetRels, SourceRelationshipDrawingVML, sheetRelationshipsDrawingVML, "")
|
||||
f.addRels(sheetRels, SourceRelationshipComments, sheetRelationshipsComments, "")
|
||||
f.addSheetNameSpace(sheet, SourceRelationship)
|
||||
|
|
|
@ -33,7 +33,8 @@ func (f *File) prepareDrawing(ws *xlsxWorksheet, drawingID int, sheet, drawingXM
|
|||
drawingXML = strings.ReplaceAll(sheetRelationshipsDrawingXML, "..", "xl")
|
||||
} else {
|
||||
// Add first picture for given sheet.
|
||||
sheetRels := "xl/worksheets/_rels/" + strings.TrimPrefix(f.sheetMap[trimSheetName(sheet)], "xl/worksheets/") + ".rels"
|
||||
sheetXMLPath, _ := f.getSheetXMLPath(sheet)
|
||||
sheetRels := "xl/worksheets/_rels/" + strings.TrimPrefix(sheetXMLPath, "xl/worksheets/") + ".rels"
|
||||
rID := f.addRels(sheetRels, SourceRelationshipDrawingML, sheetRelationshipsDrawingXML, "")
|
||||
f.addSheetDrawing(sheet, rID)
|
||||
}
|
||||
|
@ -45,7 +46,8 @@ func (f *File) prepareDrawing(ws *xlsxWorksheet, drawingID int, sheet, drawingXM
|
|||
func (f *File) prepareChartSheetDrawing(cs *xlsxChartsheet, drawingID int, sheet string) {
|
||||
sheetRelationshipsDrawingXML := "../drawings/drawing" + strconv.Itoa(drawingID) + ".xml"
|
||||
// Only allow one chart in a chartsheet.
|
||||
sheetRels := "xl/chartsheets/_rels/" + strings.TrimPrefix(f.sheetMap[trimSheetName(sheet)], "xl/chartsheets/") + ".rels"
|
||||
sheetXMLPath, _ := f.getSheetXMLPath(sheet)
|
||||
sheetRels := "xl/chartsheets/_rels/" + strings.TrimPrefix(sheetXMLPath, "xl/chartsheets/") + ".rels"
|
||||
rID := f.addRels(sheetRels, SourceRelationshipDrawingML, sheetRelationshipsDrawingXML, "")
|
||||
f.addSheetNameSpace(sheet, SourceRelationship)
|
||||
cs.Drawing = &xlsxDrawing{
|
||||
|
|
|
@ -230,7 +230,7 @@ func (f *File) workSheetReader(sheet string) (ws *xlsxWorksheet, err error) {
|
|||
name string
|
||||
ok bool
|
||||
)
|
||||
if name, ok = f.sheetMap[trimSheetName(sheet)]; !ok {
|
||||
if name, ok = f.getSheetXMLPath(sheet); !ok {
|
||||
err = fmt.Errorf("sheet %s is not exist", sheet)
|
||||
return
|
||||
}
|
||||
|
|
6
lib.go
6
lib.go
|
@ -187,8 +187,8 @@ func JoinCellName(col string, row int) (string, error) {
|
|||
}
|
||||
|
||||
// ColumnNameToNumber provides a function to convert Excel sheet column name
|
||||
// to int. Column name case-insensitive. The function returns an error if
|
||||
// column name incorrect.
|
||||
// (case-insensitive) to int. The function returns an error if column name
|
||||
// incorrect.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
|
@ -690,7 +690,7 @@ func (f *File) setIgnorableNameSpace(path string, index int, ns xml.Attr) {
|
|||
|
||||
// addSheetNameSpace add XML attribute for worksheet.
|
||||
func (f *File) addSheetNameSpace(sheet string, ns xml.Attr) {
|
||||
name := f.sheetMap[trimSheetName(sheet)]
|
||||
name, _ := f.getSheetXMLPath(sheet)
|
||||
f.addNameSpaces(name, ns)
|
||||
}
|
||||
|
||||
|
|
|
@ -200,7 +200,7 @@ func (f *File) AddPictureFromBytes(sheet, cell, format, name, extension string,
|
|||
// xl/worksheets/_rels/sheet%d.xml.rels by given worksheet name and
|
||||
// relationship index.
|
||||
func (f *File) deleteSheetRelationships(sheet, rID string) {
|
||||
name, ok := f.sheetMap[trimSheetName(sheet)]
|
||||
name, ok := f.getSheetXMLPath(sheet)
|
||||
if !ok {
|
||||
name = strings.ToLower(sheet) + ".xml"
|
||||
}
|
||||
|
@ -450,7 +450,7 @@ func (f *File) addContentTypePart(index int, contentType string) {
|
|||
// value in xl/worksheets/_rels/sheet%d.xml.rels by given worksheet name and
|
||||
// relationship index.
|
||||
func (f *File) getSheetRelationshipsTargetByID(sheet, rID string) string {
|
||||
name, ok := f.sheetMap[trimSheetName(sheet)]
|
||||
name, ok := f.getSheetXMLPath(sheet)
|
||||
if !ok {
|
||||
name = strings.ToLower(sheet) + ".xml"
|
||||
}
|
||||
|
|
|
@ -190,7 +190,7 @@ func (f *File) parseFormatPivotTableSet(opt *PivotTableOption) (*xlsxWorksheet,
|
|||
if err != nil {
|
||||
return dataSheet, "", err
|
||||
}
|
||||
pivotTableSheetPath, ok := f.sheetMap[trimSheetName(pivotTableSheetName)]
|
||||
pivotTableSheetPath, ok := f.getSheetXMLPath(pivotTableSheetName)
|
||||
if !ok {
|
||||
return dataSheet, pivotTableSheetPath, fmt.Errorf("sheet %s is not exist", pivotTableSheetName)
|
||||
}
|
||||
|
|
19
rows.go
19
rows.go
|
@ -26,13 +26,16 @@ import (
|
|||
"github.com/mohae/deepcopy"
|
||||
)
|
||||
|
||||
// GetRows return all the rows in a sheet by given worksheet name
|
||||
// (case sensitive), returned as a two-dimensional array, where the value of
|
||||
// the cell is converted to the string type. If the cell format can be applied
|
||||
// to the value of the cell, the applied value will be used, otherwise the
|
||||
// original value will be used. GetRows fetched the rows with value or formula
|
||||
// cells, the continually blank cells in the tail of each row will be skipped,
|
||||
// so the length of each row may be inconsistent. For example:
|
||||
// GetRows return all the rows in a sheet by given worksheet name, returned as
|
||||
// a two-dimensional array, where the value of the cell is converted to the
|
||||
// string type. If the cell format can be applied to the value of the cell,
|
||||
// the applied value will be used, otherwise the original value will be used.
|
||||
// GetRows fetched the rows with value or formula cells, the continually blank
|
||||
// cells in the tail of each row will be skipped, so the length of each row
|
||||
// may be inconsistent.
|
||||
//
|
||||
// For example, get and traverse the value of all cells by rows on a worksheet
|
||||
// named 'Sheet1':
|
||||
//
|
||||
// rows, err := f.GetRows("Sheet1")
|
||||
// if err != nil {
|
||||
|
@ -233,7 +236,7 @@ func (rows *Rows) rowXMLHandler(rowIterator *rowXMLIterator, xmlElement *xml.Sta
|
|||
// }
|
||||
//
|
||||
func (f *File) Rows(sheet string) (*Rows, error) {
|
||||
name, ok := f.sheetMap[trimSheetName(sheet)]
|
||||
name, ok := f.getSheetXMLPath(sheet)
|
||||
if !ok {
|
||||
return nil, ErrSheetNotExist{sheet}
|
||||
}
|
||||
|
|
3
shape.go
3
shape.go
|
@ -300,7 +300,8 @@ func (f *File) AddShape(sheet, cell, format string) error {
|
|||
drawingXML = strings.ReplaceAll(sheetRelationshipsDrawingXML, "..", "xl")
|
||||
} else {
|
||||
// Add first shape for given sheet.
|
||||
sheetRels := "xl/worksheets/_rels/" + strings.TrimPrefix(f.sheetMap[trimSheetName(sheet)], "xl/worksheets/") + ".rels"
|
||||
sheetXMLPath, _ := f.getSheetXMLPath(sheet)
|
||||
sheetRels := "xl/worksheets/_rels/" + strings.TrimPrefix(sheetXMLPath, "xl/worksheets/") + ".rels"
|
||||
rID := f.addRels(sheetRels, SourceRelationshipDrawingML, sheetRelationshipsDrawingXML, "")
|
||||
f.addSheetDrawing(sheet, rID)
|
||||
f.addSheetNameSpace(sheet, SourceRelationship)
|
||||
|
|
112
sheet.go
112
sheet.go
|
@ -34,17 +34,16 @@ import (
|
|||
)
|
||||
|
||||
// NewSheet provides the function to create a new sheet by given a worksheet
|
||||
// name and returns the index of the sheets in the workbook
|
||||
// (spreadsheet) after it appended. Note that the worksheet names are not
|
||||
// case-sensitive, when creating a new spreadsheet file, the default
|
||||
// worksheet named `Sheet1` will be created.
|
||||
func (f *File) NewSheet(name string) int {
|
||||
// name and returns the index of the sheets in the workbook after it appended.
|
||||
// Note that when creating a new workbook, the default worksheet named
|
||||
// `Sheet1` will be created.
|
||||
func (f *File) NewSheet(sheet string) int {
|
||||
// Check if the worksheet already exists
|
||||
index := f.GetSheetIndex(name)
|
||||
index := f.GetSheetIndex(sheet)
|
||||
if index != -1 {
|
||||
return index
|
||||
}
|
||||
f.DeleteSheet(name)
|
||||
f.DeleteSheet(sheet)
|
||||
f.SheetCount++
|
||||
wb := f.workbookReader()
|
||||
sheetID := 0
|
||||
|
@ -59,12 +58,12 @@ func (f *File) NewSheet(name string) int {
|
|||
// Update [Content_Types].xml
|
||||
f.setContentTypes("/xl/worksheets/sheet"+strconv.Itoa(sheetID)+".xml", ContentTypeSpreadSheetMLWorksheet)
|
||||
// Create new sheet /xl/worksheets/sheet%d.xml
|
||||
f.setSheet(sheetID, name)
|
||||
f.setSheet(sheetID, sheet)
|
||||
// Update workbook.xml.rels
|
||||
rID := f.addRels(f.getWorkbookRelsPath(), SourceRelationshipWorkSheet, fmt.Sprintf("/xl/worksheets/sheet%d.xml", sheetID), "")
|
||||
// Update workbook.xml
|
||||
f.setWorkbook(name, sheetID, rID)
|
||||
return f.GetSheetIndex(name)
|
||||
f.setWorkbook(sheet, sheetID, rID)
|
||||
return f.GetSheetIndex(sheet)
|
||||
}
|
||||
|
||||
// contentTypesReader provides a function to get the pointer to the
|
||||
|
@ -345,7 +344,7 @@ func (f *File) getActiveSheetID() int {
|
|||
func (f *File) SetSheetName(oldName, newName string) {
|
||||
oldName = trimSheetName(oldName)
|
||||
newName = trimSheetName(newName)
|
||||
if newName == oldName {
|
||||
if strings.EqualFold(newName, oldName) {
|
||||
return
|
||||
}
|
||||
content := f.workbookReader()
|
||||
|
@ -374,9 +373,10 @@ func (f *File) GetSheetName(index int) (name string) {
|
|||
// getSheetID provides a function to get worksheet ID of the spreadsheet by
|
||||
// given sheet name. If given worksheet name is invalid, will return an
|
||||
// integer type value -1.
|
||||
func (f *File) getSheetID(name string) int {
|
||||
for sheetID, sheet := range f.GetSheetMap() {
|
||||
if strings.EqualFold(sheet, trimSheetName(name)) {
|
||||
func (f *File) getSheetID(sheet string) int {
|
||||
sheetName := trimSheetName(sheet)
|
||||
for sheetID, name := range f.GetSheetMap() {
|
||||
if strings.EqualFold(name, sheetName) {
|
||||
return sheetID
|
||||
}
|
||||
}
|
||||
|
@ -384,12 +384,12 @@ func (f *File) getSheetID(name string) int {
|
|||
}
|
||||
|
||||
// GetSheetIndex provides a function to get a sheet index of the workbook by
|
||||
// the given sheet name, the sheet names are not case-sensitive. If the given
|
||||
// sheet name is invalid or sheet doesn't exist, it will return an integer
|
||||
// type value -1.
|
||||
func (f *File) GetSheetIndex(name string) int {
|
||||
for index, sheet := range f.GetSheetList() {
|
||||
if strings.EqualFold(sheet, trimSheetName(name)) {
|
||||
// the given sheet name. If the given sheet name is invalid or sheet doesn't
|
||||
// exist, it will return an integer type value -1.
|
||||
func (f *File) GetSheetIndex(sheet string) int {
|
||||
sheetName := trimSheetName(sheet)
|
||||
for index, name := range f.GetSheetList() {
|
||||
if strings.EqualFold(name, sheetName) {
|
||||
return index
|
||||
}
|
||||
}
|
||||
|
@ -455,6 +455,22 @@ func (f *File) getSheetMap() map[string]string {
|
|||
return maps
|
||||
}
|
||||
|
||||
// getSheetXMLPath provides a function to get XML file path by given sheet
|
||||
// name.
|
||||
func (f *File) getSheetXMLPath(sheet string) (string, bool) {
|
||||
var (
|
||||
name string
|
||||
ok bool
|
||||
)
|
||||
for sheetName, filePath := range f.sheetMap {
|
||||
if strings.EqualFold(sheetName, sheet) {
|
||||
name, ok = filePath, true
|
||||
break
|
||||
}
|
||||
}
|
||||
return name, ok
|
||||
}
|
||||
|
||||
// SetSheetBackground provides a function to set background picture by given
|
||||
// worksheet name and file path.
|
||||
func (f *File) SetSheetBackground(sheet, picture string) error {
|
||||
|
@ -469,7 +485,8 @@ func (f *File) SetSheetBackground(sheet, picture string) error {
|
|||
}
|
||||
file, _ := ioutil.ReadFile(filepath.Clean(picture))
|
||||
name := f.addMedia(file, ext)
|
||||
sheetRels := "xl/worksheets/_rels/" + strings.TrimPrefix(f.sheetMap[trimSheetName(sheet)], "xl/worksheets/") + ".rels"
|
||||
sheetXMLPath, _ := f.getSheetXMLPath(sheet)
|
||||
sheetRels := "xl/worksheets/_rels/" + strings.TrimPrefix(sheetXMLPath, "xl/worksheets/") + ".rels"
|
||||
rID := f.addRels(sheetRels, SourceRelationshipImage, strings.Replace(name, "xl", "..", 1), "")
|
||||
f.addSheetPicture(sheet, rID)
|
||||
f.addSheetNameSpace(sheet, SourceRelationship)
|
||||
|
@ -478,24 +495,23 @@ func (f *File) SetSheetBackground(sheet, picture string) error {
|
|||
}
|
||||
|
||||
// DeleteSheet provides a function to delete worksheet in a workbook by given
|
||||
// worksheet name, the sheet names are not case-sensitive. Use this method
|
||||
// with caution, which will affect changes in references such as formulas,
|
||||
// charts, and so on. If there is any referenced value of the deleted
|
||||
// worksheet, it will cause a file error when you open it. This function will
|
||||
// be invalid when only one worksheet is left
|
||||
func (f *File) DeleteSheet(name string) {
|
||||
if f.SheetCount == 1 || f.GetSheetIndex(name) == -1 {
|
||||
// worksheet name. Use this method with caution, which will affect changes in
|
||||
// references such as formulas, charts, and so on. If there is any referenced
|
||||
// value of the deleted worksheet, it will cause a file error when you open
|
||||
// it. This function will be invalid when only one worksheet is left.
|
||||
func (f *File) DeleteSheet(sheet string) {
|
||||
if f.SheetCount == 1 || f.GetSheetIndex(sheet) == -1 {
|
||||
return
|
||||
}
|
||||
sheetName := trimSheetName(name)
|
||||
sheetName := trimSheetName(sheet)
|
||||
wb := f.workbookReader()
|
||||
wbRels := f.relsReader(f.getWorkbookRelsPath())
|
||||
activeSheetName := f.GetSheetName(f.GetActiveSheetIndex())
|
||||
deleteLocalSheetID := f.GetSheetIndex(name)
|
||||
deleteLocalSheetID := f.GetSheetIndex(sheet)
|
||||
deleteAndAdjustDefinedNames(wb, deleteLocalSheetID)
|
||||
|
||||
for idx, sheet := range wb.Sheets.Sheet {
|
||||
if !strings.EqualFold(sheet.Name, sheetName) {
|
||||
for idx, v := range wb.Sheets.Sheet {
|
||||
if !strings.EqualFold(v.Name, sheetName) {
|
||||
continue
|
||||
}
|
||||
|
||||
|
@ -503,16 +519,17 @@ func (f *File) DeleteSheet(name string) {
|
|||
var sheetXML, rels string
|
||||
if wbRels != nil {
|
||||
for _, rel := range wbRels.Relationships {
|
||||
if rel.ID == sheet.ID {
|
||||
if rel.ID == v.ID {
|
||||
sheetXML = f.getWorksheetPath(rel.Target)
|
||||
rels = "xl/worksheets/_rels/" + strings.TrimPrefix(f.sheetMap[sheetName], "xl/worksheets/") + ".rels"
|
||||
sheetXMLPath, _ := f.getSheetXMLPath(sheet)
|
||||
rels = "xl/worksheets/_rels/" + strings.TrimPrefix(sheetXMLPath, "xl/worksheets/") + ".rels"
|
||||
}
|
||||
}
|
||||
}
|
||||
target := f.deleteSheetFromWorkbookRels(sheet.ID)
|
||||
target := f.deleteSheetFromWorkbookRels(v.ID)
|
||||
f.deleteSheetFromContentTypes(target)
|
||||
f.deleteCalcChain(sheet.SheetID, "")
|
||||
delete(f.sheetMap, sheet.Name)
|
||||
f.deleteCalcChain(f.getSheetID(sheet), "")
|
||||
delete(f.sheetMap, v.Name)
|
||||
f.Pkg.Delete(sheetXML)
|
||||
f.Pkg.Delete(rels)
|
||||
f.Relationships.Delete(rels)
|
||||
|
@ -613,7 +630,7 @@ func (f *File) copySheet(from, to int) error {
|
|||
if rels, ok := f.Pkg.Load(fromRels); ok && rels != nil {
|
||||
f.Pkg.Store(toRels, rels.([]byte))
|
||||
}
|
||||
fromSheetXMLPath := f.sheetMap[trimSheetName(fromSheet)]
|
||||
fromSheetXMLPath, _ := f.getSheetXMLPath(fromSheet)
|
||||
fromSheetAttr := f.xmlAttr[fromSheetXMLPath]
|
||||
f.xmlAttr[sheetXMLPath] = fromSheetAttr
|
||||
return err
|
||||
|
@ -632,12 +649,12 @@ func (f *File) copySheet(from, to int) error {
|
|||
//
|
||||
// err := f.SetSheetVisible("Sheet1", false)
|
||||
//
|
||||
func (f *File) SetSheetVisible(name string, visible bool) error {
|
||||
name = trimSheetName(name)
|
||||
func (f *File) SetSheetVisible(sheet string, visible bool) error {
|
||||
sheet = trimSheetName(sheet)
|
||||
content := f.workbookReader()
|
||||
if visible {
|
||||
for k, v := range content.Sheets.Sheet {
|
||||
if v.Name == name {
|
||||
if strings.EqualFold(v.Name, sheet) {
|
||||
content.Sheets.Sheet[k].State = ""
|
||||
}
|
||||
}
|
||||
|
@ -658,7 +675,7 @@ func (f *File) SetSheetVisible(name string, visible bool) error {
|
|||
if len(ws.SheetViews.SheetView) > 0 {
|
||||
tabSelected = ws.SheetViews.SheetView[0].TabSelected
|
||||
}
|
||||
if v.Name == name && count > 1 && !tabSelected {
|
||||
if strings.EqualFold(v.Name, sheet) && count > 1 && !tabSelected {
|
||||
content.Sheets.Sheet[k].State = "hidden"
|
||||
}
|
||||
}
|
||||
|
@ -798,11 +815,10 @@ func (f *File) SetPanes(sheet, panes string) error {
|
|||
//
|
||||
// f.GetSheetVisible("Sheet1")
|
||||
//
|
||||
func (f *File) GetSheetVisible(name string) bool {
|
||||
content := f.workbookReader()
|
||||
visible := false
|
||||
func (f *File) GetSheetVisible(sheet string) bool {
|
||||
content, name, visible := f.workbookReader(), trimSheetName(sheet), false
|
||||
for k, v := range content.Sheets.Sheet {
|
||||
if v.Name == trimSheetName(name) {
|
||||
if strings.EqualFold(v.Name, name) {
|
||||
if content.Sheets.Sheet[k].State == "" || content.Sheets.Sheet[k].State == "visible" {
|
||||
visible = true
|
||||
}
|
||||
|
@ -834,7 +850,7 @@ func (f *File) SearchSheet(sheet, value string, reg ...bool) ([]string, error) {
|
|||
for _, r := range reg {
|
||||
regSearch = r
|
||||
}
|
||||
name, ok := f.sheetMap[trimSheetName(sheet)]
|
||||
name, ok := f.getSheetXMLPath(sheet)
|
||||
if !ok {
|
||||
return result, ErrSheetNotExist{sheet}
|
||||
}
|
||||
|
@ -1609,7 +1625,7 @@ func (f *File) GroupSheets(sheets []string) error {
|
|||
sheetMap := f.GetSheetList()
|
||||
for idx, sheetName := range sheetMap {
|
||||
for _, s := range sheets {
|
||||
if s == sheetName && idx == activeSheet {
|
||||
if strings.EqualFold(s, sheetName) && idx == activeSheet {
|
||||
inActiveSheet = true
|
||||
}
|
||||
}
|
||||
|
|
|
@ -181,8 +181,8 @@ func (o *AutoPageBreaks) getSheetPrOption(pr *xlsxSheetPr) {
|
|||
// FitToPage(bool)
|
||||
// AutoPageBreaks(bool)
|
||||
// OutlineSummaryBelow(bool)
|
||||
func (f *File) SetSheetPrOptions(name string, opts ...SheetPrOption) error {
|
||||
ws, err := f.workSheetReader(name)
|
||||
func (f *File) SetSheetPrOptions(sheet string, opts ...SheetPrOption) error {
|
||||
ws, err := f.workSheetReader(sheet)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -207,8 +207,8 @@ func (f *File) SetSheetPrOptions(name string, opts ...SheetPrOption) error {
|
|||
// FitToPage(bool)
|
||||
// AutoPageBreaks(bool)
|
||||
// OutlineSummaryBelow(bool)
|
||||
func (f *File) GetSheetPrOptions(name string, opts ...SheetPrOptionPtr) error {
|
||||
ws, err := f.workSheetReader(name)
|
||||
func (f *File) GetSheetPrOptions(sheet string, opts ...SheetPrOptionPtr) error {
|
||||
ws, err := f.workSheetReader(sheet)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -200,8 +200,8 @@ func (f *File) getSheetView(sheet string, viewIndex int) (*xlsxSheetView, error)
|
|||
//
|
||||
// err = f.SetSheetViewOptions("Sheet1", -1, ShowGridLines(false))
|
||||
//
|
||||
func (f *File) SetSheetViewOptions(name string, viewIndex int, opts ...SheetViewOption) error {
|
||||
view, err := f.getSheetView(name, viewIndex)
|
||||
func (f *File) SetSheetViewOptions(sheet string, viewIndex int, opts ...SheetViewOption) error {
|
||||
view, err := f.getSheetView(sheet, viewIndex)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -233,8 +233,8 @@ func (f *File) SetSheetViewOptions(name string, viewIndex int, opts ...SheetView
|
|||
// var showGridLines excelize.ShowGridLines
|
||||
// err = f.GetSheetViewOptions("Sheet1", -1, &showGridLines)
|
||||
//
|
||||
func (f *File) GetSheetViewOptions(name string, viewIndex int, opts ...SheetViewOptionPtr) error {
|
||||
view, err := f.getSheetView(name, viewIndex)
|
||||
func (f *File) GetSheetViewOptions(sheet string, viewIndex int, opts ...SheetViewOptionPtr) error {
|
||||
view, err := f.getSheetView(sheet, viewIndex)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -106,11 +106,11 @@ func (f *File) NewStreamWriter(sheet string) (*StreamWriter, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
sheetPath := f.sheetMap[trimSheetName(sheet)]
|
||||
sheetXMLPath, _ := f.getSheetXMLPath(sheet)
|
||||
if f.streams == nil {
|
||||
f.streams = make(map[string]*StreamWriter)
|
||||
}
|
||||
f.streams[sheetPath] = sw
|
||||
f.streams[sheetXMLPath] = sw
|
||||
|
||||
_, _ = sw.rawData.WriteString(xml.Header + `<worksheet` + templateNamespaceIDMap)
|
||||
bulkAppendFields(&sw.rawData, sw.worksheet, 2, 5)
|
||||
|
|
3
table.go
3
table.go
|
@ -85,7 +85,8 @@ func (f *File) AddTable(sheet, hCell, vCell, format string) error {
|
|||
sheetRelationshipsTableXML := "../tables/table" + strconv.Itoa(tableID) + ".xml"
|
||||
tableXML := strings.ReplaceAll(sheetRelationshipsTableXML, "..", "xl")
|
||||
// Add first table for given sheet.
|
||||
sheetRels := "xl/worksheets/_rels/" + strings.TrimPrefix(f.sheetMap[trimSheetName(sheet)], "xl/worksheets/") + ".rels"
|
||||
sheetXMLPath, _ := f.getSheetXMLPath(sheet)
|
||||
sheetRels := "xl/worksheets/_rels/" + strings.TrimPrefix(sheetXMLPath, "xl/worksheets/") + ".rels"
|
||||
rID := f.addRels(sheetRels, SourceRelationshipTable, sheetRelationshipsTableXML, "")
|
||||
if err = f.addSheetTable(sheet, rID); err != nil {
|
||||
return err
|
||||
|
|
|
@ -465,9 +465,12 @@ type xlsxC struct {
|
|||
R string `xml:"r,attr,omitempty"` // Cell ID, e.g. A1
|
||||
S int `xml:"s,attr,omitempty"` // Style reference.
|
||||
// Str string `xml:"str,attr,omitempty"` // Style reference.
|
||||
T string `xml:"t,attr,omitempty"` // Type.
|
||||
F *xlsxF `xml:"f,omitempty"` // Formula
|
||||
V string `xml:"v,omitempty"` // Value
|
||||
T string `xml:"t,attr,omitempty"` // Type.
|
||||
Cm *uint `xml:"cm,attr,omitempty"` //
|
||||
Vm *uint `xml:"vm,attr,omitempty"` //
|
||||
Ph *bool `xml:"ph,attr,omitempty"` //
|
||||
F *xlsxF `xml:"f,omitempty"` // Formula
|
||||
V string `xml:"v,omitempty"` // Value
|
||||
IS *xlsxSI `xml:"is"`
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue