XsdCachingReader.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ FX-1434 / FX-1434 / 1.0 / untmp / whidbey / REDBITS / ndp / fx / src / Xml / System / Xml / Core / XsdCachingReader.cs / 2 / XsdCachingReader.cs

                            //------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// [....] 
//-----------------------------------------------------------------------------
 
 
using System.IO;
using System.Text; 
using System.Xml.Schema;
using System.Xml.XPath;
using System.Diagnostics;
using System.Globalization; 
using System.Collections;
using System.Security.Policy; 
 
namespace System.Xml {
 
    internal class XsdCachingReader : XmlReader, IXmlLineInfo {

        private enum CachingReaderState {
            None = 0, 
            Init = 1,
            Record = 2, 
            Replay = 3, 
            ReaderClosed = 4,
            Error = 5, 
        }

        private XmlReader coreReader;
        private XmlNameTable coreReaderNameTable; 

        private ValidatingReaderNodeData[] contentEvents; 
        private ValidatingReaderNodeData[] attributeEvents; 

        private ValidatingReaderNodeData cachedNode; 

        private CachingReaderState cacheState;
        int contentIndex;
        int attributeCount; 

        private bool returnOriginalStringValues; 
 
        private CachingEventHandler cacheHandler;
 
        //current state
        int currentAttrIndex;
        int currentContentIndex;
        bool readAhead; 

        //Lineinfo 
        IXmlLineInfo lineInfo; 

        //ReadAttributeValue TextNode 
        private ValidatingReaderNodeData textNode;

        //Constants
        private const int InitialAttributeCount = 8; 
        private const int InitialContentCount = 4;
 
//Constructor 
        internal XsdCachingReader(XmlReader reader, IXmlLineInfo lineInfo, CachingEventHandler handlerMethod) {
            this.coreReader = reader; 
            this.lineInfo = lineInfo;
            this.cacheHandler = handlerMethod;
            attributeEvents = new ValidatingReaderNodeData[InitialAttributeCount];
            contentEvents = new ValidatingReaderNodeData[InitialContentCount]; 
            Init();
        } 
 
        private void Init() {
            coreReaderNameTable = coreReader.NameTable; 
            cacheState = CachingReaderState.Init;
            contentIndex = 0;
            currentAttrIndex = -1;
            currentContentIndex = -1; 
            attributeCount = 0;
            cachedNode = null; 
            readAhead = false; 
            //Initialize the cachingReader with start state
            if (coreReader.NodeType == XmlNodeType.Element) { 
                ValidatingReaderNodeData element = AddContent(coreReader.NodeType);
                element.SetItemData(coreReader.LocalName, coreReader.Prefix, coreReader.NamespaceURI, coreReader.Depth);  //Only created for element node type
                element.SetLineInfo(lineInfo);
                RecordAttributes(); 
            }
        } 
 
        internal void Reset(XmlReader reader) {
            this.coreReader = reader; 
            Init();
        }

        // Settings 
        public override XmlReaderSettings Settings {
            get { 
                return coreReader.Settings; 
            }
        } 

    // Node Properties

        // Gets the type of the current node. 
        public override XmlNodeType NodeType {
            get { 
                return cachedNode.NodeType; 
            }
        } 

        // Gets the name of the current node, including the namespace prefix.
        public override string Name {
            get { 
                return cachedNode.GetAtomizedNameWPrefix(coreReaderNameTable);
            } 
        } 

        // Gets the name of the current node without the namespace prefix. 
        public override string LocalName {
            get {
                return cachedNode.LocalName;
            } 
        }
 
        // Gets the namespace URN (as defined in the W3C Namespace Specification) of the current namespace scope. 
        public override string NamespaceURI {
            get { 
                return cachedNode.Namespace;
            }
        }
 
        // Gets the namespace prefix associated with the current node.
        public override string Prefix { 
            get { 
                return cachedNode.Prefix;
            } 
        }

        // Gets a value indicating whether the current node can have a non-empty Value.
        public override bool HasValue { 
            get {
                return XmlReader.HasValueInternal(cachedNode.NodeType); 
            } 
        }
 
        // Gets the text value of the current node.
        public override string Value {
            get {
                return returnOriginalStringValues ? cachedNode.OriginalStringValue : cachedNode.RawValue; 
            }
        } 
 
        // Gets the depth of the current node in the XML element stack.
        public override int Depth { 
            get {
                return cachedNode.Depth;
            }
        } 

        // Gets the base URI of the current node. 
        public override string BaseURI { 
            get {
                return coreReader.BaseURI; 
            }
        }

        // Gets a value indicating whether the current node is an empty element (for example, ). 
        public override bool IsEmptyElement {
            get { 
                return false; 
            }
        } 

        // Gets a value indicating whether the current node is an attribute that was generated from the default value defined
        // in the DTD or schema.
        public override bool IsDefault { 
            get {
                return false; 
            } 
        }
 
        // Gets the quotation mark character used to enclose the value of an attribute node.
        public override char QuoteChar {
            get {
                return coreReader.QuoteChar; 
            }
        } 
 
        // Gets the current xml:space scope.
        public override XmlSpace XmlSpace { 
            get {
                return coreReader.XmlSpace;
            }
        } 

        // Gets the current xml:lang scope. 
        public override string XmlLang { 
            get {
                return coreReader.XmlLang; 
            }
        }

    // Attribute Accessors 

        // The number of attributes on the current node. 
        public override int AttributeCount { 
            get {
                return attributeCount; 
            }
        }

        // Gets the value of the attribute with the specified Name. 
        public override string GetAttribute( string name ) {
            int i; 
            if (name.IndexOf( ':' ) == -1) { 
                i = GetAttributeIndexWithoutPrefix(name);
            } 
            else {
                i = GetAttributeIndexWithPrefix(name);
            }
            return (i >= 0) ? attributeEvents[i].RawValue : null; 
        }
 
        // Gets the value of the attribute with the specified LocalName and NamespaceURI. 
       public override string GetAttribute( string name, string namespaceURI ) {
            namespaceURI = ( namespaceURI == null ) ? string.Empty : coreReaderNameTable.Get( namespaceURI ); 
            name = coreReaderNameTable.Get(name);
            ValidatingReaderNodeData attribute;
            for ( int i = 0; i < attributeCount; i++ ) {
                attribute = attributeEvents[i]; 
                if ( Ref.Equal(attribute.LocalName, name) && Ref.Equal(attribute.Namespace, namespaceURI) ) {
                    return attribute.RawValue; 
                } 
            }
            return null; 
        }

        // Gets the value of the attribute with the specified index.
        public override string GetAttribute( int i ) { 
            if ( i < 0 || i >= attributeCount ) {
                throw new ArgumentOutOfRangeException("i"); 
            } 
            return attributeEvents[i].RawValue;
        } 

        // Gets the value of the attribute with the specified index.
        public override string this [ int i ] {
            get { 
                return GetAttribute(i);
            } 
        } 

        // Gets the value of the attribute with the specified Name. 
        public override string this [ string name ] {
            get {
                return GetAttribute(name);
            } 
        }
 
        // Gets the value of the attribute with the specified LocalName and NamespaceURI. 
        public override string this [ string name, string namespaceURI ] {
            get { 
                return GetAttribute(name, namespaceURI);
            }
        }
 
        // Moves to the attribute with the specified Name.
        public override bool MoveToAttribute( string name ) { 
            int i; 
            if (name.IndexOf( ':' ) == -1) {
                i = GetAttributeIndexWithoutPrefix( name ); 
            }
            else {
                i = GetAttributeIndexWithPrefix( name );
            } 

            if ( i >= 0 ) { 
                currentAttrIndex = i; 
                cachedNode = attributeEvents[i];
                return true; 
            }
            else {
                return false;
            } 
        }
 
 
        // Moves to the attribute with the specified LocalName and NamespaceURI
        public override bool MoveToAttribute( string name, string ns ) { 
            ns = (ns == null) ? string.Empty : coreReaderNameTable.Get(ns);
            name = coreReaderNameTable.Get(name);
            ValidatingReaderNodeData attribute;
            for ( int i = 0; i < attributeCount; i++ ) { 
                attribute = attributeEvents[i];
                if ( Ref.Equal(attribute.LocalName, name) && 
                     Ref.Equal(attribute.Namespace, ns) ) { 
                         currentAttrIndex = i;
                         cachedNode = attributeEvents[i]; 
                    return true;
                }
            }
            return false; 
        }
 
        // Moves to the attribute with the specified index. 
        public override void MoveToAttribute(int i) {
            if ( i < 0 || i >= attributeCount ) { 
                throw new ArgumentOutOfRangeException( "i" );
            }
            currentAttrIndex = i;
            cachedNode = attributeEvents[i]; 
        }
 
        // Moves to the first attribute. 
        public override bool MoveToFirstAttribute() {
            if (attributeCount == 0) { 
                return false;
            }
            currentAttrIndex = 0;
            cachedNode = attributeEvents[0]; 
            return true;
        } 
 
        // Moves to the next attribute.
        public override bool MoveToNextAttribute() { 
            if (currentAttrIndex + 1 < attributeCount) {
                cachedNode = attributeEvents[++currentAttrIndex];
                return true;
            } 
            return false;
        } 
 
        // Moves to the element that contains the current attribute node.
        public override bool MoveToElement() { 
            if (cacheState != CachingReaderState.Replay || cachedNode.NodeType != XmlNodeType.Attribute) {
                return false;
            }
            currentContentIndex = 0; 
            currentAttrIndex = -1;
            Read(); 
            return true; 
        }
 
        // Reads the next node from the stream/TextReader.
        public override bool Read() {
            switch (cacheState) {
                case CachingReaderState.Init: 
                    cacheState = CachingReaderState.Record;
                    goto case CachingReaderState.Record; 
 
                case CachingReaderState.Record:
                    ValidatingReaderNodeData recordedNode = null; 
                    if (coreReader.Read()) {
                        switch(coreReader.NodeType) {
                            case XmlNodeType.Element:
                                //Dont record element within the content of a union type since the main reader will break on this and the underlying coreReader will be positioned on this node 
                                cacheState = CachingReaderState.ReaderClosed;
                                return false; 
 
                            case XmlNodeType.EndElement:
                                recordedNode = AddContent(coreReader.NodeType); 
                                recordedNode.SetItemData(coreReader.LocalName, coreReader.Prefix, coreReader.NamespaceURI, coreReader.Depth);  //Only created for element node type
                                recordedNode.SetLineInfo(lineInfo);
                                break;
 
                            case XmlNodeType.Comment:
                            case XmlNodeType.ProcessingInstruction: 
                            case XmlNodeType.Text: 
                            case XmlNodeType.CDATA:
                            case XmlNodeType.Whitespace: 
                            case XmlNodeType.SignificantWhitespace:
                                recordedNode = AddContent(coreReader.NodeType);
                                recordedNode.SetItemData(coreReader.Value);
                                recordedNode.SetLineInfo(lineInfo); 
                                recordedNode.Depth = coreReader.Depth;
                                break; 
 
                            default:
                                break; 
                        }
                        cachedNode = recordedNode;
                        return true;
                    } 
                    else {
                        cacheState = CachingReaderState.ReaderClosed; 
                        return false; 
                    }
 
                case CachingReaderState.Replay:
                    if (currentContentIndex >= contentIndex) { //When positioned on the last cached node, switch back as the underlying coreReader is still positioned on this node
                        cacheState = CachingReaderState.ReaderClosed;
                        cacheHandler(this); 
                        if (coreReader.NodeType != XmlNodeType.Element || readAhead) { //Only when coreReader not positioned on Element node, read ahead, otherwise it is on the next element node already, since this was not cached
                            return coreReader.Read(); 
                        } 
                        return true;
                    } 
                    cachedNode = contentEvents[currentContentIndex];
                    if (currentContentIndex > 0) {
                        ClearAttributesInfo();
                    } 
                    currentContentIndex++;
                    return true; 
 
                default:
                    return false; 
            }
        }

        internal ValidatingReaderNodeData RecordTextNode(string textValue, string originalStringValue, int depth, int lineNo, int linePos) { 
            ValidatingReaderNodeData textNode = AddContent(XmlNodeType.Text);
            textNode.SetItemData(textValue, originalStringValue); 
            textNode.SetLineInfo(lineNo, linePos); 
            textNode.Depth = depth;
            return textNode; 
        }

        internal void SwitchTextNodeAndEndElement( string textValue, string originalStringValue ) {
            Debug.Assert(coreReader.NodeType == XmlNodeType.EndElement || (coreReader.NodeType == XmlNodeType.Element && coreReader.IsEmptyElement)); 

            ValidatingReaderNodeData textNode = RecordTextNode(textValue, originalStringValue, coreReader.Depth + 1, 0, 0); 
            int endElementIndex = contentIndex - 2; 
            ValidatingReaderNodeData endElementNode = contentEvents[endElementIndex];
            Debug.Assert(endElementNode.NodeType == XmlNodeType.EndElement); 
            contentEvents[endElementIndex] = textNode;
            contentEvents[contentIndex - 1] = endElementNode;
        }
 
        internal void RecordEndElementNode() {
            ValidatingReaderNodeData recordedNode = AddContent(XmlNodeType.EndElement); 
            Debug.Assert(coreReader.NodeType == XmlNodeType.EndElement || (coreReader.NodeType == XmlNodeType.Element && coreReader.IsEmptyElement)); 
            recordedNode.SetItemData(coreReader.LocalName, coreReader.Prefix, coreReader.NamespaceURI, coreReader.Depth);
            recordedNode.SetLineInfo(coreReader as IXmlLineInfo); 
            if (coreReader.IsEmptyElement) { //Simulated endElement node for , the coreReader is on cached Element node itself.
                readAhead = true;
            }
        } 

        internal string ReadOriginalContentAsString() { 
            returnOriginalStringValues = true; 
            string strValue = InternalReadContentAsString();
            returnOriginalStringValues = false; 
            return strValue;
        }

        // Gets a value indicating whether XmlReader is positioned at the end of the stream. 
        public override bool EOF {
            get { 
                return cacheState == CachingReaderState.ReaderClosed && coreReader.EOF; 
            }
        } 

        // Closes the stream, changes the ReadState to Closed, and sets all the properties back to zero.
        public override void Close() {
            coreReader.Close(); 
            cacheState = CachingReaderState.ReaderClosed;
        } 
 
        // Returns the read state of the stream.
        public override ReadState ReadState { 
            get {
                return coreReader.ReadState;
            }
        } 

        // Skips to the end tag of the current element. 
        public override void Skip() { 
            //Skip on caching reader should move to the end of the subtree, past all cached events
            switch (cachedNode.NodeType) { 
                case XmlNodeType.Element:
                    if (coreReader.NodeType != XmlNodeType.EndElement && !readAhead) { //will be true for IsDefault cases where we peek only one node ahead
                        int startDepth = coreReader.Depth - 1;
                        while (coreReader.Read() && coreReader.Depth > startDepth) 
                        ;
                    } 
                    coreReader.Read(); 
                    cacheState = CachingReaderState.ReaderClosed;
                    cacheHandler(this); 
                    break;

                case XmlNodeType.Attribute:
                    MoveToElement(); 
                    goto case XmlNodeType.Element;
 
                default: 
                    Debug.Assert(cacheState == CachingReaderState.Replay);
                    Read(); 
                    break;
            }
        }
 
        // Gets the XmlNameTable associated with this implementation.
        public override XmlNameTable NameTable { 
            get { 
                return coreReaderNameTable;
            } 
        }

        // Resolves a namespace prefix in the current element's scope.
        public override string LookupNamespace( string prefix) { 
            return coreReader.LookupNamespace(prefix);
        } 
 
        // Resolves the entity reference for nodes of NodeType EntityReference.
        public override void ResolveEntity() { 
            throw new InvalidOperationException();
        }

        // Parses the attribute value into one or more Text and/or EntityReference node types. 
        public override bool ReadAttributeValue() {
            Debug.Assert(cacheState == CachingReaderState.Replay); 
            if (cachedNode.NodeType != XmlNodeType.Attribute) { 
                return false;
            } 
            cachedNode = CreateDummyTextNode(cachedNode.RawValue, cachedNode.Depth + 1);
            return true;
        }
 
        //
        // IXmlLineInfo members 
        // 

        bool IXmlLineInfo.HasLineInfo() { 
            return true;
        }

        int IXmlLineInfo.LineNumber { 
            get {
                return cachedNode.LineNumber; 
            } 
        }
 
        int IXmlLineInfo.LinePosition {
            get {
                return cachedNode.LinePosition;
            } 
        }
 
//Private methods 
        internal void SetToReplayMode() {
            cacheState = CachingReaderState.Replay; 
            currentContentIndex = 0;
            currentAttrIndex = -1;
            Read(); //Position on first node recorded to begin replaying
        } 

        internal XmlReader GetCoreReader() { 
            return coreReader; 
        }
 
        internal IXmlLineInfo GetLineInfo() {
            return lineInfo;
        }
 
        private void ClearAttributesInfo() {
            attributeCount = 0; 
            currentAttrIndex = -1; 
        }
 
        private ValidatingReaderNodeData AddAttribute(int attIndex) {
            Debug.Assert(attIndex <= attributeEvents.Length);
            ValidatingReaderNodeData attInfo = attributeEvents[attIndex];
            if (attInfo != null) { 
                attInfo.Clear(XmlNodeType.Attribute);
                return attInfo; 
            } 
            if (attIndex >= attributeEvents.Length -1 ) { //reached capacity of array, Need to increase capacity to twice the initial
                ValidatingReaderNodeData[] newAttributeEvents = new ValidatingReaderNodeData[attributeEvents.Length * 2]; 
                Array.Copy(attributeEvents, 0, newAttributeEvents, 0, attributeEvents.Length);
                attributeEvents = newAttributeEvents;
            }
            attInfo = attributeEvents[attIndex]; 
            if (attInfo == null) {
                attInfo = new ValidatingReaderNodeData(XmlNodeType.Attribute); 
                attributeEvents[attIndex] = attInfo; 
            }
            return attInfo; 
        }

        private ValidatingReaderNodeData AddContent(XmlNodeType nodeType) {
            Debug.Assert(contentIndex <= contentEvents.Length); 
            ValidatingReaderNodeData contentInfo = contentEvents[contentIndex];
            if (contentInfo != null) { 
                contentInfo.Clear(nodeType); 
                contentIndex++;
                return contentInfo; 
            }
            if (contentIndex >= contentEvents.Length -1 ) { //reached capacity of array, Need to increase capacity to twice the initial
                ValidatingReaderNodeData[] newContentEvents = new ValidatingReaderNodeData[contentEvents.Length * 2];
                Array.Copy(contentEvents, 0, newContentEvents, 0, contentEvents.Length); 
                contentEvents = newContentEvents;
            } 
            contentInfo = contentEvents[contentIndex]; 
            if (contentInfo == null) {
                contentInfo = new ValidatingReaderNodeData(nodeType); 
                contentEvents[contentIndex] = contentInfo;
            }
            contentIndex++;
            return contentInfo; 
        }
 
        private void RecordAttributes() { 
            Debug.Assert(coreReader.NodeType == XmlNodeType.Element);
            ValidatingReaderNodeData attInfo; 
            attributeCount = coreReader.AttributeCount;
            if (coreReader.MoveToFirstAttribute()) {
                int attIndex = 0;
                do { 
                    attInfo = AddAttribute(attIndex);
                    attInfo.SetItemData(coreReader.LocalName, coreReader.Prefix, coreReader.NamespaceURI, coreReader.Depth); 
                    attInfo.SetLineInfo(lineInfo); 
                    attInfo.RawValue = coreReader.Value;
                    attIndex++; 
                } while (coreReader.MoveToNextAttribute());
 		        coreReader.MoveToElement();
            }
        } 

        private int GetAttributeIndexWithoutPrefix(string name) { 
            name = coreReaderNameTable.Get(name); 
            if ( name == null ) {
                return -1; 
            }
            ValidatingReaderNodeData attribute;
            for ( int i = 0; i < attributeCount; i++ ) {
                attribute = attributeEvents[i]; 
                if ( Ref.Equal(attribute.LocalName, name) && attribute.Prefix.Length == 0 ) {
                    return i; 
                } 
            }
            return -1; 
        }

        private int GetAttributeIndexWithPrefix(string name) {
            name = coreReaderNameTable.Get(name); 
            if ( name == null ) {
                return -1; 
            } 
            ValidatingReaderNodeData attribute;
            for ( int i = 0; i < attributeCount; i++ ) { 
                attribute = attributeEvents[i];
                if ( Ref.Equal(attribute.GetAtomizedNameWPrefix(coreReaderNameTable), name) ) {
                    return i;
                } 
            }
            return -1; 
        } 

        private ValidatingReaderNodeData CreateDummyTextNode(string attributeValue, int depth) { 
            if (textNode == null) {
                textNode = new ValidatingReaderNodeData(XmlNodeType.Text);
            }
            textNode.Depth = depth; 
            textNode.RawValue = attributeValue;
            return textNode; 
        } 
    }
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.


                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK