This class models an XML node, an array of elements in scope is maintained while parsing for validation purposes, and these Node objects are reused to reduce object allocation, hence the reset method.
Example #1
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;
     }
 }
Example #2
0
 private void Validate(Node node)
 {
     if (this.m_dtd != null)
     {
         ElementDecl e = this.m_dtd.FindElement(node.Name);
         if (e != null)
         {
             node.DtdType = e;
             if (e.ContentModel.DeclaredContent == DeclaredContent.EMPTY)
             {
                 node.IsEmpty = true;
             }
         }
     }
 }
Example #3
0
        private void ValidateContent(Node node)
        {
            if (node.NodeType == XmlNodeType.Element)
            {
                if (!VerifyName(node.Name))
                {
                    this.Pop();
                    this.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.
                string name = node.Name.ToUpperInvariant(); // DTD is in upper case
                int i = 0;
                int 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--)
                    {
                        Node n = (Node) this.m_stack[i];
                        if (n.IsEmpty)
                        {
                            continue; // we'll have to pop this one
                        }
                        ElementDecl 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)
                {
                    Node 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
                        string closing = "";
                        for (int k = top; k >= i + 1; k--)
                        {
                            if (closing != "")
                            {
                                closing += ",";
                            }
                            Node n2 = (Node) this.m_stack[k];
                            closing += "<" + n2.Name + ">";
                        }
                        this.Log("Element '{0}' not allowed inside '{1}', closing {2}.", name, n.Name, closing);
            #endif
                    }

                    this.m_state = State.AutoClose;
                    this.m_newnode = node;
                    this.Pop(); // save this new node until we pop the others
                    this.m_poptodepth = i + 1;
                }
            }
        }
Example #4
0
        private Node Push(string name, XmlNodeType nt, string value)
        {
            Node 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;
        }
Example #5
0
 private Node Push(Node n)
 {
     // we have to do a deep clone of the Node object because
     // it is reused in the stack.
     Node n2 = this.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;
 }
Example #6
0
 private void Pop()
 {
     if (this.m_stack.Count > 1)
     {
         this.m_node = (Node) this.m_stack.Pop();
     }
 }
Example #7
0
        private bool ParseEndTag()
        {
            this.m_state = State.EndTag;
            this.m_current.ReadChar(); // consume '/' char.
            string name = this.ScanName(tagterm);
            char 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.
            bool caseInsensitive = (this.m_folding == CaseFolding.None);
            this.m_node = (Node) this.m_stack[this.m_stack.Count - 1];
            for (int i = this.m_stack.Count - 1; i > 0; i--)
            {
                Node 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;
        }
Example #8
0
 private void Init()
 {
     this.m_state = State.Initial;
     this.m_stack = new HWStack(10);
     this.m_node = this.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();
 }
Example #9
0
 private static 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;
         }
     }
 }
Example #10
0
        /// <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 (this.m_current == null)
            {
                this.OpenInput();
            }

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

            bool 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))
                        {
                            this.Pop(); // we're done!
                            this.m_state = State.Markup;
                            goto case State.Markup;
                        }
                        this.Pop(); // close one element
                        foundnode = true; // return another end element.
                        break;
                    case State.Markup:
                        if (this.m_node.IsEmpty)
                        {
                            this.Pop();
                        }
                        /*Node n = this.m_node;*/
                        foundnode = this.ParseMarkup();
                        break;
                    case State.PartialTag:
                        this.Pop(); // remove text node.
                        this.m_state = State.Markup;
                        foundnode = this.ParseTag(this.m_partial);
                        break;
                    case State.PseudoStartTag:
                        foundnode = this.ParseStartTag('<');
                        break;
                    case State.AutoClose:
                        this.Pop(); // close next node.
                        if (this.m_stack.Count <= this.m_poptodepth)
                        {
                            this.m_state = State.Markup;
                            if (this.m_newnode != null)
                            {
                                this.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 = this.ParseCData();
                        break;
                    case State.Attr:
                        goto case State.AttrValue;
                    case State.AttrValue:
                        this.m_state = State.Markup;
                        goto case State.Markup;
                    case State.Text:
                        this.Pop();
                        goto case State.Markup;
                    case State.PartialText:
                        if (this.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 = this.Top();
                    return true;
                }
            }
            if (!this.m_foundRoot && (this.NodeType == XmlNodeType.Element ||
                                      this.NodeType == XmlNodeType.Text ||
                                      this.NodeType == XmlNodeType.CDATA))
            {
                this.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;
                    Node root = this.Push("html", XmlNodeType.Element, null);
                    this.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;
        }