📄 formcontrol.java
字号:
// Jericho HTML Parser - Java based library for analysing and manipulating HTML
// Version 3.0
// Copyright (C) 2007 Martin Jericho
// http://jerichohtml.sourceforge.net/
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of either one of the following licences:
//
// 1. The Eclipse Public License (EPL) version 1.0,
// included in this distribution in the file licence-epl-1.0.html
// or available at http://www.eclipse.org/legal/epl-v10.html
//
// 2. The GNU Lesser General Public License (LGPL) version 2.1 or later,
// included in this distribution in the file licence-lgpl-2.1.txt
// or available at http://www.gnu.org/licenses/lgpl.txt
//
// This library is distributed on an "AS IS" basis,
// WITHOUT WARRANTY OF ANY KIND, either express or implied.
// See the individual licence texts for more details.
package net.htmlparser.jericho;
import java.util.*;
import java.io.*;
/**
* Represents an HTML form <a target="_blank" href="http://www.w3.org/TR/html401/interact/forms.html#form-controls">control</a>.
* <p>
* A <code>FormControl</code> consists of a single {@linkplain #getElement() element}
* that matches one of the {@linkplain FormControlType form control types}.
* <p>
* The term <i><a name="OutputElement">output element</a></i> is used to describe the element that is
* {@linkplain OutputSegment#writeTo(Writer) output} if this form control is {@linkplain OutputDocument#replace(FormControl) replaced}
* in an {@link OutputDocument}.
* <p>
* A <i><a name="PredefinedValueControl">predefined value control</a></i> is a form control for which
* {@link #getFormControlType()}.{@link FormControlType#hasPredefinedValue() hasPredefinedValue()}
* returns <code>true</code>. It has a {@linkplain #getFormControlType() control type} of
* {@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}
* or {@link FormControlType#SELECT_MULTIPLE SELECT_MULTIPLE}.
* <p>
* A <i><a name="UserValueControl">user value control</a></i> is a form control for which
* {@link #getFormControlType()}.{@link FormControlType#hasPredefinedValue() hasPredefinedValue()}
* returns <code>false</code>. It has a {@linkplain #getFormControlType() control type} of
* {@link FormControlType#FILE FILE}, {@link FormControlType#HIDDEN HIDDEN}, {@link FormControlType#PASSWORD PASSWORD},
* {@link FormControlType#TEXT TEXT} or {@link FormControlType#TEXTAREA TEXTAREA}.
* <p>
* The functionality of most significance to users of this class relates to the
* <i><a name="DisplayCharacteristics">display characteristics</a></i> of the <a href="#OutputElement">output element</a>,
* manipulated using the {@link #setDisabled(boolean)} and {@link #setOutputStyle(FormControlOutputStyle)} methods.
* <p>
* As a general rule, the operations dealing with the control's <a href="#SubmissionValue">submission values</a>
* are better performed on a {@link FormFields} or {@link FormField} object, which provide a more
* intuitive interface by grouping form controls of the same {@linkplain #getName() name} together.
* The higher abstraction level of these classes means they can automatically ensure that the
* <a href="#SubmissionValue">submission values</a> of their constituent controls are consistent with each other,
* for example by ensuring that only one {@link FormControlType#RADIO RADIO} control with a given name is
* {@link #isChecked() checked} at a time.
* <p>
* A {@link FormFields} object can be directly {@linkplain FormFields#FormFields(Collection) constructed} from
* a collection of <code>FormControl</code> objects.
* <p>
* <code>FormControl</code> instances are obtained using the {@link Element#getFormControl()} method or are created automatically
* with the creation of a {@link FormFields} object via the {@link Segment#getFormFields()} method.
*
* @see FormControlType
* @see FormFields
* @see FormField
*/
public abstract class FormControl extends Segment {
FormControlType formControlType;
String name;
ElementContainer elementContainer;
FormControlOutputStyle outputStyle=FormControlOutputStyle.NORMAL;
private static final String CHECKBOX_NULL_DEFAULT_VALUE="on";
private static Comparator<FormControl> COMPARATOR=new PositionComparator();
static FormControl construct(final Element element) {
final String tagName=element.getStartTag().getName();
if (tagName==HTMLElementName.INPUT) {
final String typeAttributeValue=element.getAttributes().getRawValue(Attribute.TYPE);
if (typeAttributeValue==null) return new InputFormControl(element,FormControlType.TEXT);
FormControlType formControlType=FormControlType.getFromInputElementType(typeAttributeValue);
if (formControlType==null) {
if (formControlType.isNonFormControl(typeAttributeValue)) return null;
if (element.source.logger.isInfoEnabled()) element.source.logger.info(element.source.getRowColumnVector(element.begin).appendTo(new StringBuilder(200)).append(": INPUT control with unrecognised type \"").append(typeAttributeValue).append("\" assumed to be type \"text\"").toString());
formControlType=FormControlType.TEXT;
}
switch (formControlType) {
case TEXT:
return new InputFormControl(element,formControlType);
case CHECKBOX: case RADIO:
return new RadioCheckboxFormControl(element,formControlType);
case SUBMIT:
return new SubmitFormControl(element,formControlType);
case IMAGE:
return new ImageSubmitFormControl(element);
case HIDDEN: case PASSWORD: case FILE:
return new InputFormControl(element,formControlType);
default:
throw new AssertionError(formControlType);
}
} else if (tagName==HTMLElementName.SELECT) {
return new SelectFormControl(element);
} else if (tagName==HTMLElementName.TEXTAREA) {
return new TextAreaFormControl(element);
} else if (tagName==HTMLElementName.BUTTON) {
return "submit".equalsIgnoreCase(element.getAttributes().getRawValue(Attribute.TYPE)) ? new SubmitFormControl(element,FormControlType.BUTTON) : null;
} else {
return null;
}
}
private FormControl(final Element element, final FormControlType formControlType, final boolean loadPredefinedValue) {
super(element.source,element.begin,element.end);
elementContainer=new ElementContainer(element,loadPredefinedValue);
this.formControlType=formControlType;
name=element.getAttributes().getValue(Attribute.NAME);
verifyName();
}
/**
* Returns the {@linkplain FormControlType type} of this form control.
* @return the {@linkplain FormControlType type} of this form control.
*/
public final FormControlType getFormControlType() {
return formControlType;
}
/**
* Returns the <a target="_blank" href="http://www.w3.org/TR/html401/interact/forms.html#control-name">name</a> of the control.
* <p>
* The name comes from the value of the <code>name</code> {@linkplain Attribute attribute} of the
* {@linkplain #getElement() form control's element}, not the {@linkplain Element#getName() name of the element} itself.
* <p>
* Since a {@link FormField} is simply a group of controls with the same name, the terms <i>control name</i> and
* <i>field name</i> are for the most part synonymous, with only a possible difference in case differentiating them.
* <p>
* In contrast to the {@link FormField#getName()} method, this method always returns the name using the original case
* from the source document, regardless of the current setting of the static
* {@link Config#CurrentCompatibilityMode}<code>.</code>{@link Config.CompatibilityMode#isFormFieldNameCaseInsensitive() FormFieldNameCaseInsensitive} property.
*
* @return the <a target="_blank" href="http://www.w3.org/TR/html401/interact/forms.html#control-name">name</a> of the control.
*/
public final String getName() {
return name;
}
/**
* Returns the {@linkplain Element element} representing this form control in the source document.
* <p>
* The {@linkplain Element#getAttributes() attributes} of this source element should correspond with the
* <a href="#OutputAttributes">output attributes</a> if the
* <a href="#DisplayCharacteristics">display characteristics</a> or <a href="FormField.html#SubmissionValue">submission values</a>
* have not been modified.
*
* @return the {@linkplain Element element} representing this form control in the source document.
*/
public final Element getElement() {
return elementContainer.element;
}
/**
* Returns an iterator over the {@link HTMLElementName#OPTION OPTION} {@linkplain Element elements} contained within this control, in order of appearance.
* <p>
* This method is only relevant to form controls with a {@linkplain #getFormControlType() type} of
* {@link FormControlType#SELECT_SINGLE SELECT_SINGLE} or {@link FormControlType#SELECT_MULTIPLE SELECT_MULTIPLE}.
*
* @return an iterator over the {@link HTMLElementName#OPTION OPTION} {@linkplain Element elements} contained within this control, in order of appearance.
* @throws UnsupportedOperationException if the {@linkplain #getFormControlType() type} of this control is not {@link FormControlType#SELECT_SINGLE SELECT_SINGLE} or {@link FormControlType#SELECT_MULTIPLE SELECT_MULTIPLE}.
*/
public Iterator<Element> getOptionElementIterator() {
// overridden in SelectFormControl
throw new UnsupportedOperationException("Only SELECT controls contain OPTION elements");
}
/**
* Returns the current {@linkplain FormControlOutputStyle output style} of this form control.
* <p>
* This property affects how this form control is displayed if it has been {@linkplain OutputDocument#replace(FormControl) replaced}
* in an {@link OutputDocument}.
* See the documentation of the {@link FormControlOutputStyle} class for information on the available output styles.
* <p>
* The default output style for every form control is {@link FormControlOutputStyle#NORMAL}.
*
* @return the current {@linkplain FormControlOutputStyle output style} of this form control.
* @see #setOutputStyle(FormControlOutputStyle)
*/
public FormControlOutputStyle getOutputStyle() {
return outputStyle;
}
/**
* Sets the {@linkplain FormControlOutputStyle output style} of this form control.
* <p>
* See the {@link #getOutputStyle()} method for a full description of this property.
*
* @param outputStyle the new {@linkplain FormControlOutputStyle output style} of this form control.
*/
public void setOutputStyle(final FormControlOutputStyle outputStyle) {
this.outputStyle=outputStyle;
}
/**
* Returns a map of the names and values of this form control's <a href="#OutputAttributes">output attributes</a>.
* <p>
* The term <i><a name="OutputAttributes">output attributes</a></i> is used in this library to refer to the
* <a target="_blank" href="http://www.w3.org/TR/html401/intro/sgmltut.html#h-3.2.2">attributes</a> of a form control's
* <a href="#OutputElement">output element</a>.
* <p>
* The map keys are the <code>String</code> attribute names, which should all be in lower case.
* The map values are the corresponding <code>String</code> attribute values, with a <code>null</code> value given
* to an attribute that {@linkplain Attribute#hasValue() has no value}.
* <p>
* Direct manipulation of the returned map affects the attributes of this form control's <a href="#OutputElement">output element</a>.
* It is the responsibility of the user to ensure that all entries added to the map use the correct key and value types,
* and that all keys (attribute names) are in lower case.
* <p>
* It is recommended that the <a href="#SubmissionValueModificationMethods">submission value modification methods</a>
* are used to modify attributes that affect the <a href="#SubmissionValue">submission value</a> of the control
* rather than manipulating the attributes map directly.
* <p>
* An iteration over the map entries will return the attributes in the same order as they appeared in the source document, or
* at the end if the attribute was not present in the source document.
* <p>
* The returned attributes only correspond with those of the {@linkplain #getElement() source element} if the control's
* <a href="#DisplayCharacteristics">display characteristics</a> and <a href="#SubmissionValue">submission values</a>
* have not been modified.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -