/// <summary> /// See 8.2.4.35 Attribute name state /// </summary> /// <param name="tag">The current tag token.</param> HtmlToken AttributeName(HtmlTagToken tag) { while (true) { var c = GetNext(); if (c == Symbols.Equality) { tag.AddAttribute(_stringBuffer.ToString()); _stringBuffer.Clear(); return AttributeBeforeValue(tag); } else if (c == Symbols.GreaterThan) { tag.AddAttribute(_stringBuffer.ToString()); _stringBuffer.Clear(); return EmitTag(tag); } else if (c.IsSpaceCharacter()) { tag.AddAttribute(_stringBuffer.ToString()); _stringBuffer.Clear(); return AttributeAfterName(tag); } else if (c == Symbols.Solidus) { tag.AddAttribute(_stringBuffer.ToString()); _stringBuffer.Clear(); return TagSelfClosing(tag); } else if (c.IsUppercaseAscii()) { _stringBuffer.Append(Char.ToLower(c)); } else if (c == Symbols.DoubleQuote || c == Symbols.SingleQuote || c == Symbols.LessThan) { RaiseErrorOccurred(HtmlParseError.AttributeNameInvalid); _stringBuffer.Append(c); } else if(c == Symbols.Null) { RaiseErrorOccurred(HtmlParseError.Null); _stringBuffer.Append(Symbols.Replacement); } else if (c != Symbols.EndOfFile) { _stringBuffer.Append(c); } else { return NewEof(); } } }
private HtmlToken ParseAttributes(HtmlTagToken tag) { var state = AttributeState.BeforeName; var quote = Symbols.DoubleQuote; var c = Symbols.Null; while (true) { switch (state) { // See 8.2.4.34 Before attribute name state case AttributeState.BeforeName: { c = SkipSpaces(); if (c == Symbols.Solidus) { return TagSelfClosing(tag); } else if (c == Symbols.GreaterThan) { return EmitTag(tag); } else if (c.IsUppercaseAscii()) { StringBuffer.Append(Char.ToLowerInvariant(c)); state = AttributeState.Name; } else if (c == Symbols.Null) { AppendReplacement(); state = AttributeState.Name; } else if (c == Symbols.SingleQuote || c == Symbols.DoubleQuote || c == Symbols.Equality || c == Symbols.LessThan) { RaiseErrorOccurred(HtmlParseError.AttributeNameInvalid); StringBuffer.Append(c); state = AttributeState.Name; } else if (c != Symbols.EndOfFile) { StringBuffer.Append(c); state = AttributeState.Name; } else { return NewEof(); } break; } // See 8.2.4.35 Attribute name state case AttributeState.Name: { c = GetNext(); if (c == Symbols.Equality) { tag.AddAttribute(FlushBuffer()); state = AttributeState.BeforeValue; } else if (c == Symbols.GreaterThan) { tag.AddAttribute(FlushBuffer()); return EmitTag(tag); } else if (c.IsSpaceCharacter()) { tag.AddAttribute(FlushBuffer()); state = AttributeState.AfterName; } else if (c == Symbols.Solidus) { tag.AddAttribute(FlushBuffer()); return TagSelfClosing(tag); } else if (c.IsUppercaseAscii()) { StringBuffer.Append(Char.ToLowerInvariant(c)); } else if (c == Symbols.DoubleQuote || c == Symbols.SingleQuote || c == Symbols.LessThan) { RaiseErrorOccurred(HtmlParseError.AttributeNameInvalid); StringBuffer.Append(c); } else if (c == Symbols.Null) { AppendReplacement(); } else if (c != Symbols.EndOfFile) { StringBuffer.Append(c); } else { return NewEof(); } break; } // See 8.2.4.36 After attribute name state case AttributeState.AfterName: { c = SkipSpaces(); if (c == Symbols.GreaterThan) { return EmitTag(tag); } else if (c == Symbols.Equality) { state = AttributeState.BeforeValue; } else if (c == Symbols.Solidus) { return TagSelfClosing(tag); } else if (c.IsUppercaseAscii()) { StringBuffer.Append(Char.ToLowerInvariant(c)); state = AttributeState.Name; } else if (c == Symbols.DoubleQuote || c == Symbols.SingleQuote || c == Symbols.LessThan) { RaiseErrorOccurred(HtmlParseError.AttributeNameInvalid); StringBuffer.Append(c); state = AttributeState.Name; } else if (c == Symbols.Null) { AppendReplacement(); state = AttributeState.Name; } else if (c != Symbols.EndOfFile) { StringBuffer.Append(c); state = AttributeState.Name; } else { return NewEof(); } break; } // See 8.2.4.37 Before attribute value state case AttributeState.BeforeValue: { c = SkipSpaces(); if (c == Symbols.DoubleQuote || c == Symbols.SingleQuote) { state = AttributeState.QuotedValue; quote = c; } else if (c == Symbols.Ampersand) { state = AttributeState.UnquotedValue; } else if (c == Symbols.GreaterThan) { RaiseErrorOccurred(HtmlParseError.TagClosedWrong); return EmitTag(tag); } else if (c == Symbols.LessThan || c == Symbols.Equality || c == Symbols.CurvedQuote) { RaiseErrorOccurred(HtmlParseError.AttributeValueInvalid); StringBuffer.Append(c); state = AttributeState.UnquotedValue; c = GetNext(); } else if (c == Symbols.Null) { AppendReplacement(); state = AttributeState.UnquotedValue; c = GetNext(); } else if (c != Symbols.EndOfFile) { StringBuffer.Append(c); state = AttributeState.UnquotedValue; c = GetNext(); } else { return NewEof(); } break; } // See 8.2.4.38 Attribute value (double-quoted) state // and 8.2.4.39 Attribute value (single-quoted) state case AttributeState.QuotedValue: { c = GetNext(); if (c == quote) { tag.SetAttributeValue(FlushBuffer()); state = AttributeState.AfterValue; } else if (c == Symbols.Ampersand) { AppendCharacterReference(GetNext(), quote); } else if (c == Symbols.Null) { AppendReplacement(); } else if (c != Symbols.EndOfFile) { StringBuffer.Append(c); } else { return NewEof(); } break; } // See 8.2.4.40 Attribute value (unquoted) state case AttributeState.UnquotedValue: { if (c == Symbols.GreaterThan) { tag.SetAttributeValue(FlushBuffer()); return EmitTag(tag); } else if (c.IsSpaceCharacter()) { tag.SetAttributeValue(FlushBuffer()); state = AttributeState.BeforeName; } else if (c == Symbols.Ampersand) { AppendCharacterReference(GetNext(), Symbols.GreaterThan); c = GetNext(); } else if (c == Symbols.Null) { AppendReplacement(); c = GetNext(); } else if (c == Symbols.DoubleQuote || c == Symbols.SingleQuote || c == Symbols.LessThan || c == Symbols.Equality || c == Symbols.CurvedQuote) { RaiseErrorOccurred(HtmlParseError.AttributeValueInvalid); StringBuffer.Append(c); c = GetNext(); } else if (c != Symbols.EndOfFile) { StringBuffer.Append(c); c = GetNext(); } else { return NewEof(); } break; } // See 8.2.4.42 After attribute value (quoted) state case AttributeState.AfterValue: { c = GetNext(); if (c == Symbols.GreaterThan) { return EmitTag(tag); } else if (c.IsSpaceCharacter()) { state = AttributeState.BeforeName; } else if (c == Symbols.Solidus) { return TagSelfClosing(tag); } else if (c == Symbols.EndOfFile) { return NewEof(); } else { RaiseErrorOccurred(HtmlParseError.AttributeNameExpected); Back(); state = AttributeState.BeforeName; } break; } } } }