浏览代码

- Initialize table support;
- go test updated

Ri Xu 8 年之前
父节点
当前提交
46b8c46d91
共有 7 个文件被更改,包括 273 次插入4 次删除
  1. 1 1
      README.md
  2. 1 1
      chart.go
  3. 14 0
      excelize_test.go
  4. 1 1
      picture.go
  5. 170 0
      table.go
  6. 3 1
      xmlDrawing.go
  7. 83 0
      xmlTable.go

+ 1 - 1
README.md

@@ -11,7 +11,7 @@
 
 ## Introduction
 
-Excelize is a library written in pure Golang and providing a set of functions that allow you to write to and read from XLSX files. Support reads and writes XLSX file generated by Office Excel 2007 and later. Support save file without losing original charts of XLSX. This library needs Go version 1.8 or later. The full API docs can be seen using go's built-in documentation tool, or online at [godoc.org](https://godoc.org/github.com/Luxurioust/excelize).
+Excelize is a library written in pure Golang and providing a set of functions that allow you to write to and read from XLSX files. Support reads and writes XLSX file generated by Microsoft Excel™ 2007 and later. Support save file without losing original charts of XLSX. This library needs Go version 1.8 or later. The full API docs can be seen using go's built-in documentation tool, or online at [godoc.org](https://godoc.org/github.com/Luxurioust/excelize).
 
 ## Basic Usage
 

+ 1 - 1
chart.go

@@ -848,7 +848,7 @@ func (f *File) addDrawingChart(sheet, drawingXML, cell string, width, height, rI
 	colStart, rowStart, _, _, colEnd, rowEnd, x2, y2 := f.positionObjectPixels(sheet, col, row, formatSet.OffsetX, formatSet.OffsetY, width, height)
 	content := encodeWsDr{}
 	content.WsDr.A = NameSpaceDrawingML
-	content.WsDr.Xdr = NameSpaceSpreadSheetDrawing
+	content.WsDr.Xdr = NameSpaceDrawingMLSpreadSheet
 	cNvPrID := 1
 	_, ok := f.XLSX[drawingXML]
 	if ok { // Append Model

+ 14 - 0
excelize_test.go

@@ -472,6 +472,20 @@ func TestCopySheet(t *testing.T) {
 	}
 }
 
+func TestAddTable(t *testing.T) {
+	xlsx, err := OpenFile("./test/Workbook_2.xlsx")
+	if err != nil {
+		t.Log(err)
+	}
+	xlsx.AddTable("Sheet1", "B26", "A21", ``)
+	xlsx.AddTable("Sheet2", "A2", "B5", `{"table_style":"TableStyleMedium2", "show_first_column":true,"show_last_column":true,"show_row_stripes":false,"show_column_stripes":true}`)
+	xlsx.AddTable("Sheet2", "F1", "F1", `{"table_style":"TableStyleMedium8"}`)
+	err = xlsx.Save()
+	if err != nil {
+		t.Log(err)
+	}
+}
+
 func TestAddChart(t *testing.T) {
 	xlsx, err := OpenFile("./test/Workbook1.xlsx")
 	if err != nil {

+ 1 - 1
picture.go

@@ -189,7 +189,7 @@ func (f *File) addDrawingPicture(sheet, drawingXML, cell, file string, width, he
 	colStart, rowStart, _, _, colEnd, rowEnd, x2, y2 := f.positionObjectPixels(sheet, col, row, formatSet.OffsetX, formatSet.OffsetY, width, height)
 	content := encodeWsDr{}
 	content.WsDr.A = NameSpaceDrawingML
-	content.WsDr.Xdr = NameSpaceSpreadSheetDrawing
+	content.WsDr.Xdr = NameSpaceDrawingMLSpreadSheet
 	cNvPrID := 1
 	_, ok := f.XLSX[drawingXML]
 	if ok { // Append Model

+ 170 - 0
table.go

@@ -0,0 +1,170 @@
+package excelize
+
+import (
+	"encoding/json"
+	"encoding/xml"
+	"strconv"
+	"strings"
+)
+
+// parseFormatTableSet provides function to parse the format settings of the
+// table with default value.
+func parseFormatTableSet(formatSet string) *formatTable {
+	format := formatTable{
+		TableStyle:     "",
+		ShowRowStripes: true,
+	}
+	json.Unmarshal([]byte(formatSet), &format)
+	return &format
+}
+
+// AddTable provides the method to add table in a worksheet by given sheet
+// index, coordinate area and format set. For example, create a table of A1:D5
+// on Sheet1:
+//
+//    xlsx.AddTable("Sheet1", "A1", "D5", ``)
+//
+// Create a table of F2:H6 on Sheet2 with format set:
+//
+//    xlsx.AddTable("Sheet2", "F2", "H6", `{"table_style":"TableStyleMedium2", "show_first_column":true,"show_last_column":true,"show_row_stripes":false,"show_column_stripes":true}`)
+//
+// Note that the table at least two lines include string type header. The two
+// chart coordinate areas can not have an intersection.
+//
+// table_style: The built-in table style names
+//
+//    TableStyleLight1 - TableStyleLight21
+//    TableStyleMedium1 - TableStyleMedium28
+//    TableStyleDark1 - TableStyleDark11
+//
+func (f *File) AddTable(sheet, hcell, vcell, format string) {
+	formatSet := parseFormatTableSet(format)
+	hcell = strings.ToUpper(hcell)
+	vcell = strings.ToUpper(vcell)
+	// Coordinate conversion, convert C1:B3 to 2,0,1,2.
+	hcol := string(strings.Map(letterOnlyMapF, hcell))
+	hrow, _ := strconv.Atoi(strings.Map(intOnlyMapF, hcell))
+	hyAxis := hrow - 1
+	hxAxis := titleToNumber(hcol)
+
+	vcol := string(strings.Map(letterOnlyMapF, vcell))
+	vrow, _ := strconv.Atoi(strings.Map(intOnlyMapF, vcell))
+	vyAxis := vrow - 1
+	vxAxis := titleToNumber(vcol)
+	if vxAxis < hxAxis {
+		hcell, vcell = vcell, hcell
+		vxAxis, hxAxis = hxAxis, vxAxis
+	}
+	if vyAxis < hyAxis {
+		hcell, vcell = vcell, hcell
+		vyAxis, hyAxis = hyAxis, vyAxis
+	}
+	tableID := f.countTables() + 1
+	sheetRelationshipsTableXML := "../tables/table" + strconv.Itoa(tableID) + ".xml"
+	tableXML := strings.Replace(sheetRelationshipsTableXML, "..", "xl", -1)
+	// Add first table for given sheet.
+	rID := f.addSheetRelationships(sheet, SourceRelationshipTable, sheetRelationshipsTableXML, "")
+	f.addSheetTable(sheet, rID)
+	f.addTable(sheet, tableXML, hxAxis, hyAxis, vxAxis, vyAxis, tableID, formatSet)
+	f.addTableContentTypePart(tableID)
+}
+
+// countTables provides function to get table files count storage in the folder
+// xl/tables.
+func (f *File) countTables() int {
+	count := 0
+	for k := range f.XLSX {
+		if strings.Contains(k, "xl/tables/table") {
+			count++
+		}
+	}
+	return count
+}
+
+// addSheetTable provides function to add tablePart element to
+// xl/worksheets/sheet%d.xml by given sheet name and relationship index.
+func (f *File) addSheetTable(sheet string, rID int) {
+	xlsx := f.workSheetReader(sheet)
+	table := &xlsxTablePart{
+		RID: "rId" + strconv.Itoa(rID),
+	}
+	if xlsx.TableParts != nil {
+		xlsx.TableParts.Count++
+		xlsx.TableParts.TableParts = append(xlsx.TableParts.TableParts, table)
+	} else {
+		xlsx.TableParts = &xlsxTableParts{
+			Count:      1,
+			TableParts: []*xlsxTablePart{table},
+		}
+	}
+
+}
+
+// addTable provides function to add table by given sheet index, coordinate area
+// and format set.
+func (f *File) addTable(sheet, tableXML string, hxAxis, hyAxis, vxAxis, vyAxis, i int, formatSet *formatTable) {
+	// Correct the minimum number of rows, the table at least two lines.
+	if hyAxis == vyAxis {
+		vyAxis++
+	}
+	// Correct table reference coordinate area, such correct C1:B3 to B1:C3.
+	ref := toAlphaString(hxAxis+1) + strconv.Itoa(hyAxis+1) + ":" + toAlphaString(vxAxis+1) + strconv.Itoa(vyAxis+1)
+	tableColumn := []*xlsxTableColumn{}
+	idx := 0
+	for i := hxAxis; i <= vxAxis; i++ {
+		idx++
+		cell := toAlphaString(i+1) + strconv.Itoa(hyAxis+1)
+		name := f.GetCellValue(sheet, cell)
+		if _, err := strconv.Atoi(name); err == nil {
+			f.SetCellStr(sheet, cell, name)
+		}
+		if name == "" {
+			name = "Column" + strconv.Itoa(idx)
+			f.SetCellStr(sheet, cell, name)
+		}
+		tableColumn = append(tableColumn, &xlsxTableColumn{
+			ID:   idx,
+			Name: name,
+		})
+	}
+	name := "Table" + strconv.Itoa(i)
+	t := xlsxTable{
+		XMLNS:       NameSpaceSpreadSheet,
+		ID:          i,
+		Name:        name,
+		DisplayName: name,
+		Ref:         ref,
+		AutoFilter: &xlsxAutoFilter{
+			Ref: ref,
+		},
+		TableColumns: &xlsxTableColumns{
+			Count:       idx,
+			TableColumn: tableColumn,
+		},
+		TableStyleInfo: &xlsxTableStyleInfo{
+			Name:              formatSet.TableStyle,
+			ShowFirstColumn:   formatSet.ShowFirstColumn,
+			ShowLastColumn:    formatSet.ShowLastColumn,
+			ShowRowStripes:    formatSet.ShowRowStripes,
+			ShowColumnStripes: formatSet.ShowColumnStripes,
+		},
+	}
+	table, _ := xml.Marshal(t)
+	f.saveFileList(tableXML, string(table))
+}
+
+// addTableContentTypePart provides function to add image part relationships
+// in the file [Content_Types].xml by given drawing index.
+func (f *File) addTableContentTypePart(index int) {
+	f.setContentTypePartImageExtensions()
+	content := f.contentTypesReader()
+	for _, v := range content.Overrides {
+		if v.PartName == "/xl/tables/table"+strconv.Itoa(index)+".xml" {
+			return
+		}
+	}
+	content.Overrides = append(content.Overrides, xlsxOverride{
+		PartName:    "/xl/tables/table" + strconv.Itoa(index) + ".xml",
+		ContentType: "application/vnd.openxmlformats-officedocument.spreadsheetml.table+xml",
+	})
+}

+ 3 - 1
xmlDrawing.go

@@ -5,6 +5,7 @@ const (
 	SourceRelationship              = "http://schemas.openxmlformats.org/officeDocument/2006/relationships"
 	SourceRelationshipChart         = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart"
 	SourceRelationshipImage         = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image"
+	SourceRelationshipTable         = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/table"
 	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"
@@ -14,7 +15,8 @@ const (
 	SourceRelationshipCompatibility = "http://schemas.openxmlformats.org/markup-compatibility/2006"
 	NameSpaceDrawingML              = "http://schemas.openxmlformats.org/drawingml/2006/main"
 	NameSpaceDrawingMLChart         = "http://schemas.openxmlformats.org/drawingml/2006/chart"
-	NameSpaceSpreadSheetDrawing     = "http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing"
+	NameSpaceDrawingMLSpreadSheet   = "http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing"
+	NameSpaceSpreadSheet            = "http://schemas.openxmlformats.org/spreadsheetml/2006/main"
 	NameSpaceXML                    = "http://www.w3.org/XML/1998/namespace"
 )
 

+ 83 - 0
xmlTable.go

@@ -0,0 +1,83 @@
+package excelize
+
+import "encoding/xml"
+
+// xlsxTable directly maps the table element. A table helps organize and provide
+// structure to lists of information in a worksheet. Tables have clearly labeled
+// columns, rows, and data regions. Tables make it easier for users to sort,
+// analyze, format, manage, add, and delete information. This element is the
+// root element for a table that is not a single cell XML table.
+type xlsxTable struct {
+	XMLName              xml.Name            `xml:"table"`
+	XMLNS                string              `xml:"xmlns,attr"`
+	DataCellStyle        string              `xml:"dataCellStyle,attr,omitempty"`
+	DataDxfID            int                 `xml:"dataDxfId,attr,omitempty"`
+	DisplayName          string              `xml:"displayName,attr,omitempty"`
+	HeaderRowBorderDxfID int                 `xml:"headerRowBorderDxfId,attr,omitempty"`
+	HeaderRowCellStyle   string              `xml:"headerRowCellStyle,attr,omitempty"`
+	HeaderRowCount       int                 `xml:"headerRowCount,attr,omitempty"`
+	HeaderRowDxfID       int                 `xml:"headerRowDxfId,attr,omitempty"`
+	ID                   int                 `xml:"id,attr"`
+	InsertRow            bool                `xml:"insertRow,attr,omitempty"`
+	InsertRowShift       bool                `xml:"insertRowShift,attr,omitempty"`
+	Name                 string              `xml:"name,attr"`
+	Published            bool                `xml:"published,attr,omitempty"`
+	Ref                  string              `xml:"ref,attr"`
+	TotalsRowCount       int                 `xml:"totalsRowCount,attr,omitempty"`
+	TotalsRowDxfID       int                 `xml:"totalsRowDxfId,attr,omitempty"`
+	TotalsRowShown       bool                `xml:"totalsRowShown,attr"`
+	AutoFilter           *xlsxAutoFilter     `xml:"autoFilter"`
+	TableColumns         *xlsxTableColumns   `xml:"tableColumns"`
+	TableStyleInfo       *xlsxTableStyleInfo `xml:"tableStyleInfo"`
+}
+
+// xlsxAutoFilter temporarily hides rows based on a filter criteria, which is
+// applied column by column to a table of data in the worksheet. This collection
+// expresses AutoFilter settings.
+type xlsxAutoFilter struct {
+	Ref string `xml:"ref,attr"`
+}
+
+// xlsxTableColumns directly maps the element representing the collection of all
+// table columns for this table.
+type xlsxTableColumns struct {
+	Count       int                `xml:"count,attr"`
+	TableColumn []*xlsxTableColumn `xml:"tableColumn"`
+}
+
+// xlsxTableColumn directly maps the element representing a single column for
+// this table.
+type xlsxTableColumn struct {
+	DataCellStyle      string `xml:"dataCellStyle,attr,omitempty"`
+	DataDxfID          int    `xml:"dataDxfId,attr,omitempty"`
+	HeaderRowCellStyle string `xml:"headerRowCellStyle,attr,omitempty"`
+	HeaderRowDxfID     int    `xml:"headerRowDxfId,attr,omitempty"`
+	ID                 int    `xml:"id,attr"`
+	Name               string `xml:"name,attr"`
+	QueryTableFieldID  int    `xml:"queryTableFieldId,attr,omitempty"`
+	TotalsRowCellStyle string `xml:"totalsRowCellStyle,attr,omitempty"`
+	TotalsRowDxfID     int    `xml:"totalsRowDxfId,attr,omitempty"`
+	TotalsRowFunction  string `xml:"totalsRowFunction,attr,omitempty"`
+	TotalsRowLabel     string `xml:"totalsRowLabel,attr,omitempty"`
+	UniqueName         string `xml:"uniqueName,attr,omitempty"`
+}
+
+// xlsxTableStyleInfo directly maps the tableStyleInfo element. This element
+// describes which style is used to display this table, and specifies which
+// portions of the table have the style applied.
+type xlsxTableStyleInfo struct {
+	Name              string `xml:"name,attr,omitempty"`
+	ShowFirstColumn   bool   `xml:"showFirstColumn,attr"`
+	ShowLastColumn    bool   `xml:"showLastColumn,attr"`
+	ShowRowStripes    bool   `xml:"showRowStripes,attr"`
+	ShowColumnStripes bool   `xml:"showColumnStripes,attr"`
+}
+
+// formatTable directly maps the format settings of the table.
+type formatTable struct {
+	TableStyle        string `json:"table_style"`
+	ShowFirstColumn   bool   `json:"show_first_column"`
+	ShowLastColumn    bool   `json:"show_last_column"`
+	ShowRowStripes    bool   `json:"show_row_stripes"`
+	ShowColumnStripes bool   `json:"show_column_stripes"`
+}