예제 #1
0
        public override bool Read() {
            if (current == null) {
                OpenInput();
            }
            State start = this.state;
            if (node.Simulated) {
                // return the next node
                node.Simulated = false;
                this.node = Top();
                this.state = this.node.CurrentState;
                return true;
            }

            bool foundnode = false;
            while (! foundnode) {
                switch (this.state) {
                    case State.Initial:
                        this.state = State.Markup;
                        this.current.ReadChar();
                        goto case State.Markup;
                    case State.Eof:
                        if (this.current.Parent != null) {
                            this.current.Close();
                            this.current = this.current.Parent;
                        } else {
                            return false;
                        }
                        break;
                    case State.EndTag:
                        if (this.endTag == (object)this.node.Name) {
                            Pop(); // we're done!
                            this.state = State.Markup;
                            goto case State.Markup;
                        }
                        Pop(); // close one element
                        foundnode = true;// return another end element.
                        break;
                    case State.Markup:
                        if (this.node.IsEmpty) {
                            Pop();
                        }
                        Node n = this.node;
                        foundnode = ParseMarkup();
                        break;
                    case State.PartialTag:
                        Pop(); // remove text node.
                        this.state = State.Markup;
                        foundnode = ParseTag(this.partial);
                        break;
                    case State.PseudoStartTag:
                        foundnode = ParseStartTag('<');
                        break;
                    case State.AutoClose:
                        Pop(); // close next node.
                        if (this.stack.Count <= this.poptodepth) {
                            this.state = State.Markup;
                            if (this.newnode != null) {
                                Push(this.newnode); // now we're ready to start the new node.
                                this.newnode = null;
                                this.state = State.Markup;
                            } else if (this.node.NodeType == XmlNodeType.Document) {
                                this.state = State.Eof;
                                goto case State.Eof;
                            }
                        }
                        foundnode = true;
                        break;
                    case State.CData:
                        foundnode = ParseCData();
                        break;
                    case State.Attr:
                        goto case State.AttrValue;
                    case State.AttrValue:
                        this.state = State.Markup;
                        goto case State.Markup;
                    case State.Text:
                        Pop();
                        goto case State.Markup;
                    case State.PartialText:
                        if (ParseText(this.current.Lastchar, false)) {
                            this.node.NodeType = XmlNodeType.Whitespace;
                        }
                        foundnode = true;
                        break;
                }
                if (foundnode && this.node.NodeType == XmlNodeType.Whitespace && this.whitespaceHandling == WhitespaceHandling.None) {
                    // strip out whitespace (caller is probably pretty printing the XML).
                    foundnode = false;
                }
                if (!foundnode && this.state == State.Eof && this.stack.Count>1) {
                    this.poptodepth = 1;
                    state = State.AutoClose;
                    this.node = Top();
                    return true;
                }
            }
            if (!foundRoot && (this.NodeType == XmlNodeType.Element ||
                               this.NodeType == XmlNodeType.Text ||
                               this.NodeType == XmlNodeType.CDATA)) {
                foundRoot = true;
                if (this.IsHtml && (this.NodeType != XmlNodeType.Element ||
                                    string.Compare(this.LocalName, "html", true, System.Globalization.CultureInfo.InvariantCulture) != 0)) {
                    // Simulate an HTML root element!
                    this.node.CurrentState = this.state;
                    Node root = Push("html", XmlNodeType.Element, null);
                    SwapTopNodes(); // make html the outer element.
                    this.node = root;
                    root.Simulated = true;
                    root.IsEmpty = false;
                    this.state = State.Markup;
                    //this.state = State.PseudoStartTag;
                    //this.startTag = name;
                }
                return true;
            }
            return true;
        }
예제 #2
0
 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;
 }
예제 #3
0
 void Pop() {
     if (this.stack.Count > 1) {
         this.node = (Node)this.stack.Pop();
     }
 }
예제 #4
0
 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;
     this.foundRoot = false;
 }
예제 #5
0
 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;
 }
예제 #6
0
 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;
     }
 }
예제 #7
0
 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;
         }
     }
 }
예제 #8
0
 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;
         }
     }
 }
예제 #9
0
 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;
         }
     }
 }
예제 #10
0
        bool ParseEndTag() {
            this.state = State.EndTag;
            this.current.ReadChar(); // consume '/' char.
            string name = this.ScanName(SgmlReader.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;
        }