diff --git a/README.md b/README.md index b3106df0..97db54a6 100644 --- a/README.md +++ b/README.md @@ -29,9 +29,9 @@ go get github.com/360EntSecGroup-Skylar/excelize go get github.com/360EntSecGroup-Skylar/excelize/v2 ``` -### Create XLSX file +### Create spreadsheet -Here is a minimal example usage that will create XLSX file. +Here is a minimal example usage that will create spreadsheet file. ```go package main @@ -58,9 +58,9 @@ func main() { } ``` -### Reading XLSX file +### Reading spreadsheet -The following constitutes the bare to read a XLSX document. +The following constitutes the bare to read a spreadsheet document. ```go package main @@ -95,7 +95,7 @@ func main() { } ``` -### Add chart to XLSX file +### Add chart to spreadsheet file With Excelize chart generation and management is as easy as a few lines of code. You can build charts based off data in your worksheet or generate charts without any data in your worksheet at all. @@ -131,7 +131,7 @@ func main() { } ``` -### Add picture to XLSX file +### Add picture to spreadsheet file ```go package main diff --git a/excelize.go b/excelize.go index 970759c1..bac569af 100644 --- a/excelize.go +++ b/excelize.go @@ -220,16 +220,25 @@ func checkSheet(xlsx *xlsxWorksheet) { // addRels provides a function to add relationships by given XML path, // relationship type, target and target mode. func (f *File) addRels(relPath, relType, target, targetMode string) int { + var uniqPart = map[string]string{ + SourceRelationshipSharedStrings: "/xl/sharedStrings.xml", + } rels := f.relsReader(relPath) if rels == nil { rels = &xlsxRelationships{} } var rID int - for _, rel := range rels.Relationships { + for idx, rel := range rels.Relationships { ID, _ := strconv.Atoi(strings.TrimPrefix(rel.ID, "rId")) if ID > rID { rID = ID } + if relType == rel.Type { + if partName, ok := uniqPart[rel.Type]; ok { + rels.Relationships[idx].Target = partName + return rID + } + } } rID++ var ID bytes.Buffer diff --git a/excelize_test.go b/excelize_test.go index b31e1c84..c2bd3ad8 100644 --- a/excelize_test.go +++ b/excelize_test.go @@ -22,7 +22,7 @@ import ( ) func TestOpenFile(t *testing.T) { - // Test update a XLSX file. + // Test update the spreadsheet file. f, err := OpenFile(filepath.Join("test", "Book1.xlsx")) assert.NoError(t, err) @@ -154,11 +154,11 @@ func TestOpenFile(t *testing.T) { // Test read cell value with given axis large than exists row. _, err = f.GetCellValue("Sheet2", "E231") assert.NoError(t, err) - // Test get active worksheet of XLSX and get worksheet name of XLSX by given worksheet index. + // Test get active worksheet of spreadsheet and get worksheet name of spreadsheet by given worksheet index. f.GetSheetName(f.GetActiveSheetIndex()) - // Test get worksheet index of XLSX by given worksheet name. + // Test get worksheet index of spreadsheet by given worksheet name. f.GetSheetIndex("Sheet1") - // Test get worksheet name of XLSX by given invalid worksheet index. + // Test get worksheet name of spreadsheet by given invalid worksheet index. f.GetSheetName(4) // Test get worksheet map of workbook. f.GetSheetMap() @@ -261,7 +261,7 @@ func TestBrokenFile(t *testing.T) { }) t.Run("OpenNotExistsFile", func(t *testing.T) { - // Test open a XLSX file with given illegal path. + // Test open a spreadsheet file with given illegal path. _, err := OpenFile(filepath.Join("test", "NotExistsFile.xlsx")) if assert.Error(t, err) { assert.True(t, os.IsNotExist(err), "Expected os.IsNotExists(err) == true") @@ -270,7 +270,7 @@ func TestBrokenFile(t *testing.T) { } func TestNewFile(t *testing.T) { - // Test create a XLSX file. + // Test create a spreadsheet file. f := NewFile() f.NewSheet("Sheet1") f.NewSheet("XLSXSheet2") diff --git a/lib.go b/lib.go index 73edb66c..5d18064c 100644 --- a/lib.go +++ b/lib.go @@ -26,10 +26,18 @@ import ( // filesystem. func ReadZipReader(r *zip.Reader) (map[string][]byte, int, error) { var err error + var docPart = map[string]string{ + "[content_types].xml": "[Content_Types].xml", + "xl/sharedstrings.xml": "xl/sharedStrings.xml", + } fileList := make(map[string][]byte, len(r.File)) worksheets := 0 for _, v := range r.File { - if fileList[v.Name], err = readFile(v); err != nil { + fileName := v.Name + if partName, ok := docPart[strings.ToLower(v.Name)]; ok { + fileName = partName + } + if fileList[fileName], err = readFile(v); err != nil { return nil, 0, err } if strings.HasPrefix(v.Name, "xl/worksheets/sheet") { diff --git a/picture.go b/picture.go index 79aa6ca5..0e9e3bb6 100644 --- a/picture.go +++ b/picture.go @@ -474,7 +474,7 @@ func (f *File) GetPicture(sheet, cell string) (string, []byte, error) { return f.getPicture(row, col, drawingXML, drawingRelationships) } -// DeletePicture provides a function to delete charts in XLSX by given +// DeletePicture provides a function to delete charts in spreadsheet by given // worksheet and cell name. Note that the image file won't be deleted from the // document currently. func (f *File) DeletePicture(sheet, cell string) (err error) { @@ -496,7 +496,7 @@ func (f *File) DeletePicture(sheet, cell string) (err error) { } // getPicture provides a function to get picture base name and raw content -// embed in XLSX by given coordinates and drawing relationships. +// embed in spreadsheet by given coordinates and drawing relationships. func (f *File) getPicture(row, col int, drawingXML, drawingRelationships string) (ret string, buf []byte, err error) { var ( wsDr *xlsxWsDr diff --git a/rows.go b/rows.go index 392cc5d4..87576c33 100644 --- a/rows.go +++ b/rows.go @@ -282,10 +282,6 @@ func (f *File) sharedStringsReader() *xlsxSST { if f.SharedStrings == nil { var sharedStrings xlsxSST ss := f.readXML("xl/sharedStrings.xml") - if len(ss) == 0 { - ss = f.readXML("xl/SharedStrings.xml") - delete(f.XLSX, "xl/SharedStrings.xml") - } if err = f.xmlNewDecoder(bytes.NewReader(namespaceStrictToTransitional(ss))). Decode(&sharedStrings); err != nil && err != io.EOF { log.Printf("xml decode error: %s", err) diff --git a/sheet.go b/sheet.go index 56dac27d..bbe84c2d 100644 --- a/sheet.go +++ b/sheet.go @@ -32,8 +32,9 @@ import ( ) // NewSheet provides function to create a new sheet by given worksheet name. -// When creating a new XLSX file, the default sheet will be created. Returns -// the number of sheets in the workbook (file) after appending the new sheet. +// When creating a new spreadsheet file, the default worksheet will be +// created. Returns the number of sheets in the workbook (file) after +// appending the new sheet. func (f *File) NewSheet(name string) int { // Check if the worksheet already exists if f.GetSheetIndex(name) != -1 { @@ -152,7 +153,7 @@ func trimCell(column []xlsxC) []xlsxC { } // setContentTypes provides a function to read and update property of contents -// type of XLSX. +// type of the spreadsheet. func (f *File) setContentTypes(partName, contentType string) { content := f.contentTypesReader() content.Overrides = append(content.Overrides, xlsxOverride{ @@ -174,8 +175,8 @@ func (f *File) setSheet(index int, name string) { f.Sheet[path] = &xlsx } -// setWorkbook update workbook property of XLSX. Maximum 31 characters are -// allowed in sheet title. +// setWorkbook update workbook property of the spreadsheet. Maximum 31 +// characters are allowed in sheet title. func (f *File) setWorkbook(name string, sheetID, rid int) { content := f.workbookReader() content.Sheets.Sheet = append(content.Sheets.Sheet, xlsxSheet{ @@ -204,9 +205,9 @@ func (f *File) setAppXML() { f.saveFileList("docProps/app.xml", []byte(templateDocpropsApp)) } -// replaceRelationshipsBytes; Some tools that read XLSX files have very strict -// requirements about the structure of the input XML. This function is a -// horrible hack to fix that after the XML marshalling is completed. +// replaceRelationshipsBytes; Some tools that read spreadsheet files have very +// strict requirements about the structure of the input XML. This function is +// a horrible hack to fix that after the XML marshalling is completed. func replaceRelationshipsBytes(content []byte) []byte { oldXmlns := stringToBytes(`xmlns:relationships="http://schemas.openxmlformats.org/officeDocument/2006/relationships" relationships`) newXmlns := stringToBytes("r") @@ -263,7 +264,7 @@ func (f *File) SetActiveSheet(index int) { } // GetActiveSheetIndex provides a function to get active sheet index of the -// XLSX. If not found the active sheet will be return integer 0. +// spreadsheet. If not found the active sheet will be return integer 0. func (f *File) GetActiveSheetIndex() (index int) { var sheetID = f.getActiveSheetID() wb := f.workbookReader() @@ -278,7 +279,7 @@ func (f *File) GetActiveSheetIndex() (index int) { } // getActiveSheetID provides a function to get active sheet index of the -// XLSX. If not found the active sheet will be return integer 0. +// spreadsheet. If not found the active sheet will be return integer 0. func (f *File) getActiveSheetID() int { wb := f.workbookReader() if wb != nil { @@ -313,9 +314,9 @@ func (f *File) SetSheetName(oldName, newName string) { } } -// getSheetNameByID provides a function to get worksheet name of XLSX by given -// worksheet ID. If given sheet ID is invalid, will return an empty -// string. +// getSheetNameByID provides a function to get worksheet name of the +// spreadsheet by given worksheet ID. If given sheet ID is invalid, will +// return an empty string. func (f *File) getSheetNameByID(ID int) string { wb := f.workbookReader() if wb == nil || ID < 1 { @@ -341,9 +342,9 @@ func (f *File) GetSheetName(index int) (name string) { return } -// getSheetID provides a function to get worksheet ID of XLSX by given -// sheet name. If given worksheet name is invalid, will return an integer type -// value -1. +// 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 { var ID = -1 for sheetID, sheet := range f.GetSheetMap() {