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.
Beispiel #1
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;
 }
Beispiel #2
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;
         }
     }
 }
Beispiel #3
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;
     }
 }
Beispiel #4
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;
         }
     }
 }
Beispiel #5
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;
         }
     }
 }   
Beispiel #6
0
 void Pop() {
     if (this.stack.Count > 1) {
         this.node = (Node)this.stack.Pop();
     }
 }
Beispiel #7
0
 void Pop()
 {
     if (_depth > 1) {
         _depth--;
         _node = _stack[_depth-1];
     }
 }
Beispiel #8
0
        private bool ParseEndTag()
        {
            this.m_state = State.EndTag;
            this.m_current.ReadChar(); // consume '/' char.
            string name = this.ScanName(SgmlReader.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;
        }
Beispiel #9
0
 private void Pop()
 {
     if (this.m_stack.Count > 1)
     {
         this.m_node = (Node)this.m_stack.Pop();
     }
 }
Beispiel #10
0
 void Init()
 {
     _state = State.Initial;
     _stack = new Node[10];
     _size = 10;
     _depth = 0;
     _node = Push(null, XmlNodeType.Document, null);
     _node.IsEmpty = false;
     _sb = new StringBuilder();
     _name = new StringBuilder();
     _poptodepth = 0;
     _current = null;
     _partial = '\0';
     _endTag = null;
     _a = null;
     _apos = 0;
     _newnode = null;
     _poptodepth = 0;
     _rootCount = 0;
 }
Beispiel #11
0
 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();
 }
Beispiel #12
0
 void Grow()
 {
     int inc = 10;
     int newsize = _size+inc;
     Node[] narray = new Node[newsize];
     Array.Copy(_stack, narray, _size);
     _size = newsize;
     _stack = narray;
 }
Beispiel #13
0
 public void CopyAttributes(Node n)
 {
     for (int i = 0; i < n._attcount; i++) {
         Attribute a = n._attributes[i];
         Attribute na = this.AddAttribute(a.Name, a.Value, a.QuoteChar);
         na.DtdType = a.DtdType;
     }
 }
Beispiel #14
0
 Node Push(string name, XmlNodeType nt, string value)
 {
     if (_depth == _size) Grow();
     Node result;
     if (_stack[_depth] == null) {
         result = new Node(name, nt, value);
         _stack[_depth] = result;
     }
     else {
         result = _stack[_depth];
         result.Reset(name, nt, value);
     }
     _depth++;
     _node = result;
     return result;
 }
Beispiel #15
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;
 }
Beispiel #16
0
        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.
                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 + ">";
                        }
                        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;
                }
            }
        }
Beispiel #17
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;
 }
Beispiel #18
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;
        }
Beispiel #19
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", StringComparison.InvariantCultureIgnoreCase) != 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;
        }
Beispiel #20
0
        bool ParseEndTag()
        {
            _state = State.EndTag;
            _current.ReadChar(); // consume '/' char.
            string name = _current.ScanToken(_sb, _tagterm, false);
            char ch = _current.SkipWhitespace();
            if (ch != '>') {
                Log("Expected empty start tag '/>' sequence instead of '{0}'", ch);
                _current.ScanToEnd(null, "Recovering", ">");
            }
            _current.ReadChar(); // consume '>'

            // Make sure there's a matching start tag for it.
            _endTag = _nametable.Add(name.ToLower());
            _node = _stack[_depth-1];
            for (int i = _depth-1; i>0; i--) {
                if ((object)_stack[i].Name == _endTag)
                    return true;
            }
            Log("No matching start tag for '</{0}>'", name);
            _state = State.Markup;
            return false;
        }