All Downloads are FREE. Search and download functionalities are using the official Maven repository.

src.au.id.jericho.lib.html.FormField Maven / Gradle / Ivy

Go to download

Jericho HTML Parser is a simple but powerful java library allowing analysis and manipulation of parts of an HTML document, including some common server-side tags, while reproducing verbatim any unrecognised or invalid HTML. It also provides high-level HTML form manipulation functions.

There is a newer version: 2.3
Show newest version
// Jericho HTML Parser - Java based library for analysing and manipulating HTML
// Version 1.5
// Copyright (C) 2004 Martin Jericho
// http://jerichohtml.sourceforge.net/
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
// http://www.gnu.org/copyleft/lesser.html
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

package au.id.jericho.lib.html;

import java.util.*;

/**
 * Represents a field in an HTML form,
 * a field being defined as the combination of all {@linkplain FormControl form controls}
 * having the same name.
 * 

* In addition to the {@link #getFormControls()} method, which returns a Collection of all the * {@link FormControl} objects that make up this field, the properties of a FormField object * describe how the values associated with the the field's * name * in a submitted form data set * should be interpreted. * These properties include whether multiple values can be expected, the number of values which would typically * be set by the user, and a list of values which are predefined in the HTML. * This information allows the server to store and format the data in an appropriate way. *

* A form field which allows user values will normally consist of a single control whose * {@link FormControlType#isPredefinedValue()} method returns false, * such as a {@link FormControlType#TEXT TEXT} control. *

* When a form field consists of more than one control, these controls will normally be all * be of the same {@linkplain FormControlType type} which has predefined values, * such as the {@link FormControlType#CHECKBOX CHECKBOX} control. *

* Form fields consisting of more than one control do not necessarily return multiple values. * A form field consisting of {@link FormControlType#CHECKBOX CHECKBOX} controls can return multiple values, whereas * a form field consisting of {@link FormControlType#CHECKBOX RADIO} controls will return at most one value. *

* Note that a select element containing multiple option elements is counted as * a single control. See the {@link FormControl} class for more details. *

* The HTML author can disregard convention and mix all types of controls with the same name in the same form, * or include multiple controls of the same name which do not have predefined values. * The evidence that such an unusual combination is present is a {@linkplain #getUserValueCount() user value count} * greater than one, so your application can either log a warning that a poorly designed form has been encountered, * or take special action to try to interpret the multiple user values that might be submitted. *

* FormField objects are created automatically with the creation of a {@link FormFields} object. *

* The case sensitivity of form field names is determined by the static {@link FormFields#FieldNameCaseSensitive} property. * * @see FormFields * @see FormControl */ public final class FormField { private String name; private int userValueCount=0; private boolean allowsMultipleValues=false; private LinkedHashSet predefinedValues=null; // null if none private LinkedHashSet formControls=new LinkedHashSet(); private transient FormControl firstFormControl=null; // this field is simply a cache for the getFirstFormControl() method protected int columnIndex; // see FormFields.initColumns() /** Constructor called from FormFields class. */ FormField(String name) { this.name=name; } /** * Returns the name of the field. *

* If {@link FormFields#FieldNameCaseSensitive} is true, the name will be returned in lower case. * * @return the name of the field. */ public String getName() { return name; } /** * Returns the number of values which would typically be set by the user, * and are not included in the list of {@linkplain #getPredefinedValues() predefined values}. * This should in most cases be either 0 or 1. *

* The word "typically" is used because the use of scripts can cause * control types * which normally have predefined values to be set by the user, which is a condition which is beyond * the scope of this library to test for. *

* A value of 0 indicates the field values will consist only of * {@linkplain #getPredefinedValues() predefined values}. * This is the case when the field consists of only * {@link FormControlType#CHECKBOX CHECKBOX}, {@link FormControlType#RADIO RADIO}, {@link FormControlType#BUTTON BUTTON}, * {@link FormControlType#SUBMIT SUBMIT}, {@link FormControlType#IMAGE IMAGE}, {@link FormControlType#SELECT_SINGLE SELECT_SINGLE} * and {@link FormControlType#SELECT_MULTIPLE SELECT_MULTIPLE} form control types. *

* A value of 1 indicates the field values will consist of at most one value set by the user. * It is still possible to receive multiple values in the unlikely event that the HTML author mixed * controls of different types with the same name, but any others should consist only of * {@linkplain #getPredefinedValues() predefined values}. *

* A value greater than 1 indicates that the HTML author has included multiple controls of the same * name which do not have predefined values. This would nearly always indicate an unintentional * error in the HTML source document. * * @return the number of values which would typically be set by the user. */ public int getUserValueCount() { return userValueCount; } /** * Indicates whether the field allows multiple values. *

* Returns false in any one of the following circumstances: *

    *
  • The field consists of only one control (unless it is a * {@linkplain FormControlType#SELECT_MULTIPLE multiple select} with more than one option) *
  • The field consists entirely of {@linkplain FormControlType#RADIO radio buttons} *
  • The field consists entirely of {@linkplain FormControlType#isSubmit() submit} buttons *
* If none of these three conditions are met, the method returns true. * * @return true if the field allows multiple values, otherwise false. */ public boolean allowsMultipleValues() { return allowsMultipleValues; } /** * Returns a collection of the {@linkplain FormControl#getPredefinedValue() predefined values} of all {@linkplain FormControl controls} that make up this field. *

* An interator over this collection will return the values in the order of appearance in the source. * * @return a collection of the {@linkplain FormControl#getPredefinedValue() predefined values} of all {@linkplain FormControl controls} that make up this field, or null if none. */ public Collection getPredefinedValues() { return predefinedValues!=null ? predefinedValues : Collections.EMPTY_SET; } /** * Returns a collection of all the {@linkplain FormControl form controls} that make up this field. *

* An iterator over this collection will return the controls in the order of appearance in the source. * * @return a collection containing all the {@linkplain FormControl form controls} that make up this field. */ public Collection getFormControls() { return formControls; } /** * **** */ public void clearValues() { for (Iterator i=formControls.iterator(); i.hasNext();) ((FormControl)i.next()).clearValues(); } /** * **** does not contain nulls */ public Collection getValues() { HashSet values=new HashSet(); for (Iterator i=formControls.iterator(); i.hasNext();) ((FormControl)i.next()).addValuesTo(values); return values; } public void setValues(Collection values) { clearValues(); addValues(values); } public boolean setValue(CharSequence value) { clearValues(); return addValue(value); } /** * **** returns true if value was taken */ public boolean addValue(CharSequence value) { List userValueControls=null; for (Iterator i=formControls.iterator(); i.hasNext();) { FormControl formControl=(FormControl)i.next(); if (formControls.size()>1 && !formControl.getFormControlType().isPredefinedValue()) { // if a user value control exists, but is not the only control with this name // (which shouldn't normally happen in a well designed form), save the user value control // for later as we will give all predefined value controls first opportunity to take the value. if (userValueControls==null) userValueControls=new LinkedList(); userValueControls.add(formControl); continue; } if (formControl.addValue(value)) return true; // return value of true from formControl.addValue(value) means the value was taken by the control } if (userValueControls==null) return false; for (Iterator i=userValueControls.iterator(); i.hasNext();) { FormControl formControl=(FormControl)i.next(); if (formControl.addValue(value)) return true; } return false; } /** * Returns a string representation of this object useful for debugging purposes. * @return a string representation of this object useful for debugging purposes. */ public String getDebugInfo() { StringBuffer sb=new StringBuffer(); sb.append("Field: ").append(name).append(", UserValueCount=").append(userValueCount).append(", AllowsMultipleValues=").append(allowsMultipleValues); if (predefinedValues!=null) { for (Iterator i=predefinedValues.iterator(); i.hasNext();) { sb.append("\nPredefinedValue: "); sb.append(i.next()); } } for (Iterator i=formControls.iterator(); i.hasNext();) { sb.append("\nFormControl: "); sb.append(((FormControl)i.next()).getDebugInfo()); } sb.append("\n\n"); return sb.toString(); } /** * Returns a string representation of this object useful for debugging purposes. *

* This is equivalent to {@link #getDebugInfo()}. * * @return a string representation of this object useful for debugging purposes. */ public String toString() { return getDebugInfo(); } protected void addValues(Collection values) { if (values!=null) for (Iterator i=values.iterator(); i.hasNext();) addValue((CharSequence)i.next()); } protected void addValues(CharSequence[] values) { if (values!=null) for (int i=0; i true // userValueCount>1 -> true // userValueCount==1 -> predefinedValues!=null ? true : false // userValueCount==0 -> // predefinedValues.size<=1 -> false // predefinedValues.size>1 -> // only one control -> control is select_multiple ? true : false // all controls are radio buttons -> false // all controls.isSubmit() -> false // otherwise allowsMultipleValues=true if (allowsMultipleValues || userValueCount>1) return true; if (userValueCount==1) return predefinedValues!=null; // at this stage we know userValueCount==0 && predefinedValues.size()>=1 if (predefinedValues.size()==1) return false; FormControlType newFormControlType=newFormControl.getFormControlType(); if (formControls.size()==1) return newFormControlType==FormControlType.SELECT_MULTIPLE; // at this stage we know there are multiple predefined values in multiple controls. // if all of the controls are radio buttons or all are submit buttons, allowsMultipleValues is false, otherwise true. // checking only the first control and the new control is equivalent to checking them all because if they weren't all the same allowsMultipleValues would already be true FormControlType firstFormControlType=getFirstFormControl().getFormControlType(); if (newFormControlType==FormControlType.RADIO && firstFormControlType==FormControlType.RADIO) return false; if (newFormControlType.isSubmit() && firstFormControlType.isSubmit()) return false; return true; } protected FormControl getFirstFormControl() { // formControls must be ordered collection for this method to work. // It has to return the first FormControl entered into the collection // for the algorithm in calculateAllowsMultipleValues() to work. if (firstFormControl==null) firstFormControl=(FormControl)formControls.iterator().next(); return firstFormControl; } /** only called from FormFields class */ protected void merge(FormField formField) { if (formField.userValueCount>userValueCount) userValueCount=formField.userValueCount; allowsMultipleValues=allowsMultipleValues || formField.allowsMultipleValues; if (predefinedValues==null) { predefinedValues=formField.predefinedValues; } else if (formField.predefinedValues!=null) { for (Iterator i=formField.predefinedValues.iterator(); i.hasNext();) predefinedValues.add(i.next()); } for (Iterator i=formField.getFormControls().iterator(); i.hasNext();) formControls.add(i.next()); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy