summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRi Xu <xuri.me@gmail.com>2017-01-19 14:05:32 +0800
committerRi Xu <xuri.me@gmail.com>2017-01-19 14:05:32 +0800
commit4a9b39afc634a2399c4729f4fb47c9f290ab1ee5 (patch)
tree71d673195ccae30d6ef174611f6cf362be7e9133
parent52796f6e58e95145e2964d0d313a2f721dcc040e (diff)
- Add hyperlink and set formula support for cell support;
- Character limits for cells added; - Update go test and fix typo
-rw-r--r--README.md7
-rw-r--r--cell.go63
-rw-r--r--excelize.go6
-rw-r--r--excelize_test.go181
-rw-r--r--picture.go11
-rw-r--r--sheet.go9
-rw-r--r--xmlDrawing.go1
-rw-r--r--xmlWorkbook.go9
8 files changed, 196 insertions, 91 deletions
diff --git a/README.md b/README.md
index 1c77058..f9ead95 100644
--- a/README.md
+++ b/README.md
@@ -106,7 +106,7 @@ func main() {
}
```
-### Add pictures to XLSX files
+### Add picture to XLSX files
```go
package main
@@ -125,6 +125,11 @@ func main() {
fmt.Println(err)
os.Exit(1)
}
+ err = xlsx.WriteTo("/tmp/Workbook.xlsx")
+ if err != nil {
+ fmt.Println(err)
+ os.Exit(1)
+ }
}
```
diff --git a/cell.go b/cell.go
index f91b661..5f8439e 100644
--- a/cell.go
+++ b/cell.go
@@ -6,8 +6,9 @@ import (
"strings"
)
-// GetCellValue provide function get value from cell by given sheet index and
-// axis in XLSX file. The value of the merged cell is not available currently.
+// GetCellValue provides function to get value from cell by given sheet index
+// and axis in XLSX file. The value of the merged cell is not available
+// currently.
func (f *File) GetCellValue(sheet string, axis string) string {
axis = strings.ToUpper(axis)
var xlsx xlsxWorksheet
@@ -50,8 +51,8 @@ func (f *File) GetCellValue(sheet string, axis string) string {
return ""
}
-// GetCellFormula provide function get formula from cell by given sheet index
-// and axis in XLSX file.
+// GetCellFormula provides function to get formula from cell by given sheet
+// index and axis in XLSX file.
func (f *File) GetCellFormula(sheet string, axis string) string {
axis = strings.ToUpper(axis)
var xlsx xlsxWorksheet
@@ -84,3 +85,57 @@ func (f *File) GetCellFormula(sheet string, axis string) string {
}
return ""
}
+
+// SetCellHyperLink provides function to set cell hyperlink by given sheet index
+// and link URL address. Only support external link currently.
+func (f *File) SetCellHyperLink(sheet, axis, link string) {
+ axis = strings.ToUpper(axis)
+ var xlsx xlsxWorksheet
+ name := "xl/worksheets/" + strings.ToLower(sheet) + ".xml"
+ xml.Unmarshal([]byte(f.readXML(name)), &xlsx)
+ rID := f.addSheetRelationships(sheet, SourceRelationshipHyperLink, link, "External")
+ hyperlink := xlsxHyperlink{
+ Ref: axis,
+ RID: "rId" + strconv.Itoa(rID),
+ }
+ if xlsx.Hyperlinks != nil {
+ xlsx.Hyperlinks.Hyperlink = append(xlsx.Hyperlinks.Hyperlink, hyperlink)
+ } else {
+ hyperlinks := xlsxHyperlinks{}
+ hyperlinks.Hyperlink = append(hyperlinks.Hyperlink, hyperlink)
+ xlsx.Hyperlinks = &hyperlinks
+ }
+ output, _ := xml.Marshal(xlsx)
+ f.saveFileList(name, replaceWorkSheetsRelationshipsNameSpace(string(output)))
+}
+
+// SetCellFormula provides function to set cell formula by given string and
+// sheet index.
+func (f *File) SetCellFormula(sheet, axis, formula string) {
+ axis = strings.ToUpper(axis)
+ var xlsx xlsxWorksheet
+ col := string(strings.Map(letterOnlyMapF, axis))
+ row, _ := strconv.Atoi(strings.Map(intOnlyMapF, axis))
+ xAxis := row - 1
+ yAxis := titleToNumber(col)
+
+ name := "xl/worksheets/" + strings.ToLower(sheet) + ".xml"
+ xml.Unmarshal([]byte(f.readXML(name)), &xlsx)
+
+ rows := xAxis + 1
+ cell := yAxis + 1
+
+ xlsx = completeRow(xlsx, rows, cell)
+ xlsx = completeCol(xlsx, rows, cell)
+
+ if xlsx.SheetData.Row[xAxis].C[yAxis].F != nil {
+ xlsx.SheetData.Row[xAxis].C[yAxis].F.Content = formula
+ } else {
+ f := xlsxF{
+ Content: formula,
+ }
+ xlsx.SheetData.Row[xAxis].C[yAxis].F = &f
+ }
+ output, _ := xml.Marshal(xlsx)
+ f.saveFileList(name, replaceWorkSheetsRelationshipsNameSpace(string(output)))
+}
diff --git a/excelize.go b/excelize.go
index fed9613..d43f123 100644
--- a/excelize.go
+++ b/excelize.go
@@ -85,9 +85,13 @@ func (f *File) SetCellInt(sheet string, axis string, value int) {
f.saveFileList(name, replaceWorkSheetsRelationshipsNameSpace(string(output)))
}
-// SetCellStr provides function to set string type value of a cell.
+// SetCellStr provides function to set string type value of a cell. Total number
+// of characters that a cell can contain 32767 characters.
func (f *File) SetCellStr(sheet string, axis string, value string) {
axis = strings.ToUpper(axis)
+ if len(value) > 32767 {
+ value = value[0:32767]
+ }
var xlsx xlsxWorksheet
col := string(strings.Map(letterOnlyMapF, axis))
row, _ := strconv.Atoi(strings.Map(intOnlyMapF, axis))
diff --git a/excelize_test.go b/excelize_test.go
index 6e41968..278912b 100644
--- a/excelize_test.go
+++ b/excelize_test.go
@@ -7,108 +7,119 @@ import (
func TestOpenFile(t *testing.T) {
// Test update a XLSX file.
- f1, err := OpenFile("./test/Workbook1.xlsx")
+ xlsx, err := OpenFile("./test/Workbook1.xlsx")
if err != nil {
t.Log(err)
}
// Test get all the rows in a not exists sheet.
- rows := f1.GetRows("Sheet4")
+ rows := xlsx.GetRows("Sheet4")
// Test get all the rows in a sheet.
- rows = f1.GetRows("Sheet2")
+ rows = xlsx.GetRows("Sheet2")
for _, row := range rows {
for _, cell := range row {
t.Log(cell, "\t")
}
t.Log("\r\n")
}
- f1.UpdateLinkedValue()
- f1.SetCellDefault("SHEET2", "A1", strconv.FormatFloat(float64(100.1588), 'f', -1, 32))
- f1.SetCellDefault("SHEET2", "A1", strconv.FormatFloat(float64(-100.1588), 'f', -1, 64))
- f1.SetCellInt("SHEET2", "A1", 100)
- f1.SetCellStr("SHEET2", "C11", "Knowns")
- f1.NewSheet(3, ":\\/?*[]Maximum 31 characters allowed in sheet title.")
+ xlsx.UpdateLinkedValue()
+ xlsx.SetCellDefault("SHEET2", "A1", strconv.FormatFloat(float64(100.1588), 'f', -1, 32))
+ xlsx.SetCellDefault("SHEET2", "A1", strconv.FormatFloat(float64(-100.1588), 'f', -1, 64))
+ xlsx.SetCellInt("SHEET2", "A1", 100)
+ xlsx.SetCellStr("SHEET2", "C11", "Knowns")
+ // Test max characters in a cell.
+ var s = "c"
+ for i := 0; i < 32768; i++ {
+ s += "c"
+ }
+ xlsx.SetCellStr("SHEET2", "D11", s)
+ xlsx.NewSheet(3, ":\\/?*[]Maximum 31 characters allowed in sheet title.")
// Test set sheet name with illegal name.
- f1.SetSheetName("Maximum 31 characters allowed i", "[Rename]:\\/?* Maximum 31 characters allowed in sheet title.")
- f1.SetCellInt("Sheet3", "A23", 10)
- f1.SetCellStr("SHEET3", "b230", "10")
- f1.SetCellStr("SHEET10", "b230", "10")
- f1.SetActiveSheet(2)
- f1.GetCellFormula("Sheet1", "B19") // Test get cell formula with given rows number.
- f1.GetCellFormula("Sheet2", "B20") // Test get cell formula with illegal sheet index.
- f1.GetCellFormula("Sheet1", "B20") // Test get cell formula with illegal rows number.
+ xlsx.SetSheetName("Maximum 31 characters allowed i", "[Rename]:\\/?* Maximum 31 characters allowed in sheet title.")
+ xlsx.SetCellInt("Sheet3", "A23", 10)
+ xlsx.SetCellStr("SHEET3", "b230", "10")
+ xlsx.SetCellStr("SHEET10", "b230", "10")
+ xlsx.SetActiveSheet(2)
+ xlsx.GetCellFormula("Sheet1", "B19") // Test get cell formula with given rows number.
+ xlsx.GetCellFormula("Sheet2", "B20") // Test get cell formula with illegal sheet index.
+ xlsx.GetCellFormula("Sheet1", "B20") // Test get cell formula with illegal rows number.
// Test read cell value with given illegal rows number.
- f1.GetCellValue("Sheet2", "a-1")
+ xlsx.GetCellValue("Sheet2", "a-1")
// Test read cell value with given lowercase column number.
- f1.GetCellValue("Sheet2", "a5")
- f1.GetCellValue("Sheet2", "C11")
- f1.GetCellValue("Sheet2", "D11")
- f1.GetCellValue("Sheet2", "D12")
+ xlsx.GetCellValue("Sheet2", "a5")
+ xlsx.GetCellValue("Sheet2", "C11")
+ xlsx.GetCellValue("Sheet2", "D11")
+ xlsx.GetCellValue("Sheet2", "D12")
// Test SetCellValue function.
- f1.SetCellValue("Sheet2", "F1", "Hello")
- f1.SetCellValue("Sheet2", "G1", []byte("World"))
- f1.SetCellValue("Sheet2", "F2", 42)
- f1.SetCellValue("Sheet2", "F2", int8(42))
- f1.SetCellValue("Sheet2", "F2", int16(42))
- f1.SetCellValue("Sheet2", "F2", int32(42))
- f1.SetCellValue("Sheet2", "F2", int64(42))
- f1.SetCellValue("Sheet2", "F2", float32(42.65418))
- f1.SetCellValue("Sheet2", "F2", float64(-42.65418))
- f1.SetCellValue("Sheet2", "F2", float32(42))
- f1.SetCellValue("Sheet2", "F2", float64(42))
- f1.SetCellValue("Sheet2", "G2", nil)
+ xlsx.SetCellValue("Sheet2", "F1", "Hello")
+ xlsx.SetCellValue("Sheet2", "G1", []byte("World"))
+ xlsx.SetCellValue("Sheet2", "F2", 42)
+ xlsx.SetCellValue("Sheet2", "F2", int8(42))
+ xlsx.SetCellValue("Sheet2", "F2", int16(42))
+ xlsx.SetCellValue("Sheet2", "F2", int32(42))
+ xlsx.SetCellValue("Sheet2", "F2", int64(42))
+ xlsx.SetCellValue("Sheet2", "F2", float32(42.65418))
+ xlsx.SetCellValue("Sheet2", "F2", float64(-42.65418))
+ xlsx.SetCellValue("Sheet2", "F2", float32(42))
+ xlsx.SetCellValue("Sheet2", "F2", float64(42))
+ xlsx.SetCellValue("Sheet2", "G2", nil)
// Test completion column.
- f1.SetCellValue("Sheet2", "M2", nil)
+ xlsx.SetCellValue("Sheet2", "M2", nil)
// Test read cell value with given axis large than exists row.
- f1.GetCellValue("Sheet2", "E231")
+ xlsx.GetCellValue("Sheet2", "E231")
// Test get active sheet of XLSX and get sheet name of XLSX by given sheet index.
- f1.GetSheetName(f1.GetActiveSheetIndex())
+ xlsx.GetSheetName(xlsx.GetActiveSheetIndex())
// Test get sheet name of XLSX by given invalid sheet index.
- f1.GetSheetName(4)
+ xlsx.GetSheetName(4)
// Test get sheet map of XLSX.
- f1.GetSheetMap()
-
+ xlsx.GetSheetMap()
for i := 1; i <= 300; i++ {
- f1.SetCellStr("SHEET3", "c"+strconv.Itoa(i), strconv.Itoa(i))
+ xlsx.SetCellStr("SHEET3", "c"+strconv.Itoa(i), strconv.Itoa(i))
+ }
+ err = xlsx.Save()
+ if err != nil {
+ t.Log(err)
+ }
+ // Test write file to not exist directory.
+ err = xlsx.WriteTo("")
+ if err != nil {
+ t.Log(err)
}
- err = f1.Save()
+}
+
+func TestAddPicture(t *testing.T) {
+ xlsx, err := OpenFile("./test/Workbook1.xlsx")
if err != nil {
t.Log(err)
}
// Test add picture to sheet.
- err = f1.AddPicture("Sheet2", "I1", "L10", "./test/images/excel.jpg")
+ err = xlsx.AddPicture("Sheet2", "I1", "L10", "./test/images/excel.jpg")
if err != nil {
t.Log(err)
}
- err = f1.AddPicture("Sheet1", "F21", "G25", "./test/images/excel.png")
+ err = xlsx.AddPicture("Sheet1", "F21", "G25", "./test/images/excel.png")
if err != nil {
t.Log(err)
}
- err = f1.AddPicture("Sheet2", "L1", "O10", "./test/images/excel.bmp")
+ err = xlsx.AddPicture("Sheet2", "L1", "O10", "./test/images/excel.bmp")
if err != nil {
t.Log(err)
}
- err = f1.AddPicture("Sheet1", "G21", "H25", "./test/images/excel.ico")
+ err = xlsx.AddPicture("Sheet1", "G21", "H25", "./test/images/excel.ico")
if err != nil {
t.Log(err)
}
// Test add picture to sheet with unsupport file type.
- err = f1.AddPicture("Sheet1", "G21", "H25", "./test/images/excel.icon")
+ err = xlsx.AddPicture("Sheet1", "G21", "H25", "./test/images/excel.icon")
if err != nil {
t.Log(err)
}
// Test add picture to sheet with invalid file path.
- err = f1.AddPicture("Sheet1", "G21", "H25", "./test/Workbook1.xlsx")
+ err = xlsx.AddPicture("Sheet1", "G21", "H25", "./test/Workbook1.xlsx")
if err != nil {
t.Log(err)
}
-
// Test write file to given path.
- err = f1.WriteTo("./test/Workbook_2.xlsx")
- if err != nil {
- t.Log(err)
- }
- // Test write file to not exist directory.
- err = f1.WriteTo("")
+ err = xlsx.WriteTo("./test/Workbook_2.xlsx")
if err != nil {
t.Log(err)
}
@@ -116,13 +127,13 @@ func TestOpenFile(t *testing.T) {
func TestBrokenFile(t *testing.T) {
// Test write file with broken file struct.
- f2 := File{}
- err := f2.Save()
+ xlsx := File{}
+ err := xlsx.Save()
if err != nil {
t.Log(err)
}
// Test write file with broken file struct with given path.
- err = f2.WriteTo("./test/Workbook_3.xlsx")
+ err = xlsx.WriteTo("./test/Workbook_3.xlsx")
if err != nil {
t.Log(err)
}
@@ -143,35 +154,63 @@ func TestBrokenFile(t *testing.T) {
func TestCreateFile(t *testing.T) {
// Test create a XLSX file.
- f4 := CreateFile()
- f4.NewSheet(2, "XLSXSheet2")
- f4.NewSheet(3, "XLSXSheet3")
- f4.SetCellInt("Sheet2", "A23", 56)
- f4.SetCellStr("SHEET1", "B20", "42")
- f4.SetActiveSheet(0)
+ xlsx := CreateFile()
+ xlsx.NewSheet(2, "XLSXSheet2")
+ xlsx.NewSheet(3, "XLSXSheet3")
+ xlsx.SetCellInt("Sheet2", "A23", 56)
+ xlsx.SetCellStr("SHEET1", "B20", "42")
+ xlsx.SetActiveSheet(0)
// Test add picture to sheet.
- err := f4.AddPicture("Sheet1", "H2", "K12", "./test/images/excel.gif")
+ err := xlsx.AddPicture("Sheet1", "H2", "K12", "./test/images/excel.gif")
if err != nil {
t.Log(err)
}
- err = f4.AddPicture("Sheet1", "C2", "F12", "./test/images/excel.tif")
+ err = xlsx.AddPicture("Sheet1", "C2", "F12", "./test/images/excel.tif")
if err != nil {
t.Log(err)
}
- err = f4.WriteTo("./test/Workbook_3.xlsx")
+ err = xlsx.WriteTo("./test/Workbook_3.xlsx")
if err != nil {
t.Log(err)
}
}
func TestSetColWidth(t *testing.T) {
- f5, err := OpenFile("./test/Workbook1.xlsx")
+ xlsx, err := OpenFile("./test/Workbook1.xlsx")
+ if err != nil {
+ t.Log(err)
+ }
+ xlsx.SetColWidth("sheet1", "B", "A", 12)
+ xlsx.SetColWidth("sheet1", "A", "B", 12)
+ err = xlsx.Save()
+ if err != nil {
+ t.Log(err)
+ }
+}
+
+func TestSetCellHyperLink(t *testing.T) {
+ xlsx, err := OpenFile("./test/Workbook1.xlsx")
+ if err != nil {
+ t.Log(err)
+ }
+ // Test set cell hyperlink in a work sheet already have hyperlinks.
+ xlsx.SetCellHyperLink("sheet1", "B19", "https://github.com/Luxurioust/excelize")
+ // Test add first hyperlink in a work sheet.
+ xlsx.SetCellHyperLink("sheet2", "C1", "https://github.com/Luxurioust/excelize")
+ err = xlsx.Save()
+ if err != nil {
+ t.Log(err)
+ }
+}
+
+func TestSetCellFormula(t *testing.T) {
+ xlsx, err := OpenFile("./test/Workbook1.xlsx")
if err != nil {
t.Log(err)
}
- f5.SetColWidth("sheet1", "B", "A", 12)
- f5.SetColWidth("sheet1", "A", "B", 12)
- err = f5.Save()
+ xlsx.SetCellFormula("sheet1", "B19", "SUM(Sheet2!D2,Sheet2!D11)")
+ xlsx.SetCellFormula("sheet1", "C19", "SUM(Sheet2!D2,Sheet2!D9)")
+ err = xlsx.Save()
if err != nil {
t.Log(err)
}
diff --git a/picture.go b/picture.go
index 62559de..bbd7cf3 100644
--- a/picture.go
+++ b/picture.go
@@ -53,7 +53,7 @@ func (f *File) AddPicture(sheet string, xAxis string, yAxis string, picture stri
drawingXML = strings.Replace(sheetRelationshipsDrawingXML, "..", "xl", -1)
} else {
// Add first picture for given sheet.
- rID := f.addSheetRelationships(sheet, SourceRelationshipDrawingML, sheetRelationshipsDrawingXML)
+ rID := f.addSheetRelationships(sheet, SourceRelationshipDrawingML, sheetRelationshipsDrawingXML, "")
f.addSheetDrawing(sheet, rID)
}
drawingRID = f.addDrawingRelationships(drawingID, SourceRelationshipImage, "../media/image"+strconv.Itoa(pictureID)+ext)
@@ -66,7 +66,7 @@ func (f *File) AddPicture(sheet string, xAxis string, yAxis string, picture stri
// addSheetRelationships provides function to add
// xl/worksheets/_rels/sheet%d.xml.rels by given sheet name, relationship type
// and target.
-func (f *File) addSheetRelationships(sheet string, relType string, target string) int {
+func (f *File) addSheetRelationships(sheet, relType, target, targetMode string) int {
var rels = "xl/worksheets/_rels/" + strings.ToLower(sheet) + ".xml.rels"
var sheetRels xlsxWorkbookRels
var rID = 1
@@ -82,9 +82,10 @@ func (f *File) addSheetRelationships(sheet string, relType string, target string
ID.WriteString(strconv.Itoa(rID))
}
sheetRels.Relationships = append(sheetRels.Relationships, xlsxWorkbookRelation{
- ID: ID.String(),
- Type: relType,
- Target: target,
+ ID: ID.String(),
+ Type: relType,
+ Target: target,
+ TargetMode: targetMode,
})
output, err := xml.Marshal(sheetRels)
if err != nil {
diff --git a/sheet.go b/sheet.go
index 3f117af..a3df037 100644
--- a/sheet.go
+++ b/sheet.go
@@ -8,10 +8,9 @@ import (
"strings"
)
-// Sprint formats using the default formats for its operands and returns the
-// resulting string. NewSheet provice function to greate a new sheet by given
-// index, when creating a new XLSX file, the default sheet will be create, when
-// you create a new file, you need to ensure that the index is continuous.
+// NewSheet provice function to greate a new sheet by given index, when creating
+// a new XLSX file, the default sheet will be create, when you create a new
+// file, you need to ensure that the index is continuous.
func (f *File) NewSheet(index int, name string) {
// Update docProps/app.xml
f.setAppXML()
@@ -126,7 +125,7 @@ func replaceRelationshipsNameSpace(workbookMarshal string) string {
return strings.Replace(workbookMarshal, oldXmlns, newXmlns, -1)
}
-// SetActiveSheet provide function to set default active sheet of XLSX by given
+// SetActiveSheet provides function to set default active sheet of XLSX by given
// index.
func (f *File) SetActiveSheet(index int) {
var content xlsxWorkbook
diff --git a/xmlDrawing.go b/xmlDrawing.go
index 89854ec..efcfa81 100644
--- a/xmlDrawing.go
+++ b/xmlDrawing.go
@@ -5,6 +5,7 @@ const (
SourceRelationship = "http://schemas.openxmlformats.org/officeDocument/2006/relationships"
SourceRelationshipImage = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image"
SourceRelationshipDrawingML = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/drawing"
+ SourceRelationshipHyperLink = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink"
SourceRelationshipWorkSheet = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet"
NameSpaceDrawingML = "http://schemas.openxmlformats.org/drawingml/2006/main"
NameSpaceSpreadSheetDrawing = "http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing"
diff --git a/xmlWorkbook.go b/xmlWorkbook.go
index 775d01b..22e9e48 100644
--- a/xmlWorkbook.go
+++ b/xmlWorkbook.go
@@ -16,11 +16,12 @@ type xlsxWorkbookRels struct {
Relationships []xlsxWorkbookRelation `xml:"Relationship"`
}
-// xmlxWorkbookRelation maps sheet id and xl/worksheets/sheet%d.xml
+// xmlxWorkbookRelation maps sheet id and xl/worksheets/_rels/sheet%d.xml.rels
type xlsxWorkbookRelation struct {
- ID string `xml:"Id,attr"`
- Target string `xml:",attr"`
- Type string `xml:",attr"`
+ ID string `xml:"Id,attr"`
+ Target string `xml:",attr"`
+ Type string `xml:",attr"`
+ TargetMode string `xml:",attr,omitempty"`
}
// xlsxWorkbook directly maps the workbook element from the namespace