Skip to content

Commit 4ed4938

Browse files
authored
This closes #1835, support get data validations which storage in the extension lists (#1834)
1 parent f20bbd1 commit 4ed4938

File tree

5 files changed

+90
-28
lines changed

5 files changed

+90
-28
lines changed

cell_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ func TestConcurrency(t *testing.T) {
9191
// Concurrency add data validation
9292
dv := NewDataValidation(true)
9393
dv.Sqref = fmt.Sprintf("A%d:B%d", val, val)
94-
dv.SetRange(10, 20, DataValidationTypeWhole, DataValidationOperatorGreaterThan)
94+
assert.NoError(t, dv.SetRange(10, 20, DataValidationTypeWhole, DataValidationOperatorGreaterThan))
9595
dv.SetInput(fmt.Sprintf("title:%d", val), strconv.Itoa(val))
9696
assert.NoError(t, f.AddDataValidation("Sheet1", dv))
9797
// Concurrency delete data validation with reference sequence

datavalidation.go

Lines changed: 61 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ package excelize
1313

1414
import (
1515
"fmt"
16+
"io"
1617
"math"
1718
"strings"
1819
"unicode/utf16"
@@ -293,36 +294,70 @@ func (f *File) GetDataValidations(sheet string) ([]*DataValidation, error) {
293294
if err != nil {
294295
return nil, err
295296
}
296-
if ws.DataValidations == nil || len(ws.DataValidations.DataValidation) == 0 {
297-
return nil, err
297+
var (
298+
dataValidations []*DataValidation
299+
decodeExtLst = new(decodeExtLst)
300+
decodeDataValidations *xlsxDataValidations
301+
ext *xlsxExt
302+
)
303+
if ws.DataValidations != nil {
304+
dataValidations = append(dataValidations, getDataValidations(ws.DataValidations)...)
298305
}
299-
var dvs []*DataValidation
300-
for _, dv := range ws.DataValidations.DataValidation {
301-
if dv != nil {
302-
dataValidation := &DataValidation{
303-
AllowBlank: dv.AllowBlank,
304-
Error: dv.Error,
305-
ErrorStyle: dv.ErrorStyle,
306-
ErrorTitle: dv.ErrorTitle,
307-
Operator: dv.Operator,
308-
Prompt: dv.Prompt,
309-
PromptTitle: dv.PromptTitle,
310-
ShowDropDown: dv.ShowDropDown,
311-
ShowErrorMessage: dv.ShowErrorMessage,
312-
ShowInputMessage: dv.ShowInputMessage,
313-
Sqref: dv.Sqref,
314-
Type: dv.Type,
315-
}
316-
if dv.Formula1 != nil {
317-
dataValidation.Formula1 = unescapeDataValidationFormula(dv.Formula1.Content)
318-
}
319-
if dv.Formula2 != nil {
320-
dataValidation.Formula2 = unescapeDataValidationFormula(dv.Formula2.Content)
306+
if ws.ExtLst != nil {
307+
if err = f.xmlNewDecoder(strings.NewReader("<extLst>" + ws.ExtLst.Ext + "</extLst>")).
308+
Decode(decodeExtLst); err != nil && err != io.EOF {
309+
return dataValidations, err
310+
}
311+
for _, ext = range decodeExtLst.Ext {
312+
if ext.URI == ExtURIDataValidations {
313+
decodeDataValidations = new(xlsxDataValidations)
314+
_ = f.xmlNewDecoder(strings.NewReader(ext.Content)).Decode(decodeDataValidations)
315+
dataValidations = append(dataValidations, getDataValidations(decodeDataValidations)...)
321316
}
322-
dvs = append(dvs, dataValidation)
323317
}
324318
}
325-
return dvs, err
319+
return dataValidations, err
320+
}
321+
322+
// getDataValidations returns data validations list by given worksheet data
323+
// validations.
324+
func getDataValidations(dvs *xlsxDataValidations) []*DataValidation {
325+
if dvs == nil {
326+
return nil
327+
}
328+
var dataValidations []*DataValidation
329+
for _, dv := range dvs.DataValidation {
330+
if dv == nil {
331+
continue
332+
}
333+
dataValidation := &DataValidation{
334+
AllowBlank: dv.AllowBlank,
335+
Error: dv.Error,
336+
ErrorStyle: dv.ErrorStyle,
337+
ErrorTitle: dv.ErrorTitle,
338+
Operator: dv.Operator,
339+
Prompt: dv.Prompt,
340+
PromptTitle: dv.PromptTitle,
341+
ShowDropDown: dv.ShowDropDown,
342+
ShowErrorMessage: dv.ShowErrorMessage,
343+
ShowInputMessage: dv.ShowInputMessage,
344+
Sqref: dv.Sqref,
345+
Type: dv.Type,
346+
}
347+
if dv.Formula1 != nil {
348+
dataValidation.Formula1 = unescapeDataValidationFormula(dv.Formula1.Content)
349+
}
350+
if dv.Formula2 != nil {
351+
dataValidation.Formula2 = unescapeDataValidationFormula(dv.Formula2.Content)
352+
}
353+
if dv.XMSqref != "" {
354+
dataValidation.Sqref = dv.XMSqref
355+
dataValidation.Formula1 = strings.TrimSuffix(strings.TrimPrefix(dataValidation.Formula1, "<xm:f>"), "</xm:f>")
356+
dataValidation.Formula2 = strings.TrimSuffix(strings.TrimPrefix(dataValidation.Formula2, "<xm:f>"), "</xm:f>")
357+
}
358+
dataValidations = append(dataValidations, dataValidation)
359+
}
360+
return dataValidations
326361
}
327362

328363
// DeleteDataValidation delete data validation by given worksheet name and

datavalidation_test.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
package excelize
1313

1414
import (
15+
"fmt"
1516
"math"
1617
"path/filepath"
1718
"strings"
@@ -104,6 +105,31 @@ func TestDataValidation(t *testing.T) {
104105
dataValidations, err = f.GetDataValidations("Sheet1")
105106
assert.NoError(t, err)
106107
assert.Equal(t, []*DataValidation(nil), dataValidations)
108+
109+
// Test get data validations which storage in the extension lists
110+
f = NewFile()
111+
ws, ok := f.Sheet.Load("xl/worksheets/sheet1.xml")
112+
assert.True(t, ok)
113+
ws.(*xlsxWorksheet).ExtLst = &xlsxExtLst{Ext: fmt.Sprintf(`<ext uri="%s" xmlns:x14="%s"><x14:dataValidations><x14:dataValidation type="list" allowBlank="1"><x14:formula1><xm:f>Sheet1!$B$1:$B$5</xm:f></x14:formula1><xm:sqref>A7:B8</xm:sqref></x14:dataValidation></x14:dataValidations></ext>`, ExtURIDataValidations, NameSpaceSpreadSheetX14.Value)}
114+
dataValidations, err = f.GetDataValidations("Sheet1")
115+
assert.NoError(t, err)
116+
assert.Equal(t, []*DataValidation{
117+
{
118+
AllowBlank: true,
119+
Type: "list",
120+
Formula1: "Sheet1!$B$1:$B$5",
121+
Sqref: "A7:B8",
122+
},
123+
}, dataValidations)
124+
125+
// Test get data validations with invalid extension list characters
126+
ws.(*xlsxWorksheet).ExtLst = &xlsxExtLst{Ext: fmt.Sprintf(`<ext uri="%s" xmlns:x14="%s"><x14:dataValidations></x14:dataValidation></x14:dataValidations></ext>`, ExtURIDataValidations, NameSpaceSpreadSheetX14.Value)}
127+
_, err = f.GetDataValidations("Sheet1")
128+
assert.EqualError(t, err, "XML syntax error on line 1: element <dataValidations> closed by </dataValidation>")
129+
130+
// Test get validations without validations
131+
assert.Nil(t, getDataValidations(nil))
132+
assert.Nil(t, getDataValidations(&xlsxDataValidations{DataValidation: []*xlsxDataValidation{nil}}))
107133
}
108134

109135
func TestDataValidationError(t *testing.T) {

templates.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ const (
103103
ExtURIConditionalFormattingRuleID = "{B025F937-C7B1-47D3-B67F-A62EFF666E3E}"
104104
ExtURIConditionalFormattings = "{78C0D931-6437-407d-A8EE-F0AAD7539E65}"
105105
ExtURIDataModel = "{FCE2AD5D-F65C-4FA6-A056-5C36A1767C68}"
106-
ExtURIDataValidations = "{CCE6A557-97BC-4B89-ADB6-D9C93CAAB3DF}"
106+
ExtURIDataValidations = "{CCE6A557-97BC-4b89-ADB6-D9C93CAAB3DF}"
107107
ExtURIDrawingBlip = "{28A0092B-C50C-407E-A947-70E740481C1C}"
108108
ExtURIExternalLinkPr = "{FCE6A71B-6B00-49CD-AB44-F6B1AE7CDE65}"
109109
ExtURIIgnoredErrors = "{01252117-D84E-4E92-8308-4BE1C098FCBB}"

xmlWorksheet.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -441,6 +441,7 @@ type xlsxDataValidation struct {
441441
ShowErrorMessage bool `xml:"showErrorMessage,attr,omitempty"`
442442
ShowInputMessage bool `xml:"showInputMessage,attr,omitempty"`
443443
Sqref string `xml:"sqref,attr"`
444+
XMSqref string `xml:"sqref,omitempty"`
444445
Type string `xml:"type,attr,omitempty"`
445446
Formula1 *xlsxInnerXML `xml:"formula1"`
446447
Formula2 *xlsxInnerXML `xml:"formula2"`

0 commit comments

Comments
 (0)