This closes #1462 and closes #1464

- Support creating a conditional format with a "stop if true" rule
- Support set border color and create solid color for the color data bar
- Fix incorrect cell type when modifying string cell with the time number
- Update unit test for the add pivot table to avoid pivot table range overlap
This commit is contained in:
xuri 2023-02-07 00:08:11 +08:00
parent 1f69f6b24a
commit 3e2406096f
No known key found for this signature in database
GPG Key ID: BA5E5BB1C948EDF7
7 changed files with 341 additions and 103 deletions

View File

@ -527,7 +527,7 @@ func (c *xlsxC) setCellDefault(value string) {
c.T, c.V, c.IS = value, value, nil
return
}
c.V = value
c.T, c.V = "", value
}
// getCellDate parse cell value which contains a date in the ISO 8601 format.

View File

@ -305,7 +305,7 @@ var (
monthNamesYiSuffix = []string{"\ua2cd\ua1aa", "\ua44d\ua1aa", "\ua315\ua1aa", "\ua1d6\ua1aa", "\ua26c\ua1aa", "\ua0d8\ua1aa", "\ua3c3\ua1aa", "\ua246\ua1aa", "\ua22c\ua1aa", "\ua2b0\ua1aa", "\ua2b0\ua2aa\ua1aa", "\ua2b0\ua44b\ua1aa"}
// monthNamesZulu list the month names in the Zulu.
monthNamesZulu = []string{"Januwari", "Febhuwari", "Mashi", "Ephreli", "Meyi", "Juni", "Julayi", "Agasti", "Septemba", "Okthoba", "Novemba", "Disemba"}
// monthNamesZuluAbbr list teh month name abbreviations in Zulu
// monthNamesZuluAbbr list the month name abbreviations in Zulu
monthNamesZuluAbbr = []string{"Jan", "Feb", "Mas", "Eph", "Mey", "Jun", "Jul", "Agas", "Sep", "Okt", "Nov", "Dis"}
// apFmtAfrikaans defined the AM/PM name in the Afrikaans.
apFmtAfrikaans = "vm./nm."

View File

@ -70,7 +70,7 @@ func TestAddPivotTable(t *testing.T) {
}))
assert.NoError(t, f.AddPivotTable(&PivotTableOptions{
DataRange: "Sheet1!$A$1:$E$31",
PivotTableRange: "Sheet1!$G$37:$W$50",
PivotTableRange: "Sheet1!$G$39:$W$52",
Rows: []PivotTableField{{Data: "Month"}},
Columns: []PivotTableField{{Data: "Region", DefaultSubtotal: true}, {Data: "Year"}},
Data: []PivotTableField{{Data: "Sales", Subtotal: "CountNums", Name: "Summarize by CountNums"}},

203
styles.go
View File

@ -3190,8 +3190,21 @@ func (f *File) SetCellStyle(sheet, hCell, vCell string, styleID int) error {
// MaxColor - Same as MinColor, see above.
//
// BarColor - Used for data_bar. Same as MinColor, see above.
//
// BarBorderColor - Used for sets the color for the border line of a data bar,
// this is only visible in Excel 2010 and later.
//
// BarOnly - Used for displays a bar data but not the data in the cells.
//
// BarSolid - Used for turns on a solid (non-gradient) fill for data bars, this
// is only visible in Excel 2010 and later.
//
// StopIfTrue - used to set the "stop if true" feature of a conditional
// formatting rule when more than one rule is applied to a cell or a range of
// cells. When this parameter is set then subsequent rules are not evaluated
// if the current rule is true.
func (f *File) SetConditionalFormat(sheet, rangeRef string, opts []ConditionalFormatOptions) error {
drawContFmtFunc := map[string]func(p int, ct string, fmtCond *ConditionalFormatOptions) *xlsxCfRule{
drawContFmtFunc := map[string]func(p int, ct, GUID string, fmtCond *ConditionalFormatOptions) (*xlsxCfRule, *xlsxX14CfRule){
"cellIs": drawCondFmtCellIs,
"top10": drawCondFmtTop10,
"aboveAverage": drawCondFmtAboveAverage,
@ -3207,6 +3220,12 @@ func (f *File) SetConditionalFormat(sheet, rangeRef string, opts []ConditionalFo
if err != nil {
return err
}
// Create a pseudo GUID for each unique rule.
var rules int
for _, cf := range ws.ConditionalFormatting {
rules += len(cf.CfRule)
}
GUID := fmt.Sprintf("{00000000-0000-0000-%04X-%012X}", f.getSheetID(sheet), rules)
var cfRule []*xlsxCfRule
for p, v := range opts {
var vt, ct string
@ -3219,7 +3238,14 @@ func (f *File) SetConditionalFormat(sheet, rangeRef string, opts []ConditionalFo
if ok || vt == "expression" {
drawFunc, ok := drawContFmtFunc[vt]
if ok {
cfRule = append(cfRule, drawFunc(p, ct, &v))
rule, x14rule := drawFunc(p, ct, GUID, &v)
if x14rule != nil {
if err = f.appendCfRule(ws, x14rule); err != nil {
return err
}
f.addSheetNameSpace(sheet, NameSpaceSpreadSheetX14)
}
cfRule = append(cfRule, rule)
}
}
}
@ -3232,11 +3258,64 @@ func (f *File) SetConditionalFormat(sheet, rangeRef string, opts []ConditionalFo
return err
}
// appendCfRule provides a function to append rules to conditional formatting.
func (f *File) appendCfRule(ws *xlsxWorksheet, rule *xlsxX14CfRule) error {
var (
err error
idx int
decodeExtLst *decodeWorksheetExt
condFmts *xlsxX14ConditionalFormattings
decodeCondFmts *decodeX14ConditionalFormattings
ext *xlsxWorksheetExt
condFmtBytes, condFmtsBytes, extLstBytes, extBytes []byte
)
if ws.ExtLst != nil { // append mode ext
decodeExtLst = new(decodeWorksheetExt)
if err = f.xmlNewDecoder(strings.NewReader("<extLst>" + ws.ExtLst.Ext + "</extLst>")).
Decode(decodeExtLst); err != nil && err != io.EOF {
return err
}
for idx, ext = range decodeExtLst.Ext {
if ext.URI == ExtURIConditionalFormattings {
decodeCondFmts = new(decodeX14ConditionalFormattings)
_ = f.xmlNewDecoder(strings.NewReader(ext.Content)).Decode(decodeCondFmts)
condFmtBytes, _ = xml.Marshal([]*xlsxX14ConditionalFormatting{
{
XMLNSXM: NameSpaceSpreadSheetExcel2006Main.Value,
CfRule: []*xlsxX14CfRule{rule},
},
})
if condFmts == nil {
condFmts = &xlsxX14ConditionalFormattings{}
}
condFmts.Content = decodeCondFmts.Content + string(condFmtBytes)
condFmtsBytes, _ = xml.Marshal(condFmts)
decodeExtLst.Ext[idx].Content = string(condFmtsBytes)
}
}
extLstBytes, _ = xml.Marshal(decodeExtLst)
ws.ExtLst = &xlsxExtLst{
Ext: strings.TrimSuffix(strings.TrimPrefix(string(extLstBytes), "<extLst>"), "</extLst>"),
}
return err
}
condFmtBytes, _ = xml.Marshal([]*xlsxX14ConditionalFormatting{
{XMLNSXM: NameSpaceSpreadSheetExcel2006Main.Value, CfRule: []*xlsxX14CfRule{rule}},
})
condFmtsBytes, _ = xml.Marshal(&xlsxX14ConditionalFormattings{Content: string(condFmtBytes)})
extBytes, err = xml.Marshal(&xlsxWorksheetExt{
URI: ExtURIConditionalFormattings,
Content: string(condFmtsBytes),
})
ws.ExtLst = &xlsxExtLst{Ext: strings.TrimSuffix(strings.TrimPrefix(string(extBytes), "<extLst>"), "</extLst>")}
return err
}
// extractCondFmtCellIs provides a function to extract conditional format
// settings for cell value (include between, not between, equal, not equal,
// greater than and less than) by given conditional formatting rule.
func extractCondFmtCellIs(c *xlsxCfRule) ConditionalFormatOptions {
format := ConditionalFormatOptions{Type: "cell", Criteria: operatorType[c.Operator], Format: *c.DxfID}
func extractCondFmtCellIs(c *xlsxCfRule, extLst *xlsxExtLst) ConditionalFormatOptions {
format := ConditionalFormatOptions{StopIfTrue: c.StopIfTrue, Type: "cell", Criteria: operatorType[c.Operator], Format: *c.DxfID}
if len(c.Formula) == 2 {
format.Minimum, format.Maximum = c.Formula[0], c.Formula[1]
return format
@ -3248,8 +3327,9 @@ func extractCondFmtCellIs(c *xlsxCfRule) ConditionalFormatOptions {
// extractCondFmtTop10 provides a function to extract conditional format
// settings for top N (default is top 10) by given conditional formatting
// rule.
func extractCondFmtTop10(c *xlsxCfRule) ConditionalFormatOptions {
func extractCondFmtTop10(c *xlsxCfRule, extLst *xlsxExtLst) ConditionalFormatOptions {
format := ConditionalFormatOptions{
StopIfTrue: c.StopIfTrue,
Type: "top",
Criteria: "=",
Format: *c.DxfID,
@ -3265,8 +3345,9 @@ func extractCondFmtTop10(c *xlsxCfRule) ConditionalFormatOptions {
// extractCondFmtAboveAverage provides a function to extract conditional format
// settings for above average and below average by given conditional formatting
// rule.
func extractCondFmtAboveAverage(c *xlsxCfRule) ConditionalFormatOptions {
func extractCondFmtAboveAverage(c *xlsxCfRule, extLst *xlsxExtLst) ConditionalFormatOptions {
return ConditionalFormatOptions{
StopIfTrue: c.StopIfTrue,
Type: "average",
Criteria: "=",
Format: *c.DxfID,
@ -3277,8 +3358,9 @@ func extractCondFmtAboveAverage(c *xlsxCfRule) ConditionalFormatOptions {
// extractCondFmtDuplicateUniqueValues provides a function to extract
// conditional format settings for duplicate and unique values by given
// conditional formatting rule.
func extractCondFmtDuplicateUniqueValues(c *xlsxCfRule) ConditionalFormatOptions {
func extractCondFmtDuplicateUniqueValues(c *xlsxCfRule, extLst *xlsxExtLst) ConditionalFormatOptions {
return ConditionalFormatOptions{
StopIfTrue: c.StopIfTrue,
Type: map[string]string{
"duplicateValues": "duplicate",
"uniqueValues": "unique",
@ -3291,8 +3373,8 @@ func extractCondFmtDuplicateUniqueValues(c *xlsxCfRule) ConditionalFormatOptions
// extractCondFmtColorScale provides a function to extract conditional format
// settings for color scale (include 2 color scale and 3 color scale) by given
// conditional formatting rule.
func extractCondFmtColorScale(c *xlsxCfRule) ConditionalFormatOptions {
var format ConditionalFormatOptions
func extractCondFmtColorScale(c *xlsxCfRule, extLst *xlsxExtLst) ConditionalFormatOptions {
format := ConditionalFormatOptions{StopIfTrue: c.StopIfTrue}
format.Type, format.Criteria = "2_color_scale", "="
values := len(c.ColorScale.Cfvo)
colors := len(c.ColorScale.Color)
@ -3326,20 +3408,58 @@ func extractCondFmtColorScale(c *xlsxCfRule) ConditionalFormatOptions {
// extractCondFmtDataBar provides a function to extract conditional format
// settings for data bar by given conditional formatting rule.
func extractCondFmtDataBar(c *xlsxCfRule) ConditionalFormatOptions {
func extractCondFmtDataBar(c *xlsxCfRule, extLst *xlsxExtLst) ConditionalFormatOptions {
format := ConditionalFormatOptions{Type: "data_bar", Criteria: "="}
if c.DataBar != nil {
format.StopIfTrue = c.StopIfTrue
format.MinType = c.DataBar.Cfvo[0].Type
format.MaxType = c.DataBar.Cfvo[1].Type
format.BarColor = "#" + strings.TrimPrefix(strings.ToUpper(c.DataBar.Color[0].RGB), "FF")
if c.DataBar.ShowValue != nil {
format.BarOnly = !*c.DataBar.ShowValue
}
}
extractDataBarRule := func(condFmts []decodeX14ConditionalFormatting) {
for _, condFmt := range condFmts {
for _, rule := range condFmt.CfRule {
if rule.DataBar != nil {
format.BarSolid = !rule.DataBar.Gradient
if rule.DataBar.BorderColor != nil {
format.BarBorderColor = "#" + strings.TrimPrefix(strings.ToUpper(rule.DataBar.BorderColor.RGB), "FF")
}
}
}
}
}
extractExtLst := func(extLst *decodeWorksheetExt) {
for _, ext := range extLst.Ext {
if ext.URI == ExtURIConditionalFormattings {
decodeCondFmts := new(decodeX14ConditionalFormattings)
if err := xml.Unmarshal([]byte(ext.Content), &decodeCondFmts); err == nil {
condFmts := []decodeX14ConditionalFormatting{}
if err = xml.Unmarshal([]byte(decodeCondFmts.Content), &condFmts); err == nil {
extractDataBarRule(condFmts)
}
}
}
}
}
if c.ExtLst != nil {
ext := decodeX14ConditionalFormattingExt{}
if err := xml.Unmarshal([]byte(c.ExtLst.Ext), &ext); err == nil && extLst != nil {
decodeExtLst := new(decodeWorksheetExt)
if err = xml.Unmarshal([]byte("<extLst>"+extLst.Ext+"</extLst>"), decodeExtLst); err == nil {
extractExtLst(decodeExtLst)
}
}
}
return format
}
// extractCondFmtExp provides a function to extract conditional format settings
// for expression by given conditional formatting rule.
func extractCondFmtExp(c *xlsxCfRule) ConditionalFormatOptions {
format := ConditionalFormatOptions{Type: "formula", Format: *c.DxfID}
func extractCondFmtExp(c *xlsxCfRule, extLst *xlsxExtLst) ConditionalFormatOptions {
format := ConditionalFormatOptions{StopIfTrue: c.StopIfTrue, Type: "formula", Format: *c.DxfID}
if len(c.Formula) > 0 {
format.Criteria = c.Formula[0]
}
@ -3349,7 +3469,7 @@ func extractCondFmtExp(c *xlsxCfRule) ConditionalFormatOptions {
// GetConditionalFormats returns conditional format settings by given worksheet
// name.
func (f *File) GetConditionalFormats(sheet string) (map[string][]ConditionalFormatOptions, error) {
extractContFmtFunc := map[string]func(c *xlsxCfRule) ConditionalFormatOptions{
extractContFmtFunc := map[string]func(c *xlsxCfRule, extLst *xlsxExtLst) ConditionalFormatOptions{
"cellIs": extractCondFmtCellIs,
"top10": extractCondFmtTop10,
"aboveAverage": extractCondFmtAboveAverage,
@ -3369,7 +3489,7 @@ func (f *File) GetConditionalFormats(sheet string) (map[string][]ConditionalForm
var opts []ConditionalFormatOptions
for _, cr := range cf.CfRule {
if extractFunc, ok := extractContFmtFunc[cr.Type]; ok {
opts = append(opts, extractFunc(cr))
opts = append(opts, extractFunc(cr, ws.ExtLst))
}
}
conditionalFormats[cf.SQRef] = opts
@ -3396,9 +3516,10 @@ func (f *File) UnsetConditionalFormat(sheet, rangeRef string) error {
// drawCondFmtCellIs provides a function to create conditional formatting rule
// for cell value (include between, not between, equal, not equal, greater
// than and less than) by given priority, criteria type and format settings.
func drawCondFmtCellIs(p int, ct string, format *ConditionalFormatOptions) *xlsxCfRule {
func drawCondFmtCellIs(p int, ct, GUID string, format *ConditionalFormatOptions) (*xlsxCfRule, *xlsxX14CfRule) {
c := &xlsxCfRule{
Priority: p + 1,
StopIfTrue: format.StopIfTrue,
Type: validType[format.Type],
Operator: ct,
DxfID: &format.Format,
@ -3410,15 +3531,16 @@ func drawCondFmtCellIs(p int, ct string, format *ConditionalFormatOptions) *xlsx
if idx := inStrSlice([]string{"equal", "notEqual", "greaterThan", "lessThan", "greaterThanOrEqual", "lessThanOrEqual", "containsText", "notContains", "beginsWith", "endsWith"}, ct, true); idx != -1 {
c.Formula = append(c.Formula, format.Value)
}
return c
return c, nil
}
// drawCondFmtTop10 provides a function to create conditional formatting rule
// for top N (default is top 10) by given priority, criteria type and format
// settings.
func drawCondFmtTop10(p int, ct string, format *ConditionalFormatOptions) *xlsxCfRule {
func drawCondFmtTop10(p int, ct, GUID string, format *ConditionalFormatOptions) (*xlsxCfRule, *xlsxX14CfRule) {
c := &xlsxCfRule{
Priority: p + 1,
StopIfTrue: format.StopIfTrue,
Bottom: format.Type == "bottom",
Type: validType[format.Type],
Rank: 10,
@ -3428,36 +3550,38 @@ func drawCondFmtTop10(p int, ct string, format *ConditionalFormatOptions) *xlsxC
if rank, err := strconv.Atoi(format.Value); err == nil {
c.Rank = rank
}
return c
return c, nil
}
// drawCondFmtAboveAverage provides a function to create conditional
// formatting rule for above average and below average by given priority,
// criteria type and format settings.
func drawCondFmtAboveAverage(p int, ct string, format *ConditionalFormatOptions) *xlsxCfRule {
func drawCondFmtAboveAverage(p int, ct, GUID string, format *ConditionalFormatOptions) (*xlsxCfRule, *xlsxX14CfRule) {
return &xlsxCfRule{
Priority: p + 1,
StopIfTrue: format.StopIfTrue,
Type: validType[format.Type],
AboveAverage: &format.AboveAverage,
DxfID: &format.Format,
}
}, nil
}
// drawCondFmtDuplicateUniqueValues provides a function to create conditional
// formatting rule for duplicate and unique values by given priority, criteria
// type and format settings.
func drawCondFmtDuplicateUniqueValues(p int, ct string, format *ConditionalFormatOptions) *xlsxCfRule {
func drawCondFmtDuplicateUniqueValues(p int, ct, GUID string, format *ConditionalFormatOptions) (*xlsxCfRule, *xlsxX14CfRule) {
return &xlsxCfRule{
Priority: p + 1,
StopIfTrue: format.StopIfTrue,
Type: validType[format.Type],
DxfID: &format.Format,
}
}, nil
}
// drawCondFmtColorScale provides a function to create conditional formatting
// rule for color scale (include 2 color scale and 3 color scale) by given
// priority, criteria type and format settings.
func drawCondFmtColorScale(p int, ct string, format *ConditionalFormatOptions) *xlsxCfRule {
func drawCondFmtColorScale(p int, ct, GUID string, format *ConditionalFormatOptions) (*xlsxCfRule, *xlsxX14CfRule) {
minValue := format.MinValue
if minValue == "" {
minValue = "0"
@ -3473,6 +3597,7 @@ func drawCondFmtColorScale(p int, ct string, format *ConditionalFormatOptions) *
c := &xlsxCfRule{
Priority: p + 1,
StopIfTrue: format.StopIfTrue,
Type: "colorScale",
ColorScale: &xlsxColorScale{
Cfvo: []*xlsxCfvo{
@ -3489,31 +3614,53 @@ func drawCondFmtColorScale(p int, ct string, format *ConditionalFormatOptions) *
}
c.ColorScale.Cfvo = append(c.ColorScale.Cfvo, &xlsxCfvo{Type: format.MaxType, Val: maxValue})
c.ColorScale.Color = append(c.ColorScale.Color, &xlsxColor{RGB: getPaletteColor(format.MaxColor)})
return c
return c, nil
}
// drawCondFmtDataBar provides a function to create conditional formatting
// rule for data bar by given priority, criteria type and format settings.
func drawCondFmtDataBar(p int, ct string, format *ConditionalFormatOptions) *xlsxCfRule {
func drawCondFmtDataBar(p int, ct, GUID string, format *ConditionalFormatOptions) (*xlsxCfRule, *xlsxX14CfRule) {
var x14CfRule *xlsxX14CfRule
var extLst *xlsxExtLst
if format.BarSolid {
extLst = &xlsxExtLst{Ext: fmt.Sprintf(`<ext uri="%s" xmlns:x14="%s"><x14:id>%s</x14:id></ext>`, ExtURIConditionalFormattingRuleID, NameSpaceSpreadSheetX14.Value, GUID)}
x14CfRule = &xlsxX14CfRule{
Type: validType[format.Type],
ID: GUID,
DataBar: &xlsx14DataBar{
MaxLength: 100,
Cfvo: []*xlsxCfvo{{Type: "autoMin"}, {Type: "autoMax"}},
NegativeFillColor: &xlsxColor{RGB: "FFFF0000"},
AxisColor: &xlsxColor{RGB: "FFFF0000"},
},
}
if format.BarBorderColor != "" {
x14CfRule.DataBar.BorderColor = &xlsxColor{RGB: getPaletteColor(format.BarBorderColor)}
}
}
return &xlsxCfRule{
Priority: p + 1,
StopIfTrue: format.StopIfTrue,
Type: validType[format.Type],
DataBar: &xlsxDataBar{
ShowValue: boolPtr(!format.BarOnly),
Cfvo: []*xlsxCfvo{{Type: format.MinType}, {Type: format.MaxType}},
Color: []*xlsxColor{{RGB: getPaletteColor(format.BarColor)}},
},
}
ExtLst: extLst,
}, x14CfRule
}
// drawCondFmtExp provides a function to create conditional formatting rule
// for expression by given priority, criteria type and format settings.
func drawCondFmtExp(p int, ct string, format *ConditionalFormatOptions) *xlsxCfRule {
func drawCondFmtExp(p int, ct, GUID string, format *ConditionalFormatOptions) (*xlsxCfRule, *xlsxX14CfRule) {
return &xlsxCfRule{
Priority: p + 1,
StopIfTrue: format.StopIfTrue,
Type: validType[format.Type],
Formula: []string{format.Criteria},
DxfID: &format.Format,
}
}, nil
}
// getPaletteColor provides a function to convert the RBG color by given

View File

@ -159,12 +159,7 @@ func TestSetConditionalFormat(t *testing.T) {
f := NewFile()
const sheet = "Sheet1"
const rangeRef = "A1:A1"
err := f.SetConditionalFormat(sheet, rangeRef, testCase.format)
if err != nil {
t.Fatalf("%s", err)
}
assert.NoError(t, f.SetConditionalFormat(sheet, rangeRef, testCase.format))
ws, err := f.workSheetReader(sheet)
assert.NoError(t, err)
cf := ws.ConditionalFormatting
@ -173,6 +168,19 @@ func TestSetConditionalFormat(t *testing.T) {
assert.Equal(t, rangeRef, cf[0].SQRef, testCase.label)
assert.EqualValues(t, testCase.rules, cf[0].CfRule, testCase.label)
}
// Test creating a conditional format with a solid color data bar style
f := NewFile()
condFmts := []ConditionalFormatOptions{
{Type: "data_bar", BarColor: "#A9D08E", BarSolid: true, Format: 0, Criteria: "=", MinType: "min", MaxType: "max"},
}
for _, ref := range []string{"A1:A2", "B1:B2"} {
assert.NoError(t, f.SetConditionalFormat("Sheet1", ref, condFmts))
}
// Test creating a conditional format with invalid extension list characters
ws, ok := f.Sheet.Load("xl/worksheets/sheet1.xml")
assert.True(t, ok)
ws.(*xlsxWorksheet).ExtLst.Ext = "<extLst><ext><x14:conditionalFormattings></x14:conditionalFormatting></x14:conditionalFormattings></ext></extLst>"
assert.EqualError(t, f.SetConditionalFormat("Sheet1", "A1:A2", condFmts), "XML syntax error on line 1: element <conditionalFormattings> closed by </conditionalFormatting>")
}
func TestGetConditionalFormats(t *testing.T) {
@ -186,7 +194,7 @@ func TestGetConditionalFormats(t *testing.T) {
{{Type: "unique", Format: 1, Criteria: "="}},
{{Type: "3_color_scale", Criteria: "=", MinType: "num", MidType: "num", MaxType: "num", MinValue: "-10", MidValue: "50", MaxValue: "10", MinColor: "#FF0000", MidColor: "#00FF00", MaxColor: "#0000FF"}},
{{Type: "2_color_scale", Criteria: "=", MinType: "num", MaxType: "num", MinColor: "#FF0000", MaxColor: "#0000FF"}},
{{Type: "data_bar", Criteria: "=", MinType: "min", MaxType: "max", BarColor: "#638EC6"}},
{{Type: "data_bar", Criteria: "=", MinType: "min", MaxType: "max", BarColor: "#638EC6", BarBorderColor: "#0000FF", BarOnly: true, BarSolid: true, StopIfTrue: true}},
{{Type: "formula", Format: 1, Criteria: "="}},
} {
f := NewFile()

View File

@ -91,7 +91,8 @@ const (
// ([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
// new child ext elements ([ISO/IEC29500-1:2016] section 18.2.7)
ExtURIConditionalFormattings = "{78C0D931-6437-407D-A8EE-F0AAD7539E65}"
ExtURIConditionalFormattingRuleID = "{B025F937-C7B1-47D3-B67F-A62EFF666E3E}"
ExtURIConditionalFormattings = "{78C0D931-6437-407d-A8EE-F0AAD7539E65}"
ExtURIDataValidations = "{CCE6A557-97BC-4B89-ADB6-D9C93CAAB3DF}"
ExtURIDrawingBlip = "{28A0092B-C50C-407E-A947-70E740481C1C}"
ExtURIIgnoredErrors = "{01252117-D84E-4E92-8308-4BE1C098FCBB}"

View File

@ -592,7 +592,7 @@ type xlsxColorScale struct {
type xlsxDataBar struct {
MaxLength int `xml:"maxLength,attr,omitempty"`
MinLength int `xml:"minLength,attr,omitempty"`
ShowValue bool `xml:"showValue,attr,omitempty"`
ShowValue *bool `xml:"showValue,attr"`
Cfvo []*xlsxCfvo `xml:"cfvo"`
Color []*xlsxColor `xml:"color"`
}
@ -601,7 +601,7 @@ type xlsxDataBar struct {
type xlsxIconSet struct {
Cfvo []*xlsxCfvo `xml:"cfvo"`
IconSet string `xml:"iconSet,attr,omitempty"`
ShowValue bool `xml:"showValue,attr,omitempty"`
ShowValue *bool `xml:"showValue,attr"`
Percent bool `xml:"percent,attr,omitempty"`
Reverse bool `xml:"reverse,attr,omitempty"`
}
@ -742,6 +742,84 @@ type decodeX14SparklineGroups struct {
Content string `xml:",innerxml"`
}
// decodeX14ConditionalFormattingExt directly maps the ext
// element.
type decodeX14ConditionalFormattingExt struct {
XMLName xml.Name `xml:"ext"`
ID string `xml:"id"`
}
// decodeX14ConditionalFormattings directly maps the conditionalFormattings
// element.
type decodeX14ConditionalFormattings struct {
XMLName xml.Name `xml:"conditionalFormattings"`
XMLNSXM string `xml:"xmlns:xm,attr"`
Content string `xml:",innerxml"`
}
// decodeX14ConditionalFormatting directly maps the conditionalFormatting
// element.
type decodeX14ConditionalFormatting struct {
XMLName xml.Name `xml:"conditionalFormatting"`
CfRule []*decodeX14CfRule `xml:"cfRule"`
}
// decodeX14CfRule directly maps the cfRule element.
type decodeX14CfRule struct {
XNLName xml.Name `xml:"cfRule"`
Type string `xml:"type,attr,omitempty"`
ID string `xml:"id,attr,omitempty"`
DataBar *decodeX14DataBar `xml:"dataBar"`
}
// decodeX14DataBar directly maps the dataBar element.
type decodeX14DataBar struct {
XNLName xml.Name `xml:"dataBar"`
MaxLength int `xml:"maxLength,attr"`
MinLength int `xml:"minLength,attr"`
Gradient bool `xml:"gradient,attr"`
ShowValue bool `xml:"showValue,attr,omitempty"`
Cfvo []*xlsxCfvo `xml:"cfvo"`
BorderColor *xlsxColor `xml:"borderColor"`
NegativeFillColor *xlsxColor `xml:"negativeFillColor"`
AxisColor *xlsxColor `xml:"axisColor"`
}
// xlsxX14ConditionalFormattings directly maps the conditionalFormattings
// element.
type xlsxX14ConditionalFormattings struct {
XMLName xml.Name `xml:"x14:conditionalFormattings"`
Content string `xml:",innerxml"`
}
// xlsxX14ConditionalFormatting directly maps the conditionalFormatting element.
type xlsxX14ConditionalFormatting struct {
XMLName xml.Name `xml:"x14:conditionalFormatting"`
XMLNSXM string `xml:"xmlns:xm,attr"`
CfRule []*xlsxX14CfRule `xml:"x14:cfRule"`
}
// xlsxX14CfRule directly maps the cfRule element.
type xlsxX14CfRule struct {
XNLName xml.Name `xml:"x14:cfRule"`
Type string `xml:"type,attr,omitempty"`
ID string `xml:"id,attr,omitempty"`
DataBar *xlsx14DataBar `xml:"x14:dataBar"`
}
// xlsx14DataBar directly maps the dataBar element.
type xlsx14DataBar struct {
XNLName xml.Name `xml:"x14:dataBar"`
MaxLength int `xml:"maxLength,attr"`
MinLength int `xml:"minLength,attr"`
Gradient bool `xml:"gradient,attr"`
ShowValue bool `xml:"showValue,attr,omitempty"`
Cfvo []*xlsxCfvo `xml:"x14:cfvo"`
BorderColor *xlsxColor `xml:"x14:borderColor"`
NegativeFillColor *xlsxColor `xml:"x14:negativeFillColor"`
AxisColor *xlsxColor `xml:"x14:axisColor"`
}
// xlsxX14SparklineGroups directly maps the sparklineGroups element.
type xlsxX14SparklineGroups struct {
XMLName xml.Name `xml:"x14:sparklineGroups"`
@ -863,6 +941,10 @@ type ConditionalFormatOptions struct {
MinLength string
MaxLength string
BarColor string
BarBorderColor string
BarOnly bool
BarSolid bool
StopIfTrue bool
}
// SheetProtectionOptions directly maps the settings of worksheet protection.