2
// RootNode.cs: Root node in ASP.NET document tree; can populate itself from
6
// Michael Hutchinson <m.j.hutchinson@gmail.com>
8
// Copyright (C) 2006 Michael Hutchinson
11
// This source code is licenced under The MIT License:
13
// Permission is hereby granted, free of charge, to any person obtaining
14
// a copy of this software and associated documentation files (the
15
// "Software"), to deal in the Software without restriction, including
16
// without limitation the rights to use, copy, modify, merge, publish,
17
// distribute, sublicense, and/or sell copies of the Software, and to
18
// permit persons to whom the Software is furnished to do so, subject to
19
// the following conditions:
21
// The above copyright notice and this permission notice shall be
22
// included in all copies or substantial portions of the Software.
24
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
35
using System.Collections.Generic;
37
using MonoDevelop.AspNet.Parser;
38
using MonoDevelop.AspNet.Parser.Internal;
40
namespace MonoDevelop.AspNet.Parser.Dom
42
public class RootNode : ParentNode
45
List<ParseException> errors = new List<ParseException> ();
47
public RootNode () : base (null)
51
internal ICollection<ParseException> ParseErrors {
52
get { return errors; }
55
public override void AcceptVisit (Visitor visitor)
58
foreach (Node n in children) {
59
if (visitor.QuickExit)
61
n.AcceptVisit (visitor);
66
public override string ToString ()
68
return string.Format ("[RootNode Filename='{0}']", fileName);
71
public override int ContainsPosition (int line, int col)
79
static string[] implicitSelfClosing = { "hr", "br", "img" };
80
static string[] implicitCloseOnBlock = { "p" };
81
static string[] blockLevel = { "p", "div", "hr", "img", "blockquote", "html", "body", "form" };
83
public void Parse (string fileName, TextReader textStream)
85
var parser = new AspParser (fileName, textStream);
86
this.fileName = fileName;
88
parser.Error += ParseError;
89
parser.TagParsed += TagParsed;
90
parser.TextParsed += TextParsed;
97
void TagParsed (ILocation location, TagType tagtype, string tagId, TagAttributes attributes)
102
TagNode tn = currentNode as TagNode;
104
errors.Add (new ParseException (location, "Closing tag '" + tagId +"' does not match an opening tag."));
106
if (tn.TagName == tagId) {
107
tn.EndLocation = location;
108
currentNode = currentNode.Parent;
111
errors.Add (new ParseException (location, "Closing tag '" + tagId +"' does not match opening tag '" + tn.TagName + "'."));
112
currentNode = currentNode.Parent;
113
TagParsed (location, TagType.Close, tagId, null);
118
case TagType.CodeRender:
119
case TagType.CodeRenderExpression:
120
case TagType.DataBinding:
122
AddtoCurrent (location, new ExpressionNode (location, tagId, tagtype == TagType.CodeRenderExpression));
123
} catch (ParseException ex) {
128
case TagType.Directive:
130
AddtoCurrent (location, new DirectiveNode (location, tagId, attributes));
131
} catch (ParseException ex) {
136
case TagType.Include:
137
throw new NotImplementedException ("Server-side includes have not yet been implemented: " + location.PlainText);
139
case TagType.ServerComment:
140
//FIXME: the parser doesn't actually return these
141
throw new NotImplementedException ("Server comments have not yet been implemented: " + location.PlainText);
143
case TagType.SelfClosing:
145
tn = new TagNode (location, tagId, attributes);
146
AddtoCurrent (location, tn);
148
} catch (ParseException ex) {
155
//HACK: implicit close on block level in HTML4
156
TagNode prevTag = currentNode as TagNode;
157
if (prevTag != null) {
158
if (Array.IndexOf (implicitCloseOnBlock, prevTag.TagName.ToLowerInvariant ()) > -1
159
&& Array.IndexOf (blockLevel, tagId.ToLowerInvariant ()) > -1) {
160
errors.Add (new ParseException (location, "Unclosed " + prevTag.TagName + " tag. Assuming implicitly closed by block level tag."));
162
currentNode = currentNode.Parent;
166
//create and add the new tag
167
TagNode child = new TagNode (location, tagId, attributes);
168
AddtoCurrent (location, child);
170
//HACK: implicitly closing tags in HTML4
171
if (Array.IndexOf (implicitSelfClosing, tagId.ToLowerInvariant ()) > -1) {
172
errors.Add (new ParseException (location, "Unclosed " + tagId + " tag. Assuming implicitly closed."));
178
} catch (ParseException ex) {
184
//FIXME: the parser doesn't actually return these
185
throw new NotImplementedException("Text tagtypes have not yet been implemented: " + location.PlainText);
189
void AddtoCurrent (ILocation location, Node n)
191
ParentNode pn = currentNode as ParentNode;
193
throw new ParseException (location, "Nodes of type " + n.GetType () + " must be inside other tags");
197
void TextParsed (ILocation location, string text)
199
currentNode.AddText (location, text);
202
void ParseError (ILocation location, string message)
204
errors.Add (new ParseException (location, message));