/// <summary> /// Parse a start tag /// </summary> protected ParsedToken ParseStartTag() { _StartTagPosition = _CurrentPosition; _TagBuffer = SourceReader.OpenBuffer(); CharInfo c = ReadChar(); // Comments ? if (c == '!') { // Expect '--' or 'DOCTYPE' c = ReadChar(); if (Char.IsLetter(c.AsChar)) { SaveChar(c); return(ParseDoctype()); } else if (c == '-') { if (ReadChar() != '-') { throw new ParseError("Comments need to start with '<!--'.", ReadPosition); } return(ParseComment()); } throw new ParseError("Comment or DOCTYPE expected.", ReadPosition); } // Process instruction ? if (c == '?') { _State = ParseState.ProcessInstruction; c = ReadChar(false); // Pass whitespace while (c != CharInfo.EOF && Char.IsWhiteSpace(c.AsChar)) { c = ReadChar(false); } } else if (c == '/') { _State = ParseState.EndTag; c = ReadChar(false); if (c == CharInfo.EOF || !Char.IsLetterOrDigit(c.AsChar)) { SaveChar(c); throw new ParseError("Invalid tag name. Need to start with an alphanumeric", ReadPosition); } } else { _State = ParseState.Tag; } // Tagname if (c == CharInfo.EOF || !Char.IsLetterOrDigit(c.AsChar)) { throw new ParseError("Invalid tag name. Need to start with an alphanumeric", ReadPosition); } // Loop tag name _CurrentRead = null; AddToCurrentRead(c); while ((c = ReadChar(false)) != CharInfo.EOF && (Char.IsLetterOrDigit(c.AsChar) || c == '.' || c == ':' || c == '-')) { AddToCurrentRead(c); } // If EndTag if (_State == ParseState.EndTag) { _CurrentToken = ParsedTag.EndTag(GetCurrentRead(true)); _CurrentToken.Position = _StartTagPosition; // Pass whitespace while (c != CharInfo.EOF && Char.IsWhiteSpace(c.AsChar)) { c = ReadChar(false); } try { if (c == CharInfo.EOF) { throw new ParseError("Unexpected end of stream.", ReadPosition); } if (IsAttributeNameChar(c.AsChar)) { throw new ParseError("End tag can't contains attribute.", ReadPosition); } if (c != '>') { throw new ParseError("Unexpected char. End tag not closed.", ReadPosition); } } catch { // Reset steam while (c != CharInfo.EOF && c != '<' && c != '>') { c = ReadChar(false); } if (c == '<') { SaveChar(c); } throw; } _State = ParseState.Content; ResetTagBuffer(); var result = _CurrentToken; _CurrentToken = null; return(result); } // Create the tag if (c != CharInfo.EOF) { SaveChar(c); } _CurrentToken = _State == ParseState.Tag ? ParsedTag.OpenTag(GetCurrentRead(true)) : ParsedTag.OpenProcessInstruction(GetCurrentRead(true)); _CurrentToken.Position = _StartTagPosition; return(_CurrentToken); }