public void Visit(DothtmlRootNode root) { ResolveFromParent(root); }
/// <summary> /// Parses the token stream and gets the node. /// </summary> public DothtmlRootNode Parse(IList <DothtmlToken> tokens) { Root = null; Tokens = tokens; CurrentIndex = 0; ElementHierarchy = new Stack <DothtmlNodeWithContent>(); // read file var root = new DothtmlRootNode(); root.Tokens.AddRange(Tokens); ElementHierarchy.Push(root); // read content var doNotAppend = false; while (Peek() != null) { if (Peek().Type == DothtmlTokenType.DirectiveStart) { // directive root.Directives.Add(ReadDirective()); doNotAppend = true; } else if (Peek().Type == DothtmlTokenType.OpenTag) { // element - check element hierarchy var element = ReadElement(); if (ElementHierarchy.Any()) { element.ParentNode = ElementHierarchy.Peek() as DothtmlElementNode; } if (!element.IsSelfClosingTag) { if (!element.IsClosingTag) { // open tag CurrentElementContent.Add(element); ElementHierarchy.Push(element); } else { // close tag if (ElementHierarchy.Count <= 1) { element.NodeErrors.Add($"The closing tag '</{element.FullTagName}>' doesn't have a matching opening tag!"); CurrentElementContent.Add(element); } else { var beginTag = (DothtmlElementNode)ElementHierarchy.Peek(); var beginTagName = beginTag.FullTagName; if (!beginTagName.Equals(element.FullTagName, StringComparison.OrdinalIgnoreCase)) { element.NodeErrors.Add($"The closing tag '</{beginTagName}>' doesn't have a matching opening tag!"); ResolveWrongClosingTag(element); beginTag = ElementHierarchy.Peek() as DothtmlElementNode; if (beginTag != null && beginTagName != beginTag.FullTagName) { beginTag.CorrespondingEndTag = element; ElementHierarchy.Pop(); } else { CurrentElementContent.Add(element); } } else { ElementHierarchy.Pop(); beginTag.CorrespondingEndTag = element; } } } } else { // self closing tag CurrentElementContent.Add(element); } } else if (Peek().Type == DothtmlTokenType.OpenBinding) { // binding CurrentElementContent.Add(ReadBinding()); } else if (Peek().Type == DothtmlTokenType.OpenCData) { CurrentElementContent.Add(ReadCData()); } else if (Peek().Type == DothtmlTokenType.OpenComment) { CurrentElementContent.Add(ReadComment()); } else if (Peek().Type == DothtmlTokenType.OpenServerComment) { // skip server-side comment CurrentElementContent.Add(ReadServerComment()); } else { // text if (!doNotAppend && CurrentElementContent.Count > 0 && CurrentElementContent[CurrentElementContent.Count - 1].GetType() == typeof(DothtmlLiteralNode) && !(CurrentElementContent[CurrentElementContent.Count - 1] is DotHtmlCommentNode)) { // append to the previous literal var lastLiteral = (DothtmlLiteralNode)CurrentElementContent[CurrentElementContent.Count - 1]; if (lastLiteral.Escape) { CurrentElementContent.Add(new DothtmlLiteralNode() { Tokens = { Peek() }, StartPosition = Peek().StartPosition }); } else { lastLiteral.Tokens.Add(Peek()); } } else { CurrentElementContent.Add(new DothtmlLiteralNode() { Tokens = { Peek() }, StartPosition = Peek().StartPosition }); } Read(); doNotAppend = false; } } // check element hierarchy if (ElementHierarchy.Count > 1) { root.NodeErrors.Add($"Unexpected end of file! The tag '<{ElementHierarchy.Peek()}>' was not closed!"); } ResolveParents(root); Root = root; return(root); }
public void Visit(DothtmlRootNode root) { LastFoundNode = root; }
private void ResolveParents(DothtmlRootNode root) { var parentResolver = new ParentResolvingVisitor(); root.Accept(parentResolver); }
/// <summary> /// Parses the token stream and gets the node. /// </summary> public DothtmlRootNode Parse(IList<DothtmlToken> tokens) { Root = null; Tokens = tokens; CurrentIndex = 0; ElementHierarchy = new Stack<DothtmlNodeWithContent>(); // read file var root = new DothtmlRootNode(); root.Tokens.AddRange(Tokens); ElementHierarchy.Push(root); SkipWhitespace(); // read directives while (Peek() != null && Peek().Type == DothtmlTokenType.DirectiveStart) { root.Directives.Add(ReadDirective()); } SkipWhitespace(); // read content while (Peek() != null) { if (Peek().Type == DothtmlTokenType.OpenTag) { // element - check element hierarchy var element = ReadElement(); if (ElementHierarchy.Any()) { element.ParentElement = ElementHierarchy.Peek() as DothtmlElementNode; } if (!element.IsSelfClosingTag) { if (!element.IsClosingTag) { // open tag CurrentElementContent.Add(element); ElementHierarchy.Push(element); } else { // close tag if (ElementHierarchy.Count <= 1) { element.NodeErrors.Add(string.Format(DothtmlParserErrors.ClosingTagHasNoMatchingOpenTag, element.FullTagName)); } else { var beginTag = (DothtmlElementNode)ElementHierarchy.Peek(); var beginTagName = beginTag.FullTagName; if (beginTagName != element.FullTagName) { element.NodeErrors.Add(string.Format(DothtmlParserErrors.ClosingTagHasNoMatchingOpenTag, beginTagName)); ResolveWrongClosingTag(element); beginTag = (DothtmlElementNode)ElementHierarchy.Peek(); } else { ElementHierarchy.Pop(); } beginTag.CorrespondingEndTag = element; } } } else { // self closing tag CurrentElementContent.Add(element); } } else if (Peek().Type == DothtmlTokenType.OpenBinding) { // binding CurrentElementContent.Add(ReadBinding()); } else if (Peek().Type == DothtmlTokenType.OpenCData) { CurrentElementContent.Add(ReadCData()); } else { // text if (CurrentElementContent.Count > 0 && CurrentElementContent[CurrentElementContent.Count - 1].GetType() == typeof(DothtmlLiteralNode)) { // append to the previous literal var lastLiteral = (DothtmlLiteralNode)CurrentElementContent[CurrentElementContent.Count - 1]; if (lastLiteral.Escape != false) CurrentElementContent.Add(new DothtmlLiteralNode() { Value = Peek().Text, Tokens = { Peek() }, StartPosition = Peek().StartPosition }); else { lastLiteral.Value += Peek().Text; lastLiteral.Tokens.Add(Peek()); } } else { CurrentElementContent.Add(new DothtmlLiteralNode() { Value = Peek().Text, Tokens = { Peek() }, StartPosition = Peek().StartPosition }); } Read(); } } // check element hierarchy if (ElementHierarchy.Count > 1) { root.NodeErrors.Add(string.Format(DothtmlParserErrors.UnexpectedEndOfInputTagNotClosed, ElementHierarchy.Peek())); } // set lengths to all nodes foreach (var node in root.EnumerateNodes()) { node.Length = node.Tokens.Select(t => t.Length).DefaultIfEmpty(0).Sum(); } Root = root; return root; }