/** * 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()); }
StringBuilder appendDebugTag(final StringBuilder sb) { if (startTagType==StartTagType.NORMAL && getAttributes().isEmpty()) { sb.append(this); } else { sb.append('<').append(getNameSegment()).append(' '); if (isSyntacticalEmptyElementTag()) sb.append('/'); sb.append(startTagType.getClosingDelimiter()); } return sb; }
/** * Indicates whether the specified source document position is at the end of a tag's {@linkplain Attributes attributes}. * <br />(<a href="TagType.html#DefaultImplementation">default implementation</a> method) * <p> * This method is called internally while parsing {@linkplain Attributes attributes} to detect where they should end. * <p> * It can be assumed that the specified position is not inside a quoted attribute value. * <p> * The default implementation simply compares the {@linkplain ParseText parse text} at the specified * position with the {@linkplain #getClosingDelimiter() closing delimiter}, and is equivalent to:<br /> * <code>source.</code>{@link Source#getParseText() getParseText()}<code>.containsAt(</code>{@link #getClosingDelimiter() getClosingDelimiter()}<code>,pos)</code> * <p> * The <code>isClosingSlashIgnored</code> parameter is only relevant in the {@link #NORMAL} start tag type, * which makes use of it to cater for the '<code>/</code>' character that can occur before the * {@linkplain #getClosingDelimiter() closing delimiter} in {@linkplain StartTag#isEmptyElementTag() empty-element tags}. * It's value is always <code>false</code> when passed to other start tag types. * * @param source the {@link Source} document. * @param pos the character position in the source document. * @param isClosingSlashIgnored indicates whether the {@linkplain StartTag#getName() name} of the {@linkplain StartTag start tag} being tested is incompatible with an {@linkplain StartTag#isEmptyElementTag() empty-element tag}. * @return <code>true</code> if the specified source document position is at the end of a tag's {@linkplain Attributes attributes}, otherwise <code>false</code>. */ public boolean atEndOfAttributes(final Source source, final int pos, final boolean isClosingSlashIgnored) { return source.getParseText().containsAt(getClosingDelimiter(),pos); }
/** * 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; } Attributes attributes=Attributes.construct(source,begin,attributesBegin,maxEnd,startTagType,name,maxErrorCount); if (attributes!=null) attributes.setStartTag(this); return attributes; }
} 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();
protected int getEnd(final Source source, final int pos) { // This method needs to be overridden because this tag type shares the same start delimiter as the downlevel hidden conditional comment. // The closing delimiter of the other tag type must not appear inside this tag. // Take the following example: // <!--[if IE]> ... <![endif]--> ... <!--[if !(IE 5)]><!--> ... <!--<![endif]--> // If the default implementation were used, then the parser would recognise the first tag as: // <!--[if IE]> ... <![endif]--> ... <!--[if !(IE 5)]><!--> final int delimiterBegin=source.getParseText().indexOf(MicrosoftConditionalCommentTagTypes.DOWNLEVEL_HIDDEN_IF.getClosingDelimiter(),pos); if (delimiterBegin==-1) return -1; if (source.getParseText().containsAt(getClosingDelimiter(),delimiterBegin)) return delimiterBegin+getClosingDelimiter().length(); // this is a downlevel hidden conditional comment, so fail this tag type silently without displaying a log message return -2; } }