/// <summary> /// Before any doctype - still in the prolog. No declaration /// allowed. /// </summary> /// <param name="token">The consumed token.</param> void BeforeDoctype(XmlToken token) { switch (token.Type) { case XmlTokenType.Doctype: { var doctypeToken = (XmlDoctypeToken)token; var doctypeNode = new DocumentType(_document, doctypeToken.Name) { SystemIdentifier = doctypeToken.SystemIdentifier, PublicIdentifier = doctypeToken.PublicIdentifier }; _document.AppendChild(doctypeNode); _currentMode = XmlTreeMode.Misc; break; } default: { InMisc(token); break; } } }
/// <summary> /// After the body state - nothing except Comment PI S allowed. /// </summary> /// <param name="token">The consumed token.</param> void AfterBody(XmlToken token) { switch (token.Type) { case XmlTokenType.ProcessingInstruction: case XmlTokenType.Comment: { InMisc(token); break; } case XmlTokenType.EndOfFile: { break; } default: { if (!token.IsIgnorable && !_options.IsSuppressingErrors) { throw XmlParseError.XmlMissingRoot.At(token.Position); } break; } } }
/// <summary> /// Consumes a token and processes it. /// </summary> /// <param name="token">The token to consume.</param> void Consume(XmlToken token) { switch (_currentMode) { case XmlTreeMode.Initial: Initial(token); break; case XmlTreeMode.Prolog: BeforeDoctype(token); break; case XmlTreeMode.Misc: InMisc(token); break; case XmlTreeMode.Body: InBody(token); break; case XmlTreeMode.After: AfterBody(token); break; } }
/// <summary> /// In the body state - no doctypes and declarations allowed. /// </summary> /// <param name="token">The consumed token.</param> void InMisc(XmlToken token) { switch (token.Type) { case XmlTokenType.Comment: { var commenToken = (XmlCommentToken)token; var commentNode = _document.CreateComment(commenToken.Data); CurrentNode.AppendChild(commentNode); break; } case XmlTokenType.ProcessingInstruction: { var piToken = (XmlPIToken)token; var piNode = _document.CreateProcessingInstruction(piToken.Target, piToken.Content); CurrentNode.AppendChild(piNode); break; } case XmlTokenType.StartTag: { _currentMode = XmlTreeMode.Body; InBody(token); break; } default: { if (!token.IsIgnorable && !_options.IsSuppressingErrors) { throw XmlParseError.XmlMissingRoot.At(token.Position); } break; } } }
/// <summary> /// The initial state. Expects an XML declaration. /// </summary> /// <param name="token">The consumed token.</param> void Initial(XmlToken token) { if (token.Type == XmlTokenType.Declaration) { var declarationToken = (XmlDeclarationToken)token; _standalone = declarationToken.Standalone; if (!declarationToken.IsEncodingMissing) { SetEncoding(declarationToken.Encoding); } if (!CheckVersion(declarationToken.Version) && !_options.IsSuppressingErrors) { throw XmlParseError.XmlDeclarationVersionUnsupported.At(token.Position); } } else { _currentMode = XmlTreeMode.Prolog; BeforeDoctype(token); } }
/// <summary> /// In the body state - no doctypes and declarations allowed. /// </summary> /// <param name="token">The consumed token.</param> void InBody(XmlToken token) { switch (token.Type) { case XmlTokenType.StartTag: { var tagToken = (XmlTagToken)token; var element = _creator.Invoke(_document, tagToken.Name, null); CurrentNode.AppendChild(element); if (!tagToken.IsSelfClosing) { _openElements.Add(element); } else if (_openElements.Count == 0) { _currentMode = XmlTreeMode.After; } for (var i = 0; i < tagToken.Attributes.Count; i++) { var name = tagToken.Attributes[i].Key; var value = tagToken.Attributes[i].Value.Trim(); element.SetAttribute(name, value); } if (_options.OnCreated != null) { _options.OnCreated.Invoke(element, tagToken.Position); } break; } case XmlTokenType.EndTag: { var tagToken = (XmlTagToken)token; if (!CurrentNode.NodeName.Is(tagToken.Name)) { if (_options.IsSuppressingErrors) { break; } throw XmlParseError.TagClosingMismatch.At(token.Position); } _openElements.RemoveAt(_openElements.Count - 1); if (_openElements.Count == 0) { _currentMode = XmlTreeMode.After; } break; } case XmlTokenType.ProcessingInstruction: case XmlTokenType.Comment: { InMisc(token); break; } case XmlTokenType.CData: { var cdataToken = (XmlCDataToken)token; CurrentNode.AppendText(cdataToken.Data); break; } case XmlTokenType.Character: { var charToken = (XmlCharacterToken)token; CurrentNode.AppendText(charToken.Data); break; } case XmlTokenType.EndOfFile: { if (_options.IsSuppressingErrors) { break; } throw XmlParseError.EOF.At(token.Position); } case XmlTokenType.Doctype: { if (_options.IsSuppressingErrors) { break; } throw XmlParseError.XmlDoctypeAfterContent.At(token.Position); } case XmlTokenType.Declaration: { if (_options.IsSuppressingErrors) { break; } throw XmlParseError.XmlDeclarationMisplaced.At(token.Position); } } }
/// <summary> /// After the body state - nothing except Comment PI S allowed. /// </summary> /// <param name="token">The consumed token.</param> void AfterBody(XmlToken token) { switch (token.Type) { case XmlTokenType.ProcessingInstruction: case XmlTokenType.Comment: { InMisc(token); break; } case XmlTokenType.EndOfFile: { break; } default: { if (!token.IsIgnorable) throw XmlParseError.XmlMissingRoot.At(token.Position); break; } } }
/// <summary> /// In the body state - no doctypes and declarations allowed. /// </summary> /// <param name="token">The consumed token.</param> void InBody(XmlToken token) { switch (token.Type) { case XmlTokenType.StartTag: { var tok = (XmlTagToken)token; var tag = new XmlElement(_document, tok.Name); CurrentNode.AppendChild(tag); if (!tok.IsSelfClosing) { _openElements.Add(tag); } else if (_openElements.Count == 0) { _currentMode = XmlTreeMode.After; } for (int i = 0; i < tok.Attributes.Count; i++) { tag.SetAttribute(tok.Attributes[i].Key, tok.Attributes[i].Value.Trim()); } break; } case XmlTokenType.EndTag: { var tok = (XmlTagToken)token; if (CurrentNode.NodeName != tok.Name) { if (_options.IsSuppressingErrors) { break; } throw XmlParseError.TagClosingMismatch.At(token.Position); } _openElements.RemoveAt(_openElements.Count - 1); if (_openElements.Count == 0) { _currentMode = XmlTreeMode.After; } break; } case XmlTokenType.ProcessingInstruction: case XmlTokenType.Comment: { InMisc(token); break; } case XmlTokenType.CData: { var tok = (XmlCDataToken)token; CurrentNode.AppendText(tok.Data); break; } case XmlTokenType.Character: { var tok = (XmlCharacterToken)token; CurrentNode.AppendText(tok.Data); break; } case XmlTokenType.EndOfFile: { if (_options.IsSuppressingErrors) { break; } throw XmlParseError.EOF.At(token.Position); } case XmlTokenType.Doctype: { if (_options.IsSuppressingErrors) { break; } throw XmlParseError.XmlDoctypeAfterContent.At(token.Position); } case XmlTokenType.Declaration: { if (_options.IsSuppressingErrors) { break; } throw XmlParseError.XmlDeclarationMisplaced.At(token.Position); } } }
/// <summary> /// In the body state - no doctypes and declarations allowed. /// </summary> /// <param name="token">The consumed token.</param> void InBody(XmlToken token) { switch (token.Type) { case XmlTokenType.StartTag: { var tok = (XmlTagToken)token; var tag = new XmlElement(_document, tok.Name); CurrentNode.AppendChild(tag); if (!tok.IsSelfClosing) _openElements.Add(tag); else if(_openElements.Count == 0) _currentMode = XmlTreeMode.After; for (int i = 0; i < tok.Attributes.Count; i++) tag.SetAttribute(tok.Attributes[i].Key, tok.Attributes[i].Value.Trim()); break; } case XmlTokenType.EndTag: { var tok = (XmlTagToken)token; if (CurrentNode.NodeName != tok.Name) throw XmlParseError.TagClosingMismatch.At(token.Position); _openElements.RemoveAt(_openElements.Count - 1); if (_openElements.Count == 0) _currentMode = XmlTreeMode.After; break; } case XmlTokenType.ProcessingInstruction: case XmlTokenType.Comment: { InMisc(token); break; } case XmlTokenType.Entity: { var tok = (XmlEntityToken)token; var str = tok.GetEntity(); CurrentNode.AppendText(str); break; } case XmlTokenType.CData: { var tok = (XmlCDataToken)token; CurrentNode.AppendText(tok.Data); break; } case XmlTokenType.Character: { var tok = (XmlCharacterToken)token; CurrentNode.AppendText(tok.Data.ToString()); break; } case XmlTokenType.EndOfFile: { throw XmlParseError.EOF.At(token.Position); } case XmlTokenType.Doctype: { throw XmlParseError.XmlDoctypeAfterContent.At(token.Position); } case XmlTokenType.Declaration: { throw XmlParseError.XmlDeclarationMisplaced.At(token.Position); } } }
/// <summary> /// In the body state - no doctypes and declarations allowed. /// </summary> /// <param name="token">The consumed token.</param> void InMisc(XmlToken token) { switch (token.Type) { case XmlTokenType.Comment: { var tok = (XmlCommentToken)token; var com = _document.CreateComment(tok.Data); CurrentNode.AppendChild(com); break; } case XmlTokenType.ProcessingInstruction: { var tok = (XmlPIToken)token; var pi = _document.CreateProcessingInstruction(tok.Target, tok.Content); CurrentNode.AppendChild(pi); break; } case XmlTokenType.StartTag: { _currentMode = XmlTreeMode.Body; InBody(token); break; } default: { if (!token.IsIgnorable) throw XmlParseError.XmlMissingRoot.At(token.Position); break; } } }
/// <summary> /// Before any doctype - still in the prolog. No declaration /// allowed. /// </summary> /// <param name="token">The consumed token.</param> void BeforeDoctype(XmlToken token) { switch (token.Type) { case XmlTokenType.Doctype: { var tok = (XmlDoctypeToken)token; _document.AppendChild(new DocumentType(_document, tok.Name) { SystemIdentifier = tok.SystemIdentifier, PublicIdentifier = tok.PublicIdentifier }); _currentMode = XmlTreeMode.Misc; break; } default: { InMisc(token); break; } } }
/// <summary> /// The initial state. Expects an XML declaration. /// </summary> /// <param name="token">The consumed token.</param> void Initial(XmlToken token) { if (token.Type == XmlTokenType.Declaration) { var tok = (XmlDeclarationToken)token; _standalone = tok.Standalone; if (!tok.IsEncodingMissing) SetEncoding(tok.Encoding); if (!CheckVersion(tok.Version)) throw XmlParseError.XmlDeclarationVersionUnsupported.At(token.Position); } else { _currentMode = XmlTreeMode.Prolog; BeforeDoctype(token); } }