Prechádzať zdrojové kódy

Add some extra information to style extracted from file

Geoffrey J. Teale 12 rokov pred
rodič
commit
2c1335f283
5 zmenil súbory, kde vykonal 189 pridanie a 37 odobranie
  1. 42 15
      lib.go
  2. 113 7
      lib_test.go
  3. 31 14
      style.go
  4. BIN
      testfile.xlsx
  5. 3 1
      workbook.go

+ 42 - 15
lib.go

@@ -1,7 +1,7 @@
 package xlsx
 
 import (
-  "archive/zip"
+	"archive/zip"
 	"encoding/xml"
 	"errors"
 	"fmt"
@@ -44,7 +44,7 @@ func (c *Cell) GetStyle() *Style {
 	style := new(Style)
 	if c.styleIndex > 0 && c.styleIndex < len(c.styles.CellXfs) {
 		xf := c.styles.CellXfs[c.styleIndex]
-		if xf.ApplyBorder != "0" {
+		if xf.ApplyBorder {
 			var border Border
 			border.Left = c.styles.Borders[xf.BorderId].Left.Style
 			border.Right = c.styles.Borders[xf.BorderId].Right.Style
@@ -52,7 +52,7 @@ func (c *Cell) GetStyle() *Style {
 			border.Bottom = c.styles.Borders[xf.BorderId].Bottom.Style
 			style.Boders = border
 		}
-		if xf.ApplyFill != "0" {
+		if xf.ApplyFill {
 			var fill Fill
 			fill.PatternType = c.styles.Fills[xf.FillId].PatternFill.PatternType
 			fill.BgColor = c.styles.Fills[xf.FillId].PatternFill.BgColor.RGB
@@ -97,8 +97,8 @@ type Border struct {
 // the contents of background and foreground color index within an Sheet.
 type Fill struct {
 	PatternType string
-	BgColor string
-	FgColor string
+	BgColor     string
+	FgColor     string
 }
 
 // File is a high level structure providing a slice of Sheet structs
@@ -315,6 +315,30 @@ func readRowsFromSheet(Worksheet *xlsxWorksheet, file *File) ([]*Row, int, int)
 	return rows, maxCol, maxRow
 }
 
+type indexedSheet struct {
+	Index int
+	Sheet *Sheet
+	Error error
+}
+
+// readSheetFromFile is the logic of converting a xlsxSheet struct
+// into a Sheet struct.  This work can be done in parallel and so
+// readSheetsFromZipFile will spawn an instance of this function per
+// sheet and get the results back on the provided channel.
+func readSheetFromFile(sc chan *indexedSheet, index int, rsheet xlsxSheet, fi *File) {
+	result := &indexedSheet{Index: index, Sheet: nil, Error: nil}
+	worksheet, error := getWorksheetFromSheet(rsheet, fi.worksheets)
+	if error != nil {
+		result.Error = error
+		sc <- result
+		return
+	}
+	sheet := new(Sheet)
+	sheet.Rows, sheet.MaxCol, sheet.MaxRow = readRowsFromSheet(worksheet, fi)
+	result.Sheet = sheet
+	sc <- result
+}
+
 // readSheetsFromZipFile is an internal helper function that loops
 // over the Worksheets defined in the XSLXWorkbook and loads them into
 // Sheet objects stored in the Sheets slice of a xlsx.File struct.
@@ -323,6 +347,7 @@ func readSheetsFromZipFile(f *zip.File, file *File) ([]*Sheet, []string, error)
 	var error error
 	var rc io.ReadCloser
 	var decoder *xml.Decoder
+	var sheetCount int
 	workbook = new(xlsxWorkbook)
 	rc, error = f.Open()
 	if error != nil {
@@ -333,17 +358,20 @@ func readSheetsFromZipFile(f *zip.File, file *File) ([]*Sheet, []string, error)
 	if error != nil {
 		return nil, nil, error
 	}
-	sheets := make([]*Sheet, len(workbook.Sheets.Sheet))
-	names := make([]string, len(workbook.Sheets.Sheet))
+	sheetCount = len(workbook.Sheets.Sheet)
+	sheets := make([]*Sheet, sheetCount)
+	names := make([]string, sheetCount)
+	sheetChan := make(chan *indexedSheet, sheetCount)
 	for i, rawsheet := range workbook.Sheets.Sheet {
-		worksheet, error := getWorksheetFromSheet(rawsheet, file.worksheets)
-		if error != nil {
-			return nil, nil, error
+		go readSheetFromFile(sheetChan, i, rawsheet, file)
+	}
+	for j := 0; j < sheetCount; j++ {
+		sheet := <-sheetChan
+		if sheet.Error != nil {
+			return nil, nil, sheet.Error
 		}
-		sheet := new(Sheet)
-		sheet.Rows, sheet.MaxCol, sheet.MaxRow = readRowsFromSheet(worksheet, file)
-		sheets[i] = sheet
-		names[i] = rawsheet.Name
+		sheets[sheet.Index] = sheet.Sheet
+		names[sheet.Index] = workbook.Sheets.Sheet[sheet.Index].Name
 	}
 	return sheets, names, nil
 }
@@ -392,7 +420,6 @@ func readStylesFromZipFile(f *zip.File) (*xlsxStyles, 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) (*File, error) {

+ 113 - 7
lib_test.go

@@ -3,7 +3,6 @@ package xlsx
 import (
 	"bytes"
 	"encoding/xml"
-	"fmt"
 	"strconv"
 	"strings"
 	"testing"
@@ -83,14 +82,65 @@ func TestReadSharedStringsFromZipFile(t *testing.T) {
 	}
 }
 
+
+func testXf(t *testing.T, result, expected *xlsxXf) {
+	if result.ApplyAlignment != expected.ApplyAlignment {
+		t.Error("Expected result.ApplyAlignment == ", expected.ApplyAlignment,
+			", got", result.ApplyAlignment)
+		return
+	}
+	if result.ApplyBorder != expected.ApplyBorder {
+		t.Error("Expected result.ApplyBorder == ", expected.ApplyBorder,
+			", got ", result.ApplyBorder)
+		return
+	}
+	if result.ApplyFont != expected.ApplyFont {
+		t.Error("Expect result.ApplyFont == ", expected.ApplyFont,
+			", got ", result.ApplyFont)
+		return
+	}
+	if result.ApplyFill != expected.ApplyFill {
+		t.Error("Expected result.ApplyFill == ", expected.ApplyFill,
+			", got ", result.ApplyFill)
+		return
+	}
+	if result.ApplyProtection != expected.ApplyProtection {
+		t.Error("Expexcted result.ApplyProtection == ", expected.ApplyProtection,
+			", got ", result.ApplyProtection)
+		return
+	}
+	if result.BorderId != expected.BorderId {
+		t.Error("Expected BorderId == ", expected.BorderId,
+			". got ", result.BorderId)
+		return
+	}
+	if result.FillId != expected.FillId {
+		t.Error("Expected result.FillId == ", expected.FillId,
+			", got ", result.FillId)
+		return
+	}
+	if result.FontId != expected.FontId {
+		t.Error("Expected result.FontId == ", expected.FontId,
+			", got ", result.FontId)
+		return
+	}
+	if result.NumFmtId != expected.NumFmtId {
+		t.Error("Expected result.NumFmtId == ", expected.NumFmtId,
+			", got ", result.NumFmtId)
+		return
+	}
+}
+
 // We can correctly extract a style table from the style.xml file
 // embedded in the XLSX file and return a styles struct from it.
 func TestReadStylesFromZipFile(t *testing.T) {
 	var xlsxFile *File
 	var error error
-	var fontCount, fillCount int
+	var fontCount, fillCount, borderCount, cellStyleXfCount, cellXfCount int
 	var font xlsxFont
 	var fill xlsxFill
+	var border xlsxBorder
+	var xf xlsxXf
 
 	xlsxFile, error = OpenFile("testfile.xlsx")
 	if error != nil {
@@ -120,13 +170,69 @@ func TestReadStylesFromZipFile(t *testing.T) {
 		t.Error("Expected exactly 3 xlsxFills, got ", fillCount)
 		return
 	}
-	fill = xlsxFile.styles.Fills[0]
-	fmt.Printf("%v\n", fill)
-	fill = xlsxFile.styles.Fills[1]
-	fmt.Printf("%v\n", fill)
 	fill = xlsxFile.styles.Fills[2]
-	fmt.Printf("%v\n", fill)
+	if fill.PatternFill.PatternType != "solid" {
+		t.Error("Expected PatternFill.PatternType == 'solid', but got ",
+			fill.PatternFill.PatternType)
+		return
+	}
+	borderCount = len(xlsxFile.styles.Borders)
+	if borderCount != 2 {
+		t.Error("Expected exactly 2 xlsxBorders, got ", borderCount)
+		return
+	}
+	border = xlsxFile.styles.Borders[1]
+	if border.Left.Style != "thin" {
+		t.Error("Expected border.Left.Style == 'thin', got ", border.Left.Style)
+		return
+	}
+	if border.Right.Style != "thin" {
+		t.Error("Expected border.Right.Style == 'thin', got ", border.Right.Style)
+		return
+	}
+	if border.Top.Style != "thin" {
+		t.Error("Expected border.Top.Style == 'thin', got ", border.Top.Style)
+		return
+	}
+	if border.Bottom.Style != "thin" {
+		t.Error("Expected border.Bottom.Style == 'thin', got ", border.Bottom.Style)
+		return
+	}
+	cellStyleXfCount = len(xlsxFile.styles.CellStyleXfs)
+	if cellStyleXfCount != 20 {
+		t.Error("Expected excactly 20 cellStyleXfs, got ", cellStyleXfCount)
+		return
+	}
+	xf = xlsxFile.styles.CellStyleXfs[0]
+	expectedXf := &xlsxXf{
+		ApplyAlignment: true,
+		ApplyBorder: true,
+		ApplyFont: true,
+		ApplyFill: false,
+		ApplyProtection: true,
+		BorderId: 0,
+		FillId: 0,
+		FontId: 0,
+		NumFmtId: 164}
+	testXf(t, &xf, expectedXf)
 
+	cellXfCount = len(xlsxFile.styles.CellXfs)
+	if cellXfCount != 3 {
+		t.Error("Expected excactly 3 cellXfs, got ", cellXfCount)
+		return
+	}
+	xf = xlsxFile.styles.CellXfs[0]
+	expectedXf = &xlsxXf{
+		ApplyAlignment: false,
+		ApplyBorder: false,
+		ApplyFont: false,
+		ApplyFill: false,
+		ApplyProtection: false,
+		BorderId: 0,
+		FillId: 0,
+		FontId: 0,
+		NumFmtId: 164}
+	testXf(t, &xf, expectedXf)
 }
 
 func TestLettersToNumeric(t *testing.T) {

+ 31 - 14
style.go

@@ -42,23 +42,25 @@ type xlsxVal struct {
 // http://schemas.openxmlformats.org/spreadsheetml/2006/main -
 // currently I have not checked it for completeness - it does as much
 // as I need.
-// ColorIndex ARGBValue
-// 0          00000000
-// 1          00FFFFFF
-// 2          00FF0000
-// 3          0000FF00
-// ...............
-// ...............
 type xlsxFill struct {
 	PatternFill xlsxPatternFill `xml:"patternFill"`
 }
 
+// xlsxPatternFill directly maps the patternFill 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 xlsxPatternFill struct {
-	PatternType string `xml:"patternType,attr"`
-	FgColor xlsxColor `xml:"fgColor"`
-	BgColor xlsxColor `xml:"bgColor"`
+	PatternType string    `xml:"patternType,attr"`
+	FgColor     xlsxColor `xml:"fgColor"`
+	BgColor     xlsxColor `xml:"bgColor"`
 }
 
+// xlsxColor is a common mapping used for both the fgColor and bgColor
+// elements 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 xlsxColor struct {
 	RGB string `xml:"rgb,attr"`
 }
@@ -87,8 +89,23 @@ type xlsxLine struct {
 // 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"`
-	ApplyFill   string `xml:"applyFill,attr"`
-	FillId      int    `xml:"fillId,attr"`
+	ApplyAlignment  bool          `xml:"applyAlignment,attr"`
+	ApplyBorder     bool          `xml:"applyBorder,attr"`
+	ApplyFont       bool          `xml:"applyFont,attr"`
+	ApplyFill       bool          `xml:"applyFill,attr"`
+	ApplyProtection bool          `xml:"applyProtection,attr"`
+	BorderId        int           `xml:"borderId,attr"`
+	FillId          int           `xml:"fillId,attr"`
+	FontId          int           `xml:"fontId,attr"`
+	NumFmtId        int           `xml:"numFmtId,attr"`
+	alignment       xlsxAlignment `xml:"alignement"`
+}
+
+type xlsxAlignment struct {
+	Horizontal   string `xml:"horizontal,attr"`
+	Indent       int    `xml:"indent,attr"`
+	ShrinkToFit  bool   `xml:"shrinkToFit,attr"`
+	TextRotation int    `xml:"textRotation,attr"`
+	Vertical     string `xml:"vertical,attr"`
+	WrapText     bool   `xml:"wrapText,attr"`
 }

BIN
testfile.xlsx


+ 3 - 1
workbook.go

@@ -102,7 +102,9 @@ type xlsxCalcPr struct {
 	CalcId string `xml:"calcId,attr"`
 }
 
-// getWorksheetFromSheet() is an internal helper function to open a sheetN.xml file, refered to by an xlsx.xlsxSheet struct, from the XLSX file and unmarshal it an xlsx.xlsxWorksheet struct
+// getWorksheetFromSheet() is an internal helper function to open a
+// sheetN.xml file, refered to by an xlsx.xlsxSheet struct, from the XLSX
+// file and unmarshal it an xlsx.xlsxWorksheet struct
 func getWorksheetFromSheet(sheet xlsxSheet, worksheets map[string]*zip.File) (*xlsxWorksheet, error) {
 	var rc io.ReadCloser
 	var decoder *xml.Decoder