diff --git a/README.md b/README.md index ce7cf3d..3e6728f 100644 --- a/README.md +++ b/README.md @@ -204,7 +204,7 @@ func main() { ## Contributing -Contributions are welcome! Open a pull request to fix a bug, or open an issue to discuss a new feature or change. XML is compliant with [part 1 of the 5th edition of the ECMA-376 Standard for Office Open XML](http://www.ecma-international.org/publications/standards/Ecma-376.htm). +Contributions are welcome! Open a pull request to fix a bug, or open an issue to discuss a new feature or change. XML is compliant with [part 1 of the 5th edition of the ECMA-376 Standard for Office Open XML](https://www.ecma-international.org/publications-and-standards/standards/ecma-376/). ## Licenses diff --git a/README_zh.md b/README_zh.md index cf9888b..4e0a499 100644 --- a/README_zh.md +++ b/README_zh.md @@ -204,7 +204,7 @@ func main() { ## 社区合作 -欢迎您为此项目贡献代码,提出建议或问题、修复 Bug 以及参与讨论对新功能的想法。 XML 符合标准: [part 1 of the 5th edition of the ECMA-376 Standard for Office Open XML](http://www.ecma-international.org/publications/standards/Ecma-376.htm)。 +欢迎您为此项目贡献代码,提出建议或问题、修复 Bug 以及参与讨论对新功能的想法。 XML 符合标准: [part 1 of the 5th edition of the ECMA-376 Standard for Office Open XML](https://www.ecma-international.org/publications-and-standards/standards/ecma-376/)。 ## 开源许可 diff --git a/excelize_test.go b/excelize_test.go index f663ae0..0dcfacb 100644 --- a/excelize_test.go +++ b/excelize_test.go @@ -54,7 +54,7 @@ func TestOpenFile(t *testing.T) { assert.NoError(t, f.SetCellStr("Sheet2", "C11", "Knowns")) // Test max characters in a cell. - assert.NoError(t, f.SetCellStr("Sheet2", "D11", strings.Repeat("c", 32769))) + assert.NoError(t, f.SetCellStr("Sheet2", "D11", strings.Repeat("c", TotalCellChars+2))) f.NewSheet(":\\/?*[]Maximum 31 characters allowed in sheet title.") // Test set worksheet name with illegal name. f.SetSheetName("Maximum 31 characters allowed i", "[Rename]:\\/?* Maximum 31 characters allowed in sheet title.") diff --git a/lib.go b/lib.go index 26d402a..3a9e807 100644 --- a/lib.go +++ b/lib.go @@ -349,6 +349,9 @@ func genXMLNamespace(attr []xml.Attr) string { var rootElement string for _, v := range attr { if lastSpace := getXMLNamespace(v.Name.Space, attr); lastSpace != "" { + if lastSpace == NameSpaceXML { + lastSpace = "xml" + } rootElement += fmt.Sprintf("%s:%s=\"%s\" ", lastSpace, v.Name.Local, v.Value) continue } diff --git a/lib_test.go b/lib_test.go index f3e9b3e..10d7c3a 100644 --- a/lib_test.go +++ b/lib_test.go @@ -228,3 +228,9 @@ func TestStack(t *testing.T) { assert.Equal(t, s.Peek(), nil) assert.Equal(t, s.Pop(), nil) } + +func TestGenXMLNamespace(t *testing.T) { + assert.Equal(t, genXMLNamespace([]xml.Attr{ + {Name: xml.Name{Space: NameSpaceXML, Local: "space"}, Value: "preserve"}, + }), `xml:space="preserve">`) +} diff --git a/stream.go b/stream.go index fdada74..57bf4a2 100644 --- a/stream.go +++ b/stream.go @@ -40,8 +40,9 @@ type StreamWriter struct { // generate new worksheet with large amounts of data. Note that after set // rows, you must call the 'Flush' method to end the streaming writing // process and ensure that the order of line numbers is ascending, the common -// API and stream API can't be work mixed to writing data on the worksheets. -// For example, set data for worksheet of size 102400 rows x 50 columns with +// API and stream API can't be work mixed to writing data on the worksheets, +// you can't get cell value when in-memory chunks data over 16MB. For +// example, set data for worksheet of size 102400 rows x 50 columns with // numbers and style: // // file := excelize.NewFile() @@ -111,7 +112,7 @@ func (f *File) NewStreamWriter(sheet string) (*StreamWriter, error) { // AddTable creates an Excel table for the StreamWriter using the given // coordinate area and format set. For example, create a table of A1:D5: // -// err := sw.AddTable("A1", "D5", ``) +// err := sw.AddTable("A1", "D5", "") // // Create a table of F2:H6 with format set: // @@ -500,8 +501,7 @@ func (bw *bufferedWriter) Reader() (io.Reader, error) { // buffer has grown large enough. Any error will be returned. func (bw *bufferedWriter) Sync() (err error) { // Try to use local storage - const chunk = 1 << 24 - if bw.buf.Len() < chunk { + if bw.buf.Len() < StreamChunkSize { return nil } if bw.tmp == nil { diff --git a/stream_test.go b/stream_test.go index 26732d8..d36883a 100644 --- a/stream_test.go +++ b/stream_test.go @@ -40,7 +40,7 @@ func TestStreamWriter(t *testing.T) { // Test max characters in a cell. row := make([]interface{}, 1) - row[0] = strings.Repeat("c", 32769) + row[0] = strings.Repeat("c", TotalCellChars+2) assert.NoError(t, streamWriter.SetRow("A1", row)) // Test leading and ending space(s) character characters in a cell. @@ -100,6 +100,16 @@ func TestStreamWriter(t *testing.T) { file.XLSX["xl/worksheets/sheet1.xml"] = MacintoshCyrillicCharset _, err = file.NewStreamWriter("Sheet1") assert.EqualError(t, err, "xml decode error: XML syntax error on line 1: invalid UTF-8") + + // Test read cell. + file = NewFile() + streamWriter, err = file.NewStreamWriter("Sheet1") + assert.NoError(t, err) + assert.NoError(t, streamWriter.SetRow("A1", []interface{}{Cell{StyleID: styleID, Value: "Data"}})) + assert.NoError(t, streamWriter.Flush()) + cellValue, err := file.GetCellValue("Sheet1", "A1") + assert.NoError(t, err) + assert.Equal(t, "Data", cellValue) } func TestStreamTable(t *testing.T) { diff --git a/styles.go b/styles.go index 15234fd..4369f29 100644 --- a/styles.go +++ b/styles.go @@ -2187,17 +2187,16 @@ func (f *File) newFont(style *Style) *xlsxFont { Family: &attrValInt{Val: intPtr(2)}, } if style.Font.Bold { - fnt.B = &style.Font.Bold + fnt.B = &attrValBool{Val: &style.Font.Bold} } if style.Font.Italic { - fnt.I = &style.Font.Italic + fnt.I = &attrValBool{Val: &style.Font.Italic} } if *fnt.Name.Val == "" { *fnt.Name.Val = f.GetDefaultFont() } if style.Font.Strike { - strike := true - fnt.Strike = &strike + fnt.Strike = &attrValBool{Val: &style.Font.Strike} } val, ok := fontUnderlineType[style.Font.Underline] if ok { diff --git a/table.go b/table.go index 973a416..12ef41a 100644 --- a/table.go +++ b/table.go @@ -35,7 +35,7 @@ func parseFormatTableSet(formatSet string) (*formatTable, error) { // name, coordinate area and format set. For example, create a table of A1:D5 // on Sheet1: // -// err := f.AddTable("Sheet1", "A1", "D5", ``) +// err := f.AddTable("Sheet1", "A1", "D5", "") // // Create a table of F2:H6 on Sheet2 with format set: // diff --git a/xmlDrawing.go b/xmlDrawing.go index a18c588..4b51b63 100644 --- a/xmlDrawing.go +++ b/xmlDrawing.go @@ -91,6 +91,7 @@ const ( // Excel specifications and limits const ( + StreamChunkSize = 1 << 24 MaxFontFamilyLength = 31 MaxFontSize = 409 MaxFileNameLength = 207 diff --git a/xmlStyles.go b/xmlStyles.go index 46604dc..92e4e6a 100644 --- a/xmlStyles.go +++ b/xmlStyles.go @@ -83,13 +83,13 @@ type xlsxFonts struct { // xlsxFont directly maps the font element. This element defines the // properties for one of the fonts used in this workbook. type xlsxFont struct { - B *bool `xml:"b,omitempty"` - I *bool `xml:"i,omitempty"` - Strike *bool `xml:"strike,omitempty"` - Outline *bool `xml:"outline,omitempty"` - Shadow *bool `xml:"shadow,omitempty"` - Condense *bool `xml:"condense,omitempty"` - Extend *bool `xml:"extend,omitempty"` + B *attrValBool `xml:"b,omitempty"` + I *attrValBool `xml:"i,omitempty"` + Strike *attrValBool `xml:"strike,omitempty"` + Outline *attrValBool `xml:"outline,omitempty"` + Shadow *attrValBool `xml:"shadow,omitempty"` + Condense *attrValBool `xml:"condense,omitempty"` + Extend *attrValBool `xml:"extend,omitempty"` U *attrValString `xml:"u"` Sz *attrValFloat `xml:"sz"` Color *xlsxColor `xml:"color"`