/[aagtl_public1]/src/net/htmlparser/jericho/FormFields.java
aagtl

Contents of /src/net/htmlparser/jericho/FormFields.java

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2 - (show annotations) (download)
Sun Aug 5 13:48:36 2012 UTC (11 years, 8 months ago) by zoffadmin
File size: 34735 byte(s)
initial import of aagtl source code
1 // Jericho HTML Parser - Java based library for analysing and manipulating HTML
2 // Version 3.2
3 // Copyright (C) 2004-2009 Martin Jericho
4 // http://jericho.htmlparser.net/
5 //
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of either one of the following licences:
8 //
9 // 1. The Eclipse Public License (EPL) version 1.0,
10 // included in this distribution in the file licence-epl-1.0.html
11 // or available at http://www.eclipse.org/legal/epl-v10.html
12 //
13 // 2. The GNU Lesser General Public License (LGPL) version 2.1 or later,
14 // included in this distribution in the file licence-lgpl-2.1.txt
15 // or available at http://www.gnu.org/licenses/lgpl.txt
16 //
17 // This library is distributed on an "AS IS" basis,
18 // WITHOUT WARRANTY OF ANY KIND, either express or implied.
19 // See the individual licence texts for more details.
20
21 package net.htmlparser.jericho;
22
23 import java.util.*;
24
25 /**
26 * Represents a collection of {@link FormField} objects.
27 * <p>
28 * This class provides the main interface for the analysis and manipulation of {@linkplain FormControl form controls}.
29 * A <code>FormFields</code> object is a collection of {@link FormField} objects, with each form field consisting of
30 * a group of {@linkplain FormControl form controls} having the same {@linkplain FormControl#getName() name}.
31 * <p>
32 * The functionality provided by this class can be used to accomplish two main tasks:
33 * <ol>
34 * <li style="margin-bottom: 1.5em">
35 * Modify the <a href="FormControl.html#SubmissionValue">submission values</a> of the constituent form controls
36 * for subsequent output in an {@link OutputDocument}.
37 * <p>
38 * The methods available for this purpose are:<br />
39 * {@link #getValues(String) List&lt;String&gt; getValues(String fieldName)}<br />
40 * {@link #getDataSet() Map&lt;String,String[]&gt; getDataSet()}<br />
41 * {@link #clearValues() void clearValues()}<br />
42 * {@link #setDataSet(Map) void setDataSet(Map&lt;String,String[]&gt;)}<br />
43 * {@link #setValue(String,String) boolean setValue(String fieldName, String value)}<br />
44 * {@link #addValue(String,String) boolean addValue(String fieldName, String value)}<br />
45 * <p>
46 * Although the {@link FormField} and {@link FormControl} classes provide methods for directly modifying
47 * the submission values of individual form fields and controls, it is generally recommended to use the interface provided by this
48 * (the <code>FormFields</code>) class unless there is a specific requirement for the lower level functionality.
49 * <p>
50 * The <a href="FormControl.html#DisplayCharacteristics">display characteristics</a> of individual controls,
51 * such as whether the control is {@linkplain FormControl#setDisabled(boolean) disabled}, replaced with a simple
52 * {@linkplain FormControlOutputStyle#DISPLAY_VALUE value}, or {@linkplain FormControlOutputStyle#REMOVE removed} altogether,
53 * can only be set on the individual {@link FormControl} objects.
54 * See below for information about retrieving a specific <code>FormControl</code> object from the <code>FormFields</code> object.
55 * <li>
56 * Convert data from a <a target="_blank" href="http://www.w3.org/TR/html401/interact/forms.html#form-data-set">form data set</a>
57 * (represented as a <a href="#FieldDataSet">field data set</a>) into a simple array format,
58 * suitable for storage in a tabular format such as a database table or <code>.CSV</code> file.
59 * <p>
60 * The methods available for this purpose are:<br />
61 * {@link #getColumnLabels() String[] getColumnLabels()}<br />
62 * {@link #getColumnValues(Map) String[] getColumnValues(Map)}<br />
63 * {@link #getColumnValues() String[] getColumnValues()}<br />
64 * <p>
65 * The {@link Util} class contains a method called {@link Util#outputCSVLine(Writer,String[]) outputCSVLine(Writer,String[])}
66 * which writes the <code>String[]</code> output of these methods to the specified <code>Writer</code> in <code>.CSV</code> format.
67 * <p>
68 * The implementation of these methods makes use of certain <a href="FormField.html#DataStructureProperties">properties</a>
69 * in the {@link FormField} class that describe the structure of the data in each field.
70 * These properties can be utilised directly in the event that a
71 * <a target="_blank" href="http://www.w3.org/TR/html401/interact/forms.html#form-data-set">form data set</a> is to be converted
72 * from its <a href="FormFields.html#FieldDataSet">normal format</a> into some other type of data structure.
73 * </ol>
74 * <p>
75 * To access a specific {@link FormControl} from a <code>FormFields</code> object, use:
76 * <ul style="margin-top: 0px">
77 * <li><code>formFields.</code>{@link #get(String) get(fieldName)}<code>.</code>{@link FormField#getFormControl() getFormControl()}
78 * if the control is the only one with the specified {@linkplain FormControl#getName() name}, or
79 * <li><code>formFields.</code>{@link #get(String) get(fieldName)}<code>.</code>{@link FormField#getFormControl(String) getFormControl(predefinedValue)}
80 * to retrieve the control having the speficied {@linkplain FormControl#getPredefinedValue() predefined value}
81 * if it is part of a {@linkplain FormField field} containing multiple controls.
82 * </ul>
83 * <p>
84 * The term <i><a name="FieldDataSet">field data set</a></i> is used in this library to refer to a data structure consisting of
85 * a set of names (in lower case), each mapped to one or more values.
86 * Generally, this is represented by a data type of <code>java.util.Map&lt;String,String[]&gt;</code>,
87 * with the keys (names) being of type <code>String</code> and the values represented by an array containing one or more items of type <code>String</code>.
88 * A field data set can be used to represent the data in an HTML
89 * <a target="_blank" href="http://www.w3.org/TR/html401/interact/forms.html#form-data-set">form data set</a>.
90 * <p>
91 * <code>FormFields</code> instances are obtained using the {@link #FormFields(Collection formControls)} constructor
92 * or by calling the {@link Segment#getFormFields()} method.
93 * <p>
94 * The case sensitivity of form field names is determined by the static
95 * {@link Config#CurrentCompatibilityMode}<code>.</code>{@link Config.CompatibilityMode#isFormFieldNameCaseInsensitive() FormFieldNameCaseInsensitive} property.
96 * <p>
97 * <b>Examples:</b>
98 * <ol>
99 * <li>
100 * Write the data received from in the current <code>ServletRequest</code> to a <code>.CSV</code> file,
101 * and then display the form populated with this data:
102 * <p><pre>
103 * Source source=new Source(htmlTextOfOriginatingForm);
104 * FormFields formFields=source.getFormFields();
105 *
106 * File csvOutputFile=new File("FormData.csv");
107 * boolean outputHeadings=!csvOutputFile.exists();
108 * Writer writer=new FileWriter(csvOutputFile,true);
109 * if (outputHeadings) Util.outputCSVLine(writer,formFields.getColumnLabels());
110 * Util.outputCSVLine(writer,formFields.getColumnValues(servletRequest.getParameterMap()));
111 * writer.close();
112 *
113 * formFields.setDataSet(servletRequest.getParameterMap());
114 * OutputDocument outputDocument=new OutputDocument(source);
115 * outputDocument.replace(formFields);
116 * outputDocument.writeTo(servletResponse.getWriter());</pre>
117 * <p>See also the sample program FormFieldCSVOutput.<br /><br />
118 * <li>Replace the initial values of controls in the form named "MyForm" with new values:
119 * <p><pre>
120 * Source source=new Source(htmlText);
121 * Element myForm=null;
122 * List formElements=source.getAllElements(Tag.FORM);
123 * for (Iterator i=formElements.iterator(); i.hasNext();) {
124 * Element formElement=(Element)i.next();
125 * String formName=formElement.getAttributes().getValue("name");
126 * if ("MyForm".equals(formName)) {
127 * myForm=form;
128 * break;
129 * }
130 * }
131 * FormFields formFields=myForm.getFormFields();
132 * formFields.clearValues(); // clear any values that might be set in the source document
133 * formFields.addValue("Name","Humphrey Bear");
134 * formFields.addValue("MailingList","A");
135 * formFields.addValue("MailingList","B");
136 * formFields.addValue("FavouriteFare","honey");
137 * OutputDocument outputDocument=new OutputDocument(source);
138 * outputDocument.replace(formFields);
139 * String newHtmlText=outputDocument.toString();</pre>
140 * <p>See also the sample program FormFieldSetValues.<br /><br />
141 * <li>Change the display characteristics of individual controls:
142 * <p><pre>
143 * Source source=new Source(htmlText);
144 * FormFields formFields=source.getFormFields();
145 * // disable some controls:
146 * formFields.get("Password").getFormControl().setDisabled(true);
147 * FormField mailingListFormField=formFields.get("MailingList");
148 * mailingListFormField.setValue("C");
149 * mailingListFormField.getFormControl("C").setDisabled(true);
150 * mailingListFormField.getFormControl("D").setDisabled(true);
151 * // remove some controls:
152 * formFields.get("button1").getFormControl().setOutputStyle(FormControlOutputStyle.REMOVE);
153 * FormControl rhubarbFormControl=formFields.get("FavouriteFare").getFormControl("rhubarb");
154 * rhubarbFormControl.setOutputStyle(FormControlOutputStyle.REMOVE);
155 * // set some controls to display value:
156 * formFields.setValue("Address","The Lodge\nDeakin ACT 2600\nAustralia");
157 * formFields.get("Address").getFormControl().setOutputStyle(FormControlOutputStyle.DISPLAY_VALUE);
158 * FormField favouriteSportsFormField=formFields.get("FavouriteSports");
159 * favouriteSportsFormField.setValue("BB");
160 * favouriteSportsFormField.addValue("AFL");
161 * favouriteSportsFormField.getFormControl().setOutputStyle(FormControlOutputStyle.DISPLAY_VALUE);
162 * OutputDocument outputDocument=new OutputDocument(source);
163 * outputDocument.replace(formFields); // adds all segments necessary to effect changes
164 * String newHtmlText=outputDocument.toString();</pre>
165 * <p>See also the sample program FormControlDisplayCharacteristics.<br /><br />
166 * </ol>
167 * @see FormField
168 * @see FormControl
169 */
170 public final class FormFields extends AbstractCollection<FormField> {
171 private final LinkedHashMap<String,FormField> map=new LinkedHashMap<String,FormField>();
172 private final ArrayList<FormControl> formControls=new ArrayList<FormControl>();
173
174 /**
175 * Constructs a new <code>FormFields</code> object consisting of the specified {@linkplain FormControl form controls}.
176 * @param formControls a collection of {@link FormControl} objects.
177 * @see Segment#getFormFields()
178 */
179 public FormFields(final Collection<FormControl> formControls) {
180 // Passing "this" as a parameter inside a constructor used to cause some strange problems back in java 1.0,
181 // but it seems to work here and there is no explicit mention in the Java language spec about any potential problems.
182 // The alternative is an ugly static FormFields constructFrom(List formControls) method.
183 for (FormControl formControl : formControls) {
184 if (formControl.getName()!=null && formControl.getName().length()!=0) {
185 formControl.addToFormFields(this);
186 this.formControls.add(formControl);
187 }
188 }
189 }
190
191 /**
192 * Returns the number of <code>FormField</code> objects.
193 * @return the number of <code>FormField</code> objects.
194 */
195 public int getCount() {
196 return map.size();
197 }
198
199 /**
200 * Returns the number of <code>FormField</code> objects.
201 * <p>
202 * This is equivalent to {@link #getCount()},
203 * and is necessary to for the implementation of the <code>java.util.Collection</code> interface.
204 *
205 * @return the number of <code>FormField</code> objects.
206 */
207 public int size() {
208 return getCount();
209 }
210
211 /**
212 * Returns the <code>FormField</code> with the specified {@linkplain FormField#getName() name}.
213 * <p>
214 * The case sensitivity of the <code>fieldName</code> argument is determined by the static
215 * {@link Config#CurrentCompatibilityMode}<code>.</code>{@link Config.CompatibilityMode#isFormFieldNameCaseInsensitive() FormFieldNameCaseInsensitive} property.
216 *
217 * @param fieldName the name of the <code>FormField</code> to get.
218 * @return the <code>FormField</code> with the specified {@linkplain FormField#getName() name}, or <code>null</code> if no <code>FormField</code> with the specified name exists.
219 */
220 public FormField get(String fieldName) {
221 if (Config.CurrentCompatibilityMode.isFormFieldNameCaseInsensitive()) fieldName=fieldName.toLowerCase();
222 return map.get(fieldName);
223 }
224
225 /**
226 * Returns an iterator over the {@link FormField} objects in the collection.
227 * <p>
228 * The order in which the form fields are iterated corresponds to the order of appearance
229 * of each form field's first {@link FormControl} in the source document.
230 * <p>
231 * If this <code>FormFields</code> object has been {@linkplain #merge(FormFields) merged} with another,
232 * the ordering is no longer defined.
233 *
234 * @return an iterator over the {@link FormField} objects in the collection.
235 */
236 public Iterator<FormField> iterator() {
237 return map.values().iterator();
238 }
239
240 /**
241 * Returns a list of the <a href="FormField.html#FieldSubmissionValues">field submission values</a> of all the specified constituent {@linkplain FormField form fields} with the specified {@linkplain FormField#getName() name}.
242 * <p>
243 * All objects in the returned list are of type <code>String</code>, with no <code>null</code> entries.
244 * <p>
245 * This is equivalent to {@link #get(String) get(fieldName)}<code>.</code>{@link FormField#getValues() getValues()},
246 * assuming that a field with the specified name exists in this collection.
247 *
248 * @param fieldName the {@linkplain FormField#getName() name} of the form field.
249 * @return a list of the <a href="FormField.html#FieldSubmissionValues">field submission values</a> of all the specified constituent {@linkplain FormField form field} with the specified {@linkplain FormField#getName() name}, or <code>null</code> if no form field with this name exists.
250 * @see FormField#getValues()
251 */
252 public List<String> getValues(final String fieldName) {
253 final FormField formField=get(fieldName);
254 return formField==null ? null : formField.getValues();
255 }
256
257 /**
258 * Returns the entire <a href="#FieldDataSet">field data set</a> represented by the {@linkplain FormField#getValues() values} of the constituent form fields.
259 * <p>
260 * The values in the map returned by this method are represented as a string array, giving the map a format consistent with the
261 * <code><a target="_blank" href="http://java.sun.com/products/servlet/2.3/javadoc/javax/servlet/ServletRequest.html#getParameterMap()">javax.servlet.ServletRequest.getParameterMap()</a></code>
262 * method.
263 * <p>
264 * Only the {@linkplain FormField#getName() names} of form fields with at least one {@linkplain FormField#getValues() value}
265 * are included in the map, meaning every <code>String[]</code> is guaranteed to have at least one entry.
266 * <p>
267 * Iterating over the map keys returns them in the order of appearance in the source document.
268 *
269 * @return the entire <a href="#FieldDataSet">field data set</a> represented by the {@linkplain FormField#getValues() values} of the constituent form fields.
270 * @see #setDataSet(Map)
271 */
272 public Map<String,String[]> getDataSet() {
273 final LinkedHashMap<String,String[]> map=new LinkedHashMap<String,String[]>((int)(getCount()/0.7));
274 for (FormField formField : this) {
275 final List<String> values=formField.getValues();
276 if (values.isEmpty()) continue;
277 map.put(formField.getName(),values.toArray(new String[values.size()]));
278 }
279 return map;
280 }
281
282 /**
283 * Clears the <a href="FormControl.html#SubmissionValue">submission values</a> of all the constituent {@linkplain #getFormControls() form controls}.
284 * @see FormControl#clearValues()
285 */
286 public void clearValues() {
287 for (FormControl formControl : formControls) formControl.clearValues();
288 }
289
290 /**
291 * Sets the <a href="FormControl.html#SubmissionValue">submission values</a> of all the constituent
292 * {@linkplain FormControl form controls} to match the data in the specified <a href="#FieldDataSet">field data set</a>.
293 * <p>
294 * The map keys must be <code>String</code> {@linkplain FormField#getName() field names},
295 * with each map value an array of <code>String</code> objects containing the field's new {@linkplain FormField#setValues(Collection) values}.
296 * <p>
297 * The map returned by the
298 * <code><a target="_blank" href="http://java.sun.com/products/servlet/2.3/javadoc/javax/servlet/ServletRequest.html#getParameterMap()">javax.servlet.ServletRequest.getParameterMap()</a></code>
299 * method has a suitable format for use with this method.
300 * <p>
301 * All existing values are {@linkplain #clearValues() cleared} before the values from the field data set are added.
302 * <p>
303 * Any map entries with a <code>null</code> value are ignored.
304 *
305 * @param dataSet the <a href="#FieldDataSet">field data set</a> containing the new {@linkplain FormField#setValues(Collection) values} of the constituent form fields.
306 * @see #getDataSet()
307 */
308 public void setDataSet(final Map<String,String[]> dataSet) {
309 clearValues();
310 if (map==null) return;
311 for (Map.Entry<String,String[]> entry : dataSet.entrySet()) {
312 final String fieldName=entry.getKey();
313 final FormField formField=get(fieldName);
314 if (formField!=null) formField.addValues(entry.getValue());
315 }
316 }
317
318 /**
319 * Sets the <a href="FormField.html#FieldSubmissionValues">field submission values</a> of the constituent
320 * {@linkplain FormField form field} with the specified {@linkplain FormField#getName() name} to the single specified value.
321 * <p>
322 * This is equivalent to {@link #get(String) get(fieldName)}<code>.</code>{@link FormField#setValue(String) setValue(value)},
323 * assuming that a field with the specified name exists in this collection.
324 * <p>
325 * The return value indicates whether the specified form field "accepted" the value.
326 * A return value of <code>false</code> implies an error condition as either no field with the specified name exists, or
327 * the specified value is not compatible with the specified field.
328 *
329 * @param fieldName the {@linkplain FormField#getName() name} of the form field.
330 * @param value the new <a href="FormField.html#FieldSubmissionValues">field submission value</a> of the specified field, or <code>null</code> to {@linkplain FormField#clearValues() clear} the field of all submission values.
331 * @return <code>true</code> if a field of the specified name exists in this collection and it accepts the specified value, otherwise <code>false</code>.
332 */
333 public boolean setValue(final String fieldName, final String value) {
334 final FormField formField=get(fieldName);
335 return formField==null ? false : formField.setValue(value);
336 }
337
338 /**
339 * Adds the specified value to the <a href="FormField.html#FieldSubmissionValues">field submission values</a> of the constituent
340 * {@linkplain FormField form field} with the specified {@linkplain FormField#getName() name}.
341 * <p>
342 * This is equivalent to {@link #get(String) get(fieldName)}<code>.</code>{@link FormField#addValue(String) addValue(value)},
343 * assuming that a field with the specified name exists in this collection.
344 * <p>
345 * The return value indicates whether the specified form field "accepted" the value.
346 * A return value of <code>false</code> implies an error condition as either no field with the specified name exists, or
347 * the specified value is not compatible with the specified field.
348 *
349 * @param fieldName the {@linkplain FormField#getName() name} of the form field.
350 * @param value the new <a href="FormField.html#FieldSubmissionValues">field submission value</a> to add to the specified field, must not be <code>null</code>.
351 * @return <code>true</code> if a field of the specified name exists in this collection and it accepts the specified value, otherwise <code>false</code>.
352 */
353 public boolean addValue(final String fieldName, final String value) {
354 final FormField formField=get(fieldName);
355 return formField==null ? false : formField.addValue(value);
356 }
357
358 /**
359 * Returns a string array containing the column labels corresponding to the values from the {@link #getColumnValues(Map)} method.
360 * <p>
361 * Instead of using the {@linkplain FormField#getName() name} of each constituent form field to construct the labels,
362 * the {@linkplain FormControl#getName() name} of the first {@linkplain FormControl form control} from each form field is used.
363 * This allows the labels to be constructed using the names with the original case from the source document rather than
364 * unsing the all lower case names of the form fields.
365 * <p>
366 * See the documentation of the {@link #getColumnValues(Map)} method for more details.
367 *
368 * @return a string array containing the column labels corresponding to the values from the {@link #getColumnValues(Map)} method.
369 * @see Util#outputCSVLine(Writer,String[])
370 */
371 public String[] getColumnLabels() {
372 initColumns();
373 final String[] columnLabels=new String[columns.length];
374 for (int i=0 ; i<columns.length; i++) {
375 final Column column=columns[i];
376 final String fieldName=column.formField.getFirstFormControl().getName(); // use this instead of formControl.getName() so that the original case is used even if Config.CurrentCompatibilityMode.isFormFieldNameCaseInsensitive() is true.
377 columnLabels[i]=column.predefinedValue!=null
378 ? fieldName+'.'+column.predefinedValue
379 : fieldName;
380 }
381 return columnLabels;
382 }
383
384 /**
385 * Converts the data values in the specified <a href="#FieldDataSet">field data set</a> into a simple string array,
386 * suitable for storage in a tabular format such as a database table or <code>.CSV</code> file.
387 * <p>
388 * The conversion is performed in a way that allows the multiple values of certain fields to be stored in separate columns,
389 * by analysing the possible <a target="_blank" href="http://www.w3.org/TR/html401/interact/forms.html#form-data-set">form data sets</a>
390 * that can be generated from the constituent {@linkplain #getFormControls() form controls}.
391 * <p>
392 * The column labels and values are determined as follows:
393 * <p>
394 * <ul class="HalfSeparated">
395 * <li>
396 * For each {@linkplain FormField form field} in this collection (taken in {@linkplain #iterator() iterator} order):
397 * <ul>
398 * <li>
399 * If the form field has no {@linkplain FormField#getPredefinedValues() predefined values},
400 * such as a single {@linkplain FormControlType#TEXT text control}, then:
401 * <ul>
402 * <li>
403 * Add a single column:
404 * <table class="CompactDL">
405 * <tr><td>{@linkplain #getColumnLabels() Label}:<td>the {@linkplain FormField#getName() name} of the form field in original case
406 * <tr><td>Value:<td>the single value mapped to this field in the specified <a href="#FieldDataSet">field data set</a>.
407 * </table>
408 * In the unlikely event that this field contains more than one value, all values are included in this one column and
409 * separated by the text defined in the static {@link Config#ColumnMultipleValueSeparator} property.
410 * </ul>
411 * <li>
412 * Otherwise, if the form field does have {@linkplain FormField#getPredefinedValues() predefined values},
413 * but does not {@linkplain FormField#allowsMultipleValues() allow multiple values}, then:
414 * <ul>
415 * <li>
416 * If the form field has only one {@linkplain FormField#getPredefinedValues() predefined value},
417 * such as a single {@linkplain FormControlType#CHECKBOX checkbox}, then:
418 * <ul>
419 * <li>
420 * Add a single boolean column:
421 * <table class="CompactDL">
422 * <tr><td>{@linkplain #getColumnLabels() Label}:<td>the {@linkplain FormField#getName() name} of the form field in original case
423 * <tr><td>Value:<td>the currently configured string representation for <i>{@linkplain Config#ColumnValueTrue true}</i>
424 * if a value mapped to this field in the specified <a href="#FieldDataSet">field data set</a> matches the
425 * {@linkplain FormField#getPredefinedValues() predefined value}, otherwise <i>{@linkplain Config#ColumnValueFalse false}</i>
426 * </table>
427 * </ul>
428 * <li>
429 * Otherwise, if the form field has more than one {@linkplain FormField#getPredefinedValues() predefined value},
430 * such as a set of {@linkplain FormControlType#RADIO radio buttons}, then:
431 * <ul>
432 * <li>
433 * Add a single column:
434 * <table class="CompactDL">
435 * <tr><td>{@linkplain #getColumnLabels() Label}:<td>the {@linkplain FormField#getName() name} of the form field in original case
436 * <tr><td>Value:<td>the single value mapped to this field in the specified <a href="#FieldDataSet">field data set</a>,
437 * which in the case of a set of radio buttons should be the {@linkplain FormControl#getPredefinedValue() predefined value}
438 * of the {@linkplain FormControl#isChecked() checked} radio button.
439 * </table>
440 * </ul>
441 * </ul>
442 * <li>
443 * Otherwise, if the form field has {@linkplain FormField#getPredefinedValues() predefined values}
444 * and {@linkplain FormField#allowsMultipleValues() allows multiple values},
445 * such as a set of {@linkplain FormControlType#CHECKBOX checkboxes}, then:
446 * <ul>
447 * <li>
448 * For each {@linkplain FormField#getPredefinedValues() predefined value} in the form field:
449 * <ul>
450 * <li>
451 * Add a boolean column:
452 * <table class="CompactDL">
453 * <tr><td>{@linkplain #getColumnLabels() Label}:<td>"<code><i>FieldName</i>.<i>PredefinedValue</i></code>",
454 * where <code><i>FieldName</i></code> is the {@linkplain FormField#getName() name} of the form field in original case,
455 * and <code><i>PredefinedValue</i></code> is the {@linkplain FormField#getPredefinedValues() predefined value}.
456 * <tr><td>Value:<td>the currently configured string representation for <i>{@linkplain Config#ColumnValueTrue true}</i>
457 * if a value mapped to this field in the specified <a href="#FieldDataSet">field data set</a> matches the
458 * {@linkplain FormField#getPredefinedValues() predefined value}, otherwise <i>{@linkplain Config#ColumnValueFalse false}</i>
459 * </table>
460 * </ul>
461 * <li>
462 * In addition, if the form field can also contain user values ({@link FormField#getUserValueCount()}<code>&gt;0</code>), then:
463 * <ul>
464 * <li>
465 * Add another column:
466 * <table class="CompactDL">
467 * <tr><td>{@linkplain #getColumnLabels() Label}:<td>the {@linkplain FormField#getName() name} of the form field in original case
468 * <tr><td>Value:<td>all values mapped to this field in the specified <a href="#FieldDataSet">field data set</a>
469 * that do not match any of the {@linkplain FormField#getPredefinedValues() predefined values},
470 * separated by the text defined in the static {@link Config#ColumnMultipleValueSeparator} property.
471 * </table>
472 * </ul>
473 * </ul>
474 * </ul>
475 * </ul>
476 * <p>
477 * The sample program FormFieldCSVOutput demonstrates the use of this method and its output.
478 *
479 * @param dataSet a <a href="#FieldDataSet">field data set</a> containing the data to convert.
480 * @return the data values in the specified <a href="#FieldDataSet">field data set</a> in the form of a simple string array.
481 * @see Util#outputCSVLine(Writer,String[])
482 * @see #getColumnLabels()
483 * @see #getColumnValues()
484 */
485 public String[] getColumnValues(final Map<String,String[]> dataSet) {
486 initColumns();
487 final String[] columnValues=new String[columns.length];
488 if (Config.ColumnValueFalse!=null) {
489 // initialise all boolean columns with false string
490 for (int i=0; i<columns.length; i++)
491 if (columns[i].isBoolean) columnValues[i]=Config.ColumnValueFalse;
492 }
493 for (Map.Entry<String,String[]> entry : dataSet.entrySet()) {
494 final String fieldName=entry.getKey();
495 final FormField formField=get(fieldName);
496 if (formField!=null) {
497 final int columnIndex=formField.columnIndex;
498 for (String value : entry.getValue()) {
499 for (int ci=columnIndex; ci<columns.length; ci++) {
500 final Column column=columns[ci];
501 if (column.formField!=formField) break;
502 if (column.predefinedValue!=null) {
503 if (!column.predefinedValue.equals(value)) continue;
504 columnValues[ci]=Config.ColumnValueTrue;
505 } else {
506 if (column.isBoolean) {
507 if (value!=null) columnValues[ci]=Config.ColumnValueTrue;
508 } else if (columnValues[ci]==null) {
509 columnValues[ci]=value;
510 } else {
511 columnValues[ci]=columnValues[ci]+Config.ColumnMultipleValueSeparator+value;
512 }
513 }
514 break;
515 }
516 }
517 }
518 }
519 return columnValues;
520 }
521
522 /**
523 * Converts all the {@linkplain FormField#getValues() form submission values} of the constituent form fields into a simple string array,
524 * suitable for storage in a tabular format such as a database table or <code>.CSV</code> file.
525 * <p>
526 * This is equivalent to {@link #getColumnValues(Map) getColumnValues}<code>(</code>{@link #getDataSet()}<code>)</code>.
527 *
528 * @return all the {@linkplain FormField#getValues() form submission values} of the constituent form fields in the form of a simple string array.
529 */
530 public String[] getColumnValues() {
531 return getColumnValues(getDataSet());
532 }
533
534 private void initColumns() {
535 if (columns!=null) return;
536 final ArrayList<Column> columnList=new ArrayList<Column>();
537 for (FormField formField : this) {
538 formField.columnIndex=columnList.size();
539 if (!formField.allowsMultipleValues() || formField.getPredefinedValues().isEmpty()) {
540 columnList.add(new Column(formField,formField.getPredefinedValues().size()==1,null));
541 } else {
542 // add a column for every predefined value
543 for (String predefinedValue : formField.getPredefinedValues())
544 columnList.add(new Column(formField,true,predefinedValue));
545 if (formField.getUserValueCount()>0) columnList.add(new Column(formField,false,null)); // add a column for user values, must come after predefined values for algorithm in getColumnValues to work
546 }
547 }
548 columns=columnList.toArray(new Column[columnList.size()]);
549 }
550 private Column[] columns=null;
551
552 private static class Column {
553 public FormField formField;
554 public boolean isBoolean;
555 public String predefinedValue;
556 public Column(final FormField formField, final boolean isBoolean, final String predefinedValue) {
557 this.formField=formField;
558 this.isBoolean=isBoolean;
559 this.predefinedValue=predefinedValue;
560 }
561 }
562
563 /**
564 * Returns a list of all the {@linkplain FormField#getFormControls() constituent form controls} from all the {@linkplain FormField form fields} in this collection.
565 * @return a list of all the {@linkplain FormField#getFormControls() constituent form controls} from all the {@linkplain FormField form fields} in this collection.
566 */
567 public List getFormControls() {
568 return formControls;
569 }
570
571 /**
572 * Merges the specified <code>FormFields</code> into this <code>FormFields</code> collection.
573 * This is useful if a full collection of possible form fields is required from multiple {@linkplain Source source} documents.
574 * <p>
575 * If both collections contain a <code>FormField</code> with the same {@linkplain FormField#getName() name},
576 * the resulting <code>FormField</code> has the following properties:
577 * <ul>
578 * <li>{@link FormField#getUserValueCount() getUserValueCount()} : the maximum user value count from both form fields</li>
579 * <li>{@link FormField#allowsMultipleValues() allowsMultipleValues()} : <code>true</code> if either form field allows multiple values</li>
580 * <li>{@link FormField#getPredefinedValues() getPredefinedValues()} : the union of predefined values in both form fields</li>
581 * <li>{@link FormField#getFormControls() getFormControls()} : the union of {@linkplain FormControl form controls} from both form fields</li>
582 * </ul>
583 * <p>
584 * NOTE: Some underlying data structures may end up being shared between the two merged <code>FormFields</code> collections.
585 */
586 public void merge(final FormFields formFields) {
587 for (FormField formField : formFields) {
588 final String fieldName=formField.getName();
589 final FormField existingFormField=get(fieldName);
590 if (existingFormField==null)
591 map.put(formField.getName(),formField);
592 else
593 existingFormField.merge(formField);
594 }
595 }
596
597 /**
598 * Returns a string representation of this object useful for debugging purposes.
599 * @return a string representation of this object useful for debugging purposes.
600 */
601 public String getDebugInfo() {
602 final StringBuilder sb=new StringBuilder();
603 for (FormField formField : this) sb.append(formField);
604 return sb.toString();
605 }
606
607 /**
608 * Returns a string representation of this object useful for debugging purposes.
609 * <p>
610 * This is equivalent to {@link #getDebugInfo()}.
611 *
612 * @return a string representation of this object useful for debugging purposes.
613 */
614 public String toString() {
615 return getDebugInfo();
616 }
617
618 void add(final FormControl formControl) {
619 add(formControl,formControl.getPredefinedValue());
620 }
621
622 void add(final FormControl formControl, final String predefinedValue) {
623 add(formControl,predefinedValue,formControl.name);
624 }
625
626 void addName(final FormControl formControl, final String fieldName) {
627 add(formControl,null,fieldName);
628 }
629
630 void add(final FormControl formControl, final String predefinedValue, String fieldName) {
631 if (Config.CurrentCompatibilityMode.isFormFieldNameCaseInsensitive()) fieldName=fieldName.toLowerCase();
632 FormField formField=(FormField)map.get(fieldName);
633 if (formField==null) {
634 formField=new FormField(fieldName);
635 map.put(formField.getName(),formField);
636 }
637 formField.addFormControl(formControl,predefinedValue);
638 }
639
640 void replaceInOutputDocument(final OutputDocument outputDocument) {
641 for (FormControl formControl : formControls) outputDocument.replace(formControl);
642 }
643 }

   
Visit the aagtl Website