void ValidateContent(Node node) { if (this.dtd != null) { // See if this element is allowed inside the current element. // If it isn't, then auto-close elements until we find one // that it is allowed to be in. string name = this.nametable.Add(node.Name.ToUpper()); // DTD is in upper case int i = 0; int top = this.stack.Count-2; if (node.DtdType != null) { // it is a known element, let's see if it's allowed in the // current context. for (i = top; i>0; i--) { Node n = (Node)this.stack[i]; if (n.IsEmpty) continue; // we'll have to pop this one ElementDecl f = n.DtdType; if (f != null) { if (f.Name == this.dtd.Name) break; // can't pop the root element. if (f.CanContain(name, this.dtd)) { break; } else if (!f.EndTagOptional) { // If the end tag is not optional then we can't // auto-close it. We'll just have to live with the // junk we've found and move on. break; } } else { // Since we don't understand this tag anyway, // we might as well allow this content! break; } } } if (i == 0) { // Tag was not found or is not allowed anywhere, ignore it and // continue on. } else if (i < top) { Node n = (Node)this.stack[top]; if (i == top - 1 && name == n.Name) { // e.g. p not allowed inside p, not an interesting error. } else { string closing = ""; for (int k = top; k >= i+1; k--) { if (closing != "") closing += ","; Node n2 = (Node)this.stack[k]; closing += "<"+n2.Name+">"; } Log("Element '{0}' not allowed inside '{1}', closing {2}.", name, n.Name, closing); } this.state = State.AutoClose; this.newnode = node; Pop(); // save this new node until we pop the others this.poptodepth = i+1; } } }
public void CopyAttributes(Node n) { for (int i = 0, len = n.attributes.Count; i < len; i++) { Attribute a = (Attribute)n.attributes[i]; Attribute na = this.AddAttribute(a.Name, a.Value, a.QuoteChar, false); na.DtdType = a.DtdType; } }
void Validate(Node node) { if (this.dtd != null) { ElementDecl e = this.dtd.FindElement(node.Name); if (e != null) { node.DtdType = e; if (e.ContentModel.DeclaredContent == DeclaredContent.EMPTY) node.IsEmpty = true; } } }
void ValidateAttribute(Node node, Attribute a) { ElementDecl e = node.DtdType; if (e != null) { AttDef ad = e.FindAttribute(a.Name); if (ad != null) { a.DtdType = ad; } } }
Node Push(Node n) { // we have to do a deep clone of the Node object because // it is reused in the stack. Node n2 = Push(n.Name, n.NodeType, n.Value); n2.DtdType = n.DtdType; n2.IsEmpty = n.IsEmpty; n2.Space = n.Space; n2.XmlLang = n.XmlLang; n2.CurrentState = n.CurrentState; n2.CopyAttributes(n); this.node = n2; return n2; }
Node Push(string name, XmlNodeType nt, string value) { Node result = (Node)this.stack.Push(); if (result == null) { result = new Node(); this.stack[this.stack.Count-1] = result; } result.Reset(name, nt, value); this.node = result; return result; }
void Pop() { if (this.stack.Count > 1) { this.node = (Node)this.stack.Pop(); } }
bool ParseEndTag() { this.state = State.EndTag; this.current.ReadChar(); // consume '/' char. string name = this.ScanName(tagterm); char ch = this.current.SkipWhitespace(); if (ch != '>') { Log("Expected empty start tag '/>' sequence instead of '{0}'", ch); this.current.ScanToEnd(null, "Recovering", ">"); } this.current.ReadChar(); // consume '>' this.endTag = name; // Make sure there's a matching start tag for it. bool caseInsensitive = (this.folding == CaseFolding.None); this.node = (Node)this.stack[this.stack.Count-1]; for (int i = this.stack.Count-1; i>0; i--) { Node n = (Node)this.stack[i]; if (caseInsensitive && string.Compare(n.Name, name, true) == 0) { this.endTag = n.Name; return true; } else if ((object)n.Name == (object)name) { return true; } } Log("No matching start tag for '</{0}>'", name); this.state = State.Markup; return false; }
void Init() { this.state = State.Initial; this.stack = new HWStack(10); this.node = Push(null, XmlNodeType.Document, null); this.node.IsEmpty = false; this.sb = new StringBuilder(); this.name = new StringBuilder(); this.poptodepth = 0; this.current = null; this.partial = '\0'; this.endTag = null; this.a = null; this.apos = 0; this.newnode = null; this.rootCount = 0; }