parent
2868bd3ec9
commit
46b8c46d91
@ -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",
|
||||||
|
})
|
||||||
|
}
|
@ -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"`
|
||||||
|
}
|
Loading…
Reference in new issue