Du kannst nicht mehr als 25 Themen auswählen Themen müssen mit entweder einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

XSSFDataValidationConstraint.java 9.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  1. /* ====================================================================
  2. Licensed to the Apache Software Foundation (ASF) under one or more
  3. contributor license agreements. See the NOTICE file distributed with
  4. this work for additional information regarding copyright ownership.
  5. The ASF licenses this file to You under the Apache License, Version 2.0
  6. (the "License"); you may not use this file except in compliance with
  7. the License. You may obtain a copy of the License at
  8. http://www.apache.org/licenses/LICENSE-2.0
  9. Unless required by applicable law or agreed to in writing, software
  10. distributed under the License is distributed on an "AS IS" BASIS,
  11. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. See the License for the specific language governing permissions and
  13. limitations under the License.
  14. ==================================================================== */
  15. package org.apache.poi.xssf.usermodel;
  16. import java.util.Arrays;
  17. import java.util.regex.Pattern;
  18. import org.apache.poi.ss.usermodel.DataValidationConstraint;
  19. import org.apache.poi.util.StringUtil;
  20. import org.openxmlformats.schemas.spreadsheetml.x2006.main.STDataValidationType;
  21. import org.openxmlformats.schemas.spreadsheetml.x2006.main.STDataValidationOperator.Enum;
  22. public class XSSFDataValidationConstraint implements DataValidationConstraint {
  23. /**
  24. * Excel validation constraints with static lists are delimited with optional whitespace and the Windows List Separator,
  25. * which is typically comma, but can be changed by users. POI will just assume comma.
  26. * In addition, Excel validation with static lists has a maximum size of 255 characters, including separators and excluding quotes.
  27. */
  28. private static final String LIST_SEPARATOR = ",";
  29. private static final Pattern LIST_SPLIT_REGEX = Pattern.compile("\\s*" + LIST_SEPARATOR + "\\s*");
  30. private static final String QUOTE = "\"";
  31. private static final int MAX_EXPLICIT_LIST_LENGTH = 257;
  32. private String formula1;
  33. private String formula2;
  34. private final int validationType;
  35. private int operator = -1;
  36. private String[] explicitListOfValues;
  37. /**
  38. * list literal constructor
  39. */
  40. public XSSFDataValidationConstraint(String[] explicitListOfValues) {
  41. if( explicitListOfValues==null || explicitListOfValues.length==0) {
  42. throw new IllegalArgumentException("List validation with explicit values must specify at least one value");
  43. }
  44. this.validationType = ValidationType.LIST;
  45. setExplicitListValues(explicitListOfValues);
  46. validate();
  47. }
  48. public XSSFDataValidationConstraint(int validationType, String formula1) {
  49. super();
  50. setFormula1(formula1);
  51. this.validationType = validationType;
  52. validate();
  53. }
  54. public XSSFDataValidationConstraint(int validationType, int operator, String formula1) {
  55. super();
  56. setFormula1(formula1);
  57. this.validationType = validationType;
  58. this.operator = operator;
  59. validate();
  60. }
  61. /**
  62. * This is the constructor called using the OOXML raw data. Excel overloads formula1 to also encode explicit value lists,
  63. * so this constructor has to check for and parse that syntax.
  64. * @param formula1 Overloaded: formula1 or list of explicit values
  65. * @param formula2 (formula1 is a list of explicit values, this is ignored: use {@code null})
  66. */
  67. public XSSFDataValidationConstraint(int validationType, int operator, String formula1, String formula2) {
  68. super();
  69. //removes leading equals sign if present
  70. setFormula1(formula1);
  71. setFormula2(formula2);
  72. this.validationType = validationType;
  73. this.operator = operator;
  74. validate();
  75. //FIXME: Need to confirm if this is not a formula.
  76. // empirical testing shows Excel saves explicit lists surrounded by double quotes,
  77. // range formula expressions can't start with quotes (I think - anyone have a creative counter example?)
  78. if ( ValidationType.LIST == validationType
  79. && this.formula1 != null
  80. && isQuoted(this.formula1) ) {
  81. explicitListOfValues = LIST_SPLIT_REGEX.split(unquote(this.formula1));
  82. }
  83. }
  84. /* (non-Javadoc)
  85. * @see org.apache.poi.ss.usermodel.DataValidationConstraint#getExplicitListValues()
  86. */
  87. @Override
  88. public String[] getExplicitListValues() {
  89. return explicitListOfValues;
  90. }
  91. /* (non-Javadoc)
  92. * @see org.apache.poi.ss.usermodel.DataValidationConstraint#getFormula1()
  93. */
  94. @Override
  95. public String getFormula1() {
  96. return formula1;
  97. }
  98. /* (non-Javadoc)
  99. * @see org.apache.poi.ss.usermodel.DataValidationConstraint#getFormula2()
  100. */
  101. @Override
  102. public String getFormula2() {
  103. return formula2;
  104. }
  105. /* (non-Javadoc)
  106. * @see org.apache.poi.ss.usermodel.DataValidationConstraint#getOperator()
  107. */
  108. @Override
  109. public int getOperator() {
  110. return operator;
  111. }
  112. /* (non-Javadoc)
  113. * @see org.apache.poi.ss.usermodel.DataValidationConstraint#getValidationType()
  114. */
  115. @Override
  116. public int getValidationType() {
  117. return validationType;
  118. }
  119. /* (non-Javadoc)
  120. * @see org.apache.poi.ss.usermodel.DataValidationConstraint#setExplicitListValues(java.lang.String[])
  121. */
  122. @Override
  123. public void setExplicitListValues(String[] explicitListValues) {
  124. this.explicitListOfValues = explicitListValues;
  125. // for OOXML we need to set formula1 to the quoted csv list of values (doesn't appear documented, but that's where Excel puts its lists)
  126. // further, Excel has no escaping for commas in explicit lists, so we don't need to worry about that.
  127. if ( explicitListOfValues!=null && explicitListOfValues.length > 0 ) {
  128. StringBuilder builder = new StringBuilder(QUOTE);
  129. for (String string : explicitListValues) {
  130. if (builder.length() > 1) {
  131. builder.append(LIST_SEPARATOR);
  132. }
  133. builder.append(string);
  134. }
  135. builder.append(QUOTE);
  136. setFormula1(builder.toString());
  137. }
  138. }
  139. /* (non-Javadoc)
  140. * @see org.apache.poi.ss.usermodel.DataValidationConstraint#setFormula1(java.lang.String)
  141. */
  142. @Override
  143. public void setFormula1(String formula1) {
  144. this.formula1 = removeLeadingEquals(formula1);
  145. }
  146. protected static String removeLeadingEquals(String formula1) {
  147. return isFormulaEmpty(formula1) ? formula1 : formula1.charAt(0)=='=' ? formula1.substring(1) : formula1;
  148. }
  149. private static boolean isQuoted(String s) {
  150. return s.startsWith(QUOTE) && s.endsWith(QUOTE);
  151. }
  152. private static String unquote(String s) {
  153. // removes leading and trailing quotes from a quoted string
  154. if (isQuoted(s)) {
  155. return s.substring(1, s.length()-1);
  156. }
  157. return s;
  158. }
  159. protected static boolean isFormulaEmpty(String formula1) {
  160. return StringUtil.isBlank(formula1);
  161. }
  162. /* (non-Javadoc)
  163. * @see org.apache.poi.ss.usermodel.DataValidationConstraint#setFormula2(java.lang.String)
  164. */
  165. @Override
  166. public void setFormula2(String formula2) {
  167. this.formula2 = removeLeadingEquals(formula2);
  168. }
  169. /* (non-Javadoc)
  170. * @see org.apache.poi.ss.usermodel.DataValidationConstraint#setOperator(int)
  171. */
  172. @Override
  173. public void setOperator(int operator) {
  174. this.operator = operator;
  175. }
  176. public void validate() {
  177. if (validationType==ValidationType.ANY) {
  178. return;
  179. }
  180. if (validationType==ValidationType.LIST ) {
  181. if (isFormulaEmpty(formula1)) {
  182. throw new IllegalArgumentException("A valid formula or a list of values must be specified for list validation.");
  183. }
  184. if(formula1.length() > MAX_EXPLICIT_LIST_LENGTH) {
  185. throw new IllegalArgumentException("A valid formula or a list of values must be less than or equal to 255 characters (including separators).");
  186. }
  187. } else {
  188. if( isFormulaEmpty(formula1) ) {
  189. throw new IllegalArgumentException("Formula is not specified. Formula is required for all validation types except explicit list validation.");
  190. }
  191. if( validationType!= ValidationType.FORMULA ) {
  192. if (operator==-1) {
  193. throw new IllegalArgumentException("This validation type requires an operator to be specified.");
  194. } else if (( operator==OperatorType.BETWEEN || operator==OperatorType.NOT_BETWEEN) && isFormulaEmpty(formula2)) {
  195. throw new IllegalArgumentException("Between and not between comparisons require two formulae to be specified.");
  196. }
  197. }
  198. }
  199. }
  200. public String prettyPrint() {
  201. StringBuilder builder = new StringBuilder();
  202. STDataValidationType.Enum vt = XSSFDataValidation.validationTypeMappings.get(validationType);
  203. Enum ot = XSSFDataValidation.operatorTypeMappings.get(operator);
  204. builder.append(vt);
  205. builder.append(' ');
  206. if (validationType!=ValidationType.ANY) {
  207. if (validationType != ValidationType.LIST
  208. && validationType != ValidationType.FORMULA) {
  209. builder.append(LIST_SEPARATOR).append(ot).append(", ");
  210. }
  211. final String NOQUOTE = "";
  212. if (validationType == ValidationType.LIST && explicitListOfValues != null) {
  213. builder.append(NOQUOTE).append(Arrays.asList(explicitListOfValues)).append(NOQUOTE).append(' ');
  214. } else {
  215. builder.append(NOQUOTE).append(formula1).append(NOQUOTE).append(' ');
  216. }
  217. if (formula2 != null) {
  218. builder.append(NOQUOTE).append(formula2).append(NOQUOTE).append(' ');
  219. }
  220. }
  221. return builder.toString();
  222. }
  223. }