From 4ed493819a82313907217faeecb9f8713bbc66f0 Mon Sep 17 00:00:00 2001
From: Evan lu <55533161+iEvan-lhr@users.noreply.github.com>
Date: Wed, 6 Mar 2024 09:26:38 +0800
Subject: [PATCH] This closes #1835, support get data validations which storage
in the extension lists (#1834)
---
cell_test.go | 2 +-
datavalidation.go | 87 +++++++++++++++++++++++++++++-------------
datavalidation_test.go | 26 +++++++++++++
templates.go | 2 +-
xmlWorksheet.go | 1 +
5 files changed, 90 insertions(+), 28 deletions(-)
diff --git a/cell_test.go b/cell_test.go
index 42472cf..61178c2 100644
--- a/cell_test.go
+++ b/cell_test.go
@@ -91,7 +91,7 @@ func TestConcurrency(t *testing.T) {
// Concurrency add data validation
dv := NewDataValidation(true)
dv.Sqref = fmt.Sprintf("A%d:B%d", val, val)
- dv.SetRange(10, 20, DataValidationTypeWhole, DataValidationOperatorGreaterThan)
+ assert.NoError(t, dv.SetRange(10, 20, DataValidationTypeWhole, DataValidationOperatorGreaterThan))
dv.SetInput(fmt.Sprintf("title:%d", val), strconv.Itoa(val))
assert.NoError(t, f.AddDataValidation("Sheet1", dv))
// Concurrency delete data validation with reference sequence
diff --git a/datavalidation.go b/datavalidation.go
index c2ec1f1..40ffd19 100644
--- a/datavalidation.go
+++ b/datavalidation.go
@@ -13,6 +13,7 @@ package excelize
import (
"fmt"
+ "io"
"math"
"strings"
"unicode/utf16"
@@ -293,36 +294,70 @@ func (f *File) GetDataValidations(sheet string) ([]*DataValidation, error) {
if err != nil {
return nil, err
}
- if ws.DataValidations == nil || len(ws.DataValidations.DataValidation) == 0 {
- return nil, err
+ var (
+ dataValidations []*DataValidation
+ decodeExtLst = new(decodeExtLst)
+ decodeDataValidations *xlsxDataValidations
+ ext *xlsxExt
+ )
+ if ws.DataValidations != nil {
+ dataValidations = append(dataValidations, getDataValidations(ws.DataValidations)...)
}
- var dvs []*DataValidation
- for _, dv := range ws.DataValidations.DataValidation {
- if dv != nil {
- dataValidation := &DataValidation{
- AllowBlank: dv.AllowBlank,
- Error: dv.Error,
- ErrorStyle: dv.ErrorStyle,
- ErrorTitle: dv.ErrorTitle,
- Operator: dv.Operator,
- Prompt: dv.Prompt,
- PromptTitle: dv.PromptTitle,
- ShowDropDown: dv.ShowDropDown,
- ShowErrorMessage: dv.ShowErrorMessage,
- ShowInputMessage: dv.ShowInputMessage,
- Sqref: dv.Sqref,
- Type: dv.Type,
+ if ws.ExtLst != nil {
+ if err = f.xmlNewDecoder(strings.NewReader("" + ws.ExtLst.Ext + "")).
+ Decode(decodeExtLst); err != nil && err != io.EOF {
+ return dataValidations, err
+ }
+ for _, ext = range decodeExtLst.Ext {
+ if ext.URI == ExtURIDataValidations {
+ decodeDataValidations = new(xlsxDataValidations)
+ _ = f.xmlNewDecoder(strings.NewReader(ext.Content)).Decode(decodeDataValidations)
+ dataValidations = append(dataValidations, getDataValidations(decodeDataValidations)...)
}
- if dv.Formula1 != nil {
- dataValidation.Formula1 = unescapeDataValidationFormula(dv.Formula1.Content)
- }
- if dv.Formula2 != nil {
- dataValidation.Formula2 = unescapeDataValidationFormula(dv.Formula2.Content)
- }
- dvs = append(dvs, dataValidation)
}
}
- return dvs, err
+ return dataValidations, err
+}
+
+// getDataValidations returns data validations list by given worksheet data
+// validations.
+func getDataValidations(dvs *xlsxDataValidations) []*DataValidation {
+ if dvs == nil {
+ return nil
+ }
+ var dataValidations []*DataValidation
+ for _, dv := range dvs.DataValidation {
+ if dv == nil {
+ continue
+ }
+ dataValidation := &DataValidation{
+ AllowBlank: dv.AllowBlank,
+ Error: dv.Error,
+ ErrorStyle: dv.ErrorStyle,
+ ErrorTitle: dv.ErrorTitle,
+ Operator: dv.Operator,
+ Prompt: dv.Prompt,
+ PromptTitle: dv.PromptTitle,
+ ShowDropDown: dv.ShowDropDown,
+ ShowErrorMessage: dv.ShowErrorMessage,
+ ShowInputMessage: dv.ShowInputMessage,
+ Sqref: dv.Sqref,
+ Type: dv.Type,
+ }
+ if dv.Formula1 != nil {
+ dataValidation.Formula1 = unescapeDataValidationFormula(dv.Formula1.Content)
+ }
+ if dv.Formula2 != nil {
+ dataValidation.Formula2 = unescapeDataValidationFormula(dv.Formula2.Content)
+ }
+ if dv.XMSqref != "" {
+ dataValidation.Sqref = dv.XMSqref
+ dataValidation.Formula1 = strings.TrimSuffix(strings.TrimPrefix(dataValidation.Formula1, ""), "")
+ dataValidation.Formula2 = strings.TrimSuffix(strings.TrimPrefix(dataValidation.Formula2, ""), "")
+ }
+ dataValidations = append(dataValidations, dataValidation)
+ }
+ return dataValidations
}
// DeleteDataValidation delete data validation by given worksheet name and
diff --git a/datavalidation_test.go b/datavalidation_test.go
index 8816df0..7508ba3 100644
--- a/datavalidation_test.go
+++ b/datavalidation_test.go
@@ -12,6 +12,7 @@
package excelize
import (
+ "fmt"
"math"
"path/filepath"
"strings"
@@ -104,6 +105,31 @@ func TestDataValidation(t *testing.T) {
dataValidations, err = f.GetDataValidations("Sheet1")
assert.NoError(t, err)
assert.Equal(t, []*DataValidation(nil), dataValidations)
+
+ // Test get data validations which storage in the extension lists
+ f = NewFile()
+ ws, ok := f.Sheet.Load("xl/worksheets/sheet1.xml")
+ assert.True(t, ok)
+ ws.(*xlsxWorksheet).ExtLst = &xlsxExtLst{Ext: fmt.Sprintf(`Sheet1!$B$1:$B$5A7:B8`, ExtURIDataValidations, NameSpaceSpreadSheetX14.Value)}
+ dataValidations, err = f.GetDataValidations("Sheet1")
+ assert.NoError(t, err)
+ assert.Equal(t, []*DataValidation{
+ {
+ AllowBlank: true,
+ Type: "list",
+ Formula1: "Sheet1!$B$1:$B$5",
+ Sqref: "A7:B8",
+ },
+ }, dataValidations)
+
+ // Test get data validations with invalid extension list characters
+ ws.(*xlsxWorksheet).ExtLst = &xlsxExtLst{Ext: fmt.Sprintf(``, ExtURIDataValidations, NameSpaceSpreadSheetX14.Value)}
+ _, err = f.GetDataValidations("Sheet1")
+ assert.EqualError(t, err, "XML syntax error on line 1: element closed by ")
+
+ // Test get validations without validations
+ assert.Nil(t, getDataValidations(nil))
+ assert.Nil(t, getDataValidations(&xlsxDataValidations{DataValidation: []*xlsxDataValidation{nil}}))
}
func TestDataValidationError(t *testing.T) {
diff --git a/templates.go b/templates.go
index 60c895d..0f21be5 100644
--- a/templates.go
+++ b/templates.go
@@ -103,7 +103,7 @@ const (
ExtURIConditionalFormattingRuleID = "{B025F937-C7B1-47D3-B67F-A62EFF666E3E}"
ExtURIConditionalFormattings = "{78C0D931-6437-407d-A8EE-F0AAD7539E65}"
ExtURIDataModel = "{FCE2AD5D-F65C-4FA6-A056-5C36A1767C68}"
- ExtURIDataValidations = "{CCE6A557-97BC-4B89-ADB6-D9C93CAAB3DF}"
+ ExtURIDataValidations = "{CCE6A557-97BC-4b89-ADB6-D9C93CAAB3DF}"
ExtURIDrawingBlip = "{28A0092B-C50C-407E-A947-70E740481C1C}"
ExtURIExternalLinkPr = "{FCE6A71B-6B00-49CD-AB44-F6B1AE7CDE65}"
ExtURIIgnoredErrors = "{01252117-D84E-4E92-8308-4BE1C098FCBB}"
diff --git a/xmlWorksheet.go b/xmlWorksheet.go
index 83e0805..c5e06b8 100644
--- a/xmlWorksheet.go
+++ b/xmlWorksheet.go
@@ -441,6 +441,7 @@ type xlsxDataValidation struct {
ShowErrorMessage bool `xml:"showErrorMessage,attr,omitempty"`
ShowInputMessage bool `xml:"showInputMessage,attr,omitempty"`
Sqref string `xml:"sqref,attr"`
+ XMSqref string `xml:"sqref,omitempty"`
Type string `xml:"type,attr,omitempty"`
Formula1 *xlsxInnerXML `xml:"formula1"`
Formula2 *xlsxInnerXML `xml:"formula2"`