/// <summary> /// Setups a new SVG element with the attributes from the token. /// </summary> /// <param name="element">The element to setup.</param> /// <param name="tag">The tag token to use.</param> /// <returns>The finished element.</returns> public static SvgElement Setup(this SvgElement element, HtmlTagToken tag) { var count = tag.Attributes.Count; for (var i = 0; i < count; i++) { var name = tag.Attributes[i].Key; var value = tag.Attributes[i].Value; element.AdjustAttribute(name.AdjustToSvgAttribute(), value); } return(element); }
/// <summary> /// See 8.2.4.40 Attribute value (unquoted) state /// </summary> /// <param name="c">The next input character.</param> /// <param name="tag">The current tag token.</param> /// <returns>The emitted token.</returns> HtmlToken AttributeUnquotedValue(Char c, HtmlTagToken tag) { while (true) { if (c.IsSpaceCharacter()) { tag.SetAttributeValue(_stringBuffer.ToString()); return AttributeBeforeName(Next, tag); } else if (c == Specification.Ampersand) { var value = CharacterReference(Next, Specification.GreaterThan); if (value == null) _stringBuffer.Append(Specification.Ampersand); else _stringBuffer.Append(value); } else if (c == Specification.GreaterThan) { tag.SetAttributeValue(_stringBuffer.ToString()); return EmitTag(tag); } else if (c == Specification.Null) { RaiseErrorOccurred(ErrorCode.Null); _stringBuffer.Append(Specification.Replacement); } else if (c == Specification.DoubleQuote || c == Specification.SingleQuote || c == Specification.LessThan || c == Specification.Equality || c == Specification.CurvedQuote) { RaiseErrorOccurred(ErrorCode.AttributeValueInvalid); _stringBuffer.Append(c); } else if (c == Specification.EndOfFile) return HtmlToken.EOF; else _stringBuffer.Append(c); c = Next; } }
/// <summary> /// See 8.2.4.35 Attribute name state /// </summary> /// <param name="c">The next input character.</param> /// <param name="tag">The current tag token.</param> /// <returns>The emitted token.</returns> HtmlToken AttributeName(Char c, HtmlTagToken tag) { while (true) { if (c.IsSpaceCharacter()) { tag.AddAttribute(_stringBuffer.ToString()); return AttributeAfterName(Next, tag); } else if (c == Specification.Solidus) { tag.AddAttribute(_stringBuffer.ToString()); return TagSelfClosing(Next, tag); } else if (c == Specification.Equality) { tag.AddAttribute(_stringBuffer.ToString()); return AttributeBeforeValue(Next, tag); } else if (c == Specification.GreaterThan) { tag.AddAttribute(_stringBuffer.ToString()); return EmitTag(tag); } else if (c == Specification.EndOfFile) return HtmlToken.EOF; else if (c == Specification.Null) { RaiseErrorOccurred(ErrorCode.Null); _stringBuffer.Append(Specification.Replacement); } else if (c.IsUppercaseAscii()) _stringBuffer.Append(Char.ToLower(c)); else if (c == Specification.DoubleQuote || c == Specification.SingleQuote || c == Specification.LessThan) { RaiseErrorOccurred(ErrorCode.AttributeNameInvalid); _stringBuffer.Append(c); } else _stringBuffer.Append(c); c = Next; } }
/// <summary> /// See 8.2.4.39 Attribute value (single-quoted) state /// </summary> /// <param name="c">The next input character.</param> /// <param name="tag">The current tag token.</param> /// <returns>The emitted token.</returns> HtmlToken AttributeSingleQuotedValue(Char c, HtmlTagToken tag) { while (true) { if (c == Specification.SingleQuote) { tag.SetAttributeValue(_stringBuffer.ToString()); return AttributeAfterValue(Next, tag); } else if (c == Specification.Ampersand) { var value = CharacterReference(Next, Specification.SingleQuote); if (value == null) _stringBuffer.Append(Specification.Ampersand); else _stringBuffer.Append(value); } else if (c == Specification.Null) { RaiseErrorOccurred(ErrorCode.Null); _stringBuffer.Append(Specification.Replacement); } else if (c == Specification.EndOfFile) return HtmlToken.EOF; else _stringBuffer.Append(c); c = Next; } }
/// <summary> /// See 8.2.4.43 Self-closing start tag state /// </summary> /// <param name="c">The next input character.</param> /// <param name="tag">The current tag token.</param> /// <returns>The emitted token.</returns> HtmlToken TagSelfClosing(Char c, HtmlTagToken tag) { if (c == Specification.GreaterThan) { tag.IsSelfClosing = true; return EmitTag(tag); } else if (c == Specification.EndOfFile) { RaiseErrorOccurred(ErrorCode.EOF); return HtmlToken.EOF; } else { RaiseErrorOccurred(ErrorCode.ClosingSlashMisplaced); return AttributeBeforeName(c, tag); } }
/// <summary> /// See 8.2.4.37 Before attribute value state /// </summary> /// <param name="c">The next input character.</param> /// <param name="tag">The current tag token.</param> /// <returns>The emitted token.</returns> HtmlToken AttributeBeforeValue(Char c, HtmlTagToken tag) { while (c.IsSpaceCharacter()) c = Next; if (c == Specification.DoubleQuote) { _stringBuffer.Clear(); return AttributeDoubleQuotedValue(Next, tag); } else if (c == Specification.Ampersand) { _stringBuffer.Clear(); return AttributeUnquotedValue(c, tag); } else if (c == Specification.SingleQuote) { _stringBuffer.Clear(); return AttributeSingleQuotedValue(Next, tag); } else if (c == Specification.Null) { RaiseErrorOccurred(ErrorCode.Null); _stringBuffer.Append(Specification.Replacement); return AttributeUnquotedValue(Next, tag); } else if (c == Specification.GreaterThan) { RaiseErrorOccurred(ErrorCode.TagClosedWrong); return EmitTag(tag); } else if (c == Specification.LessThan || c == Specification.Equality || c == Specification.CurvedQuote) { RaiseErrorOccurred(ErrorCode.AttributeValueInvalid); _stringBuffer.Clear().Append(c); return AttributeUnquotedValue(Next, tag); } else if (c == Specification.EndOfFile) { return HtmlToken.EOF; } else { _stringBuffer.Clear().Append(c); return AttributeUnquotedValue(Next, tag); } }
/// <summary> /// See 8.2.4.10 Tag name state /// </summary> /// <param name="c">The next input character.</param> /// <param name="tag">The current tag token.</param> /// <returns>The emitted token.</returns> HtmlToken TagName(Char c, HtmlTagToken tag) { while (true) { if (c.IsSpaceCharacter()) { tag.Name = _stringBuffer.ToString(); return AttributeBeforeName(Next, tag); } else if (c == Specification.Solidus) { tag.Name = _stringBuffer.ToString(); return TagSelfClosing(Next, tag); } else if (c == Specification.GreaterThan) { tag.Name = _stringBuffer.ToString(); return EmitTag(tag); } else if (c == Specification.Null) { RaiseErrorOccurred(ErrorCode.Null); _stringBuffer.Append(Specification.Replacement); } else if (c == Specification.EndOfFile) { RaiseErrorOccurred(ErrorCode.EOF); return HtmlToken.EOF; } else if (c.IsUppercaseAscii()) _stringBuffer.Append(Char.ToLower(c)); else _stringBuffer.Append(c); c = Next; } }
/// <summary> /// See 8.2.4.19 Script data end tag name state /// </summary> /// <param name="c">The next input character.</param> /// <param name="tag">The current tag token.</param> /// <returns>The emitted token.</returns> HtmlToken ScriptDataNameEndTag(Char c, HtmlTagToken tag) { var name = _stringBuffer.ToString().ToLower(); var appropriateEndTag = name == _lastStartTag; if (appropriateEndTag && c.IsSpaceCharacter()) { tag.Name = name; return AttributeBeforeName(Next, tag); } else if (appropriateEndTag && c == Specification.Solidus) { tag.Name = name; return TagSelfClosing(Next, tag); } else if (appropriateEndTag && c == Specification.GreaterThan) { tag.Name = name; return EmitTag(tag); } else if (c.IsLetter()) { _stringBuffer.Append(c); return ScriptDataNameEndTag(Next, tag); } _buffer.Append(Specification.LessThan).Append(Specification.Solidus); _buffer.Append(_stringBuffer.ToString()); return ScriptData(c); }
/// <summary> /// See 8.2.4.26 Script data escaped end tag open state /// </summary> /// <param name="c">The next input character.</param> /// <param name="tag">The current tag token.</param> /// <returns>The emitted token.</returns> HtmlToken ScriptDataEscapedEndTag(Char c, HtmlTagToken tag) { if (c.IsLetter()) { _stringBuffer.Clear(); _stringBuffer.Append(c); return ScriptDataEscapedEndTag(Next, tag); } _buffer.Append(Specification.LessThan).Append(Specification.Solidus); return ScriptDataEscaped(c); }
/// <summary> /// See 8.2.4.42 After attribute value (quoted) state /// </summary> /// <param name="c">The next input character.</param> /// <param name="tag">The current tag token.</param> /// <returns>The emitted token.</returns> HtmlToken AttributeAfterValue(Char c, HtmlTagToken tag) { if (c.IsSpaceCharacter()) return AttributeBeforeName(Next, tag); else if (c == Specification.Solidus) return TagSelfClosing(Next, tag); else if (c == Specification.GreaterThan) return EmitTag(tag); else if (c == Specification.EndOfFile) return HtmlTagToken.EOF; RaiseErrorOccurred(ErrorCode.AttributeNameExpected); return AttributeBeforeName(c, tag); }
/// <summary> /// Emits the current token as a tag token. /// </summary> HtmlTagToken EmitTag(HtmlTagToken tag) { _state = HtmlParseMode.PCData; if (tag.Type == HtmlTokenType.StartTag) { for (var i = tag.Attributes.Count - 1; i > 0; i--) { for (var j = i - 1; j >= 0; j--) { if (tag.Attributes[j].Key == tag.Attributes[i].Key) { tag.Attributes.RemoveAt(i); RaiseErrorOccurred(ErrorCode.AttributeDuplicateOmitted); break; } } } _lastStartTag = tag.Name; } else { if (tag.IsSelfClosing) RaiseErrorOccurred(ErrorCode.EndTagCannotBeSelfClosed); if (tag.Attributes.Count != 0) RaiseErrorOccurred(ErrorCode.EndTagCannotHaveAttributes); } return tag; }