datavalidation.go 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  1. // Copyright 2016 - 2021 The excelize Authors. All rights reserved. Use of
  2. // this source code is governed by a BSD-style license that can be found in
  3. // the LICENSE file.
  4. //
  5. // Package excelize providing a set of functions that allow you to write to
  6. // and read from XLSX / XLSM / XLTM files. Supports reading and writing
  7. // spreadsheet documents generated by Microsoft Excel™ 2007 and later. Supports
  8. // complex components by high compatibility, and provided streaming API for
  9. // generating or reading data from a worksheet with huge amounts of data. This
  10. // library needs Go version 1.15 or later.
  11. package excelize
  12. import (
  13. "fmt"
  14. "math"
  15. "strings"
  16. "unicode/utf16"
  17. )
  18. // DataValidationType defined the type of data validation.
  19. type DataValidationType int
  20. // Data validation types.
  21. const (
  22. _DataValidationType = iota
  23. typeNone // inline use
  24. DataValidationTypeCustom
  25. DataValidationTypeDate
  26. DataValidationTypeDecimal
  27. typeList // inline use
  28. DataValidationTypeTextLeng
  29. DataValidationTypeTime
  30. // DataValidationTypeWhole Integer
  31. DataValidationTypeWhole
  32. )
  33. const (
  34. // dataValidationFormulaStrLen 255 characters
  35. dataValidationFormulaStrLen = 255
  36. )
  37. // DataValidationErrorStyle defined the style of data validation error alert.
  38. type DataValidationErrorStyle int
  39. // Data validation error styles.
  40. const (
  41. _ DataValidationErrorStyle = iota
  42. DataValidationErrorStyleStop
  43. DataValidationErrorStyleWarning
  44. DataValidationErrorStyleInformation
  45. )
  46. // Data validation error styles.
  47. const (
  48. styleStop = "stop"
  49. styleWarning = "warning"
  50. styleInformation = "information"
  51. )
  52. // DataValidationOperator operator enum.
  53. type DataValidationOperator int
  54. // Data validation operators.
  55. const (
  56. _DataValidationOperator = iota
  57. DataValidationOperatorBetween
  58. DataValidationOperatorEqual
  59. DataValidationOperatorGreaterThan
  60. DataValidationOperatorGreaterThanOrEqual
  61. DataValidationOperatorLessThan
  62. DataValidationOperatorLessThanOrEqual
  63. DataValidationOperatorNotBetween
  64. DataValidationOperatorNotEqual
  65. )
  66. // formulaEscaper mimics the Excel escaping rules for data validation,
  67. // which converts `"` to `""` instead of `"`.
  68. var formulaEscaper = strings.NewReplacer(
  69. `&`, `&`,
  70. `<`, `&lt;`,
  71. `>`, `&gt;`,
  72. `"`, `""`,
  73. )
  74. // NewDataValidation return data validation struct.
  75. func NewDataValidation(allowBlank bool) *DataValidation {
  76. return &DataValidation{
  77. AllowBlank: allowBlank,
  78. ShowErrorMessage: false,
  79. ShowInputMessage: false,
  80. }
  81. }
  82. // SetError set error notice.
  83. func (dd *DataValidation) SetError(style DataValidationErrorStyle, title, msg string) {
  84. dd.Error = &msg
  85. dd.ErrorTitle = &title
  86. strStyle := styleStop
  87. switch style {
  88. case DataValidationErrorStyleStop:
  89. strStyle = styleStop
  90. case DataValidationErrorStyleWarning:
  91. strStyle = styleWarning
  92. case DataValidationErrorStyleInformation:
  93. strStyle = styleInformation
  94. }
  95. dd.ShowErrorMessage = true
  96. dd.ErrorStyle = &strStyle
  97. }
  98. // SetInput set prompt notice.
  99. func (dd *DataValidation) SetInput(title, msg string) {
  100. dd.ShowInputMessage = true
  101. dd.PromptTitle = &title
  102. dd.Prompt = &msg
  103. }
  104. // SetDropList data validation list.
  105. func (dd *DataValidation) SetDropList(keys []string) error {
  106. formula := strings.Join(keys, ",")
  107. if dataValidationFormulaStrLen < len(utf16.Encode([]rune(formula))) {
  108. return ErrDataValidationFormulaLenth
  109. }
  110. dd.Formula1 = fmt.Sprintf(`<formula1>"%s"</formula1>`, formulaEscaper.Replace(formula))
  111. dd.Type = convDataValidationType(typeList)
  112. return nil
  113. }
  114. // SetRange provides function to set data validation range in drop list.
  115. func (dd *DataValidation) SetRange(f1, f2 float64, t DataValidationType, o DataValidationOperator) error {
  116. if math.Abs(f1) > math.MaxFloat32 || math.Abs(f2) > math.MaxFloat32 {
  117. return ErrDataValidationRange
  118. }
  119. dd.Formula1 = fmt.Sprintf("<formula1>%.17g</formula1>", f1)
  120. dd.Formula2 = fmt.Sprintf("<formula2>%.17g</formula2>", f2)
  121. dd.Type = convDataValidationType(t)
  122. dd.Operator = convDataValidationOperatior(o)
  123. return nil
  124. }
  125. // SetSqrefDropList provides set data validation on a range with source
  126. // reference range of the worksheet by given data validation object and
  127. // worksheet name. The data validation object can be created by
  128. // NewDataValidation function. For example, set data validation on
  129. // Sheet1!A7:B8 with validation criteria source Sheet1!E1:E3 settings, create
  130. // in-cell dropdown by allowing list source:
  131. //
  132. // dvRange := excelize.NewDataValidation(true)
  133. // dvRange.Sqref = "A7:B8"
  134. // dvRange.SetSqrefDropList("$E$1:$E$3", true)
  135. // f.AddDataValidation("Sheet1", dvRange)
  136. //
  137. func (dd *DataValidation) SetSqrefDropList(sqref string, isCurrentSheet bool) error {
  138. if isCurrentSheet {
  139. dd.Formula1 = sqref
  140. dd.Type = convDataValidationType(typeList)
  141. return nil
  142. }
  143. return fmt.Errorf("cross-sheet sqref cell are not supported")
  144. }
  145. // SetSqref provides function to set data validation range in drop list.
  146. func (dd *DataValidation) SetSqref(sqref string) {
  147. if dd.Sqref == "" {
  148. dd.Sqref = sqref
  149. } else {
  150. dd.Sqref = fmt.Sprintf("%s %s", dd.Sqref, sqref)
  151. }
  152. }
  153. // convDataValidationType get excel data validation type.
  154. func convDataValidationType(t DataValidationType) string {
  155. typeMap := map[DataValidationType]string{
  156. typeNone: "none",
  157. DataValidationTypeCustom: "custom",
  158. DataValidationTypeDate: "date",
  159. DataValidationTypeDecimal: "decimal",
  160. typeList: "list",
  161. DataValidationTypeTextLeng: "textLength",
  162. DataValidationTypeTime: "time",
  163. DataValidationTypeWhole: "whole",
  164. }
  165. return typeMap[t]
  166. }
  167. // convDataValidationOperatior get excel data validation operator.
  168. func convDataValidationOperatior(o DataValidationOperator) string {
  169. typeMap := map[DataValidationOperator]string{
  170. DataValidationOperatorBetween: "between",
  171. DataValidationOperatorEqual: "equal",
  172. DataValidationOperatorGreaterThan: "greaterThan",
  173. DataValidationOperatorGreaterThanOrEqual: "greaterThanOrEqual",
  174. DataValidationOperatorLessThan: "lessThan",
  175. DataValidationOperatorLessThanOrEqual: "lessThanOrEqual",
  176. DataValidationOperatorNotBetween: "notBetween",
  177. DataValidationOperatorNotEqual: "notEqual",
  178. }
  179. return typeMap[o]
  180. }
  181. // AddDataValidation provides set data validation on a range of the worksheet
  182. // by given data validation object and worksheet name. The data validation
  183. // object can be created by NewDataValidation function.
  184. //
  185. // Example 1, set data validation on Sheet1!A1:B2 with validation criteria
  186. // settings, show error alert after invalid data is entered with "Stop" style
  187. // and custom title "error body":
  188. //
  189. // dvRange := excelize.NewDataValidation(true)
  190. // dvRange.Sqref = "A1:B2"
  191. // dvRange.SetRange(10, 20, excelize.DataValidationTypeWhole, excelize.DataValidationOperatorBetween)
  192. // dvRange.SetError(excelize.DataValidationErrorStyleStop, "error title", "error body")
  193. // err := f.AddDataValidation("Sheet1", dvRange)
  194. //
  195. // Example 2, set data validation on Sheet1!A3:B4 with validation criteria
  196. // settings, and show input message when cell is selected:
  197. //
  198. // dvRange = excelize.NewDataValidation(true)
  199. // dvRange.Sqref = "A3:B4"
  200. // dvRange.SetRange(10, 20, excelize.DataValidationTypeWhole, excelize.DataValidationOperatorGreaterThan)
  201. // dvRange.SetInput("input title", "input body")
  202. // err = f.AddDataValidation("Sheet1", dvRange)
  203. //
  204. // Example 3, set data validation on Sheet1!A5:B6 with validation criteria
  205. // settings, create in-cell dropdown by allowing list source:
  206. //
  207. // dvRange = excelize.NewDataValidation(true)
  208. // dvRange.Sqref = "A5:B6"
  209. // dvRange.SetDropList([]string{"1", "2", "3"})
  210. // err = f.AddDataValidation("Sheet1", dvRange)
  211. //
  212. func (f *File) AddDataValidation(sheet string, dv *DataValidation) error {
  213. ws, err := f.workSheetReader(sheet)
  214. if err != nil {
  215. return err
  216. }
  217. if nil == ws.DataValidations {
  218. ws.DataValidations = new(xlsxDataValidations)
  219. }
  220. ws.DataValidations.DataValidation = append(ws.DataValidations.DataValidation, dv)
  221. ws.DataValidations.Count = len(ws.DataValidations.DataValidation)
  222. return err
  223. }
  224. // DeleteDataValidation delete data validation by given worksheet name and
  225. // reference sequence.
  226. func (f *File) DeleteDataValidation(sheet, sqref string) error {
  227. ws, err := f.workSheetReader(sheet)
  228. if err != nil {
  229. return err
  230. }
  231. if ws.DataValidations == nil {
  232. return nil
  233. }
  234. dv := ws.DataValidations
  235. for i := 0; i < len(dv.DataValidation); i++ {
  236. if dv.DataValidation[i].Sqref == sqref {
  237. dv.DataValidation = append(dv.DataValidation[:i], dv.DataValidation[i+1:]...)
  238. i--
  239. }
  240. }
  241. dv.Count = len(dv.DataValidation)
  242. if dv.Count == 0 {
  243. ws.DataValidations = nil
  244. }
  245. return nil
  246. }