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