private void MyXmlLexer_LexStateChanged(XmlLexerEvent lexEvent, int startIndex, int len) { switch (lexEvent) { default: { throw new NotSupportedException(); } case XmlLexerEvent.VisitOpenAngle: { //enter new context } break; case XmlLexerEvent.CommentContent: { } break; case XmlLexerEvent.NamePrefix: { //name prefix of #if DEBUG string testStr = _textSnapshot.Substring(startIndex, len); #endif switch (_parseState) { default: throw new NotSupportedException(); case 0: _nodeNamePrefix = new TextSpan(startIndex, len); _hasNodeNamePrefix = true; break; case 1: //attribute part _attrPrefix = new TextSpan(startIndex, len); _hasAttrPrefix = true; break; case 2: // </a _nodeNamePrefix = new TextSpan(startIndex, len); _hasNodeNamePrefix = true; break; } } break; case XmlLexerEvent.FromContentPart: { //text content of the element OnTextNode(new TextSpan(startIndex, len)); } break; case XmlLexerEvent.AttributeValueAsLiteralString: { //assign value and add to parent //string attrValue = textSnapshot.Substring(startIndex, len); if (_parseState == 11) { //doctype node //add to its parameter } else { //add value to current attribute node _parseState = 1; OnAttribute(_attrName, new TextSpan(startIndex, len)); } } break; case XmlLexerEvent.Attribute: { //create attribute node and wait for its value _attrName = new TextSpan(startIndex, len); //string attrName = textSnapshot.Substring(startIndex, len); } break; case XmlLexerEvent.NodeNameOrAttribute: { //the lexer dose not store state of element name or attribute name //so we use parseState to decide here string name = _textSnapshot.Substring(startIndex, len); switch (_parseState) { case 0: { //element name=> create element if (_currentNodeName != null) { OnEnteringElementBody(); _openEltStack.Push(_currentNodeName); } _currentNodeName = name; //enter new node OnVisitNewElement(new TextSpan(startIndex, len)); _parseState = 1; //enter attribute _waitingAttrName = null; } break; case 1: { //wait for attr value if (_waitingAttrName != null) { //push waiting attr //create new attribute //eg. in html //but this is not valid in Xml throw new NotSupportedException(); } _waitingAttrName = name; } break; case 2: { //**** //node name after open slash </ //TODO: review here,avoid direct string comparison if (_currentNodeName == name) { OnExitingElementBody(); if (_openEltStack.Count > 0) { _waitingAttrName = null; _currentNodeName = _openEltStack.Pop(); } _parseState = 3; } else { //eg. in html //but this is not valid in Xml //not match open-close tag throw new NotSupportedException(); } } break; case 4: { //attribute value as id *** //eg. in Html, but not for general Xml throw new NotSupportedException(); } case 10: { //eg <! _parseState = 11; } break; case 11: { //comment node } break; default: { } break; } } break; case XmlLexerEvent.VisitCloseAngle: { //close angle of current new node //enter into its content if (_parseState == 11) { //add doctype to html } else { } _waitingAttrName = null; _parseState = 0; } break; case XmlLexerEvent.VisitAttrAssign: { _parseState = 4; } break; case XmlLexerEvent.VisitOpenSlashAngle: { _parseState = 2; } break; case XmlLexerEvent.VisitCloseSlashAngle: { // /> if (_openEltStack.Count > 0) { OnExitingElementBody(); //curTextNode = null; //curAttr = null; _waitingAttrName = null; _currentNodeName = _openEltStack.Pop(); } _parseState = 0; } break; case XmlLexerEvent.VisitOpenAngleExclimation: { _parseState = 10; } break; } }
void LexStateChanged(HtmlLexerEvent lexEvent, int startIndex, int len) { switch (lexEvent) { case HtmlLexerEvent.CommentContent: { //var commentContent = this.textSnapshot.Copy(startIndex, len); } break; case HtmlLexerEvent.FromContentPart: { if (curTextNode == null) { curTextNode = _resultHtmlDoc.CreateTextNode( HtmlDecodeHelper.DecodeHtml(this.textSnapshot, startIndex, len)); if (curHtmlNode != null) { curHtmlNode.AddChild(curTextNode); } } else { curTextNode.AppendTextContent(HtmlDecodeHelper.DecodeHtml(this.textSnapshot, startIndex, len)); } } break; case HtmlLexerEvent.AttributeValueAsLiteralString: { //assign value and add to parent if (parseState == 11) { //document node //doc domDocNode.AddParameter(textSnapshot.Substring(startIndex, len)); } else { curAttr.Value = textSnapshot.Substring(startIndex, len); curHtmlNode.AddAttribute(curAttr); } } break; case HtmlLexerEvent.Attribute: { //create attribute node and wait for its value string nodename = textSnapshot.Substring(startIndex, len); curAttr = this._resultHtmlDoc.CreateAttribute(null, nodename); } break; case HtmlLexerEvent.NodeNameOrAttribute: { //the lexer dose not store state of element name or attribute name //so we use parseState to decide here string name = textSnapshot.Substring(startIndex, len); switch (parseState) { case 0: { //create element DomElement elem = this._resultHtmlDoc.CreateElement(null, name); if (curHtmlNode != null) { curHtmlNode.AddChild(elem); openEltStack.Push(curHtmlNode); } curHtmlNode = elem; parseState = 1; //attribute curTextNode = null; curAttr = null; waitingAttrName = null; } break; case 1: { //wait for attr value if (waitingAttrName != null) { //push waiting attr curAttr = this._resultHtmlDoc.CreateAttribute(null, waitingAttrName); curAttr.Value = ""; curHtmlNode.AddAttribute(curAttr); curAttr = null; } waitingAttrName = name; } break; case 2: { //**** //node name after open slash //TODO: review here,avoid direct string comparison if (curHtmlNode.LocalName == name) { if (openEltStack.Count > 0) { waitingAttrName = null; curTextNode = null; curAttr = null; curHtmlNode = openEltStack.Pop(); } parseState = 3; } else { //if not equal then check if current node need close tag or not if (HtmlTagMatching.IsSingleTag(curHtmlNode.LocalNameIndex)) { if (openEltStack.Count > 0) { waitingAttrName = null; curHtmlNode = openEltStack.Pop(); curAttr = null; curTextNode = null; } if (curHtmlNode.LocalName == name) { if (openEltStack.Count > 0) { curTextNode = null; curAttr = null; curHtmlNode = openEltStack.Pop(); waitingAttrName = null; } parseState = 3; } else { //implement err handling here! throw new NotSupportedException(); } } else { //implement err handling here! throw new NotSupportedException(); } } } break; case 4: { //attribute value as id if (curAttr != null) { curAttr.Value = name; curAttr = null; parseState = 0; waitingAttrName = null; } else { } } break; case 10: { //document node parseState = 11; //after docnodename , this may be attr of the document node this.domDocNode = (DomDocumentNode)this._resultHtmlDoc.CreateDocumentNodeElement(); domDocNode.DocNodeName = name; } break; case 11: { //doc domDocNode.AddParameter(name); } break; default: { } break; } } break; case HtmlLexerEvent.VisitCloseAngle: { //close angle of current new node //enter into its content if (parseState == 11) { //add doctype to html this._resultHtmlDoc.RootNode.AddChild(this.domDocNode); domDocNode = null; } if (waitingAttrName != null) { curAttr = this._resultHtmlDoc.CreateAttribute(null, waitingAttrName); curAttr.Value = ""; curHtmlNode.AddAttribute(curAttr); curAttr = null; } waitingAttrName = null; parseState = 0; curTextNode = null; curAttr = null; } break; case HtmlLexerEvent.VisitAttrAssign: { parseState = 4; } break; case HtmlLexerEvent.VisitOpenSlashAngle: { parseState = 2; } break; case HtmlLexerEvent.VisitCloseSlashAngle: { if (openEltStack.Count > 0) { curTextNode = null; curAttr = null; waitingAttrName = null; curHtmlNode = openEltStack.Pop(); } parseState = 0; } break; case HtmlLexerEvent.VisitOpenAngleExclimation: { //eg. doctype parseState = 10; } break; default: { //1. visit open angle } break; } }