Sfoglia il codice sorgente

add read style support

add read style support
zhcy 13 anni fa
parent
commit
46087827d6
3 ha cambiato i file con 151 aggiunte e 2 eliminazioni
  1. 76 2
      lib.go
  2. 74 0
      style.go
  3. 1 0
      worksheet.go

+ 76 - 2
lib.go

@@ -27,6 +27,8 @@ func (e *XLSXReaderError) Error() string {
 // the contents of Cell within an xlsx.Row.
 type Cell struct {
 	Value string
+	styleIndex int
+	styles *xlsxStyles
 }
 
 // CellInterface defines the public API of the Cell.
@@ -38,6 +40,27 @@ func (c *Cell) String() string {
 	return c.Value
 }
 
+func (c *Cell) GetStyle() *Style {	
+	if c.styleIndex > 0 && c.styleIndex < len(c.styles.CellXfs) {
+		xf := c.styles.CellXfs[c.styleIndex]
+		if xf.ApplyBorder != "0" {
+			var border Border
+			style := new(Style)
+			border.Left = c.styles.Borders[xf.BorderId].Left.Style
+			border.Right = c.styles.Borders[xf.BorderId].Right.Style
+			border.Top = c.styles.Borders[xf.BorderId].Top.Style
+			border.Bottom = c.styles.Borders[xf.BorderId].Bottom.Style
+			style.Boders = border
+			return style
+		} else {
+			return new(Style)
+		}
+	} else {
+		return new(Style)
+	}
+	return new(Style)
+}
+
 // Row is a high level structure indended to provide user access to a
 // row within a xlsx.Sheet.  An xlsx.Row contains a slice of xlsx.Cell.
 type Row struct {
@@ -52,11 +75,27 @@ type Sheet struct {
 	MaxCol int
 }
 
+// Style is a high level structure intended to provide user access to
+// the contents of Style within an XLSX file.
+type Style struct {
+	Boders Border
+}
+
+// Border is a high level structure intended to provide user access to
+// the contents of Border Style within an Sheet.
+type Border struct {
+	Left string
+	Right string
+	Top string 
+	Bottom string
+}
+
 // File is a high level structure providing a slice of Sheet structs
 // to the user.
 type File struct {
 	worksheets     map[string]*zip.File
 	referenceTable []string
+	styles         *xlsxStyles
 	Sheets         []*Sheet // sheet access by index
 	Sheet map[string]*Sheet // sheet access by name
 }
@@ -254,11 +293,13 @@ func getValueFromCellData(rawcell xlsxC, reftable []string) string {
 // readRowsFromSheet is an internal helper function that extracts the
 // rows from a XSLXWorksheet, poulates them with Cells and resolves
 // the value references from the reference table and stores them in
-func readRowsFromSheet(Worksheet *xlsxWorksheet, reftable []string) ([]*Row ,int) {
+func readRowsFromSheet(Worksheet *xlsxWorksheet, file *File) ([]*Row ,int) {
 	var rows []*Row
 	var row *Row
 	var maxCol int
+	var reftable []string
 
+	reftable = file.referenceTable
 	rows = make([]*Row, len(Worksheet.SheetData.Row))
 	maxCol = 0
 	for i, rawrow := range Worksheet.SheetData.Row {
@@ -277,9 +318,12 @@ func readRowsFromSheet(Worksheet *xlsxWorksheet, reftable []string) ([]*Row ,int
 				maxCol = x
 			}
 			row.Cells[x].Value = getValueFromCellData(rawcell, reftable)
+			row.Cells[x].styleIndex = rawcell.S
+			row.Cells[x].styles = file.styles
 		}
 		rows[i] = row
 	}
+	maxCol += 1
 	return rows,maxCol
 }
 
@@ -309,7 +353,7 @@ func readSheetsFromZipFile(f *zip.File, file *File) ([]*Sheet, []string, error)
 			return nil, nil, error
 		}
 		sheet := new(Sheet)
-		sheet.Rows,sheet.MaxCol = readRowsFromSheet(worksheet, file.referenceTable)
+		sheet.Rows,sheet.MaxCol = readRowsFromSheet(worksheet, file)
 		sheets[i] = sheet
 		sheet.MaxRow = len(sheet.Rows)
 		names[i] = rawsheet.Name
@@ -340,6 +384,28 @@ func readSharedStringsFromZipFile(f *zip.File) ([]string, error) {
 	return reftable, nil
 }
 
+// readStylesFromZipFile() is an internal helper function to
+// extract a style table from the style.xml file within
+// the XLSX zip file.
+func readStylesFromZipFile(f *zip.File) (*xlsxStyles, error) {
+	var style *xlsxStyles
+	var error error
+	var rc io.ReadCloser
+	var decoder *xml.Decoder
+	rc, error = f.Open()
+	if error != nil {
+		return nil, error
+	}
+	style = new(xlsxStyles)
+	decoder = xml.NewDecoder(rc)
+	error = decoder.Decode(style)
+	if error != nil {
+		return nil, error
+	}
+	return style, nil
+}
+
+
 // OpenFile() take the name of an XLSX file and returns a populated
 // xlsx.File struct for it.
 func OpenFile(filename string) (x *File, e error) {
@@ -348,6 +414,7 @@ func OpenFile(filename string) (x *File, e error) {
 	var file *File
 	var v *zip.File
 	var workbook *zip.File
+	var styles *zip.File
 	var sharedStrings *zip.File
 	var reftable []string
 	var worksheets map[string]*zip.File
@@ -365,6 +432,8 @@ func OpenFile(filename string) (x *File, e error) {
 			sharedStrings = v
 		case "xl/workbook.xml":
 			workbook = v
+		case "xl/styles.xml":
+			styles = v
 		default:
 			if len(v.Name) > 12 {
 				if v.Name[0:13] == "xl/worksheets" {
@@ -384,6 +453,11 @@ func OpenFile(filename string) (x *File, e error) {
 		return nil, error
 	}
 	file.referenceTable = reftable
+	style , error := readStylesFromZipFile(styles)
+	if error != nil {
+		return nil, error
+	}
+	file.styles = style
 	sheets, names, error := readSheetsFromZipFile(workbook, file)
 	if error != nil {
 		return nil, error

+ 74 - 0
style.go

@@ -0,0 +1,74 @@
+// xslx is a package designed to help with reading data from
+// spreadsheets stored in the XLSX format used in recent versions of
+// Microsoft's Excel spreadsheet.
+//
+// For a concise example of how to use this library why not check out
+// the source for xlsx2csv here: https://github.com/tealeg/xlsx2csv
+
+package xlsx
+
+// xlsxStyle directly maps the style element in the namespace
+// http://schemas.openxmlformats.org/spreadsheetml/2006/main -
+// currently I have not checked it for completeness - it does as much
+// as I need.
+type xlsxStyles struct {
+	Fonts        []xlsxFont   `xml:"fonts>font"`
+	Fills        []xlsxFill   `xml:"fills>fill"`
+	Borders      []xlsxBorder `xml:"borders>border"`
+	CellStyleXfs []xlsxXf     `xml:"cellStyleXfs>xf"`
+	CellXfs      []xlsxXf     `xml:"cellXfs>xf"`
+}
+
+// xlsxFont directly maps the font element in the namespace
+// http://schemas.openxmlformats.org/spreadsheetml/2006/main -
+// currently I have not checked it for completeness - it does as much
+// as I need.
+type xlsxFont struct {
+	Sz      xlsxVal `xml:"sz"`
+	Name    xlsxVal `xml:"name"`
+	Family  xlsxVal `xml:"family"`
+	Charset xlsxVal `xml:"charset"`
+}
+
+// xlsxVal directly maps the val element in the namespace
+// http://schemas.openxmlformats.org/spreadsheetml/2006/main -
+// currently I have not checked it for completeness - it does as much
+// as I need.
+type xlsxVal struct {
+	Val string `xml:"val,attr"`
+}
+
+// xlsxFill directly maps the fill element in the namespace
+// http://schemas.openxmlformats.org/spreadsheetml/2006/main -
+// currently I have not checked it for completeness - it does as much
+// as I need.
+type xlsxFill struct {
+}
+
+// xlsxBorder directly maps the border element in the namespace
+// http://schemas.openxmlformats.org/spreadsheetml/2006/main -
+// currently I have not checked it for completeness - it does as much
+// as I need.
+type xlsxBorder struct {
+	Left   xlsxLine `xml:"left"`
+	Right  xlsxLine `xml:"right"`
+	Top    xlsxLine `xml:"top"`
+	Bottom xlsxLine `xml:"bottom"`
+}
+
+// xlsxLine directly maps the line style element in the namespace
+// http://schemas.openxmlformats.org/spreadsheetml/2006/main -
+// currently I have not checked it for completeness - it does as much
+// as I need.
+type xlsxLine struct {
+	Style string `xml:"style,attr"`
+}
+
+// xlsxXf directly maps the xf element in the namespace
+// http://schemas.openxmlformats.org/spreadsheetml/2006/main -
+// currently I have not checked it for completeness - it does as much
+// as I need.
+type xlsxXf struct {
+	ApplyBorder string `xml:"applyBorder,attr"`
+	BorderId    int `xml:"borderId,attr"`
+}

+ 1 - 0
worksheet.go

@@ -81,6 +81,7 @@ type xlsxRow struct {
 // as I need.
 type xlsxC struct {
 	R string `xml:"r,attr"`
+	S int `xml:"s,attr"`
 	T string `xml:"t,attr"`
 	V string  `xml:"v"`
 }