diff options
-rw-r--r-- | stream.go | 219 | ||||
-rw-r--r-- | stream_test.go | 66 | ||||
-rw-r--r-- | xmlTable.go | 1 | ||||
-rw-r--r-- | xmlWorksheet.go | 180 |
4 files changed, 386 insertions, 80 deletions
diff --git a/stream.go b/stream.go new file mode 100644 index 0000000..0d91ddd --- /dev/null +++ b/stream.go @@ -0,0 +1,219 @@ +// Copyright 2016 - 2019 The excelize Authors. All rights reserved. Use of +// this source code is governed by a BSD-style license that can be found in +// the LICENSE file. +// +// Package excelize 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.10 or later. + +package excelize + +import ( + "bytes" + "encoding/xml" + "errors" + "fmt" + "io/ioutil" + "os" + "reflect" +) + +// StreamWriter defined the type of stream writer. +type StreamWriter struct { + tmpFile *os.File + File *File + Sheet string + SheetID int + SheetData bytes.Buffer +} + +// NewStreamWriter return stream writer struct by given worksheet name for +// 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. For +// example, set data for worksheet of size 102400 rows x 50 columns with +// numbers: +// +// file := excelize.NewFile() +// streamWriter, err := file.NewStreamWriter("Sheet1") +// if err != nil { +// panic(err) +// } +// for rowID := 1; rowID <= 102400; rowID++ { +// row := make([]interface{}, 50) +// for colID := 0; colID < 50; colID++ { +// row[colID] = rand.Intn(640000) +// } +// cell, _ := excelize.CoordinatesToCellName(1, rowID) +// if err := streamWriter.SetRow(cell, &row); err != nil { +// panic(err) +// } +// } +// if err := streamWriter.Flush(); err != nil { +// panic(err) +// } +// if err := file.SaveAs("Book1.xlsx"); err != nil { +// panic(err) +// } +// +func (f *File) NewStreamWriter(sheet string) (*StreamWriter, error) { + sheetID := f.GetSheetIndex(sheet) + if sheetID == 0 { + return nil, fmt.Errorf("sheet %s is not exist", sheet) + } + rsw := &StreamWriter{ + File: f, + Sheet: sheet, + SheetID: sheetID, + } + rsw.SheetData.WriteString("<sheetData>") + return rsw, nil +} + +// SetRow writes an array to streaming row by given worksheet name, starting +// coordinate and a pointer to array type 'slice'. Note that, cell settings +// with styles are not supported currently and after set rows, you must call the +// 'Flush' method to end the streaming writing process. The following +// shows the supported data types: +// +// int +// string +// +func (sw *StreamWriter) SetRow(axis string, slice interface{}) error { + col, row, err := CellNameToCoordinates(axis) + if err != nil { + return err + } + // Make sure 'slice' is a Ptr to Slice + v := reflect.ValueOf(slice) + if v.Kind() != reflect.Ptr || v.Elem().Kind() != reflect.Slice { + return errors.New("pointer to slice expected") + } + v = v.Elem() + sw.SheetData.WriteString(fmt.Sprintf(`<row r="%d">`, row)) + for i := 0; i < v.Len(); i++ { + axis, err := CoordinatesToCellName(col+i, row) + if err != nil { + return err + } + switch val := v.Index(i).Interface().(type) { + case int: + sw.SheetData.WriteString(fmt.Sprintf(`<c r="%s"><v>%d</v></c>`, axis, val)) + case string: + sw.SheetData.WriteString(sw.setCellStr(axis, val)) + default: + sw.SheetData.WriteString(sw.setCellStr(axis, fmt.Sprint(val))) + } + } + sw.SheetData.WriteString(`</row>`) + // Try to use local storage + chunk := 1 << 24 + if sw.SheetData.Len() >= chunk { + if sw.tmpFile == nil { + err := sw.createTmp() + if err != nil { + // can not use local storage + return nil + } + } + // use local storage + _, err := sw.tmpFile.Write(sw.SheetData.Bytes()) + if err != nil { + return nil + } + sw.SheetData.Reset() + } + return err +} + +// Flush ending the streaming writing process. +func (sw *StreamWriter) Flush() error { + sw.SheetData.WriteString(`</sheetData>`) + + ws, err := sw.File.workSheetReader(sw.Sheet) + if err != nil { + return err + } + sheetXML := fmt.Sprintf("xl/worksheets/sheet%d.xml", sw.SheetID) + delete(sw.File.Sheet, sheetXML) + delete(sw.File.checked, sheetXML) + var sheetDataByte []byte + if sw.tmpFile != nil { + // close the local storage file + if err = sw.tmpFile.Close(); err != nil { + return err + } + + file, err := os.Open(sw.tmpFile.Name()) + if err != nil { + return err + } + + sheetDataByte, err = ioutil.ReadAll(file) + if err != nil { + return err + } + + if err := file.Close(); err != nil { + return err + } + + err = os.Remove(sw.tmpFile.Name()) + if err != nil { + return err + } + } + + sheetDataByte = append(sheetDataByte, sw.SheetData.Bytes()...) + replaceMap := map[string][]byte{ + "XMLName": []byte{}, + "SheetData": sheetDataByte, + } + sw.SheetData.Reset() + sw.File.XLSX[fmt.Sprintf("xl/worksheets/sheet%d.xml", sw.SheetID)] = + StreamMarshalSheet(ws, replaceMap) + return err +} + +// createTmp creates a temporary file in the operating system default +// temporary directory. +func (sw *StreamWriter) createTmp() (err error) { + sw.tmpFile, err = ioutil.TempFile(os.TempDir(), "excelize-") + return err +} + +// StreamMarshalSheet provides method to serialization worksheets by field as +// streaming. +func StreamMarshalSheet(ws *xlsxWorksheet, replaceMap map[string][]byte) []byte { + s := reflect.ValueOf(ws).Elem() + typeOfT := s.Type() + var marshalResult []byte + marshalResult = append(marshalResult, []byte(XMLHeader+`<worksheet`+templateNamespaceIDMap)...) + for i := 0; i < s.NumField(); i++ { + f := s.Field(i) + content, ok := replaceMap[typeOfT.Field(i).Name] + if ok { + marshalResult = append(marshalResult, content...) + continue + } + out, _ := xml.Marshal(f.Interface()) + marshalResult = append(marshalResult, out...) + } + marshalResult = append(marshalResult, []byte(`</worksheet>`)...) + return marshalResult +} + +// setCellStr provides a function to set string type value of a cell as +// streaming. Total number of characters that a cell can contain 32767 +// characters. +func (sw *StreamWriter) setCellStr(axis, value string) string { + if len(value) > 32767 { + value = value[0:32767] + } + // Leading and ending space(s) character detection. + if len(value) > 0 && (value[0] == 32 || value[len(value)-1] == 32) { + return fmt.Sprintf(`<c xml:space="preserve" r="%s" t="str"><v>%s</v></c>`, axis, value) + } + return fmt.Sprintf(`<c r="%s" t="str"><v>%s</v></c>`, axis, value) +} diff --git a/stream_test.go b/stream_test.go new file mode 100644 index 0000000..97c55a7 --- /dev/null +++ b/stream_test.go @@ -0,0 +1,66 @@ +package excelize + +import ( + "math/rand" + "path/filepath" + "strings" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestStreamWriter(t *testing.T) { + file := NewFile() + streamWriter, err := file.NewStreamWriter("Sheet1") + assert.NoError(t, err) + + // Test max characters in a cell. + row := make([]interface{}, 1) + row[0] = strings.Repeat("c", 32769) + assert.NoError(t, streamWriter.SetRow("A1", &row)) + + // Test leading and ending space(s) character characters in a cell. + row = make([]interface{}, 1) + row[0] = " characters" + assert.NoError(t, streamWriter.SetRow("A2", &row)) + + row = make([]interface{}, 1) + row[0] = []byte("Word") + assert.NoError(t, streamWriter.SetRow("A3", &row)) + + for rowID := 10; rowID <= 51200; rowID++ { + row := make([]interface{}, 50) + for colID := 0; colID < 50; colID++ { + row[colID] = rand.Intn(640000) + } + cell, _ := CoordinatesToCellName(1, rowID) + assert.NoError(t, streamWriter.SetRow(cell, &row)) + } + + err = streamWriter.Flush() + assert.NoError(t, err) + // Save xlsx file by the given path. + assert.NoError(t, file.SaveAs(filepath.Join("test", "TestStreamWriter.xlsx"))) + + // Test error exceptions + streamWriter, err = file.NewStreamWriter("SheetN") + assert.EqualError(t, err, "sheet SheetN is not exist") +} + +func TestFlush(t *testing.T) { + // Test error exceptions + file := NewFile() + streamWriter, err := file.NewStreamWriter("Sheet1") + assert.NoError(t, err) + streamWriter.Sheet = "SheetN" + assert.EqualError(t, streamWriter.Flush(), "sheet SheetN is not exist") +} + +func TestSetRow(t *testing.T) { + // Test error exceptions + file := NewFile() + streamWriter, err := file.NewStreamWriter("Sheet1") + assert.NoError(t, err) + assert.EqualError(t, streamWriter.SetRow("A", &[]interface{}{}), `cannot convert cell "A" to coordinates: invalid cell name "A"`) + assert.EqualError(t, streamWriter.SetRow("A1", []interface{}{}), `pointer to slice expected`) +} diff --git a/xmlTable.go b/xmlTable.go index ca4ce03..017bda1 100644 --- a/xmlTable.go +++ b/xmlTable.go @@ -44,6 +44,7 @@ type xlsxTable struct { // applied column by column to a table of data in the worksheet. This collection // expresses AutoFilter settings. type xlsxAutoFilter struct { + XMLName xml.Name `xml:"autoFilter"` Ref string `xml:"ref,attr"` FilterColumn *xlsxFilterColumn `xml:"filterColumn"` } diff --git a/xmlWorksheet.go b/xmlWorksheet.go index cb854cd..a071e4d 100644 --- a/xmlWorksheet.go +++ b/xmlWorksheet.go @@ -59,7 +59,8 @@ type xlsxWorksheet struct { // xlsxDrawing change r:id to rid in the namespace. type xlsxDrawing struct { - RID string `xml:"http://schemas.openxmlformats.org/officeDocument/2006/relationships id,attr,omitempty"` + XMLName xml.Name `xml:"drawing"` + RID string `xml:"http://schemas.openxmlformats.org/officeDocument/2006/relationships id,attr,omitempty"` } // xlsxHeaderFooter directly maps the headerFooter element in the namespace @@ -70,6 +71,7 @@ type xlsxDrawing struct { // footers on the first page can differ from those on odd- and even-numbered // pages. In the latter case, the first page is not considered an odd page. type xlsxHeaderFooter struct { + XMLName xml.Name `xml:"headerFooter"` AlignWithMargins bool `xml:"alignWithMargins,attr,omitempty"` DifferentFirst bool `xml:"differentFirst,attr,omitempty"` DifferentOddEven bool `xml:"differentOddEven,attr,omitempty"` @@ -91,32 +93,33 @@ type xlsxHeaderFooter struct { // each of the left section, center section and right section of a header and // a footer. type xlsxDrawingHF struct { - Content string `xml:",chardata"` + Content string `xml:",innerxml"` } // xlsxPageSetUp directly maps the pageSetup element in the namespace // http://schemas.openxmlformats.org/spreadsheetml/2006/main - Page setup // settings for the worksheet. type xlsxPageSetUp struct { - BlackAndWhite bool `xml:"blackAndWhite,attr,omitempty"` - CellComments string `xml:"cellComments,attr,omitempty"` - Copies int `xml:"copies,attr,omitempty"` - Draft bool `xml:"draft,attr,omitempty"` - Errors string `xml:"errors,attr,omitempty"` - FirstPageNumber int `xml:"firstPageNumber,attr,omitempty"` - FitToHeight int `xml:"fitToHeight,attr,omitempty"` - FitToWidth int `xml:"fitToWidth,attr,omitempty"` - HorizontalDPI float32 `xml:"horizontalDpi,attr,omitempty"` - RID string `xml:"http://schemas.openxmlformats.org/officeDocument/2006/relationships id,attr,omitempty"` - Orientation string `xml:"orientation,attr,omitempty"` - PageOrder string `xml:"pageOrder,attr,omitempty"` - PaperHeight string `xml:"paperHeight,attr,omitempty"` - PaperSize int `xml:"paperSize,attr,omitempty"` - PaperWidth string `xml:"paperWidth,attr,omitempty"` - Scale int `xml:"scale,attr,omitempty"` - UseFirstPageNumber bool `xml:"useFirstPageNumber,attr,omitempty"` - UsePrinterDefaults bool `xml:"usePrinterDefaults,attr,omitempty"` - VerticalDPI float32 `xml:"verticalDpi,attr,omitempty"` + XMLName xml.Name `xml:"pageSetup"` + BlackAndWhite bool `xml:"blackAndWhite,attr,omitempty"` + CellComments string `xml:"cellComments,attr,omitempty"` + Copies int `xml:"copies,attr,omitempty"` + Draft bool `xml:"draft,attr,omitempty"` + Errors string `xml:"errors,attr,omitempty"` + FirstPageNumber int `xml:"firstPageNumber,attr,omitempty"` + FitToHeight int `xml:"fitToHeight,attr,omitempty"` + FitToWidth int `xml:"fitToWidth,attr,omitempty"` + HorizontalDPI float32 `xml:"horizontalDpi,attr,omitempty"` + RID string `xml:"http://schemas.openxmlformats.org/officeDocument/2006/relationships id,attr,omitempty"` + Orientation string `xml:"orientation,attr,omitempty"` + PageOrder string `xml:"pageOrder,attr,omitempty"` + PaperHeight string `xml:"paperHeight,attr,omitempty"` + PaperSize int `xml:"paperSize,attr,omitempty"` + PaperWidth string `xml:"paperWidth,attr,omitempty"` + Scale int `xml:"scale,attr,omitempty"` + UseFirstPageNumber bool `xml:"useFirstPageNumber,attr,omitempty"` + UsePrinterDefaults bool `xml:"usePrinterDefaults,attr,omitempty"` + VerticalDPI float32 `xml:"verticalDpi,attr,omitempty"` } // xlsxPrintOptions directly maps the printOptions element in the namespace @@ -124,44 +127,48 @@ type xlsxPageSetUp struct { // the sheet. Printer-specific settings are stored separately in the Printer // Settings part. type xlsxPrintOptions struct { - GridLines bool `xml:"gridLines,attr,omitempty"` - GridLinesSet bool `xml:"gridLinesSet,attr,omitempty"` - Headings bool `xml:"headings,attr,omitempty"` - HorizontalCentered bool `xml:"horizontalCentered,attr,omitempty"` - VerticalCentered bool `xml:"verticalCentered,attr,omitempty"` + XMLName xml.Name `xml:"printOptions"` + GridLines bool `xml:"gridLines,attr,omitempty"` + GridLinesSet bool `xml:"gridLinesSet,attr,omitempty"` + Headings bool `xml:"headings,attr,omitempty"` + HorizontalCentered bool `xml:"horizontalCentered,attr,omitempty"` + VerticalCentered bool `xml:"verticalCentered,attr,omitempty"` } // xlsxPageMargins directly maps the pageMargins element in the namespace // http://schemas.openxmlformats.org/spreadsheetml/2006/main - Page margins for // a sheet or a custom sheet view. type xlsxPageMargins struct { - Bottom float64 `xml:"bottom,attr"` - Footer float64 `xml:"footer,attr"` - Header float64 `xml:"header,attr"` - Left float64 `xml:"left,attr"` - Right float64 `xml:"right,attr"` - Top float64 `xml:"top,attr"` + XMLName xml.Name `xml:"pageMargins"` + Bottom float64 `xml:"bottom,attr"` + Footer float64 `xml:"footer,attr"` + Header float64 `xml:"header,attr"` + Left float64 `xml:"left,attr"` + Right float64 `xml:"right,attr"` + Top float64 `xml:"top,attr"` } // xlsxSheetFormatPr directly maps the sheetFormatPr element in the namespace // http://schemas.openxmlformats.org/spreadsheetml/2006/main. This element // specifies the sheet formatting properties. type xlsxSheetFormatPr struct { - BaseColWidth uint8 `xml:"baseColWidth,attr,omitempty"` - DefaultColWidth float64 `xml:"defaultColWidth,attr,omitempty"` - DefaultRowHeight float64 `xml:"defaultRowHeight,attr"` - CustomHeight bool `xml:"customHeight,attr,omitempty"` - ZeroHeight bool `xml:"zeroHeight,attr,omitempty"` - ThickTop bool `xml:"thickTop,attr,omitempty"` - ThickBottom bool `xml:"thickBottom,attr,omitempty"` - OutlineLevelRow uint8 `xml:"outlineLevelRow,attr,omitempty"` - OutlineLevelCol uint8 `xml:"outlineLevelCol,attr,omitempty"` + XMLName xml.Name `xml:"sheetFormatPr"` + BaseColWidth uint8 `xml:"baseColWidth,attr,omitempty"` + DefaultColWidth float64 `xml:"defaultColWidth,attr,omitempty"` + DefaultRowHeight float64 `xml:"defaultRowHeight,attr"` + CustomHeight bool `xml:"customHeight,attr,omitempty"` + ZeroHeight bool `xml:"zeroHeight,attr,omitempty"` + ThickTop bool `xml:"thickTop,attr,omitempty"` + ThickBottom bool `xml:"thickBottom,attr,omitempty"` + OutlineLevelRow uint8 `xml:"outlineLevelRow,attr,omitempty"` + OutlineLevelCol uint8 `xml:"outlineLevelCol,attr,omitempty"` } // xlsxSheetViews directly maps the sheetViews element in the namespace // http://schemas.openxmlformats.org/spreadsheetml/2006/main - Worksheet views // collection. type xlsxSheetViews struct { + XMLName xml.Name `xml:"sheetViews"` SheetView []xlsxSheetView `xml:"sheetView"` } @@ -263,7 +270,8 @@ type xlsxTabColor struct { // http://schemas.openxmlformats.org/spreadsheetml/2006/main - currently I have // not checked it for completeness - it does as much as I need. type xlsxCols struct { - Col []xlsxCol `xml:"col"` + XMLName xml.Name `xml:"cols"` + Col []xlsxCol `xml:"col"` } // xlsxCol directly maps the col (Column Width & Formatting). Defines column @@ -289,7 +297,8 @@ type xlsxCol struct { // When an entire column is formatted, only the first cell in that column is // considered used. type xlsxDimension struct { - Ref string `xml:"ref,attr"` + XMLName xml.Name `xml:"dimension"` + Ref string `xml:"ref,attr"` } // xlsxSheetData directly maps the sheetData element in the namespace @@ -322,6 +331,7 @@ type xlsxRow struct { // xlsxCustomSheetViews directly maps the customSheetViews element. This is a // collection of custom sheet views. type xlsxCustomSheetViews struct { + XMLName xml.Name `xml:"customSheetViews"` CustomSheetView []*xlsxCustomSheetView `xml:"customSheetView"` } @@ -384,13 +394,15 @@ type xlsxMergeCell struct { // xlsxMergeCells directly maps the mergeCells element. This collection // expresses all the merged cells in the sheet. type xlsxMergeCells struct { - Count int `xml:"count,attr,omitempty"` - Cells []*xlsxMergeCell `xml:"mergeCell,omitempty"` + XMLName xml.Name `xml:"mergeCells"` + Count int `xml:"count,attr,omitempty"` + Cells []*xlsxMergeCell `xml:"mergeCell,omitempty"` } // xlsxDataValidations expresses all data validation information for cells in a // sheet which have data validation features applied. type xlsxDataValidations struct { + XMLName xml.Name `xml:"dataValidations"` Count int `xml:"count,attr,omitempty"` DisablePrompts bool `xml:"disablePrompts,attr,omitempty"` XWindow int `xml:"xWindow,attr,omitempty"` @@ -434,14 +446,15 @@ type DataValidation struct { // str (String) | Cell containing a formula string. // type xlsxC struct { - R string `xml:"r,attr"` // Cell ID, e.g. A1 - S int `xml:"s,attr,omitempty"` // Style reference. - // Str string `xml:"str,attr,omitempty"` // Style reference. - T string `xml:"t,attr,omitempty"` // Type. - F *xlsxF `xml:"f,omitempty"` // Formula - V string `xml:"v,omitempty"` // Value - IS *xlsxSI `xml:"is"` + XMLName xml.Name `xml:"c"` XMLSpace xml.Attr `xml:"space,attr,omitempty"` + R string `xml:"r,attr"` // Cell ID, e.g. A1 + S int `xml:"s,attr,omitempty"` // Style reference. + // Str string `xml:"str,attr,omitempty"` // Style reference. + T string `xml:"t,attr,omitempty"` // Type. + F *xlsxF `xml:"f,omitempty"` // Formula + V string `xml:"v,omitempty"` // Value + IS *xlsxSI `xml:"is"` } func (c *xlsxC) hasValue() bool { @@ -461,27 +474,28 @@ type xlsxF struct { // xlsxSheetProtection collection expresses the sheet protection options to // enforce when the sheet is protected. type xlsxSheetProtection struct { - AlgorithmName string `xml:"algorithmName,attr,omitempty"` - Password string `xml:"password,attr,omitempty"` - HashValue string `xml:"hashValue,attr,omitempty"` - SaltValue string `xml:"saltValue,attr,omitempty"` - SpinCount int `xml:"spinCount,attr,omitempty"` - Sheet bool `xml:"sheet,attr"` - Objects bool `xml:"objects,attr"` - Scenarios bool `xml:"scenarios,attr"` - FormatCells bool `xml:"formatCells,attr"` - FormatColumns bool `xml:"formatColumns,attr"` - FormatRows bool `xml:"formatRows,attr"` - InsertColumns bool `xml:"insertColumns,attr"` - InsertRows bool `xml:"insertRows,attr"` - InsertHyperlinks bool `xml:"insertHyperlinks,attr"` - DeleteColumns bool `xml:"deleteColumns,attr"` - DeleteRows bool `xml:"deleteRows,attr"` - SelectLockedCells bool `xml:"selectLockedCells,attr"` - Sort bool `xml:"sort,attr"` - AutoFilter bool `xml:"autoFilter,attr"` - PivotTables bool `xml:"pivotTables,attr"` - SelectUnlockedCells bool `xml:"selectUnlockedCells,attr"` + XMLName xml.Name `xml:"sheetProtection"` + AlgorithmName string `xml:"algorithmName,attr,omitempty"` + Password string `xml:"password,attr,omitempty"` + HashValue string `xml:"hashValue,attr,omitempty"` + SaltValue string `xml:"saltValue,attr,omitempty"` + SpinCount int `xml:"spinCount,attr,omitempty"` + Sheet bool `xml:"sheet,attr"` + Objects bool `xml:"objects,attr"` + Scenarios bool `xml:"scenarios,attr"` + FormatCells bool `xml:"formatCells,attr"` + FormatColumns bool `xml:"formatColumns,attr"` + FormatRows bool `xml:"formatRows,attr"` + InsertColumns bool `xml:"insertColumns,attr"` + InsertRows bool `xml:"insertRows,attr"` + InsertHyperlinks bool `xml:"insertHyperlinks,attr"` + DeleteColumns bool `xml:"deleteColumns,attr"` + DeleteRows bool `xml:"deleteRows,attr"` + SelectLockedCells bool `xml:"selectLockedCells,attr"` + Sort bool `xml:"sort,attr"` + AutoFilter bool `xml:"autoFilter,attr"` + PivotTables bool `xml:"pivotTables,attr"` + SelectUnlockedCells bool `xml:"selectUnlockedCells,attr"` } // xlsxPhoneticPr (Phonetic Properties) represents a collection of phonetic @@ -492,9 +506,10 @@ type xlsxSheetProtection struct { // every phonetic hint is expressed as a phonetic run (rPh), and these // properties specify how to display that phonetic run. type xlsxPhoneticPr struct { - Alignment string `xml:"alignment,attr,omitempty"` - FontID *int `xml:"fontId,attr"` - Type string `xml:"type,attr,omitempty"` + XMLName xml.Name `xml:"phoneticPr"` + Alignment string `xml:"alignment,attr,omitempty"` + FontID *int `xml:"fontId,attr"` + Type string `xml:"type,attr,omitempty"` } // A Conditional Format is a format, such as cell shading or font color, that a @@ -502,8 +517,9 @@ type xlsxPhoneticPr struct { // condition is true. This collection expresses conditional formatting rules // applied to a particular cell or range. type xlsxConditionalFormatting struct { - SQRef string `xml:"sqref,attr,omitempty"` - CfRule []*xlsxCfRule `xml:"cfRule"` + XMLName xml.Name `xml:"conditionalFormatting"` + SQRef string `xml:"sqref,attr,omitempty"` + CfRule []*xlsxCfRule `xml:"cfRule"` } // xlsxCfRule (Conditional Formatting Rule) represents a description of a @@ -568,6 +584,7 @@ type xlsxCfvo struct { // be stored in a package as a relationship. Hyperlinks shall be identified by // containing a target which specifies the destination of the given hyperlink. type xlsxHyperlinks struct { + XMLName xml.Name `xml:"hyperlinks"` Hyperlink []xlsxHyperlink `xml:"hyperlink"` } @@ -612,6 +629,7 @@ type xlsxHyperlink struct { // </worksheet> // type xlsxTableParts struct { + XMLName xml.Name `xml:"tableParts"` Count int `xml:"count,attr,omitempty"` TableParts []*xlsxTablePart `xml:"tablePart"` } @@ -629,7 +647,8 @@ type xlsxTablePart struct { // <picture r:id="rId1"/> // type xlsxPicture struct { - RID string `xml:"http://schemas.openxmlformats.org/officeDocument/2006/relationships id,attr,omitempty"` + XMLName xml.Name `xml:"picture"` + RID string `xml:"http://schemas.openxmlformats.org/officeDocument/2006/relationships id,attr,omitempty"` } // xlsxLegacyDrawing directly maps the legacyDrawing element in the namespace @@ -642,7 +661,8 @@ type xlsxPicture struct { // can also be used to explain assumptions made in a formula or to call out // something special about the cell. type xlsxLegacyDrawing struct { - RID string `xml:"http://schemas.openxmlformats.org/officeDocument/2006/relationships id,attr,omitempty"` + XMLName xml.Name `xml:"legacyDrawing"` + RID string `xml:"http://schemas.openxmlformats.org/officeDocument/2006/relationships id,attr,omitempty"` } type xlsxInnerXML struct { |