@ Override protected HtmlToken produce ( ) { HtmlToken token = readToken ( ) ; if ( token == null ) { return null ; } switch ( token . type ) { // Keep track of whether we're inside a tag or not. case TAGBEGIN : state = State . IN_TAG ; break ; case TAGEND : if ( state == State . SAW_EQ && HtmlTokenType . TAGEND == token . type ) { // Distinguish <input type=checkbox checked=> from // <input type=checkbox checked> pushbackToken ( token ) ; state = State . IN_TAG ; return HtmlToken . instance ( token . start , token . start , HtmlTokenType . ATTRVALUE ) ; } state = State . OUTSIDE_TAG ; break ; // Drop ignorable tokens by zeroing out the one received and recursing case IGNORABLE : return produce ( ) ; // collapse adjacent text nodes if we're outside a tag, or otherwise, // Recognize attribute names and values. default : switch ( state ) { case OUTSIDE_TAG : if ( HtmlTokenType . TEXT == token . type || HtmlTokenType . UNESCAPED == token . type ) { token = collapseSubsequent ( token ) ; } break ; case IN_TAG : if ( HtmlTokenType . TEXT == token . type && ! token . tokenInContextMatches ( input , "=" ) ) { // Reclassify as attribute name token = HtmlInputSplitter . reclassify ( token , HtmlTokenType . ATTRNAME ) ; state = State . SAW_NAME ; } break ; case SAW_NAME : if ( HtmlTokenType . TEXT == token . type ) { if ( token . tokenInContextMatches ( input , "=" ) ) { state = State . SAW_EQ ; // Skip the '=' token return produce ( ) ; } else { // Reclassify as attribute name token = HtmlInputSplitter . reclassify ( token , HtmlTokenType . ATTRNAME ) ; } } else { state = State . IN_TAG ; } break ; case SAW_EQ : if ( HtmlTokenType . TEXT == token . type || HtmlTokenType . QSTRING == token . type ) { if ( HtmlTokenType . TEXT == token . type ) { // Collapse adjacent text nodes to properly handle // <a onclick=this.clicked=true> // <a title=foo bar> token = collapseAttributeName ( token ) ; } // Reclassify as value token = HtmlInputSplitter . reclassify ( token , HtmlTokenType . ATTRVALUE ) ; state = State . IN_TAG ; } break ; } break ; } return token ; }
Makes sure that this . token contains a token if one is available . This may require fetching and combining multiple tokens from the underlying splitter .