KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > au > id > jericho > lib > html > FormFields


1 // Jericho HTML Parser - Java based library for analysing and manipulating HTML
2
// Version 2.2
3
// Copyright (C) 2006 Martin Jericho
4
// http://sourceforge.net/projects/jerichohtml/
5
//
6
// This library is free software; you can redistribute it and/or
7
// modify it under the terms of the GNU Lesser General Public
8
// License as published by the Free Software Foundation; either
9
// version 2.1 of the License, or (at your option) any later version.
10
// http://www.gnu.org/copyleft/lesser.html
11
//
12
// This library is distributed in the hope that it will be useful,
13
// but WITHOUT ANY WARRANTY; without even the implied warranty of
14
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
// Lesser General Public License for more details.
16
//
17
// You should have received a copy of the GNU Lesser General Public
18
// License along with this library; if not, write to the Free Software
19
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20

21 package au.id.jericho.lib.html;
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) Collection getValues(String fieldName)}<br />
40  * {@link #getDataSet() Map getDataSet()}<br />
41  * {@link #clearValues() void clearValues()}<br />
42  * {@link #setDataSet(Map) void setDataSet(Map)}<br />
43  * {@link #setValue(String,CharSequence) boolean setValue(String fieldName, CharSequence value)}<br />
44  * {@link #addValue(String,CharSequence) boolean addValue(String fieldName, CharSequence 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 <code>java.util.Map</code> with the keys (names) being of type <code>String</code> and the
87  * values represented by either an array or collection containing one or more items of type <code>CharSequence</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#findFormFields()} method.
93  * <p>
94  * The case sensitivity of form field names is determined by the
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.findFormFields();
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.findAllElements(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.findFormFields();
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("FavouriteFair","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.findFormFields();
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("FavouriteFair").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 {
171     private final LinkedHashMap map=new LinkedHashMap();
172     private final ArrayList formControls=new ArrayList();
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#findFormFields()
178      */

179     public FormFields(final Collection 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 (final Iterator i=formControls.iterator(); i.hasNext();) {
184             final FormControl formControl=(FormControl)i.next();
185             if (formControl.getName()!=null && formControl.getName().length()!=0) {
186                 formControl.addToFormFields(this);
187                 this.formControls.add(formControl);
188             }
189         }
190     }
191
192     /**
193      * Returns the number of <code>FormField</code> objects.
194      * @return the number of <code>FormField</code> objects.
195      */

196     public int getCount() {
197         return map.size();
198     }
199
200     /**
201      * Returns the number of <code>FormField</code> objects.
202      * <p>
203      * This is equivalent to {@link #getCount()},
204      * and is necessary to for the implementation of the <code>java.util.Collection</code> interface.
205      *
206      * @return the number of <code>FormField</code> objects.
207      */

208     public int size() {
209         return getCount();
210     }
211
212     /**
213      * Returns the <code>FormField</code> with the specified {@linkplain FormField#getName() name}.
214      * <p>
215      * The case sensitivity of the <code>fieldName</code> argument is determined by the
216      * {@link Config#CurrentCompatibilityMode}<code>.</code>{@link Config.CompatibilityMode#isFormFieldNameCaseInsensitive() FormFieldNameCaseInsensitive} property.
217      *
218      * @param fieldName the name of the <code>FormField</code> to get.
219      * @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.
220      */

221     public FormField get(String JavaDoc fieldName) {
222         if (Config.CurrentCompatibilityMode.isFormFieldNameCaseInsensitive()) fieldName=fieldName.toLowerCase();
223         return (FormField)map.get(fieldName);
224     }
225
226     /**
227      * Returns an iterator over the {@link FormField} objects in the collection.
228      * <p>
229      * The order in which the form fields are iterated corresponds to the order of appearance
230      * of each form field's first {@link FormControl} in the source document.
231      * <p>
232      * If this <code>FormFields</code> object has been {@linkplain #merge(FormFields) merged} with another,
233      * the ordering is no longer defined.
234      *
235      * @return an iterator over the {@link FormField} objects in the collection.
236      */

237     public Iterator iterator() {
238         return map.values().iterator();
239     }
240
241     /**
242      * Returns a collection of the <a HREF="FormField.html#FieldSubmissionValue">field submission values</a> of all the specified constituent {@linkplain FormField form field} with the specified {@linkplain FormField#getName() name}.
243      * <p>
244      * All objects in the returned collection are of type <code>CharSequence</code>, with no <code>null</code> entries.
245      * <p>
246      * This is equivalent to {@link #get(String) get(fieldName)}<code>.</code>{@link FormField#getValues() getValues()},
247      * assuming that a field with the specified name exists in this collection.
248      *
249      * @param fieldName the {@linkplain FormField#getName() name} of the form field.
250      * @return a collection of the <a HREF="FormField.html#FieldSubmissionValue">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.
251      * @see FormField#getValues()
252      */

253     public Collection getValues(final String JavaDoc fieldName) {
254         final FormField formField=get(fieldName);
255         return formField==null ? null : formField.getValues();
256     }
257
258     /**
259      * Returns the entire <a HREF="#FieldDataSet">field data set</a> represented by the {@linkplain FormField#getValues() values} of the constituent form fields.
260      * <p>
261      * The values in the map returned by this method are represented as a string array, giving the map a format consistent with the
262      * <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>
263      * method.
264      * <p>
265      * Only the {@linkplain FormField#getName() names} of form fields with at least one {@linkplain FormField#getValues() value}
266      * are included in the map, meaning every <code>String[]</code> is guaranteed to have at least one entry.
267      *
268      * @return the entire <a HREF="#FieldDataSet">field data set</a> represented by the {@linkplain FormField#getValues() values} of the constituent form fields.
269      * @see #setDataSet(Map)
270      */

271     public Map getDataSet() {
272         final HashMap map=new HashMap((int)(getCount()/0.7));
273         for (final Iterator i=iterator(); i.hasNext();) {
274             final FormField formField=(FormField)i.next();
275             final Collection values=formField.getValues();
276             if (values.isEmpty()) continue;
277             final String JavaDoc[] valuesArray=new String JavaDoc[values.size()];
278             final Iterator valuesIterator=values.iterator();
279             for (int x=0; x<values.size(); x++) valuesArray[x]=valuesIterator.next().toString();
280             map.put(formField.getName(),valuesArray);
281         }
282         return map;
283     }
284
285     /**
286      * Clears the <a HREF="FormControl.html#SubmissionValue">submission values</a> of all the constituent {@linkplain #getFormControls() form controls}.
287      * @see FormControl#clearValues()
288      */

289     public void clearValues() {
290         for (final Iterator i=formControls.iterator(); i.hasNext();)
291             ((FormControl)i.next()).clearValues();
292     }
293
294     /**
295      * Sets the <a HREF="FormControl.html#SubmissionValue">submission values</a> of all the constituent
296      * {@linkplain FormControl form controls} to match the data in the specified <a HREF="#FieldDataSet">field data set</a>.
297      * <p>
298      * The map keys must be <code>String</code> {@linkplain FormField#getName() field names}, with each map value either an array or
299      * <code>Collection</code> of <code>CharSequence</code> objects containing the field's new
300      * {@linkplain FormField#setValues(Collection) values}.
301      * <p>
302      * The map returned by the
303      * <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>
304      * method has a suitable format for use with this method.
305      * <p>
306      * All existing values are {@linkplain #clearValues() cleared} before the values from the field data set are added.
307      * <p>
308      * Any map entries with a <code>null</code> value are ignored.
309      *
310      * @param dataSet the <a HREF="#FieldDataSet">field data set</a> containing the new {@linkplain FormField#setValues(Collection) values} of the constituent form fields.
311      * @see #getDataSet()
312      */

313     public void setDataSet(final Map dataSet) {
314         clearValues();
315         if (map==null) return;
316         for (final Iterator i=dataSet.entrySet().iterator(); i.hasNext();) {
317             final Map.Entry entry=(Map.Entry)i.next();
318             final String JavaDoc fieldName=entry.getKey().toString();
319             final FormField formField=get(fieldName);
320             if (formField!=null) {
321                 if (entry.getValue() instanceof Collection)
322                     formField.addValues((Collection)entry.getValue());
323                 else
324                     formField.addValues((CharSequence JavaDoc[])entry.getValue());
325             }
326         }
327     }
328
329     /**
330      * Sets the <a HREF="FormField.html#FieldSubmissionValues">field submission values</a> of the constituent
331      * {@linkplain FormField form field} with the specified {@linkplain FormField#getName() name} to the single specified value.
332      * <p>
333      * This is equivalent to {@link #get(String) get(fieldName)}<code>.</code>{@link FormField#setValue(CharSequence) setValue(value)},
334      * assuming that a field with the specified name exists in this collection.
335      * <p>
336      * The return value indicates whether the specified form field "accepted" the value.
337      * A return value of <code>false</code> implies an error condition as either no field with the specified name exists, or
338      * the specified value is not compatible with the specified field.
339      *
340      * @param fieldName the {@linkplain FormField#getName() name} of the form field.
341      * @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.
342      * @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>.
343      */

344     public boolean setValue(final String JavaDoc fieldName, final CharSequence JavaDoc value) {
345         final FormField formField=get(fieldName);
346         return formField==null ? false : formField.setValue(value);
347     }
348
349     /**
350      * Adds the specified value to the <a HREF="FormField.html#FieldSubmissionValues">field submission values</a> of the constituent
351      * {@linkplain FormField form field} with the specified {@linkplain FormField#getName() name}.
352      * <p>
353      * This is equivalent to {@link #get(String) get(fieldName)}<code>.</code>{@link FormField#addValue(CharSequence) addValue(value)},
354      * assuming that a field with the specified name exists in this collection.
355      * <p>
356      * The return value indicates whether the specified form field "accepted" the value.
357      * A return value of <code>false</code> implies an error condition as either no field with the specified name exists, or
358      * the specified value is not compatible with the specified field.
359      *
360      * @param fieldName the {@linkplain FormField#getName() name} of the form field.
361      * @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>.
362      * @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>.
363      */

364     public boolean addValue(final String JavaDoc fieldName, final CharSequence JavaDoc value) {
365         final FormField formField=get(fieldName);
366         return formField==null ? false : formField.addValue(value);
367     }
368
369     /**
370      * Returns a string array containing the column labels corresponding to the values from the {@link #getColumnValues(Map)} method.
371      * <p>
372      * Instead of using the {@linkplain FormField#getName() name} of each constituent form field to construct the labels,
373      * the {@linkplain FormControl#getName() name} of the first {@linkplain FormControl form control} from each form field is used.
374      * This allows the labels to be constructed using the names with the original case from the source document rather than
375      * unsing the all lower case names of the form fields.
376      * <p>
377      * See the documentation of the {@link #getColumnValues(Map)} method for more details.
378      *
379      * @return a string array containing the column labels corresponding to the values from the {@link #getColumnValues(Map)} method.
380      * @see Util#outputCSVLine(Writer,String[])
381      */

382     public String JavaDoc[] getColumnLabels() {
383         initColumns();
384         final String JavaDoc[] columnLabels=new String JavaDoc[columns.length];
385         for (int i=0; i<columns.length; i++) {
386             final Column column=columns[i];
387             final String JavaDoc 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.
388
columnLabels[i]=column.predefinedValue!=null
389                 ? fieldName+'.'+column.predefinedValue
390                 : fieldName;
391         }
392         return columnLabels;
393     }
394
395     /**
396      * Converts the data values in the specified <a HREF="#FieldDataSet">field data set</a> into a simple string array,
397      * suitable for storage in a tabular format such as a database table or <code>.CSV</code> file.
398      * <p>
399      * The conversion is performed in a way that allows the multiple values of certain fields to be stored in separate columns,
400      * by analysing the possible <a target="_blank" HREF="http://www.w3.org/TR/html401/interact/forms.html#form-data-set">form data sets</a>
401      * that can be generated from the constituent {@linkplain #getFormControls() form controls}.
402      * <p>
403      * The column labels and values are determined as follows:
404      * <p>
405      * <ul class="HalfSeparated">
406      * <li>
407      * For each {@linkplain FormField form field} in this collection (taken in {@linkplain #iterator() iterator} order):
408      * <ul>
409      * <li>
410      * If the form field has no {@linkplain FormField#getPredefinedValues() predefined values},
411      * such as a single {@linkplain FormControlType#TEXT text control}, then:
412      * <ul>
413      * <li>
414      * Add a single column:
415      * <table class="CompactDL">
416      * <tr><td>{@linkplain #getColumnLabels() Label}:<td>the {@linkplain FormField#getName() name} of the form field in original case
417      * <tr><td>Value:<td>the single value mapped to this field in the specified <a HREF="#FieldDataSet">field data set</a>.
418      * </table>
419      * In the unlikely event that this field contains more than one value, all values are included in this one column and
420      * separated by the text defined in the {@link Config#ColumnMultipleValueSeparator} property.
421      * </ul>
422      * <li>
423      * Otherwise, if the form field does have {@linkplain FormField#getPredefinedValues() predefined values},
424      * but does not {@linkplain FormField#allowsMultipleValues() allow multiple values}, then:
425      * <ul>
426      * <li>
427      * If the form field has only one {@linkplain FormField#getPredefinedValues() predefined value},
428      * such as a single {@linkplain FormControlType#CHECKBOX checkbox}, then:
429      * <ul>
430      * <li>
431      * Add a single boolean column:
432      * <table class="CompactDL">
433      * <tr><td>{@linkplain #getColumnLabels() Label}:<td>the {@linkplain FormField#getName() name} of the form field in original case
434      * <tr><td>Value:<td>the currently configured string representation for <i>{@linkplain Config#ColumnValueTrue true}</i>
435      * if a value mapped to this field in the specified <a HREF="#FieldDataSet">field data set</a> matches the
436      * {@linkplain FormField#getPredefinedValues() predefined value}, otherwise <i>{@linkplain Config#ColumnValueFalse false}</i>
437      * </table>
438      * </ul>
439      * <li>
440      * Otherwise, if the form field has more than one {@linkplain FormField#getPredefinedValues() predefined value},
441      * such as a set of {@linkplain FormControlType#RADIO radio buttons}, then:
442      * <ul>
443      * <li>
444      * Add a single column:
445      * <table class="CompactDL">
446      * <tr><td>{@linkplain #getColumnLabels() Label}:<td>the {@linkplain FormField#getName() name} of the form field in original case
447      * <tr><td>Value:<td>the single value mapped to this field in the specified <a HREF="#FieldDataSet">field data set</a>,
448      * which in the case of a set of radio buttons should be the {@linkplain FormControl#getPredefinedValue() predefined value}
449      * of the {@linkplain FormControl#isChecked() checked} radio button.
450      * </table>
451      * </ul>
452      * </ul>
453      * <li>
454      * Otherwise, if the form field has {@linkplain FormField#getPredefinedValues() predefined values}
455      * and {@linkplain FormField#allowsMultipleValues() allows multiple values},
456      * such as a set of {@linkplain FormControlType#CHECKBOX checkboxes}, then:
457      * <ul>
458      * <li>
459      * For each {@linkplain FormField#getPredefinedValues() predefined value} in the form field:
460      * <ul>
461      * <li>
462      * Add a boolean column:
463      * <table class="CompactDL">
464      * <tr><td>{@linkplain #getColumnLabels() Label}:<td>"<code><i>FieldName</i>.<i>PredefinedValue</i></code>",
465      * where <code><i>FieldName</i></code> is the {@linkplain FormField#getName() name} of the form field in original case,
466      * and <code><i>PredefinedValue</i></code> is the {@linkplain FormField#getPredefinedValues() predefined value}.
467      * <tr><td>Value:<td>the currently configured string representation for <i>{@linkplain Config#ColumnValueTrue true}</i>
468      * if a value mapped to this field in the specified <a HREF="#FieldDataSet">field data set</a> matches the
469      * {@linkplain FormField#getPredefinedValues() predefined value}, otherwise <i>{@linkplain Config#ColumnValueFalse false}</i>
470      * </table>
471      * </ul>
472      * <li>
473      * In addition, if the form field can also contain user values ({@link FormField#getUserValueCount()}<code>&gt;0</code>), then:
474      * <ul>
475      * <li>
476      * Add another column:
477      * <table class="CompactDL">
478      * <tr><td>{@linkplain #getColumnLabels() Label}:<td>the {@linkplain FormField#getName() name} of the form field in original case
479      * <tr><td>Value:<td>all values mapped to this field in the specified <a HREF="#FieldDataSet">field data set</a>
480      * that do not match any of the {@linkplain FormField#getPredefinedValues() predefined values},
481      * separated by the text defined in the {@link Config#ColumnMultipleValueSeparator} property.
482      * </table>
483      * </ul>
484      * </ul>
485      * </ul>
486      * </ul>
487      * <p>
488      * The sample program FormFieldCSVOutput demonstrates the use of this method and its output.
489      *
490      * @param dataSet a <a HREF="#FieldDataSet">field data set</a> containing the data to convert.
491      * @return the data values in the specified <a HREF="#FieldDataSet">field data set</a> in the form of a simple string array.
492      * @see Util#outputCSVLine(Writer,String[])
493      * @see #getColumnLabels()
494      * @see #getColumnValues()
495      */

496     public String JavaDoc[] getColumnValues(final Map dataSet) {
497         initColumns();
498         final String JavaDoc[] columnValues=new String JavaDoc[columns.length];
499         if (Config.ColumnValueFalse!=null) {
500             // initialise all boolean columns with false string
501
for (int i=0; i<columns.length; i++)
502                 if (columns[i].isBoolean) columnValues[i]=Config.ColumnValueFalse;
503         }
504         for (final Iterator i=dataSet.entrySet().iterator(); i.hasNext();) {
505             final Map.Entry entry=(Map.Entry)i.next();
506             final String JavaDoc fieldName=entry.getKey().toString();
507             final FormField formField=get(fieldName);
508             if (formField!=null) {
509                 final Collection values=(entry.getValue() instanceof Collection)
510                     ? (Collection)entry.getValue()
511                     : Arrays.asList((CharSequence JavaDoc[])entry.getValue());
512                 final int columnIndex=formField.columnIndex;
513                 for (final Iterator valueIterator=values.iterator(); valueIterator.hasNext();) {
514                     final String JavaDoc value=valueIterator.next().toString();
515                     for (int ci=columnIndex; ci<columns.length; ci++) {
516                         final Column column=columns[ci];
517                         if (column.formField!=formField) break;
518                         if (column.predefinedValue!=null) {
519                             if (!column.predefinedValue.equals(value)) continue;
520                             columnValues[ci]=Config.ColumnValueTrue;
521                         } else {
522                             if (column.isBoolean) {
523                                 if (value!=null) columnValues[ci]=Config.ColumnValueTrue;
524                             } else if (columnValues[ci]==null) {
525                                 columnValues[ci]=value;
526                             } else {
527                                 columnValues[ci]=columnValues[ci]+Config.ColumnMultipleValueSeparator+value;
528                             }
529                         }
530                         break;
531                     }
532                 }
533             }
534         }
535         return columnValues;
536     }
537
538     /**
539      * Converts all the {@linkplain FormField#getValues() form submission values} of the constituent form fields into a simple string array,
540      * suitable for storage in a tabular format such as a database table or <code>.CSV</code> file.
541      * <p>
542      * This is equivalent to {@link #getColumnValues(Map) getColumnValues}<code>(</code>{@link #getDataSet()}<code>)</code>.
543      *
544      * @return all the {@linkplain FormField#getValues() form submission values} of the constituent form fields in the form of a simple string array.
545      */

546     public String JavaDoc[] getColumnValues() {
547         return getColumnValues(getDataSet());
548     }
549
550     private void initColumns() {
551         if (columns!=null) return;
552         final ArrayList columnList=new ArrayList();
553         for (final Iterator i=iterator(); i.hasNext();) {
554             final FormField formField=(FormField)i.next();
555             formField.columnIndex=columnList.size();
556             if (!formField.allowsMultipleValues() || formField.getPredefinedValues().isEmpty()) {
557                 columnList.add(new Column(formField,formField.getPredefinedValues().size()==1,null));
558             } else {
559                 // add a column for every predefined value
560
for (final Iterator pvi=formField.getPredefinedValues().iterator(); pvi.hasNext();)
561                     columnList.add(new Column(formField,true,(String JavaDoc)pvi.next()));
562                 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
563
}
564         }
565         columns=(Column[])columnList.toArray(new Column[columnList.size()]);
566     }
567     private Column[] columns=null;
568
569     private static class Column {
570         public FormField formField;
571         public boolean isBoolean;
572         public String JavaDoc predefinedValue;
573         public Column(final FormField formField, final boolean isBoolean, final String JavaDoc predefinedValue) {
574             this.formField=formField;
575             this.isBoolean=isBoolean;
576             this.predefinedValue=predefinedValue;
577         }
578     }
579
580     /**
581      * Returns a list of all the {@linkplain FormField#getFormControls() constituent form controls} from all the {@linkplain FormField form fields} in this collection.
582      * @return a list of all the {@linkplain FormField#getFormControls() constituent form controls} from all the {@linkplain FormField form fields} in this collection.
583      */

584     public List getFormControls() {
585         return formControls;
586     }
587
588     /**
589      * Merges the specified <code>FormFields</code> into this <code>FormFields</code> collection.
590      * This is useful if a full collection of possible form fields is required from multiple {@linkplain Source source} documents.
591      * <p>
592      * If both collections contain a <code>FormField</code> with the same {@linkplain FormField#getName() name},
593      * the resulting <code>FormField</code> has the following properties:
594      * <ul>
595      * <li>{@link FormField#getUserValueCount() getUserValueCount()} : the maximum user value count from both form fields</li>
596      * <li>{@link FormField#allowsMultipleValues() allowsMultipleValues()} : <code>true</code> if either form field allows multiple values</li>
597      * <li>{@link FormField#getPredefinedValues() getPredefinedValues()} : the union of predefined values in both form fields</li>
598      * <li>{@link FormField#getFormControls() getFormControls()} : the union of {@linkplain FormControl form controls} from both form fields</li>
599      * </ul>
600      * <p>
601      * NOTE: Some underlying data structures may end up being shared between the two merged <code>FormFields</code> collections.
602      */

603     public void merge(final FormFields formFields) {
604         for (final Iterator i=formFields.iterator(); i.hasNext();) {
605             final FormField formField=(FormField)i.next();
606             final String JavaDoc fieldName=formField.getName();
607             final FormField existingFormField=get(fieldName);
608             if (existingFormField==null)
609                 add(formField);
610             else
611                 existingFormField.merge(formField);
612         }
613     }
614
615     /**
616      * Returns a string representation of this object useful for debugging purposes.
617      * @return a string representation of this object useful for debugging purposes.
618      */

619     public String JavaDoc getDebugInfo() {
620         final StringBuffer JavaDoc sb=new StringBuffer JavaDoc();
621         for (final Iterator i=iterator(); i.hasNext();) {
622             sb.append(i.next());
623         }
624         return sb.toString();
625     }
626
627     /**
628      * Returns a string representation of this object useful for debugging purposes.
629      * <p>
630      * This is equivalent to {@link #getDebugInfo()}.
631      *
632      * @return a string representation of this object useful for debugging purposes.
633      */

634     public String JavaDoc toString() {
635         return getDebugInfo();
636     }
637
638     void add(final FormControl formControl) {
639         add(formControl,formControl.getPredefinedValue());
640     }
641
642     void add(final FormControl formControl, final String JavaDoc predefinedValue) {
643         add(formControl,predefinedValue,formControl.name);
644     }
645
646     void addName(final FormControl formControl, final String JavaDoc fieldName) {
647         add(formControl,null,fieldName);
648     }
649
650     void add(final FormControl formControl, final String JavaDoc predefinedValue, String JavaDoc fieldName) {
651         if (Config.CurrentCompatibilityMode.isFormFieldNameCaseInsensitive()) fieldName=fieldName.toLowerCase();
652         FormField formField=(FormField)map.get(fieldName);
653         if (formField==null) {
654             formField=new FormField(fieldName);
655             add(formField);
656         }
657         formField.addFormControl(formControl,predefinedValue);
658     }
659
660     void replaceInOutputDocument(final OutputDocument outputDocument) {
661         for (final Iterator i=formControls.iterator(); i.hasNext();)
662             outputDocument.replace((FormControl)i.next());
663     }
664
665     private void add(final FormField formField) {
666         map.put(formField.getName(),formField);
667     }
668 }
669
Popular Tags