Jelajahi Sumber

Resolve #217, new function add VBA project supported.

xuri 6 tahun lalu
induk
melakukan
35e485756f
4 mengubah file dengan 89 tambahan dan 0 penghapusan
  1. 77 0
      excelize.go
  2. 11 0
      excelize_test.go
  3. TEMPAT SAMPAH
      test/vbaProject.bin
  4. 1 0
      xmlDrawing.go

+ 77 - 0
excelize.go

@@ -19,7 +19,9 @@ import (
 	"io"
 	"io"
 	"io/ioutil"
 	"io/ioutil"
 	"os"
 	"os"
+	"path"
 	"strconv"
 	"strconv"
+	"strings"
 )
 )
 
 
 // File define a populated XLSX file struct.
 // File define a populated XLSX file struct.
@@ -226,3 +228,78 @@ func (f *File) UpdateLinkedValue() error {
 	}
 	}
 	return nil
 	return nil
 }
 }
+
+// AddVBAProject provides the method to add vbaProject.bin file which contains
+// functions and/or macros. The file extension should be .xlsm. For example:
+//
+//    err := f.SetSheetPrOptions("Sheet1", excelize.CodeName("Sheet1"))
+//    if err != nil {
+//        fmt.Println(err)
+//    }
+//    err = f.AddVBAProject("vbaProject.bin")
+//    if err != nil {
+//        fmt.Println(err)
+//    }
+//    err = f.SaveAs("macros.xlsm")
+//    if err != nil {
+//        fmt.Println(err)
+//    }
+//
+func (f *File) AddVBAProject(bin string) error {
+	var err error
+	// Check vbaProject.bin exists first.
+	if _, err = os.Stat(bin); os.IsNotExist(err) {
+		return err
+	}
+	if path.Ext(bin) != ".bin" {
+		return errors.New("unsupported VBA project extension")
+	}
+	f.setContentTypePartVBAProjectExtensions()
+	wb := f.workbookRelsReader()
+	var rID int
+	var ok bool
+	for _, rel := range wb.Relationships {
+		if rel.Target == "vbaProject.bin" && rel.Type == SourceRelationshipVBAProject {
+			ok = true
+			continue
+		}
+		t, _ := strconv.Atoi(strings.TrimPrefix(rel.ID, "rId"))
+		if t > rID {
+			rID = t
+		}
+	}
+	rID++
+	if !ok {
+		wb.Relationships = append(wb.Relationships, xlsxWorkbookRelation{
+			ID:     "rId" + strconv.Itoa(rID),
+			Target: "vbaProject.bin",
+			Type:   SourceRelationshipVBAProject,
+		})
+	}
+	file, _ := ioutil.ReadFile(bin)
+	f.XLSX["xl/vbaProject.bin"] = file
+	return err
+}
+
+// setContentTypePartVBAProjectExtensions provides a function to set the
+// content type for relationship parts and the main document part.
+func (f *File) setContentTypePartVBAProjectExtensions() {
+	var ok bool
+	content := f.contentTypesReader()
+	for _, v := range content.Defaults {
+		if v.Extension == "bin" {
+			ok = true
+		}
+	}
+	for idx, o := range content.Overrides {
+		if o.PartName == "/xl/workbook.xml" {
+			content.Overrides[idx].ContentType = "application/vnd.ms-excel.sheet.macroEnabled.main+xml"
+		}
+	}
+	if !ok {
+		content.Defaults = append(content.Defaults, xlsxDefault{
+			Extension:   "bin",
+			ContentType: "application/vnd.ms-office.vbaProject",
+		})
+	}
+}

+ 11 - 0
excelize_test.go

@@ -1078,6 +1078,17 @@ func TestSetDefaultTimeStyle(t *testing.T) {
 	assert.EqualError(t, f.setDefaultTimeStyle("SheetN", "", 0), "sheet SheetN is not exist")
 	assert.EqualError(t, f.setDefaultTimeStyle("SheetN", "", 0), "sheet SheetN is not exist")
 }
 }
 
 
+func TestAddVBAProject(t *testing.T) {
+	f := NewFile()
+	assert.NoError(t, f.SetSheetPrOptions("Sheet1", CodeName("Sheet1")))
+	assert.EqualError(t, f.AddVBAProject("macros.bin"), "stat macros.bin: no such file or directory")
+	assert.EqualError(t, f.AddVBAProject(filepath.Join("test", "Book1.xlsx")), "unsupported VBA project extension")
+	assert.NoError(t, f.AddVBAProject(filepath.Join("test", "vbaProject.bin")))
+	// Test add VBA project twice.
+	assert.NoError(t, f.AddVBAProject(filepath.Join("test", "vbaProject.bin")))
+	assert.NoError(t, f.SaveAs(filepath.Join("test", "TestAddVBAProject.xlsm")))
+}
+
 func prepareTestBook1() (*File, error) {
 func prepareTestBook1() (*File, error) {
 	f, err := OpenFile(filepath.Join("test", "Book1.xlsx"))
 	f, err := OpenFile(filepath.Join("test", "Book1.xlsx"))
 	if err != nil {
 	if err != nil {

TEMPAT SAMPAH
test/vbaProject.bin


+ 1 - 0
xmlDrawing.go

@@ -22,6 +22,7 @@ const (
 	SourceRelationshipDrawingVML         = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/vmlDrawing"
 	SourceRelationshipDrawingVML         = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/vmlDrawing"
 	SourceRelationshipHyperLink          = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink"
 	SourceRelationshipHyperLink          = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink"
 	SourceRelationshipWorkSheet          = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet"
 	SourceRelationshipWorkSheet          = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet"
+	SourceRelationshipVBAProject         = "http://schemas.microsoft.com/office/2006/relationships/vbaProject"
 	SourceRelationshipChart201506        = "http://schemas.microsoft.com/office/drawing/2015/06/chart"
 	SourceRelationshipChart201506        = "http://schemas.microsoft.com/office/drawing/2015/06/chart"
 	SourceRelationshipChart20070802      = "http://schemas.microsoft.com/office/drawing/2007/8/2/chart"
 	SourceRelationshipChart20070802      = "http://schemas.microsoft.com/office/drawing/2007/8/2/chart"
 	SourceRelationshipChart2014          = "http://schemas.microsoft.com/office/drawing/2014/chart"
 	SourceRelationshipChart2014          = "http://schemas.microsoft.com/office/drawing/2014/chart"