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.
Пример #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;
     }
 }
Пример #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;
             }
         }
     }
 }
Пример #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;
                }
            }
        }
Пример #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;
        }
Пример #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;
 }
Пример #6
0
 private void Pop()
 {
     if (this.m_stack.Count > 1)
     {
         this.m_node = (Node) this.m_stack.Pop();
     }
 }
Пример #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;
        }
Пример #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();
 }
Пример #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;
         }
     }
 }
Пример #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;
        }