📄 starttag.java
字号:
* <code>NullPointerException</code>.
*
* @param attributeName the name of the attribute to get.
* @return the {@linkplain CharacterReference#decode(CharSequence) decoded} value of the attribute with the specified name, or <code>null</code> if the attribute does not exist or {@linkplain Attribute#hasValue() has no value}.
*/
public String getAttributeValue(final String attributeName) {
return attributes==null ? null : attributes.getValue(attributeName);
}
/**
* Parses the attributes specified in this start tag, regardless of the type of start tag.
* This method is only required in the unusual situation where attributes exist in a start tag whose
* {@linkplain #getStartTagType() type} doesn't {@linkplain StartTagType#hasAttributes() have attributes}.
* <p>
* This method returns the cached attributes from the {@link StartTag#getAttributes()} method
* if its value is not <code>null</code>, otherwise the source is physically parsed with each call to this method.
* <p>
* This is equivalent to {@link #parseAttributes(int) parseAttributes}<code>(</code>{@link Attributes#getDefaultMaxErrorCount()}<code>)}</code>.
*
* @return the attributes specified in this start tag, or <code>null</code> if too many errors occur while parsing.
* @see #getAttributes()
* @see Source#parseAttributes(int pos, int maxEnd)
*/
public Attributes parseAttributes() {
return parseAttributes(Attributes.getDefaultMaxErrorCount());
}
/**
* Parses the attributes specified in this start tag, regardless of the type of start tag.
* This method is only required in the unusual situation where attributes exist in a start tag whose
* {@linkplain #getStartTagType() type} doesn't {@linkplain StartTagType#hasAttributes() have attributes}.
* <p>
* See the documentation of the {@link #parseAttributes()} method for more information.
*
* @param maxErrorCount the maximum number of minor errors allowed while parsing
* @return the attributes specified in this start tag, or <code>null</code> if too many errors occur while parsing.
* @see #getAttributes()
*/
public Attributes parseAttributes(final int maxErrorCount) {
if (attributes!=null) return attributes;
final int maxEnd=end-startTagType.getClosingDelimiter().length();
int attributesBegin=begin+1+name.length();
// skip any non-name characters directly after the name (which are quite common)
while (!isXMLNameStartChar(source.charAt(attributesBegin))) {
attributesBegin++;
if (attributesBegin==maxEnd) return null;
}
return Attributes.construct(source,begin,attributesBegin,maxEnd,startTagType,name,maxErrorCount);
}
/**
* Returns the segment between the end of the tag's {@linkplain #getName() name} and the start of its <a href="#EndDelimiter">end delimiter</a>.
* <p>
* This method is normally only of use for start tags whose content is something other than {@linkplain #getAttributes() attributes}.
* <p>
* A new {@link Segment} object is created with each call to this method.
*
* @return the segment between the end of the tag's {@linkplain #getName() name} and the start of the <a href="#EndDelimiter">end delimiter</a>.
*/
public Segment getTagContent() {
return new Segment(source,begin+1+name.length(),end-startTagType.getClosingDelimiter().length());
}
/**
* Returns the {@link FormControl} defined by this start tag.
* <p>
* This is equivalent to {@link #getElement()}<code>.</code>{@link Element#getFormControl() getFormControl()}.
*
* @return the {@link FormControl} defined by this start tag, or <code>null</code> if it is not a <a target="_blank" href="http://www.w3.org/TR/html401/interact/forms.html#form-controls">control</a>.
*/
public FormControl getFormControl() {
return getElement().getFormControl();
}
/**
* Indicates whether a matching end tag is forbidden.
* <p>
* This property returns <code>true</code> if one of the following conditions is met:
* <ul>
* <li>The {@linkplain #getStartTagType() type} of this start tag does not specify a
* {@linkplain StartTagType#getCorrespondingEndTagType() corresponding end tag type}.
* <li>The {@linkplain #getName() name} of this start tag indicates it is the start of an
* <a href="Element.html#HTML">HTML element</a> whose {@linkplain HTMLElements#getEndTagForbiddenElementNames() end tag is forbidden}.
* <li>This start tag is {@linkplain #isSyntacticalEmptyElementTag() syntactically an empty-element tag} and its
* {@linkplain #getName() name} indicates it is the start of a <a href="HTMLElements.html#NonHTMLElement">non-HTML element</a>.
* </ul>
* <p>
* If this property returns <code>true</code> then this start tag's {@linkplain #getElement() element} will always be a
* <a href="Element.html#SingleTag">single tag element</a>.
*
* @return <code>true</code> if a matching end tag is forbidden, otherwise <code>false</code>.
*/
public boolean isEndTagForbidden() {
if (getStartTagType()!=StartTagType.NORMAL)
return getStartTagType().getCorrespondingEndTagType()==null;
if (HTMLElements.getEndTagForbiddenElementNames().contains(name)) return true;
if (HTMLElements.getElementNames().contains(name)) return false;
return isSyntacticalEmptyElementTag();
}
/**
* Indicates whether a matching end tag is required.
* <p>
* This property returns <code>true</code> if one of the following conditions is met:
* <ul>
* <li>The {@linkplain #getStartTagType() type} of this start tag is NOT {@link StartTagType#NORMAL}, but specifies a
* {@linkplain StartTagType#getCorrespondingEndTagType() corresponding end tag type}.
* <li>The {@linkplain #getName() name} of this start tag indicates it is the start of an
* <a href="Element.html#HTML">HTML element</a> whose {@linkplain HTMLElements#getEndTagRequiredElementNames() end tag is required}.
* <li>This start tag is NOT {@linkplain #isSyntacticalEmptyElementTag() syntactically an empty-element tag} and its
* {@linkplain #getName() name} indicates it is the start of a <a href="HTMLElements.html#NonHTMLElement">non-HTML element</a>.
* </ul>
*
* @return <code>true</code> if a matching end tag is required, otherwise <code>false</code>.
*/
public boolean isEndTagRequired() {
if (getStartTagType()!=StartTagType.NORMAL)
return getStartTagType().getCorrespondingEndTagType()!=null;
if (HTMLElements.getEndTagRequiredElementNames().contains(name)) return true;
if (HTMLElements.getElementNames().contains(name)) return false;
return !isSyntacticalEmptyElementTag();
}
// Documentation inherited from Tag
public boolean isUnregistered() {
return startTagType==StartTagType.UNREGISTERED;
}
/**
* Returns an XML representation of this start tag.
* <p>
* This is equivalent to {@link #tidy(boolean) tidy(false)}, thereby keeping the {@linkplain #getName() name} of the tag in its original case.
* <p>
* See the documentation of the {@link #tidy(boolean toXHTML)} method for more details.
*
* @return an XML representation of this start tag, or the {@linkplain Segment#toString() source text} if it is of a {@linkplain #getStartTagType() type} that does not {@linkplain StartTagType#hasAttributes() have attributes}.
*/
public String tidy() {
return tidy(false);
}
/**
* Returns an XML or XHTML representation of this start tag.
* <p>
* The tidying of the tag is carried out as follows:
* <ul>
* <li>if this start tag is of a {@linkplain #getStartTagType() type} that does not {@linkplain StartTagType#hasAttributes() have attributes},
* then the original {@linkplain Segment#toString() source text} of the enture tag is returned.
* <li>if this start tag contain any {@linkplain TagType#isServerTag() server tags} outside of an attribute value,
* then the original {@linkplain Segment#toString() source text} of the entire tag is returned.
* <li>name converted to lower case if the <code>toXHTML</code> argument is <code>true</code> and this is a {@linkplain StartTagType#NORMAL normal} start tag
* <li>attributes separated by a single space
* <li>attribute names in original case
* <li>attribute values are enclosed in double quotes and {@linkplain CharacterReference#reencode(CharSequence) re-encoded}
* <li>if this start tag forms an <a href="Element.html#HTML">HTML element</a> that has no {@linkplain Element#getEndTag() end tag},
* a slash is inserted before the closing angle bracket, separated from the {@linkplain #getName() name} or last attribute by a single space.
* <li>if an attribute value contains a {@linkplain TagType#isServerTag() server tag} it is inserted verbatim instead of being
* {@linkplain CharacterReference#encode(CharSequence) encoded}.
* </ul>
* <p>
* The <code>toXHTML</code> parameter determines only whether the name is converted to lower case for {@linkplain StartTagType#NORMAL normal} tags.
* In all other respects the generated tag is already valid XHTML.
* <p>
* <dl>
* <dt>Example:</dt>
* <dd>
* <p>
* The following source text:
* <blockquote class="code">
* <code><INPUT name=Company value='G&uuml;nter O&#39;Reilly &amp Associés'></code>
* </blockquote>
* produces the following regenerated HTML:
* <blockquote class="code">
* <code><input name="Company" value="G&uuml;nter O'Reilly &amp; Associ&eacute;s" /></code>
* </blockquote>
* </dd>
* </dl>
*
* @param toXHTML specifies whether the output is XHTML.
* @return an XML or XHTML representation of this start tag, or the {@linkplain Segment#toString() source text} if it is of a {@linkplain #getStartTagType() type} that does not {@linkplain StartTagType#hasAttributes() have attributes}.
*/
public String tidy(boolean toXHTML) {
if (attributes==null || attributes.containsServerTagOutsideOfAttributeValue) return toString();
final StringBuilder sb=new StringBuilder();
sb.append('<');
if (toXHTML && startTagType==StartTagType.NORMAL) {
sb.append(name);
} else {
int i=begin+startTagType.startDelimiterPrefix.length();
final int nameSegmentEnd=i+name.length();
while (i<nameSegmentEnd) {
sb.append(source.charAt(i));
i++;
}
}
try {
attributes.appendTidy(sb,getNextTag());
} catch (IOException ex) {throw new RuntimeException(ex);} // never happens
if (startTagType==StartTagType.NORMAL && getElement().getEndTag()==null && !HTMLElements.getEndTagOptionalElementNames().contains(name)) sb.append(" /");
sb.append(startTagType.getClosingDelimiter());
return sb.toString();
}
/**
* Generates the HTML text of a {@linkplain StartTagType#NORMAL normal} start tag with the specified tag name and {@linkplain Attributes#populateMap(Map,boolean) attributes map}.
* <p>
* The output of the attributes is as described in the {@link Attributes#generateHTML(Map attributesMap)} method.
* <p>
* The <code>emptyElementTag</code> parameter specifies whether the start tag should be an
* <a target="_blank" href="http://www.w3.org/TR/REC-xml#dt-eetag">empty-element tag</a>,
* in which case a slash is inserted before the closing angle bracket, separated from the name
* or last attribute by a single space.
* <p>
* <dl>
* <dt>Example:</dt>
* <dd>
* <p>
* The following code:
* <blockquote class="code">
* <pre>
* LinkedHashMap attributesMap=new LinkedHashMap();
* attributesMap.put("name","Company");
* attributesMap.put("value","G\n00fcnter O'Reilly & Associés");
* System.out.println(StartTag.generateHTML("INPUT",attributesMap,true));</pre>
* </blockquote>
* generates the following output:
* <blockquote class="code">
* <code><INPUT name="Company" value="G&uuml;nter O'Reilly &amp; Associ&eacute;s" /></code>
* </blockquote>
* </dd>
* </dl>
*
* @param tagName the name of the start tag.
* @param attributesMap a map containing attribute name/value pairs.
* @param emptyElementTag specifies whether the start tag should be an <a target="_blank" href="http://www.w3.org/TR/REC-xml#dt-eetag">empty-element tag</a>.
* @return the HTML text of a {@linkplain StartTagType#NORMAL normal} start tag with the specified tag name and {@linkplain Attributes#populateMap(Map,boolean) attributes map}.
* @see EndTag#generateHTML(String tagName)
*/
public static String generateHTML(final String tagName, final Map<String,String> attributesMap, final boolean emptyElementTag) {
final StringBuilder sb=new StringBuilder();
sb.append('<').append(tagName);
try {
Attributes.appendHTML(sb,attributesMap);
} catch (IOException ex) {throw new RuntimeException(ex);} // never happens
if (emptyElementTag)
sb.append(" />");
else
sb.append('>');
return sb.toString();
}
public String getDebugInfo() {
final StringBuilder sb=new StringBuilder();
appendDebugTag(sb);
sb.append(' ');
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -