Exemple #1
0
 public void CopyAttributes(Node n) {
     for (int i = 0, len = n.attributes.Count; i < len; i++) {
         var a = (Attribute)n.attributes[i];
         var na = this.AddAttribute(a.Name, a.Value, a.QuoteChar, false);
         na.DtdType = a.DtdType;
     }
 }
        /// <summary>
        ///     Reads the next node from the stream.
        /// </summary>
        /// <returns>true if the next node was read successfully; false if there are no more nodes to read.</returns>
        public override bool Read() {
            if (m_current == null) {
                OpenInput();
            }

            var start = this.m_state;
            if (m_node.Simulated) {
                // return the next node
                m_node.Simulated = false;
                this.m_node = Top();
                this.m_state = this.m_node.CurrentState;
                return true;
            }

            var foundnode = false;
            while (!foundnode) {
                switch (this.m_state) {
                    case State.Initial:
                        this.m_state = State.Markup;
                        this.m_current.ReadChar();
                        goto case State.Markup;
                    case State.Eof:
                        if (this.m_current.Parent != null) {
                            this.m_current.Close();
                            this.m_current = this.m_current.Parent;
                        } else {
                            return false;
                        }
                        break;
                    case State.EndTag:
                        if (string.Equals(this.m_endTag, this.m_node.Name, StringComparison.OrdinalIgnoreCase)) {
                            Pop(); // we're done!
                            this.m_state = State.Markup;
                            goto case State.Markup;
                        }
                        Pop(); // close one element
                        foundnode = true; // return another end element.
                        break;
                    case State.Markup:
                        if (this.m_node.IsEmpty) {
                            Pop();
                        }
                        var n = this.m_node;
                        foundnode = ParseMarkup();
                        break;
                    case State.PartialTag:
                        Pop(); // remove text node.
                        this.m_state = State.Markup;
                        foundnode = ParseTag(this.m_partial);
                        break;
                    case State.PseudoStartTag:
                        foundnode = ParseStartTag('<');
                        break;
                    case State.AutoClose:
                        Pop(); // close next node.
                        if (this.m_stack.Count <= this.m_poptodepth) {
                            this.m_state = State.Markup;
                            if (this.m_newnode != null) {
                                Push(this.m_newnode); // now we're ready to start the new node.
                                this.m_newnode = null;
                                this.m_state = State.Markup;
                            } else if (this.m_node.NodeType == XmlNodeType.Document) {
                                this.m_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.m_state = State.Markup;
                        goto case State.Markup;
                    case State.Text:
                        Pop();
                        goto case State.Markup;
                    case State.PartialText:
                        if (ParseText(this.m_current.Lastchar, false)) {
                            this.m_node.NodeType = XmlNodeType.Whitespace;
                        }

                        foundnode = true;
                        break;
                }

                if (foundnode && this.m_node.NodeType == XmlNodeType.Whitespace && this.m_whitespaceHandling == WhitespaceHandling.None) {
                    // strip out whitespace (caller is probably pretty printing the XML).
                    foundnode = false;
                }
                if (!foundnode && this.m_state == State.Eof && this.m_stack.Count > 1) {
                    this.m_poptodepth = 1;
                    this.m_state = State.AutoClose;
                    this.m_node = Top();
                    return true;
                }
            }
            if (!m_foundRoot && (this.NodeType == XmlNodeType.Element ||
                this.NodeType == XmlNodeType.Text ||
                this.NodeType == XmlNodeType.CDATA)) {
                m_foundRoot = true;
                if (this.IsHtml && (this.NodeType != XmlNodeType.Element ||
                    !string.Equals(this.LocalName, "html", StringComparison.OrdinalIgnoreCase))) {
                    // Simulate an HTML root element!
                    this.m_node.CurrentState = this.m_state;
                    var root = Push("html", XmlNodeType.Element, null);
                    SwapTopNodes(); // make html the outer element.
                    this.m_node = root;
                    root.Simulated = true;
                    root.IsEmpty = false;
                    this.m_state = State.Markup;
                    //this.state = State.PseudoStartTag;
                    //this.startTag = name;
                }

                return true;
            }

            return true;
        }
 private void Pop() {
     if (this.m_stack.Count > 1) {
         this.m_node = (Node)this.m_stack.Pop();
     }
 }
 private Node Push(Node n) {
     // we have to do a deep clone of the Node object because
     // it is reused in the stack.
     var 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.m_node = n2;
     return n2;
 }
        private Node Push(string name, XmlNodeType nt, string value) {
            var result = (Node)this.m_stack.Push();
            if (result == null) {
                result = new Node();
                this.m_stack[this.m_stack.Count - 1] = result;
            }

            result.Reset(name, nt, value);
            this.m_node = result;
            return result;
        }
 private void Init() {
     this.m_state = State.Initial;
     this.m_stack = new HWStack(10);
     this.m_node = Push(null, XmlNodeType.Document, null);
     this.m_node.IsEmpty = false;
     this.m_sb = new StringBuilder();
     this.m_name = new StringBuilder();
     this.m_poptodepth = 0;
     this.m_current = null;
     this.m_partial = '\0';
     this.m_endTag = null;
     this.m_a = null;
     this.m_apos = 0;
     this.m_newnode = null;
     this.m_rootCount = 0;
     this.m_foundRoot = false;
     this.unknownNamespaces.Clear();
 }
        private void ValidateContent(Node node) {
            if (node.NodeType == XmlNodeType.Element) {
                if (!VerifyName(node.Name)) {
                    Pop();
                    Push(null, XmlNodeType.Text, "<" + node.Name + ">");
                    return;
                }
            }

            if (this.m_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.                                  
                var name = node.Name.ToUpperInvariant(); // DTD is in upper case
                var i = 0;
                var top = this.m_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--) {
                        var n = (Node)this.m_stack[i];
                        if (n.IsEmpty) {
                            continue; // we'll have to pop this one
                        }
                        var f = n.DtdType;
                        if (f != null) {
                            if ((i == 2) && string.Equals(f.Name, "BODY", StringComparison.OrdinalIgnoreCase)) // NOTE (steveb): never close the BODY tag too early
                            {
                                break;
                            } else if (string.Equals(f.Name, this.m_dtd.Name, StringComparison.OrdinalIgnoreCase)) {
                                break; // can't pop the root element.
                            } else if (f.CanContain(name, this.m_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.
                    return;
                } else if (i < top) {
                    var n = (Node)this.m_stack[top];
                    if (i == top - 1 && string.Equals(name, n.Name, StringComparison.OrdinalIgnoreCase)) {
                        // e.g. p not allowed inside p, not an interesting error.
                    } else {
#if DEBUG
                        var closing = "";
                        for (var k = top; k >= i + 1; k--) {
                            if (closing != "") {
                                closing += ",";
                            }
                            var n2 = (Node)this.m_stack[k];
                            closing += "<" + n2.Name + ">";
                        }
                        Log("Element '{0}' not allowed inside '{1}', closing {2}.", name, n.Name, closing);
#endif
                    }

                    this.m_state = State.AutoClose;
                    this.m_newnode = node;
                    Pop(); // save this new node until we pop the others
                    this.m_poptodepth = i + 1;
                }
            }
        }
 private static void ValidateAttribute(Node node, Attribute a) {
     var e = node.DtdType;
     if (e != null) {
         var ad = e.FindAttribute(a.Name);
         if (ad != null) {
             a.DtdType = ad;
         }
     }
 }
 private void Validate(Node node) {
     if (this.m_dtd != null) {
         var e = this.m_dtd.FindElement(node.Name);
         if (e != null) {
             node.DtdType = e;
             if (e.ContentModel.DeclaredContent == DeclaredContent.EMPTY) {
                 node.IsEmpty = true;
             }
         }
     }
 }
        private bool ParseEndTag() {
            this.m_state = State.EndTag;
            this.m_current.ReadChar(); // consume '/' char.
            var name = this.ScanName(tagterm);
            var ch = this.m_current.SkipWhitespace();
            if (ch != '>') {
                Log("Expected empty start tag '/>' sequence instead of '{0}'", ch);
                this.m_current.ScanToEnd(null, "Recovering", ">");
            }

            this.m_current.ReadChar(); // consume '>'

            this.m_endTag = name;

            // Make sure there's a matching start tag for it.                        
            var caseInsensitive = (this.m_folding == CaseFolding.None);
            this.m_node = (Node)this.m_stack[this.m_stack.Count - 1];
            for (var i = this.m_stack.Count - 1; i > 0; i--) {
                var n = (Node)this.m_stack[i];
                if (string.Equals(n.Name, name, caseInsensitive ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal)) {
                    this.m_endTag = n.Name;
                    return true;
                }
            }

            Log("No matching start tag for '</{0}>'", name);
            this.m_state = State.Markup;
            return false;
        }