305 changes: 230 additions & 75 deletions sheet.go

Large diffs are not rendered by default.

57 changes: 47 additions & 10 deletions sheet_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,15 @@ func ExampleFile_SetPageLayout() {
"Sheet1",
excelize.PageLayoutOrientation(excelize.OrientationLandscape),
); err != nil {
println(err.Error())
fmt.Println(err)
}
if err := f.SetPageLayout(
"Sheet1",
excelize.PageLayoutPaperSize(10),
excelize.FitToHeight(2),
excelize.FitToWidth(2),
); err != nil {
println(err.Error())
fmt.Println(err)
}
// Output:
}
Expand All @@ -41,17 +41,17 @@ func ExampleFile_GetPageLayout() {
fitToWidth excelize.FitToWidth
)
if err := f.GetPageLayout("Sheet1", &orientation); err != nil {
println(err.Error())
fmt.Println(err)
}
if err := f.GetPageLayout("Sheet1", &paperSize); err != nil {
println(err.Error())
fmt.Println(err)
}
if err := f.GetPageLayout("Sheet1", &fitToHeight); err != nil {
println(err.Error())
fmt.Println(err)
}

if err := f.GetPageLayout("Sheet1", &fitToWidth); err != nil {
println(err.Error())
fmt.Println(err)
}
fmt.Println("Defaults:")
fmt.Printf("- orientation: %q\n", orientation)
Expand Down Expand Up @@ -264,12 +264,49 @@ func TestUngroupSheets(t *testing.T) {
assert.NoError(t, f.UngroupSheets())
}

func TestInsertPageBreak(t *testing.T) {
f := excelize.NewFile()
assert.NoError(t, f.InsertPageBreak("Sheet1", "A1"))
assert.NoError(t, f.InsertPageBreak("Sheet1", "B2"))
assert.NoError(t, f.InsertPageBreak("Sheet1", "C3"))
assert.NoError(t, f.InsertPageBreak("Sheet1", "C3"))
assert.EqualError(t, f.InsertPageBreak("Sheet1", "A"), `cannot convert cell "A" to coordinates: invalid cell name "A"`)
assert.EqualError(t, f.InsertPageBreak("SheetN", "C3"), "sheet SheetN is not exist")
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestInsertPageBreak.xlsx")))
}

func TestRemovePageBreak(t *testing.T) {
f := excelize.NewFile()
assert.NoError(t, f.RemovePageBreak("Sheet1", "A2"))

assert.NoError(t, f.InsertPageBreak("Sheet1", "A2"))
assert.NoError(t, f.InsertPageBreak("Sheet1", "B2"))
assert.NoError(t, f.RemovePageBreak("Sheet1", "A1"))
assert.NoError(t, f.RemovePageBreak("Sheet1", "B2"))

assert.NoError(t, f.InsertPageBreak("Sheet1", "C3"))
assert.NoError(t, f.RemovePageBreak("Sheet1", "C3"))

assert.NoError(t, f.InsertPageBreak("Sheet1", "A3"))
assert.NoError(t, f.RemovePageBreak("Sheet1", "B3"))
assert.NoError(t, f.RemovePageBreak("Sheet1", "A3"))

f.NewSheet("Sheet2")
assert.NoError(t, f.InsertPageBreak("Sheet2", "B2"))
assert.NoError(t, f.InsertPageBreak("Sheet2", "C2"))
assert.NoError(t, f.RemovePageBreak("Sheet2", "B2"))

assert.EqualError(t, f.RemovePageBreak("Sheet1", "A"), `cannot convert cell "A" to coordinates: invalid cell name "A"`)
assert.EqualError(t, f.RemovePageBreak("SheetN", "C3"), "sheet SheetN is not exist")
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestRemovePageBreak.xlsx")))
}

func TestGetSheetName(t *testing.T) {
f, _ := excelize.OpenFile(filepath.Join("test", "Book1.xlsx"))
assert.Equal(t, "Sheet1", f.GetSheetName(1))
assert.Equal(t, "Sheet2", f.GetSheetName(2))
assert.Equal(t, "", f.GetSheetName(0))
assert.Equal(t, "", f.GetSheetName(3))
assert.Equal(t, "Sheet1", f.GetSheetName(0))
assert.Equal(t, "Sheet2", f.GetSheetName(1))
assert.Equal(t, "", f.GetSheetName(-1))
assert.Equal(t, "", f.GetSheetName(2))
}

func TestGetSheetMap(t *testing.T) {
Expand Down
8 changes: 4 additions & 4 deletions sheetpr_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ func ExampleFile_SetSheetPrOptions() {
excelize.AutoPageBreaks(true),
excelize.OutlineSummaryBelow(false),
); err != nil {
println(err.Error())
fmt.Println(err)
}
// Output:
}
Expand All @@ -66,7 +66,7 @@ func ExampleFile_GetSheetPrOptions() {
&autoPageBreaks,
&outlineSummaryBelow,
); err != nil {
println(err.Error())
fmt.Println(err)
}
fmt.Println("Defaults:")
fmt.Printf("- codeName: %q\n", codeName)
Expand Down Expand Up @@ -189,7 +189,7 @@ func ExampleFile_SetPageMargins() {
excelize.PageMarginRight(1.0),
excelize.PageMarginTop(1.0),
); err != nil {
println(err.Error())
fmt.Println(err)
}
// Output:
}
Expand All @@ -215,7 +215,7 @@ func ExampleFile_GetPageMargins() {
&marginRight,
&marginTop,
); err != nil {
println(err.Error())
fmt.Println(err)
}
fmt.Println("Defaults:")
fmt.Println("- marginBottom:", marginBottom)
Expand Down
24 changes: 12 additions & 12 deletions sheetview_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,30 +47,30 @@ func ExampleFile_SetSheetViewOptions() {
excelize.ZoomScale(80),
excelize.TopLeftCell("C3"),
); err != nil {
println(err.Error())
fmt.Println(err)
}

var zoomScale excelize.ZoomScale
fmt.Println("Default:")
fmt.Println("- zoomScale: 80")

if err := f.SetSheetViewOptions(sheet, 0, excelize.ZoomScale(500)); err != nil {
println(err.Error())
fmt.Println(err)
}

if err := f.GetSheetViewOptions(sheet, 0, &zoomScale); err != nil {
println(err.Error())
fmt.Println(err)
}

fmt.Println("Used out of range value:")
fmt.Println("- zoomScale:", zoomScale)

if err := f.SetSheetViewOptions(sheet, 0, excelize.ZoomScale(123)); err != nil {
println(err.Error())
fmt.Println(err)
}

if err := f.GetSheetViewOptions(sheet, 0, &zoomScale); err != nil {
println(err.Error())
fmt.Println(err)
}

fmt.Println("Used correct value:")
Expand Down Expand Up @@ -111,7 +111,7 @@ func ExampleFile_GetSheetViewOptions() {
&zoomScale,
&topLeftCell,
); err != nil {
println(err.Error())
fmt.Println(err)
}

fmt.Println("Default:")
Expand All @@ -125,27 +125,27 @@ func ExampleFile_GetSheetViewOptions() {
fmt.Println("- topLeftCell:", `"`+topLeftCell+`"`)

if err := f.SetSheetViewOptions(sheet, 0, excelize.TopLeftCell("B2")); err != nil {
println(err.Error())
fmt.Println(err)
}

if err := f.GetSheetViewOptions(sheet, 0, &topLeftCell); err != nil {
println(err.Error())
fmt.Println(err)
}

if err := f.SetSheetViewOptions(sheet, 0, excelize.ShowGridLines(false)); err != nil {
println(err.Error())
fmt.Println(err)
}

if err := f.GetSheetViewOptions(sheet, 0, &showGridLines); err != nil {
println(err.Error())
fmt.Println(err)
}

if err := f.SetSheetViewOptions(sheet, 0, excelize.ShowZeros(false)); err != nil {
println(err.Error())
fmt.Println(err)
}

if err := f.GetSheetViewOptions(sheet, 0, &showZeros); err != nil {
println(err.Error())
fmt.Println(err)
}

fmt.Println("After change:")
Expand Down
5 changes: 2 additions & 3 deletions sparkline.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
package excelize

import (
"bytes"
"encoding/xml"
"errors"
"io"
Expand Down Expand Up @@ -509,14 +508,14 @@ func (f *File) appendSparkline(ws *xlsxWorksheet, group *xlsxX14SparklineGroup,
sparklineGroupsBytes, sparklineGroupBytes, extLstBytes []byte
)
decodeExtLst = new(decodeWorksheetExt)
if err = f.xmlNewDecoder(bytes.NewReader([]byte("<extLst>" + ws.ExtLst.Ext + "</extLst>"))).
if err = f.xmlNewDecoder(strings.NewReader("<extLst>" + ws.ExtLst.Ext + "</extLst>")).
Decode(decodeExtLst); err != nil && err != io.EOF {
return
}
for idx, ext = range decodeExtLst.Ext {
if ext.URI == ExtURISparklineGroups {
decodeSparklineGroups = new(decodeX14SparklineGroups)
if err = f.xmlNewDecoder(bytes.NewReader([]byte(ext.Content))).
if err = f.xmlNewDecoder(strings.NewReader(ext.Content)).
Decode(decodeSparklineGroups); err != nil && err != io.EOF {
return
}
Expand Down
4 changes: 2 additions & 2 deletions sparkline_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -298,12 +298,12 @@ func prepareSparklineDataset() *File {
f.NewSheet("Sheet3")
for row, data := range sheet2 {
if err := f.SetSheetRow("Sheet2", fmt.Sprintf("A%d", row+1), &data); err != nil {
println(err.Error())
fmt.Println(err)
}
}
for row, data := range sheet3 {
if err := f.SetSheetRow("Sheet3", fmt.Sprintf("A%d", row+1), &data); err != nil {
println(err.Error())
fmt.Println(err)
}
}
return f
Expand Down
45 changes: 20 additions & 25 deletions stream.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ type StreamWriter struct {
File *File
Sheet string
SheetID int
worksheet *xlsxWorksheet
rawData bufferedWriter
tableParts string
}
Expand All @@ -41,14 +42,14 @@ type StreamWriter struct {
// file := excelize.NewFile()
// streamWriter, err := file.NewStreamWriter("Sheet1")
// if err != nil {
// println(err.Error())
// fmt.Println(err)
// }
// styleID, err := file.NewStyle(`{"font":{"color":"#777777"}}`)
// if err != nil {
// println(err.Error())
// fmt.Println(err)
// }
// if err := streamWriter.SetRow("A1", []interface{}{excelize.Cell{StyleID: styleID, Value: "Data"}}); err != nil {
// println(err.Error())
// fmt.Println(err)
// }
// for rowID := 2; rowID <= 102400; rowID++ {
// row := make([]interface{}, 50)
Expand All @@ -57,18 +58,18 @@ type StreamWriter struct {
// }
// cell, _ := excelize.CoordinatesToCellName(1, rowID)
// if err := streamWriter.SetRow(cell, row); err != nil {
// println(err.Error())
// fmt.Println(err)
// }
// }
// if err := streamWriter.Flush(); err != nil {
// println(err.Error())
// fmt.Println(err)
// }
// if err := file.SaveAs("Book1.xlsx"); err != nil {
// println(err.Error())
// fmt.Println(err)
// }
//
func (f *File) NewStreamWriter(sheet string) (*StreamWriter, error) {
sheetID := f.GetSheetIndex(sheet)
sheetID := f.getSheetID(sheet)
if sheetID == 0 {
return nil, fmt.Errorf("sheet %s is not exist", sheet)
}
Expand All @@ -77,15 +78,15 @@ func (f *File) NewStreamWriter(sheet string) (*StreamWriter, error) {
Sheet: sheet,
SheetID: sheetID,
}

ws, err := f.workSheetReader(sheet)
var err error
sw.worksheet, err = f.workSheetReader(sheet)
if err != nil {
return nil, err
}
sw.rawData.WriteString(XMLHeader + `<worksheet` + templateNamespaceIDMap)
bulkAppendOtherFields(&sw.rawData, ws, "XMLName", "SheetData", "TableParts")
bulkAppendFields(&sw.rawData, sw.worksheet, 1, 5)
sw.rawData.WriteString(`<sheetData>`)
return sw, nil
return sw, err
}

// AddTable creates an Excel table for the StreamWriter using the given
Expand Down Expand Up @@ -364,7 +365,7 @@ func writeCell(buf *bufferedWriter, c xlsxC) {
buf.WriteString(`>`)
if c.V != "" {
buf.WriteString(`<v>`)
xml.EscapeText(buf, []byte(c.V))
xml.EscapeText(buf, stringToBytes(c.V))
buf.WriteString(`</v>`)
}
buf.WriteString(`</c>`)
Expand All @@ -373,7 +374,9 @@ func writeCell(buf *bufferedWriter, c xlsxC) {
// Flush ending the streaming writing process.
func (sw *StreamWriter) Flush() error {
sw.rawData.WriteString(`</sheetData>`)
bulkAppendFields(&sw.rawData, sw.worksheet, 7, 37)
sw.rawData.WriteString(sw.tableParts)
bulkAppendFields(&sw.rawData, sw.worksheet, 39, 39)
sw.rawData.WriteString(`</worksheet>`)
if err := sw.rawData.Flush(); err != nil {
return err
Expand All @@ -392,23 +395,15 @@ func (sw *StreamWriter) Flush() error {
return nil
}

// bulkAppendOtherFields bulk-appends fields in a worksheet, skipping the
// specified field names.
func bulkAppendOtherFields(w io.Writer, ws *xlsxWorksheet, skip ...string) {
skipMap := make(map[string]struct{})
for _, name := range skip {
skipMap[name] = struct{}{}
}

// bulkAppendFields bulk-appends fields in a worksheet by specified field
// names order range.
func bulkAppendFields(w io.Writer, ws *xlsxWorksheet, from, to int) {
s := reflect.ValueOf(ws).Elem()
typeOfT := s.Type()
enc := xml.NewEncoder(w)
for i := 0; i < s.NumField(); i++ {
f := s.Field(i)
if _, ok := skipMap[typeOfT.Field(i).Name]; ok {
continue
if from <= i && i <= to {
enc.Encode(s.Field(i).Interface())
}
enc.Encode(f.Interface())
}
}

Expand Down
7 changes: 7 additions & 0 deletions stream_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,13 @@ func TestStreamWriter(t *testing.T) {
_, err = streamWriter.rawData.Reader()
assert.NoError(t, err)
assert.NoError(t, os.Remove(streamWriter.rawData.tmp.Name()))

// Test unsupport charset
file = NewFile()
delete(file.Sheet, "xl/worksheets/sheet1.xml")
file.XLSX["xl/worksheets/sheet1.xml"] = MacintoshCyrillicCharset
streamWriter, err = file.NewStreamWriter("Sheet1")
assert.EqualError(t, err, "xml decode error: XML syntax error on line 1: invalid UTF-8")
}

func TestStreamTable(t *testing.T) {
Expand Down
250 changes: 145 additions & 105 deletions styles.go

Large diffs are not rendered by default.

47 changes: 44 additions & 3 deletions styles_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package excelize

import (
"fmt"
"path/filepath"
"testing"

"github.com/stretchr/testify/assert"
Expand Down Expand Up @@ -31,9 +33,9 @@ func TestStyleFill(t *testing.T) {
styles := xl.stylesReader()
style := styles.CellXfs.Xf[styleID]
if testCase.expectFill {
assert.NotEqual(t, style.FillID, 0, testCase.label)
assert.NotEqual(t, *style.FillID, 0, testCase.label)
} else {
assert.Equal(t, style.FillID, 0, testCase.label)
assert.Equal(t, *style.FillID, 0, testCase.label)
}
}
}
Expand Down Expand Up @@ -166,15 +168,33 @@ func TestSetConditionalFormat(t *testing.T) {
}
}

func TestUnsetConditionalFormat(t *testing.T) {
f := NewFile()
assert.NoError(t, f.SetCellValue("Sheet1", "A1", 7))
assert.NoError(t, f.UnsetConditionalFormat("Sheet1", "A1:A10"))
format, err := f.NewConditionalStyle(`{"font":{"color":"#9A0511"},"fill":{"type":"pattern","color":["#FEC7CE"],"pattern":1}}`)
assert.NoError(t, err)
assert.NoError(t, f.SetConditionalFormat("Sheet1", "A1:A10", fmt.Sprintf(`[{"type":"cell","criteria":">","format":%d,"value":"6"}]`, format)))
assert.NoError(t, f.UnsetConditionalFormat("Sheet1", "A1:A10"))
// Test unset conditional format on not exists worksheet.
assert.EqualError(t, f.UnsetConditionalFormat("SheetN", "A1:A10"), "sheet SheetN is not exist")
// Save xlsx file by the given path.
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestUnsetConditionalFormat.xlsx")))
}

func TestNewStyle(t *testing.T) {
f := NewFile()
styleID, err := f.NewStyle(`{"font":{"bold":true,"italic":true,"family":"Times New Roman","size":36,"color":"#777777"}}`)
assert.NoError(t, err)
styles := f.stylesReader()
fontID := styles.CellXfs.Xf[styleID].FontID
font := styles.Fonts.Font[fontID]
font := styles.Fonts.Font[*fontID]
assert.Contains(t, *font.Name.Val, "Times New Roman", "Stored font should contain font name")
assert.Equal(t, 2, styles.CellXfs.Count, "Should have 2 styles")
_, err = f.NewStyle(&Style{})
assert.NoError(t, err)
_, err = f.NewStyle(Style{})
assert.EqualError(t, err, "invalid parameter type")
}

func TestGetDefaultFont(t *testing.T) {
Expand All @@ -191,3 +211,24 @@ func TestSetDefaultFont(t *testing.T) {
assert.Equal(t, s, "Ariel", "Default font should change to Ariel")
assert.Equal(t, *styles.CellStyles.CellStyle[0].CustomBuiltIn, true)
}

func TestStylesReader(t *testing.T) {
f := NewFile()
// Test read styles with unsupport charset.
f.Styles = nil
f.XLSX["xl/styles.xml"] = MacintoshCyrillicCharset
assert.EqualValues(t, new(xlsxStyleSheet), f.stylesReader())
}

func TestThemeReader(t *testing.T) {
f := NewFile()
// Test read theme with unsupport charset.
f.XLSX["xl/theme/theme1.xml"] = MacintoshCyrillicCharset
assert.EqualValues(t, new(xlsxTheme), f.themeReader())
}

func TestSetCellStyle(t *testing.T) {
f := NewFile()
// Test set cell style on not exists worksheet.
assert.EqualError(t, f.SetCellStyle("SheetN", "A1", "A2", 1), "sheet SheetN is not exist")
}
Binary file modified test/images/chart.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion xmlChart.go
Original file line number Diff line number Diff line change
Expand Up @@ -604,7 +604,7 @@ type formatChart struct {
type formatChartLegend struct {
None bool `json:"none"`
DeleteSeries []int `json:"delete_series"`
Font formatFont `json:"font"`
Font Font `json:"font"`
Layout formatLayout `json:"layout"`
Position string `json:"position"`
ShowLegendEntry bool `json:"show_legend_entry"`
Expand Down
88 changes: 88 additions & 0 deletions xmlChartSheet.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
// Copyright 2016 - 2020 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.
//
// struct code generated by github.com/xuri/xgen
//
// 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 "encoding/xml"

// xlsxChartsheet directly maps the chartsheet element of Chartsheet Parts in
// a SpreadsheetML document.
type xlsxChartsheet struct {
XMLName xml.Name `xml:"http://schemas.openxmlformats.org/spreadsheetml/2006/main chartsheet"`
SheetPr []*xlsxChartsheetPr `xml:"sheetPr"`
SheetViews []*xlsxChartsheetViews `xml:"sheetViews"`
SheetProtection []*xlsxChartsheetProtection `xml:"sheetProtection"`
CustomSheetViews []*xlsxCustomChartsheetViews `xml:"customSheetViews"`
PageMargins *xlsxPageMargins `xml:"pageMargins"`
PageSetup []*xlsxPageSetUp `xml:"pageSetup"`
HeaderFooter *xlsxHeaderFooter `xml:"headerFooter"`
Drawing *xlsxDrawing `xml:"drawing"`
DrawingHF []*xlsxDrawingHF `xml:"drawingHF"`
Picture []*xlsxPicture `xml:"picture"`
WebPublishItems []*xlsxInnerXML `xml:"webPublishItems"`
ExtLst []*xlsxExtLst `xml:"extLst"`
}

// xlsxChartsheetPr specifies chart sheet properties.
type xlsxChartsheetPr struct {
XMLName xml.Name `xml:"sheetPr"`
PublishedAttr bool `xml:"published,attr,omitempty"`
CodeNameAttr string `xml:"codeName,attr,omitempty"`
TabColor []*xlsxTabColor `xml:"tabColor"`
}

// xlsxChartsheetViews specifies chart sheet views.
type xlsxChartsheetViews struct {
XMLName xml.Name `xml:"sheetViews"`
SheetView []*xlsxChartsheetView `xml:"sheetView"`
ExtLst []*xlsxExtLst `xml:"extLst"`
}

// xlsxChartsheetView defines custom view properties for chart sheets.
type xlsxChartsheetView struct {
XMLName xml.Name `xml:"sheetView"`
TabSelectedAttr bool `xml:"tabSelected,attr,omitempty"`
ZoomScaleAttr uint32 `xml:"zoomScale,attr,omitempty"`
WorkbookViewIDAttr uint32 `xml:"workbookViewId,attr"`
ZoomToFitAttr bool `xml:"zoomToFit,attr,omitempty"`
ExtLst []*xlsxExtLst `xml:"extLst"`
}

// xlsxChartsheetProtection collection expresses the chart sheet protection
// options to enforce when the chart sheet is protected.
type xlsxChartsheetProtection struct {
XMLName xml.Name `xml:"sheetProtection"`
AlgorithmNameAttr string `xml:"algorithmName,attr,omitempty"`
HashValueAttr []byte `xml:"hashValue,attr,omitempty"`
SaltValueAttr []byte `xml:"saltValue,attr,omitempty"`
SpinCountAttr uint32 `xml:"spinCount,attr,omitempty"`
ContentAttr bool `xml:"content,attr,omitempty"`
ObjectsAttr bool `xml:"objects,attr,omitempty"`
}

// xlsxCustomChartsheetViews collection of custom Chart Sheet View
// information.
type xlsxCustomChartsheetViews struct {
XMLName xml.Name `xml:"customChartsheetViews"`
CustomSheetView []*xlsxCustomChartsheetView `xml:"customSheetView"`
}

// xlsxCustomChartsheetView defines custom view properties for chart sheets.
type xlsxCustomChartsheetView struct {
XMLName xml.Name `xml:"customChartsheetView"`
GUIDAttr string `xml:"guid,attr"`
ScaleAttr uint32 `xml:"scale,attr,omitempty"`
StateAttr string `xml:"state,attr,omitempty"`
ZoomToFitAttr bool `xml:"zoomToFit,attr,omitempty"`
PageMargins []*xlsxPageMargins `xml:"pageMargins"`
PageSetup []*xlsxPageSetUp `xml:"pageSetup"`
HeaderFooter []*xlsxHeaderFooter `xml:"headerFooter"`
}
108 changes: 66 additions & 42 deletions xmlDrawing.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,40 +13,55 @@ import "encoding/xml"

// Source relationship and namespace.
const (
SourceRelationship = "http://schemas.openxmlformats.org/officeDocument/2006/relationships"
SourceRelationshipChart = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart"
SourceRelationshipComments = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments"
SourceRelationshipImage = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image"
SourceRelationshipTable = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/table"
SourceRelationshipDrawingML = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/drawing"
SourceRelationshipDrawingVML = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/vmlDrawing"
SourceRelationshipHyperLink = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink"
SourceRelationshipWorkSheet = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet"
SourceRelationshipPivotTable = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/pivotTable"
SourceRelationshipPivotCache = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/pivotCacheDefinition"
SourceRelationshipVBAProject = "http://schemas.microsoft.com/office/2006/relationships/vbaProject"
SourceRelationshipChart201506 = "http://schemas.microsoft.com/office/drawing/2015/06/chart"
SourceRelationshipChart20070802 = "http://schemas.microsoft.com/office/drawing/2007/8/2/chart"
SourceRelationshipChart2014 = "http://schemas.microsoft.com/office/drawing/2014/chart"
SourceRelationshipCompatibility = "http://schemas.openxmlformats.org/markup-compatibility/2006"
NameSpaceDrawingML = "http://schemas.openxmlformats.org/drawingml/2006/main"
NameSpaceDrawingMLChart = "http://schemas.openxmlformats.org/drawingml/2006/chart"
NameSpaceDrawingMLSpreadSheet = "http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing"
NameSpaceSpreadSheet = "http://schemas.openxmlformats.org/spreadsheetml/2006/main"
NameSpaceSpreadSheetX14 = "http://schemas.microsoft.com/office/spreadsheetml/2009/9/main"
NameSpaceSpreadSheetX15 = "http://schemas.microsoft.com/office/spreadsheetml/2010/11/main"
NameSpaceSpreadSheetExcel2006Main = "http://schemas.microsoft.com/office/excel/2006/main"
NameSpaceMacExcel2008Main = "http://schemas.microsoft.com/office/mac/excel/2008/main"
NameSpaceXML = "http://www.w3.org/XML/1998/namespace"
NameSpaceXMLSchemaInstance = "http://www.w3.org/2001/XMLSchema-instance"
StrictSourceRelationship = "http://purl.oclc.org/ooxml/officeDocument/relationships"
StrictSourceRelationshipChart = "http://purl.oclc.org/ooxml/officeDocument/relationships/chart"
StrictSourceRelationshipComments = "http://purl.oclc.org/ooxml/officeDocument/relationships/comments"
StrictSourceRelationshipImage = "http://purl.oclc.org/ooxml/officeDocument/relationships/image"
StrictNameSpaceSpreadSheet = "http://purl.oclc.org/ooxml/spreadsheetml/main"
NameSpaceDublinCore = "http://purl.org/dc/elements/1.1/"
NameSpaceDublinCoreTerms = "http://purl.org/dc/terms/"
NameSpaceDublinCoreMetadataIntiative = "http://purl.org/dc/dcmitype/"
SourceRelationship = "http://schemas.openxmlformats.org/officeDocument/2006/relationships"
SourceRelationshipChart = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart"
SourceRelationshipComments = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments"
SourceRelationshipImage = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image"
SourceRelationshipTable = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/table"
SourceRelationshipDrawingML = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/drawing"
SourceRelationshipDrawingVML = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/vmlDrawing"
SourceRelationshipHyperLink = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink"
SourceRelationshipWorkSheet = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet"
SourceRelationshipChartsheet = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chartsheet"
SourceRelationshipDialogsheet = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/dialogsheet"
SourceRelationshipPivotTable = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/pivotTable"
SourceRelationshipPivotCache = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/pivotCacheDefinition"
SourceRelationshipSharedStrings = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings"
SourceRelationshipVBAProject = "http://schemas.microsoft.com/office/2006/relationships/vbaProject"
SourceRelationshipChart201506 = "http://schemas.microsoft.com/office/drawing/2015/06/chart"
SourceRelationshipChart20070802 = "http://schemas.microsoft.com/office/drawing/2007/8/2/chart"
SourceRelationshipChart2014 = "http://schemas.microsoft.com/office/drawing/2014/chart"
SourceRelationshipCompatibility = "http://schemas.openxmlformats.org/markup-compatibility/2006"
NameSpaceDrawingML = "http://schemas.openxmlformats.org/drawingml/2006/main"
NameSpaceDrawingMLChart = "http://schemas.openxmlformats.org/drawingml/2006/chart"
NameSpaceDrawingMLSpreadSheet = "http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing"
NameSpaceSpreadSheet = "http://schemas.openxmlformats.org/spreadsheetml/2006/main"
NameSpaceSpreadSheetX14 = "http://schemas.microsoft.com/office/spreadsheetml/2009/9/main"
NameSpaceSpreadSheetX15 = "http://schemas.microsoft.com/office/spreadsheetml/2010/11/main"
NameSpaceSpreadSheetExcel2006Main = "http://schemas.microsoft.com/office/excel/2006/main"
NameSpaceMacExcel2008Main = "http://schemas.microsoft.com/office/mac/excel/2008/main"
NameSpaceXML = "http://www.w3.org/XML/1998/namespace"
NameSpaceXMLSchemaInstance = "http://www.w3.org/2001/XMLSchema-instance"
StrictSourceRelationship = "http://purl.oclc.org/ooxml/officeDocument/relationships"
StrictSourceRelationshipChart = "http://purl.oclc.org/ooxml/officeDocument/relationships/chart"
StrictSourceRelationshipComments = "http://purl.oclc.org/ooxml/officeDocument/relationships/comments"
StrictSourceRelationshipImage = "http://purl.oclc.org/ooxml/officeDocument/relationships/image"
StrictNameSpaceSpreadSheet = "http://purl.oclc.org/ooxml/spreadsheetml/main"
NameSpaceDublinCore = "http://purl.org/dc/elements/1.1/"
NameSpaceDublinCoreTerms = "http://purl.org/dc/terms/"
NameSpaceDublinCoreMetadataIntiative = "http://purl.org/dc/dcmitype/"
ContentTypeDrawing = "application/vnd.openxmlformats-officedocument.drawing+xml"
ContentTypeDrawingML = "application/vnd.openxmlformats-officedocument.drawingml.chart+xml"
ContentTypeMacro = "application/vnd.ms-excel.sheet.macroEnabled.main+xml"
ContentTypeSpreadSheetMLChartsheet = "application/vnd.openxmlformats-officedocument.spreadsheetml.chartsheet+xml"
ContentTypeSpreadSheetMLComments = "application/vnd.openxmlformats-officedocument.spreadsheetml.comments+xml"
ContentTypeSpreadSheetMLPivotCacheDefinition = "application/vnd.openxmlformats-officedocument.spreadsheetml.pivotCacheDefinition+xml"
ContentTypeSpreadSheetMLPivotTable = "application/vnd.openxmlformats-officedocument.spreadsheetml.pivotTable+xml"
ContentTypeSpreadSheetMLSharedStrings = "application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml"
ContentTypeSpreadSheetMLTable = "application/vnd.openxmlformats-officedocument.spreadsheetml.table+xml"
ContentTypeSpreadSheetMLWorksheet = "application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml"
ContentTypeVBA = "application/vnd.ms-office.vbaProject"
ContentTypeVML = "application/vnd.openxmlformats-officedocument.vmlDrawing"
// ExtURIConditionalFormattings is the extLst child element
// ([ISO/IEC29500-1:2016] section 18.2.10) of the worksheet element
// ([ISO/IEC29500-1:2016] section 18.3.1.99) is extended by the addition of
Expand Down Expand Up @@ -240,6 +255,7 @@ type xdrClientData struct {
// with cells and its extents are in EMU units.
type xdrCellAnchor struct {
EditAs string `xml:"editAs,attr,omitempty"`
Pos *xlsxPoint2D `xml:"xdr:pos"`
From *xlsxFrom `xml:"xdr:from"`
To *xlsxTo `xml:"xdr:to"`
Ext *xlsxExt `xml:"xdr:ext"`
Expand All @@ -249,15 +265,23 @@ type xdrCellAnchor struct {
ClientData *xdrClientData `xml:"xdr:clientData"`
}

// xlsxPoint2D describes the position of a drawing element within a spreadsheet.
type xlsxPoint2D struct {
XMLName xml.Name `xml:"xdr:pos"`
X int `xml:"x,attr"`
Y int `xml:"y,attr"`
}

// xlsxWsDr directly maps the root element for a part of this content type shall
// wsDr.
type xlsxWsDr struct {
XMLName xml.Name `xml:"xdr:wsDr"`
OneCellAnchor []*xdrCellAnchor `xml:"xdr:oneCellAnchor"`
TwoCellAnchor []*xdrCellAnchor `xml:"xdr:twoCellAnchor"`
A string `xml:"xmlns:a,attr,omitempty"`
Xdr string `xml:"xmlns:xdr,attr,omitempty"`
R string `xml:"xmlns:r,attr,omitempty"`
XMLName xml.Name `xml:"xdr:wsDr"`
AbsoluteAnchor []*xdrCellAnchor `xml:"xdr:absoluteAnchor"`
OneCellAnchor []*xdrCellAnchor `xml:"xdr:oneCellAnchor"`
TwoCellAnchor []*xdrCellAnchor `xml:"xdr:twoCellAnchor"`
A string `xml:"xmlns:a,attr,omitempty"`
Xdr string `xml:"xmlns:xdr,attr,omitempty"`
R string `xml:"xmlns:r,attr,omitempty"`
}

// xlsxGraphicFrame (Graphic Frame) directly maps the xdr:graphicFrame element.
Expand Down Expand Up @@ -417,8 +441,8 @@ type formatShape struct {
// formatShapeParagraph directly maps the format settings of the paragraph in
// the shape.
type formatShapeParagraph struct {
Font formatFont `json:"font"`
Text string `json:"text"`
Font Font `json:"font"`
Text string `json:"text"`
}

// formatShapeColor directly maps the color settings of the shape.
Expand Down
6 changes: 3 additions & 3 deletions xmlPivotTable.go
Original file line number Diff line number Diff line change
Expand Up @@ -251,9 +251,9 @@ type xlsxPageFields struct {
type xlsxPageField struct {
Fld int `xml:"fld,attr"`
Item int `xml:"item,attr,omitempty"`
Hier int `xml:"hier,attr"`
Name string `xml:"name,attr"`
Cap string `xml:"cap,attr"`
Hier int `xml:"hier,attr,omitempty"`
Name string `xml:"name,attr,omitempty"`
Cap string `xml:"cap,attr,omitempty"`
ExtLst *xlsxExtLst `xml:"extLst"`
}

Expand Down
59 changes: 45 additions & 14 deletions xmlSharedStrings.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,31 +28,46 @@ type xlsxSST struct {
SI []xlsxSI `xml:"si"`
}

// xlsxSI directly maps the si element from the namespace
// http://schemas.openxmlformats.org/spreadsheetml/2006/main - currently I have
// not checked this for completeness - it does as much as I need.
// xlsxSI (String Item) is the representation of an individual string in the
// Shared String table. If the string is just a simple string with formatting
// applied at the cell level, then the String Item (si) should contain a
// single text element used to express the string. However, if the string in
// the cell is more complex - i.e., has formatting applied at the character
// level - then the string item shall consist of multiple rich text runs which
// collectively are used to express the string.
type xlsxSI struct {
T string `xml:"t"`
T string `xml:"t,omitempty"`
R []xlsxR `xml:"r"`
}

// String extracts characters from a string item.
func (x xlsxSI) String() string {
if len(x.R) > 0 {
var rows strings.Builder
for _, s := range x.R {
rows.WriteString(s.T)
if s.T != nil {
rows.WriteString(s.T.Val)
}
}
return rows.String()
}
return x.T
}

// xlsxR directly maps the r element from the namespace
// http://schemas.openxmlformats.org/spreadsheetml/2006/main - currently I have
// not checked this for completeness - it does as much as I need.
// xlsxR represents a run of rich text. A rich text run is a region of text
// that share a common set of properties, such as formatting properties. The
// properties are defined in the rPr element, and the text displayed to the
// user is defined in the Text (t) element.
type xlsxR struct {
RPr *xlsxRPr `xml:"rPr"`
T string `xml:"t"`
T *xlsxT `xml:"t"`
}

// xlsxT directly maps the t element in the run properties.
type xlsxT struct {
XMLName xml.Name `xml:"t"`
Space string `xml:"xml:space,attr,omitempty"`
Val string `xml:",innerxml"`
}

// xlsxRPr (Run Properties) specifies a set of run properties which shall be
Expand All @@ -61,9 +76,25 @@ type xlsxR struct {
// they are directly applied to the run and supersede any formatting from
// styles.
type xlsxRPr struct {
B string `xml:"b,omitempty"`
Sz *attrValFloat `xml:"sz"`
Color *xlsxColor `xml:"color"`
RFont *attrValString `xml:"rFont"`
Family *attrValInt `xml:"family"`
RFont *attrValString `xml:"rFont"`
Charset *attrValInt `xml:"charset"`
Family *attrValInt `xml:"family"`
B string `xml:"b,omitempty"`
I string `xml:"i,omitempty"`
Strike string `xml:"strike,omitempty"`
Outline string `xml:"outline,omitempty"`
Shadow string `xml:"shadow,omitempty"`
Condense string `xml:"condense,omitempty"`
Extend string `xml:"extend,omitempty"`
Color *xlsxColor `xml:"color"`
Sz *attrValFloat `xml:"sz"`
U *attrValString `xml:"u"`
VertAlign *attrValString `xml:"vertAlign"`
Scheme *attrValString `xml:"scheme"`
}

// RichTextRun directly maps the settings of the rich text run.
type RichTextRun struct {
Font *Font
Text string
}
116 changes: 64 additions & 52 deletions xmlStyles.go
Original file line number Diff line number Diff line change
Expand Up @@ -186,12 +186,12 @@ type xlsxCellStyles struct {
// workbook.
type xlsxCellStyle struct {
XMLName xml.Name `xml:"cellStyle"`
BuiltInID *int `xml:"builtinId,attr,omitempty"`
CustomBuiltIn *bool `xml:"customBuiltin,attr,omitempty"`
Hidden *bool `xml:"hidden,attr,omitempty"`
ILevel *bool `xml:"iLevel,attr,omitempty"`
Name string `xml:"name,attr"`
XfID int `xml:"xfId,attr"`
BuiltInID *int `xml:"builtinId,attr,omitempty"`
ILevel *int `xml:"iLevel,attr,omitempty"`
Hidden *bool `xml:"hidden,attr,omitempty"`
CustomBuiltIn *bool `xml:"customBuiltin,attr,omitempty"`
}

// xlsxCellStyleXfs directly maps the cellStyleXfs element. This element
Expand All @@ -209,19 +209,19 @@ type xlsxCellStyleXfs struct {
// xlsxXf directly maps the xf element. A single xf element describes all of the
// formatting for a cell.
type xlsxXf struct {
ApplyAlignment bool `xml:"applyAlignment,attr"`
ApplyBorder bool `xml:"applyBorder,attr"`
ApplyFill bool `xml:"applyFill,attr"`
ApplyFont bool `xml:"applyFont,attr"`
ApplyNumberFormat bool `xml:"applyNumberFormat,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"`
PivotButton bool `xml:"pivotButton,attr,omitempty"`
QuotePrefix bool `xml:"quotePrefix,attr,omitempty"`
NumFmtID *int `xml:"numFmtId,attr"`
FontID *int `xml:"fontId,attr"`
FillID *int `xml:"fillId,attr"`
BorderID *int `xml:"borderId,attr"`
XfID *int `xml:"xfId,attr"`
QuotePrefix *bool `xml:"quotePrefix,attr"`
PivotButton *bool `xml:"pivotButton,attr"`
ApplyNumberFormat *bool `xml:"applyNumberFormat,attr"`
ApplyFont *bool `xml:"applyFont,attr"`
ApplyFill *bool `xml:"applyFill,attr"`
ApplyBorder *bool `xml:"applyBorder,attr"`
ApplyAlignment *bool `xml:"applyAlignment,attr"`
ApplyProtection *bool `xml:"applyProtection,attr"`
Alignment *xlsxAlignment `xml:"alignment"`
Protection *xlsxProtection `xml:"protection"`
}
Expand Down Expand Up @@ -313,8 +313,28 @@ type xlsxStyleColors struct {
Color string `xml:",innerxml"`
}

// formatFont directly maps the styles settings of the fonts.
type formatFont struct {
// Alignment directly maps the alignment settings of the cells.
type Alignment struct {
Horizontal string `json:"horizontal"`
Indent int `json:"indent"`
JustifyLastLine bool `json:"justify_last_line"`
ReadingOrder uint64 `json:"reading_order"`
RelativeIndent int `json:"relative_indent"`
ShrinkToFit bool `json:"shrink_to_fit"`
TextRotation int `json:"text_rotation"`
Vertical string `json:"vertical"`
WrapText bool `json:"wrap_text"`
}

// Border directly maps the border settings of the cells.
type Border struct {
Type string `json:"type"`
Color string `json:"color"`
Style int `json:"style"`
}

// Font directly maps the font settings of the fonts.
type Font struct {
Bold bool `json:"bold"`
Italic bool `json:"italic"`
Underline string `json:"underline"`
Expand All @@ -324,38 +344,30 @@ type formatFont struct {
Color string `json:"color"`
}

// formatStyle directly maps the styles settings of the cells.
type formatStyle struct {
Border []struct {
Type string `json:"type"`
Color string `json:"color"`
Style int `json:"style"`
} `json:"border"`
Fill struct {
Type string `json:"type"`
Pattern int `json:"pattern"`
Color []string `json:"color"`
Shading int `json:"shading"`
} `json:"fill"`
Font *formatFont `json:"font"`
Alignment *struct {
Horizontal string `json:"horizontal"`
Indent int `json:"indent"`
JustifyLastLine bool `json:"justify_last_line"`
ReadingOrder uint64 `json:"reading_order"`
RelativeIndent int `json:"relative_indent"`
ShrinkToFit bool `json:"shrink_to_fit"`
TextRotation int `json:"text_rotation"`
Vertical string `json:"vertical"`
WrapText bool `json:"wrap_text"`
} `json:"alignment"`
Protection *struct {
Hidden bool `json:"hidden"`
Locked bool `json:"locked"`
} `json:"protection"`
NumFmt int `json:"number_format"`
DecimalPlaces int `json:"decimal_places"`
CustomNumFmt *string `json:"custom_number_format"`
Lang string `json:"lang"`
NegRed bool `json:"negred"`
// Fill directly maps the fill settings of the cells.
type Fill struct {
Type string `json:"type"`
Pattern int `json:"pattern"`
Color []string `json:"color"`
Shading int `json:"shading"`
}

// Protection directly maps the protection settings of the cells.
type Protection struct {
Hidden bool `json:"hidden"`
Locked bool `json:"locked"`
}

// Style directly maps the style settings of the cells.
type Style struct {
Border []Border `json:"border"`
Fill Fill `json:"fill"`
Font *Font `json:"font"`
Alignment *Alignment `json:"alignment"`
Protection *Protection `json:"protection"`
NumFmt int `json:"number_format"`
DecimalPlaces int `json:"decimal_places"`
CustomNumFmt *string `json:"custom_number_format"`
Lang string `json:"lang"`
NegRed bool `json:"negred"`
}
11 changes: 5 additions & 6 deletions xmlWorksheet.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@ package excelize
import "encoding/xml"

// xlsxWorksheet directly maps the worksheet 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.
// http://schemas.openxmlformats.org/spreadsheetml/2006/main.
type xlsxWorksheet struct {
XMLName xml.Name `xml:"http://schemas.openxmlformats.org/spreadsheetml/2006/main worksheet"`
SheetPr *xlsxSheetPr `xml:"sheetPr"`
Expand Down Expand Up @@ -357,9 +356,9 @@ type xlsxBrk struct {

// xlsxBreaks directly maps a collection of the row or column breaks.
type xlsxBreaks struct {
Brk *xlsxBrk `xml:"brk"`
Count int `xml:"count,attr,omitempty"`
ManualBreakCount int `xml:"manualBreakCount,attr,omitempty"`
Brk []*xlsxBrk `xml:"brk"`
Count int `xml:"count,attr,omitempty"`
ManualBreakCount int `xml:"manualBreakCount,attr,omitempty"`
}

// xlsxCustomSheetView directly maps the customSheetView element.
Expand Down Expand Up @@ -475,7 +474,7 @@ func (c *xlsxC) hasValue() bool {
// http://schemas.openxmlformats.org/spreadsheetml/2006/main - currently I have
// not checked it for completeness - it does as much as I need.
type xlsxF struct {
Content string `xml:",innerxml"`
Content string `xml:",chardata"`
T string `xml:"t,attr,omitempty"` // Formula type
Ref string `xml:"ref,attr,omitempty"` // Shared formula ref
Si string `xml:"si,attr,omitempty"` // Shared formula index
Expand Down