File: System\Xml\Core\XsdValidatingReader.cs
Project: ndp\fx\src\Xml\System.Xml.csproj (System.Xml)

//------------------------------------------------------------------------------
// <copyright file="XsdValidatingReader.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>
// <owner current="true" primary="true">Microsoft</owner>
//------------------------------------------------------------------------------
 
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;
using System.Collections.Generic;
using System.Runtime.Versioning;
 
namespace System.Xml {
 
    internal delegate void CachingEventHandler(XsdCachingReader cachingReader);
 
    internal class AttributePSVIInfo {
        internal string localName;
        internal string namespaceUri;
        internal object typedAttributeValue;
        internal XmlSchemaInfo attributeSchemaInfo;
 
        internal AttributePSVIInfo() {
            attributeSchemaInfo = new XmlSchemaInfo();
        }
 
        internal void Reset() {
            typedAttributeValue = null;
            localName = string.Empty;
            namespaceUri = string.Empty;
            attributeSchemaInfo.Clear();
        }
    }
 
    internal partial class XsdValidatingReader : XmlReader, IXmlSchemaInfo, IXmlLineInfo, IXmlNamespaceResolver {
 
        private enum ValidatingReaderState {
            None = 0,
            Init = 1,
            Read = 2,
            OnDefaultAttribute = -1,
            OnReadAttributeValue = -2,
            OnAttribute = 3,
            ClearAttributes = 4,
            ParseInlineSchema = 5,
            ReadAhead = 6,
            OnReadBinaryContent = 7,
            ReaderClosed = 8,
            EOF = 9,
            Error = 10,
        }
        //Validation
        private XmlReader coreReader;
        private IXmlNamespaceResolver coreReaderNSResolver;
        private IXmlNamespaceResolver thisNSResolver;
        private XmlSchemaValidator validator;
        private XmlResolver xmlResolver;
        private ValidationEventHandler validationEvent;
        private ValidatingReaderState validationState;
        private XmlValueGetter valueGetter;
 
        // namespace management
        XmlNamespaceManager nsManager;
        bool manageNamespaces;
        bool processInlineSchema;
        bool replayCache;
 
        //Current Node handling
        private ValidatingReaderNodeData cachedNode; //Used to cache current node when looking ahead or default attributes                           
        private AttributePSVIInfo attributePSVI;
 
        //Attributes
        int attributeCount; //Total count of attributes including default
        int coreReaderAttributeCount;
        int currentAttrIndex;
        AttributePSVIInfo[] attributePSVINodes;
        ArrayList defaultAttributes;
 
        //Inline Schema
        private Parser inlineSchemaParser = null;
 
        //Typed Value & PSVI
        private object atomicValue;
        private XmlSchemaInfo xmlSchemaInfo;
        
        // original string of the atomic value
        private string originalAtomicValueString;
 
        //cached coreReader information
        private XmlNameTable coreReaderNameTable;
        private XsdCachingReader cachingReader;
 
        //ReadAttributeValue TextNode
        private ValidatingReaderNodeData textNode;
 
        //To avoid SchemaNames creation
        private string NsXmlNs;
        private string NsXs;
        private string NsXsi;
        private string XsiType;
        private string XsiNil;
        private string XsdSchema;
        private string XsiSchemaLocation;
        private string XsiNoNamespaceSchemaLocation;
 
        //XmlCharType instance
        private XmlCharType xmlCharType = XmlCharType.Instance;
 
        //Underlying reader's IXmlLineInfo
        IXmlLineInfo lineInfo;
 
        // helpers for Read[Element]ContentAs{Base64,BinHex} methods
        ReadContentAsBinaryHelper readBinaryHelper;
        ValidatingReaderState savedState;
 
        //Constants
        private const int InitialAttributeCount = 8;
 
        static volatile Type TypeOfString;
 
        //Constructor
        internal XsdValidatingReader(XmlReader reader, XmlResolver xmlResolver, XmlReaderSettings readerSettings, XmlSchemaObject partialValidationType) {
            this.coreReader = reader;
            this.coreReaderNSResolver = reader as IXmlNamespaceResolver;
            this.lineInfo = reader as IXmlLineInfo;
            coreReaderNameTable = coreReader.NameTable;
            if (coreReaderNSResolver == null) {
                nsManager = new XmlNamespaceManager(coreReaderNameTable);
                manageNamespaces = true;
            }
            thisNSResolver = this as IXmlNamespaceResolver;
            this.xmlResolver = xmlResolver;
            this.processInlineSchema = (readerSettings.ValidationFlags & XmlSchemaValidationFlags.ProcessInlineSchema) != 0;
            Init();
            SetupValidator(readerSettings, reader, partialValidationType);
            validationEvent = readerSettings.GetEventHandler();
        }
 
        internal XsdValidatingReader(XmlReader reader, XmlResolver xmlResolver, XmlReaderSettings readerSettings)
            :
        this(reader, xmlResolver, readerSettings, null) { }
 
        private void Init() {
            validationState = ValidatingReaderState.Init;
            defaultAttributes = new ArrayList();
            currentAttrIndex = -1;
            attributePSVINodes = new AttributePSVIInfo[InitialAttributeCount];
            valueGetter = new XmlValueGetter(GetStringValue);
            TypeOfString = typeof(System.String);
            xmlSchemaInfo = new XmlSchemaInfo();
 
            //Add common strings to be compared to NameTable
            NsXmlNs = coreReaderNameTable.Add(XmlReservedNs.NsXmlNs);
            NsXs = coreReaderNameTable.Add(XmlReservedNs.NsXs);
            NsXsi = coreReaderNameTable.Add(XmlReservedNs.NsXsi);
            XsiType = coreReaderNameTable.Add("type");
            XsiNil = coreReaderNameTable.Add("nil");
            XsiSchemaLocation = coreReaderNameTable.Add("schemaLocation");
            XsiNoNamespaceSchemaLocation = coreReaderNameTable.Add("noNamespaceSchemaLocation");
            XsdSchema = coreReaderNameTable.Add("schema");
        }
 
        private void SetupValidator(XmlReaderSettings readerSettings, XmlReader reader, XmlSchemaObject partialValidationType) {
            validator = new XmlSchemaValidator(coreReaderNameTable, readerSettings.Schemas, thisNSResolver, readerSettings.ValidationFlags);
            validator.XmlResolver = this.xmlResolver;
            validator.SourceUri = XmlConvert.ToUri(reader.BaseURI); //Not using XmlResolver.ResolveUri as it checks for relative Uris,reader.BaseURI will be absolute file paths or string.Empty
            validator.ValidationEventSender = this;
            validator.ValidationEventHandler += readerSettings.GetEventHandler();
            validator.LineInfoProvider = this.lineInfo;
            if (validator.ProcessSchemaHints) {
                validator.SchemaSet.ReaderSettings.DtdProcessing = readerSettings.DtdProcessing;
            }
            validator.SetDtdSchemaInfo(reader.DtdInfo);
            if (partialValidationType != null) {
                validator.Initialize(partialValidationType);
            }
            else {
                validator.Initialize();
            }
        }
 
        // Settings
        public override XmlReaderSettings Settings {
            get {
                XmlReaderSettings settings = coreReader.Settings;
                if (null != settings)
                    settings = settings.Clone();
                if (settings == null) {
                    settings = new XmlReaderSettings();
                }
                settings.Schemas = validator.SchemaSet;
                settings.ValidationType = ValidationType.Schema;
                settings.ValidationFlags = validator.ValidationFlags;
                settings.ReadOnly = true;
                return settings;
            }
        }
 
        // Node Properties
 
        // Gets the type of the current node.
        public override XmlNodeType NodeType {
            get {
                if ((int)validationState < 0) {
                    return cachedNode.NodeType;
                }
                else { 
                    XmlNodeType nodeType = coreReader.NodeType;
                    //Check for significant whitespace
                    if (nodeType == XmlNodeType.Whitespace && (validator.CurrentContentType == XmlSchemaContentType.TextOnly || validator.CurrentContentType == XmlSchemaContentType.Mixed)) {
                        return XmlNodeType.SignificantWhitespace;
                    }
                    return nodeType;
                }
            }
        }
 
        // Gets the name of the current node, including the namespace prefix.
        public override string Name {
            get {
                if (validationState == ValidatingReaderState.OnDefaultAttribute) {
                    string prefix = validator.GetDefaultAttributePrefix(cachedNode.Namespace);
                    if (prefix != null && prefix.Length != 0) {
                        return string.Concat(prefix + ":" + cachedNode.LocalName);
                    }
                    return cachedNode.LocalName;
                }
                return coreReader.Name;
            }
        }
 
        // Gets the name of the current node without the namespace prefix.
        public override string LocalName {
            get {
                if ((int)validationState < 0) {
                    return cachedNode.LocalName;
                }
                return coreReader.LocalName;
            }
        }
 
        // Gets the namespace URN (as defined in the W3C Namespace Specification) of the current namespace scope.
        public override string NamespaceURI {
            get {
                if ((int)validationState < 0) {
                    return cachedNode.Namespace;
                }
                return coreReader.NamespaceURI;
            }
        }
 
        // Gets the namespace prefix associated with the current node.
        public override string Prefix {
            get {
                if ((int)validationState < 0) {
                    return cachedNode.Prefix;
                }
                return coreReader.Prefix;
            }
        }
 
        // Gets a value indicating whether the current node can have a non-empty Value
        public override bool HasValue {
            get {
                if ((int)validationState < 0) {
                    return true;
                }
                return coreReader.HasValue;
            }
        }
 
        // Gets the text value of the current node.
        public override string Value {
            get {
                if ((int)validationState < 0) {
                    return cachedNode.RawValue;
                }
                return coreReader.Value;
            }
        }
 
        // Gets the depth of the current node in the XML element stack.
        public override int Depth {
            get {
                if ((int)validationState < 0) {
                    return cachedNode.Depth;
                }
                return coreReader.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, <MyElement/>).
        public override bool IsEmptyElement {
            get {
                return coreReader.IsEmptyElement;
            }
        }
 
        // 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 {
                if (validationState == ValidatingReaderState.OnDefaultAttribute) { //XSD default attributes
                    return true;
                }
                return coreReader.IsDefault; //This is DTD Default attribute
            }
        }
 
        // 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;
            }
        }
 
        public override IXmlSchemaInfo SchemaInfo {
            get {
                return this as IXmlSchemaInfo;
            }
        }
 
        public override System.Type ValueType {
            get {
                switch (NodeType) {
                    case XmlNodeType.Element:
                    case XmlNodeType.EndElement: //
                        if (xmlSchemaInfo.ContentType == XmlSchemaContentType.TextOnly) {
                            return xmlSchemaInfo.SchemaType.Datatype.ValueType;
                        }
                        goto default;
 
                    case XmlNodeType.Attribute:
                        if (attributePSVI != null && AttributeSchemaInfo.ContentType == XmlSchemaContentType.TextOnly) {
                            return AttributeSchemaInfo.SchemaType.Datatype.ValueType;
                        }
                        goto default;
 
                    default:
                        return TypeOfString;
                }
            }
        }
 
        public override  object  ReadContentAsObject() {
            if (!CanReadContentAs(this.NodeType)) {
                throw CreateReadContentAsException("ReadContentAsObject");
            }
 
            return InternalReadContentAsObject(true);
 
        }
 
        public override  bool  ReadContentAsBoolean() {
            if (!CanReadContentAs(this.NodeType)) {
                throw CreateReadContentAsException("ReadContentAsBoolean");
            }
            object typedValue = InternalReadContentAsObject();
            XmlSchemaType xmlType = NodeType == XmlNodeType.Attribute ? AttributeXmlType : ElementXmlType;
            try {
                if (xmlType != null) {
                    return xmlType.ValueConverter.ToBoolean(typedValue);
                }
                else {
                    return XmlUntypedConverter.Untyped.ToBoolean(typedValue);
                }
            }
            catch (InvalidCastException e) {
                throw new XmlException(Res.Xml_ReadContentAsFormatException, "Boolean", e, this as IXmlLineInfo);
            }
            catch (FormatException e) {
                throw new XmlException(Res.Xml_ReadContentAsFormatException, "Boolean", e, this as IXmlLineInfo);
            }
            catch (OverflowException e) {
                throw new XmlException(Res.Xml_ReadContentAsFormatException, "Boolean", e, this as IXmlLineInfo);
            }
        }
 
        public override  DateTime  ReadContentAsDateTime() {
            if (!CanReadContentAs(this.NodeType)) {
                throw CreateReadContentAsException("ReadContentAsDateTime");
            }
            object typedValue = InternalReadContentAsObject();
            XmlSchemaType xmlType = NodeType == XmlNodeType.Attribute ? AttributeXmlType : ElementXmlType;
            try {
                if (xmlType != null) {
                    return xmlType.ValueConverter.ToDateTime(typedValue);
                }
                else {
                    return XmlUntypedConverter.Untyped.ToDateTime(typedValue);
                }
            }
            catch (InvalidCastException e) {
                throw new XmlException(Res.Xml_ReadContentAsFormatException, "DateTime", e, this as IXmlLineInfo);
            }
            catch (FormatException e) {
                throw new XmlException(Res.Xml_ReadContentAsFormatException, "DateTime", e, this as IXmlLineInfo);
            }
            catch (OverflowException e) {
                throw new XmlException(Res.Xml_ReadContentAsFormatException, "DateTime", e, this as IXmlLineInfo);
            }
        }
 
        public override  double  ReadContentAsDouble() {
            if (!CanReadContentAs(this.NodeType)) {
                throw CreateReadContentAsException("ReadContentAsDouble");
            }
            object typedValue = InternalReadContentAsObject();
            XmlSchemaType xmlType = NodeType == XmlNodeType.Attribute ? AttributeXmlType : ElementXmlType;
            try {
                if (xmlType != null) {
                    return xmlType.ValueConverter.ToDouble(typedValue);
                }
                else {
                    return XmlUntypedConverter.Untyped.ToDouble(typedValue);
                }
            }
            catch (InvalidCastException e) {
                throw new XmlException(Res.Xml_ReadContentAsFormatException, "Double", e, this as IXmlLineInfo);
            }
            catch (FormatException e) {
                throw new XmlException(Res.Xml_ReadContentAsFormatException, "Double", e, this as IXmlLineInfo);
            }
            catch (OverflowException e) {
                throw new XmlException(Res.Xml_ReadContentAsFormatException, "Double", e, this as IXmlLineInfo);
            }
        }
 
        public override  float  ReadContentAsFloat() {
            if (!CanReadContentAs(this.NodeType)) {
                throw CreateReadContentAsException("ReadContentAsFloat");
            }
            object typedValue = InternalReadContentAsObject();
            XmlSchemaType xmlType = NodeType == XmlNodeType.Attribute ? AttributeXmlType : ElementXmlType;
            try {
                if (xmlType != null) {
                    return xmlType.ValueConverter.ToSingle(typedValue);
                }
                else {
                    return XmlUntypedConverter.Untyped.ToSingle(typedValue);
                }
            }
            catch (InvalidCastException e) {
                throw new XmlException(Res.Xml_ReadContentAsFormatException, "Float", e, this as IXmlLineInfo);
            }
            catch (FormatException e) {
                throw new XmlException(Res.Xml_ReadContentAsFormatException, "Float", e, this as IXmlLineInfo);
            }
            catch (OverflowException e) {
                throw new XmlException(Res.Xml_ReadContentAsFormatException, "Float", e, this as IXmlLineInfo);
            }
        }
 
        public override  decimal  ReadContentAsDecimal() {
            if (!CanReadContentAs(this.NodeType)) {
                throw CreateReadContentAsException("ReadContentAsDecimal");
            }
            object typedValue = InternalReadContentAsObject();
            XmlSchemaType xmlType = NodeType == XmlNodeType.Attribute ? AttributeXmlType : ElementXmlType;
            try {
                if (xmlType != null) {
                    return xmlType.ValueConverter.ToDecimal(typedValue);
                }
                else {
                    return XmlUntypedConverter.Untyped.ToDecimal(typedValue);
                }
            }
            catch (InvalidCastException e) {
                throw new XmlException(Res.Xml_ReadContentAsFormatException, "Decimal", e, this as IXmlLineInfo);
            }
            catch (FormatException e) {
                throw new XmlException(Res.Xml_ReadContentAsFormatException, "Decimal", e, this as IXmlLineInfo);
            }
            catch (OverflowException e) {
                throw new XmlException(Res.Xml_ReadContentAsFormatException, "Decimal", e, this as IXmlLineInfo);
            }
        }
 
        public override  int  ReadContentAsInt() {
            if (!CanReadContentAs(this.NodeType)) {
                throw CreateReadContentAsException("ReadContentAsInt");
            }
            object typedValue = InternalReadContentAsObject();
            XmlSchemaType xmlType = NodeType == XmlNodeType.Attribute ? AttributeXmlType : ElementXmlType;
            try {
                if (xmlType != null) {
                    return xmlType.ValueConverter.ToInt32(typedValue);
                }
                else {
                    return XmlUntypedConverter.Untyped.ToInt32(typedValue);
                }
            }
            catch (InvalidCastException e) {
                throw new XmlException(Res.Xml_ReadContentAsFormatException, "Int", e, this as IXmlLineInfo);
            }
            catch (FormatException e) {
                throw new XmlException(Res.Xml_ReadContentAsFormatException, "Int", e, this as IXmlLineInfo);
            }
            catch (OverflowException e) {
                throw new XmlException(Res.Xml_ReadContentAsFormatException, "Int", e, this as IXmlLineInfo);
            }
        }
 
        public override  long  ReadContentAsLong() {
            if (!CanReadContentAs(this.NodeType)) {
                throw CreateReadContentAsException("ReadContentAsLong");
            }
            object typedValue = InternalReadContentAsObject();
            XmlSchemaType xmlType = NodeType == XmlNodeType.Attribute ? AttributeXmlType : ElementXmlType;
            try {
                if (xmlType != null) {
                    return xmlType.ValueConverter.ToInt64(typedValue);
                }
                else {
                    return XmlUntypedConverter.Untyped.ToInt64(typedValue);
                }
            }
            catch (InvalidCastException e) {
                throw new XmlException(Res.Xml_ReadContentAsFormatException, "Long", e, this as IXmlLineInfo);
            }
            catch (FormatException e) {
                throw new XmlException(Res.Xml_ReadContentAsFormatException, "Long", e, this as IXmlLineInfo);
            }
            catch (OverflowException e) {
                throw new XmlException(Res.Xml_ReadContentAsFormatException, "Long", e, this as IXmlLineInfo);
            }
        }
 
        public override  string  ReadContentAsString() {
            if (!CanReadContentAs(this.NodeType)) {
                throw CreateReadContentAsException("ReadContentAsString");
            }
            object typedValue = InternalReadContentAsObject();
            XmlSchemaType xmlType = NodeType == XmlNodeType.Attribute ? AttributeXmlType : ElementXmlType;
            try {
                if (xmlType != null) {
                    return xmlType.ValueConverter.ToString(typedValue);
                }
                else {
                    return typedValue as string;
                }
            }
            catch (InvalidCastException e) {
                throw new XmlException(Res.Xml_ReadContentAsFormatException, "String", e, this as IXmlLineInfo);
            }
            catch (FormatException e) {
                throw new XmlException(Res.Xml_ReadContentAsFormatException, "String", e, this as IXmlLineInfo);
            }
            catch (OverflowException e) {
                throw new XmlException(Res.Xml_ReadContentAsFormatException, "String", e, this as IXmlLineInfo);
            }
        }
 
        public override  object  ReadContentAs(Type returnType, IXmlNamespaceResolver namespaceResolver) {
            if (!CanReadContentAs(this.NodeType)) {
                throw CreateReadContentAsException("ReadContentAs");
            }
            string originalStringValue;
 
            object typedValue = InternalReadContentAsObject(false, out originalStringValue);
 
            XmlSchemaType xmlType = NodeType == XmlNodeType.Attribute ? AttributeXmlType : ElementXmlType; //
            try {
                if (xmlType != null) {
                    // special-case convertions to DateTimeOffset; typedValue is by default a DateTime 
                    // which cannot preserve time zone, so we need to convert from the original string
                    if (returnType == typeof(DateTimeOffset) && xmlType.Datatype is Datatype_dateTimeBase) {
                        typedValue = originalStringValue;
                    }
                    return xmlType.ValueConverter.ChangeType(typedValue, returnType);
                }
                else {
                    return XmlUntypedConverter.Untyped.ChangeType(typedValue, returnType, namespaceResolver);
                }
            }
            catch (FormatException e) {
                throw new XmlException(Res.Xml_ReadContentAsFormatException, returnType.ToString(), e, this as IXmlLineInfo);
            }
            catch (InvalidCastException e) {
                throw new XmlException(Res.Xml_ReadContentAsFormatException, returnType.ToString(), e, this as IXmlLineInfo);
            }
            catch (OverflowException e) {
                throw new XmlException(Res.Xml_ReadContentAsFormatException, returnType.ToString(), e, this as IXmlLineInfo);
            }
        }
 
        public override  object  ReadElementContentAsObject() {
            if (this.NodeType != XmlNodeType.Element) {
                throw CreateReadElementContentAsException("ReadElementContentAsObject");
            }
            XmlSchemaType xmlType;
 
            return InternalReadElementContentAsObject(out xmlType, true);
 
        }
 
        public override  bool  ReadElementContentAsBoolean() {
            if (this.NodeType != XmlNodeType.Element) {
                throw CreateReadElementContentAsException("ReadElementContentAsBoolean");
            }
            XmlSchemaType xmlType;
 
            object typedValue = InternalReadElementContentAsObject(out xmlType);
 
            try {
                if (xmlType != null) {
                    return xmlType.ValueConverter.ToBoolean(typedValue);
                }
                else {
                    return XmlUntypedConverter.Untyped.ToBoolean(typedValue);
                }
            }
            catch (FormatException e) {
                throw new XmlException(Res.Xml_ReadContentAsFormatException, "Boolean", e, this as IXmlLineInfo);
            }
            catch (InvalidCastException e) {
                throw new XmlException(Res.Xml_ReadContentAsFormatException, "Boolean", e, this as IXmlLineInfo);
            }
            catch (OverflowException e) {
                throw new XmlException(Res.Xml_ReadContentAsFormatException, "Boolean", e, this as IXmlLineInfo);
            }
        }
 
        public override  DateTime  ReadElementContentAsDateTime() {
            if (this.NodeType != XmlNodeType.Element) {
                throw CreateReadElementContentAsException("ReadElementContentAsDateTime");
            }
            XmlSchemaType xmlType;
 
            object typedValue = InternalReadElementContentAsObject(out xmlType);
 
            try {
                if (xmlType != null) {
                    return xmlType.ValueConverter.ToDateTime(typedValue);
                }
                else {
                    return XmlUntypedConverter.Untyped.ToDateTime(typedValue);
                }
            }
            catch (FormatException e) {
                throw new XmlException(Res.Xml_ReadContentAsFormatException, "DateTime", e, this as IXmlLineInfo);
            }
            catch (InvalidCastException e) {
                throw new XmlException(Res.Xml_ReadContentAsFormatException, "DateTime", e, this as IXmlLineInfo);
            }
            catch (OverflowException e) {
                throw new XmlException(Res.Xml_ReadContentAsFormatException, "DateTime", e, this as IXmlLineInfo);
            }
        }
 
        public override  double  ReadElementContentAsDouble() {
            if (this.NodeType != XmlNodeType.Element) {
                throw CreateReadElementContentAsException("ReadElementContentAsDouble");
            }
            XmlSchemaType xmlType;
 
            object typedValue = InternalReadElementContentAsObject(out xmlType);
 
            try {
                if (xmlType != null) {
                    return xmlType.ValueConverter.ToDouble(typedValue);
                }
                else {
                    return XmlUntypedConverter.Untyped.ToDouble(typedValue);
                }
            }
            catch (FormatException e) {
                throw new XmlException(Res.Xml_ReadContentAsFormatException, "Double", e, this as IXmlLineInfo);
            }
            catch (InvalidCastException e) {
                throw new XmlException(Res.Xml_ReadContentAsFormatException, "Double", e, this as IXmlLineInfo);
            }
            catch (OverflowException e) {
                throw new XmlException(Res.Xml_ReadContentAsFormatException, "Double", e, this as IXmlLineInfo);
            }
        }
 
        public override  float  ReadElementContentAsFloat() {
            if (this.NodeType != XmlNodeType.Element) {
                throw CreateReadElementContentAsException("ReadElementContentAsFloat");
            }
            XmlSchemaType xmlType;
 
            object typedValue = InternalReadElementContentAsObject(out xmlType);
 
            try {
                if (xmlType != null) {
                    return xmlType.ValueConverter.ToSingle(typedValue);
                }
                else {
                    return XmlUntypedConverter.Untyped.ToSingle(typedValue);
                }
            }
            catch (FormatException e) {
                throw new XmlException(Res.Xml_ReadContentAsFormatException, "Float", e, this as IXmlLineInfo);
            }
            catch (InvalidCastException e) {
                throw new XmlException(Res.Xml_ReadContentAsFormatException, "Float", e, this as IXmlLineInfo);
            }
            catch (OverflowException e) {
                throw new XmlException(Res.Xml_ReadContentAsFormatException, "Float", e, this as IXmlLineInfo);
            }
        }
 
        public override  Decimal  ReadElementContentAsDecimal() {
            if (this.NodeType != XmlNodeType.Element) {
                throw CreateReadElementContentAsException("ReadElementContentAsDecimal");
            }
            XmlSchemaType xmlType;
 
            object typedValue = InternalReadElementContentAsObject(out xmlType);
 
            try {
                if (xmlType != null) {
                    return xmlType.ValueConverter.ToDecimal(typedValue);
                }
                else {
                    return XmlUntypedConverter.Untyped.ToDecimal(typedValue);
                }
            }
            catch (FormatException e) {
                throw new XmlException(Res.Xml_ReadContentAsFormatException, "Decimal", e, this as IXmlLineInfo);
            }
            catch (InvalidCastException e) {
                throw new XmlException(Res.Xml_ReadContentAsFormatException, "Decimal", e, this as IXmlLineInfo);
            }
            catch (OverflowException e) {
                throw new XmlException(Res.Xml_ReadContentAsFormatException, "Decimal", e, this as IXmlLineInfo);
            }
        }
 
        public override  int  ReadElementContentAsInt() {
            if (this.NodeType != XmlNodeType.Element) {
                throw CreateReadElementContentAsException("ReadElementContentAsInt");
            }
            XmlSchemaType xmlType;
 
            object typedValue = InternalReadElementContentAsObject(out xmlType);
 
            try {
                if (xmlType != null) {
                    return xmlType.ValueConverter.ToInt32(typedValue);
                }
                else {
                    return XmlUntypedConverter.Untyped.ToInt32(typedValue);
                }
            }
            catch (FormatException e) {
                throw new XmlException(Res.Xml_ReadContentAsFormatException, "Int", e, this as IXmlLineInfo);
            }
            catch (InvalidCastException e) {
                throw new XmlException(Res.Xml_ReadContentAsFormatException, "Int", e, this as IXmlLineInfo);
            }
            catch (OverflowException e) {
                throw new XmlException(Res.Xml_ReadContentAsFormatException, "Int", e, this as IXmlLineInfo);
            }
        }
 
        public override  long  ReadElementContentAsLong() {
            if (this.NodeType != XmlNodeType.Element) {
                throw CreateReadElementContentAsException("ReadElementContentAsLong");
            }
            XmlSchemaType xmlType;
 
            object typedValue = InternalReadElementContentAsObject(out xmlType);
 
            try {
                if (xmlType != null) {
                    return xmlType.ValueConverter.ToInt64(typedValue);
                }
                else {
                    return XmlUntypedConverter.Untyped.ToInt64(typedValue);
                }
            }
            catch (FormatException e) {
                throw new XmlException(Res.Xml_ReadContentAsFormatException, "Long", e, this as IXmlLineInfo);
            }
            catch (InvalidCastException e) {
                throw new XmlException(Res.Xml_ReadContentAsFormatException, "Long", e, this as IXmlLineInfo);
            }
            catch (OverflowException e) {
                throw new XmlException(Res.Xml_ReadContentAsFormatException, "Long", e, this as IXmlLineInfo);
            }
        }
 
        public override  string  ReadElementContentAsString() {
            if (this.NodeType != XmlNodeType.Element) {
                throw CreateReadElementContentAsException("ReadElementContentAsString");
            }
            XmlSchemaType xmlType;
 
            object typedValue = InternalReadElementContentAsObject(out xmlType);
 
            try {
                if (xmlType != null) {
                    return xmlType.ValueConverter.ToString(typedValue);
                }
                else {
                    return typedValue as string;
                }
            }
            catch (InvalidCastException e) {
                throw new XmlException(Res.Xml_ReadContentAsFormatException, "String", e, this as IXmlLineInfo);
            }
            catch (FormatException e) {
                throw new XmlException(Res.Xml_ReadContentAsFormatException, "String", e, this as IXmlLineInfo);
            }
            catch (OverflowException e) {
                throw new XmlException(Res.Xml_ReadContentAsFormatException, "String", e, this as IXmlLineInfo);
            }
        }
 
        public override  object  ReadElementContentAs(Type returnType, IXmlNamespaceResolver namespaceResolver) {
            if (this.NodeType != XmlNodeType.Element) {
                throw CreateReadElementContentAsException("ReadElementContentAs");
            }
            XmlSchemaType xmlType;
            string originalStringValue;
 
            object typedValue = InternalReadElementContentAsObject(out xmlType, false, out originalStringValue);
 
            try {
                if (xmlType != null) {
                    // special-case convertions to DateTimeOffset; typedValue is by default a DateTime 
                    // which cannot preserve time zone, so we need to convert from the original string
                    if (returnType == typeof(DateTimeOffset) && xmlType.Datatype is Datatype_dateTimeBase) { 
                        typedValue = originalStringValue;
                    }
                    return xmlType.ValueConverter.ChangeType(typedValue, returnType, namespaceResolver);
                }
                else {
                    return XmlUntypedConverter.Untyped.ChangeType(typedValue, returnType, namespaceResolver);
                }
            }
            catch (FormatException e) {
                throw new XmlException(Res.Xml_ReadContentAsFormatException, returnType.ToString(), e, this as IXmlLineInfo);
            }
            catch (InvalidCastException e) {
                throw new XmlException(Res.Xml_ReadContentAsFormatException, returnType.ToString(), e, this as IXmlLineInfo);
            }
            catch (OverflowException e) {
                throw new XmlException(Res.Xml_ReadContentAsFormatException, returnType.ToString(), e, this as IXmlLineInfo);
            }
        }
 
        // 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) {
            string attValue = coreReader.GetAttribute(name);
 
            if (attValue == null && attributeCount > 0) { //Could be default attribute
                ValidatingReaderNodeData defaultNode = GetDefaultAttribute(name, false);
                if (defaultNode != null) { //Default found
                    attValue = defaultNode.RawValue;
                }
            }
            return attValue;
        }
 
        // Gets the value of the attribute with the specified LocalName and NamespaceURI.
        public override string GetAttribute(string name, string namespaceURI) {
            string attValue = coreReader.GetAttribute(name, namespaceURI);
 
            if (attValue == null && attributeCount > 0) { //Could be default attribute
                namespaceURI = (namespaceURI == null) ? string.Empty : coreReaderNameTable.Get(namespaceURI);
                name = coreReaderNameTable.Get(name); 
                if (name == null || namespaceURI == null) { //Attribute not present since we did not see it
                    return null;
                }
                ValidatingReaderNodeData attNode = GetDefaultAttribute(name, namespaceURI, false);
                if (attNode != null) {
                    return attNode.RawValue;
                }
            }
            return attValue;
        }
 
        // Gets the value of the attribute with the specified index.
        public override string GetAttribute(int i) {
            if (attributeCount == 0) {
                return null;
            }
            if (i < coreReaderAttributeCount) {
                return coreReader.GetAttribute(i);
            }
            else {
                int defaultIndex = i - coreReaderAttributeCount;
                ValidatingReaderNodeData attNode = (ValidatingReaderNodeData)defaultAttributes[defaultIndex];
                Debug.Assert(attNode != null);
                return attNode.RawValue;
            }
        }
 
        // Moves to the attribute with the specified Name
        public override bool MoveToAttribute(string name) {
 
            if (coreReader.MoveToAttribute(name)) {
                validationState = ValidatingReaderState.OnAttribute;
                attributePSVI = GetAttributePSVI(name);
                goto Found;
            }
            else if (attributeCount > 0) { //Default attribute
                ValidatingReaderNodeData defaultNode = GetDefaultAttribute(name, true);
                if (defaultNode != null) {
                    validationState = ValidatingReaderState.OnDefaultAttribute;
                    attributePSVI = defaultNode.AttInfo;
                    cachedNode = defaultNode;
                    goto Found;
                }
            }
            return false;
        Found:
            if (validationState == ValidatingReaderState.OnReadBinaryContent) {
                readBinaryHelper.Finish();
                validationState = savedState;
            }
            return true;
        }
 
        // Moves to the attribute with the specified LocalName and NamespaceURI
        public override bool MoveToAttribute(string name, string ns) {
            //Check atomized local name and ns
            name = coreReaderNameTable.Get(name);
            ns = ns != null ? coreReaderNameTable.Get(ns) : string.Empty;
            if (name == null || ns == null) { //Name or ns not found in the nameTable, then attribute is not found
                return false;
            }
            if (coreReader.MoveToAttribute(name, ns)) {
                validationState = ValidatingReaderState.OnAttribute;
                if (inlineSchemaParser == null) {
                    attributePSVI = GetAttributePSVI(name, ns);
                    Debug.Assert(attributePSVI != null);
                }
                else { //Parsing inline schema, no PSVI for schema attributes
                    attributePSVI = null;
                }
                goto Found;
            }
            else { //Default attribute
                ValidatingReaderNodeData defaultNode = GetDefaultAttribute(name, ns, true);
                if (defaultNode != null) {
                    attributePSVI = defaultNode.AttInfo;
                    cachedNode = defaultNode;
                    validationState = ValidatingReaderState.OnDefaultAttribute;
                    goto Found;
                }
            }
            return false;
        Found:
            if (validationState == ValidatingReaderState.OnReadBinaryContent) {
                readBinaryHelper.Finish();
                validationState = savedState;
            }
            return true;
        }
 
        // 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;
            if (i < coreReaderAttributeCount) { //reader attribute
                coreReader.MoveToAttribute(i);
                if (inlineSchemaParser == null) {
                    attributePSVI = attributePSVINodes[i];
                }
                else {
                    attributePSVI = null;
                }
                validationState = ValidatingReaderState.OnAttribute;
            }
            else { //default attribute
                int defaultIndex = i - coreReaderAttributeCount;
                cachedNode = (ValidatingReaderNodeData)defaultAttributes[defaultIndex];
                attributePSVI = cachedNode.AttInfo;
                validationState = ValidatingReaderState.OnDefaultAttribute;
            }
            if (validationState == ValidatingReaderState.OnReadBinaryContent) {
                readBinaryHelper.Finish();
                validationState = savedState;
            }
        }
 
        // Moves to the first attribute.
        public override bool MoveToFirstAttribute() {
            if (coreReader.MoveToFirstAttribute()) {
                currentAttrIndex = 0;
                if (inlineSchemaParser == null) {
                    attributePSVI = attributePSVINodes[0];
                }
                else {
                    attributePSVI = null;
                }
                validationState = ValidatingReaderState.OnAttribute;
                goto Found;
            }
            else if (defaultAttributes.Count > 0) { //check for default
                cachedNode = (ValidatingReaderNodeData)defaultAttributes[0];
                attributePSVI = cachedNode.AttInfo;
                currentAttrIndex = 0;
                validationState = ValidatingReaderState.OnDefaultAttribute;
                goto Found;
            }
            return false;
        Found:
            if (validationState == ValidatingReaderState.OnReadBinaryContent) {
                readBinaryHelper.Finish();
                validationState = savedState;
            }
            return true;
        }
 
        // Moves to the next attribute.
        public override bool MoveToNextAttribute() {
            if (currentAttrIndex + 1 < coreReaderAttributeCount) {
                bool moveTo = coreReader.MoveToNextAttribute();
                Debug.Assert(moveTo);
                currentAttrIndex++;
                if (inlineSchemaParser == null) {
                    attributePSVI = attributePSVINodes[currentAttrIndex];
                }
                else {
                    attributePSVI = null;
                }
                validationState = ValidatingReaderState.OnAttribute;
                goto Found;
            }
            else if (currentAttrIndex + 1 < attributeCount) { //default attribute
                int defaultIndex = ++currentAttrIndex - coreReaderAttributeCount;
                cachedNode = (ValidatingReaderNodeData)defaultAttributes[defaultIndex];
                attributePSVI = cachedNode.AttInfo;
                validationState = ValidatingReaderState.OnDefaultAttribute;
                goto Found;
            }
            return false;
        Found:
            if (validationState == ValidatingReaderState.OnReadBinaryContent) {
                readBinaryHelper.Finish();
                validationState = savedState;
            }
            return true;
        }
 
        // Moves to the element that contains the current attribute node.
        public override bool MoveToElement() {
            if (coreReader.MoveToElement() || (int)validationState < 0) { //states OnDefaultAttribute or OnReadAttributeValue
                currentAttrIndex = -1;
                validationState = ValidatingReaderState.ClearAttributes;
                return true;
            }
            return false;
        }
 
        // Reads the next node from the stream/TextReader.
        public override  bool  Read() {
            switch (validationState) {
                case ValidatingReaderState.Read:
                    if (coreReader.Read()) {
                        ProcessReaderEvent();
                        return true;
                    }
                    else {
                        validator.EndValidation();
                        if (coreReader.EOF) {
                            validationState = ValidatingReaderState.EOF;
                        }
                        return false;
                    }
 
                case ValidatingReaderState.ParseInlineSchema:
                    ProcessInlineSchema();
                    return true;
 
                case ValidatingReaderState.OnAttribute:
                case ValidatingReaderState.OnDefaultAttribute:
                case ValidatingReaderState.ClearAttributes:
                case ValidatingReaderState.OnReadAttributeValue:
                    ClearAttributesInfo();
                    if (inlineSchemaParser != null) {
                        validationState = ValidatingReaderState.ParseInlineSchema;
                        goto case ValidatingReaderState.ParseInlineSchema;
                    }
                    else {
                        validationState = ValidatingReaderState.Read;
                        goto case ValidatingReaderState.Read;
                    }
 
                case ValidatingReaderState.ReadAhead: //Will enter here on calling Skip() 
                    ClearAttributesInfo();
                    ProcessReaderEvent();
                    validationState = ValidatingReaderState.Read;
                    return true;
 
                case ValidatingReaderState.OnReadBinaryContent:
                    validationState = savedState;
                    readBinaryHelper.Finish();
                    return Read();
 
                case ValidatingReaderState.Init:
                    validationState = ValidatingReaderState.Read;
                    if (coreReader.ReadState == ReadState.Interactive) { //If the underlying reader is already positioned on a ndoe, process it
                        ProcessReaderEvent();
                        return true;
                    }
                    else {
                        goto case ValidatingReaderState.Read;
                    }
 
                case ValidatingReaderState.ReaderClosed:
                case ValidatingReaderState.EOF:
                    return false;
 
                default:
                    return false;
            }
        }
 
        // Gets a value indicating whether XmlReader is positioned at the end of the stream/TextReader.
        public override bool EOF {
            get {
                return coreReader.EOF;
            }
        }
 
        // Closes the stream, changes the ReadState to Closed, and sets all the properties back to zero.
        public override void Close() {
            coreReader.Close();
            validationState = ValidatingReaderState.ReaderClosed;
        }
 
        // Returns the read state of the XmlReader.
        public override ReadState ReadState {
            get {
                return (validationState == ValidatingReaderState.Init) ? ReadState.Initial : coreReader.ReadState;
            }
        }
 
        // Skips to the end tag of the current element.
        public override void Skip() {
            int startDepth = Depth;
            switch (NodeType) {
                case XmlNodeType.Element:
                    if (coreReader.IsEmptyElement) {
                        break;
                    }
                    bool callSkipToEndElem = true;
                    //If union and unionValue has been parsed till EndElement, then validator.ValidateEndElement has been called
                    //Hence should not call SkipToEndElement as the current context has already been popped in the validator
                    if ((xmlSchemaInfo.IsUnionType || xmlSchemaInfo.IsDefault) && coreReader is XsdCachingReader) {
                        callSkipToEndElem = false;
                    }
                    coreReader.Skip();
                    validationState = ValidatingReaderState.ReadAhead;
                    if (callSkipToEndElem) {
                        validator.SkipToEndElement(xmlSchemaInfo);
                    }
                    break;
 
                case XmlNodeType.Attribute:
                    MoveToElement();
                    goto case XmlNodeType.Element;
            }
            //For all other NodeTypes Skip() same as Read()
            Read();
            return;
        }
 
        // 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 thisNSResolver.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() {
            if (validationState == ValidatingReaderState.OnReadBinaryContent) {
                readBinaryHelper.Finish();
                validationState = savedState;
            }
            if (NodeType == XmlNodeType.Attribute) {
                if (validationState == ValidatingReaderState.OnDefaultAttribute) {
                    cachedNode = CreateDummyTextNode(cachedNode.RawValue, cachedNode.Depth + 1);
                    validationState = ValidatingReaderState.OnReadAttributeValue;
                    return true;
                }
                return coreReader.ReadAttributeValue();
            }
            return false;
        }
 
        public override bool CanReadBinaryContent {
            get {
                return true;
            }
        }
 
        public override  int  ReadContentAsBase64(byte[] buffer, int index, int count) {
            if (ReadState != ReadState.Interactive) {
                return 0;
            }
 
            // init ReadContentAsBinaryHelper when called first time
            if (validationState != ValidatingReaderState.OnReadBinaryContent) {
                readBinaryHelper = ReadContentAsBinaryHelper.CreateOrReset(readBinaryHelper, this);
                savedState = validationState;
            }
 
            // restore original state in order to have a normal Read() behavior when called from readBinaryHelper
            validationState = savedState;
 
            // call to the helper
            int readCount = readBinaryHelper.ReadContentAsBase64(buffer, index, count);
 
            // set OnReadBinaryContent state again and return
            savedState = validationState;
            validationState = ValidatingReaderState.OnReadBinaryContent;
            return readCount;
        }
 
        public override  int  ReadContentAsBinHex(byte[] buffer, int index, int count) {
            if (ReadState != ReadState.Interactive) {
                return 0;
            }
 
            // init ReadContentAsBinaryHelper when called first time
            if (validationState != ValidatingReaderState.OnReadBinaryContent) {
                readBinaryHelper = ReadContentAsBinaryHelper.CreateOrReset(readBinaryHelper, this);
                savedState = validationState;
            }
 
            // restore original state in order to have a normal Read() behavior when called from readBinaryHelper
            validationState = savedState;
 
            // call to the helper
            int readCount = readBinaryHelper.ReadContentAsBinHex(buffer, index, count);
 
            // set OnReadBinaryContent state again and return
            savedState = validationState;
            validationState = ValidatingReaderState.OnReadBinaryContent;
            return readCount;
        }
 
        public override  int  ReadElementContentAsBase64(byte[] buffer, int index, int count) {
            if (ReadState != ReadState.Interactive) {
                return 0;
            }
 
            // init ReadContentAsBinaryHelper when called first time
            if (validationState != ValidatingReaderState.OnReadBinaryContent) {
                readBinaryHelper = ReadContentAsBinaryHelper.CreateOrReset(readBinaryHelper, this);
                savedState = validationState;
            }
 
            // restore original state in order to have a normal Read() behavior when called from readBinaryHelper
            validationState = savedState;
 
            // call to the helper
            int readCount = readBinaryHelper.ReadElementContentAsBase64(buffer, index, count);
 
            // set OnReadBinaryContent state again and return
            savedState = validationState;
            validationState = ValidatingReaderState.OnReadBinaryContent;
            return readCount;
        }
 
        public override  int  ReadElementContentAsBinHex(byte[] buffer, int index, int count) {
            if (ReadState != ReadState.Interactive) {
                return 0;
            }
 
            // init ReadContentAsBinaryHelper when called first time
            if (validationState != ValidatingReaderState.OnReadBinaryContent) {
                readBinaryHelper = ReadContentAsBinaryHelper.CreateOrReset(readBinaryHelper, this);
                savedState = validationState;
            }
 
            // restore original state in order to have a normal Read() behavior when called from readBinaryHelper
            validationState = savedState;
 
            // call to the helper
            int readCount = readBinaryHelper.ReadElementContentAsBinHex(buffer, index, count);
 
            // set OnReadBinaryContent state again and return
            savedState = validationState;
            validationState = ValidatingReaderState.OnReadBinaryContent;
            return readCount;
        }
 
        //
        // IXmlSchemaInfo interface
        //
        bool IXmlSchemaInfo.IsDefault {
            get {
                switch (NodeType) {
                    case XmlNodeType.Element:
                        if (!coreReader.IsEmptyElement) {
                            GetIsDefault();
                        }
                        return xmlSchemaInfo.IsDefault;
 
                    case XmlNodeType.EndElement:
                        return xmlSchemaInfo.IsDefault;
 
                    case XmlNodeType.Attribute:
                        if (attributePSVI != null) {
                            return AttributeSchemaInfo.IsDefault;
                        }
                        break;
 
                    default:
                        break;
                }
                return false;
            }
        }
 
        bool IXmlSchemaInfo.IsNil {
            get {
                switch (NodeType) {
                    case XmlNodeType.Element:
                    case XmlNodeType.EndElement:
                        return xmlSchemaInfo.IsNil;
 
                    default:
                        break;
                }
                return false;
            }
        }
 
        XmlSchemaValidity IXmlSchemaInfo.Validity {
            get {
                switch (NodeType) {
                    case XmlNodeType.Element:
                        if (coreReader.IsEmptyElement) {
                            return xmlSchemaInfo.Validity;
                        }
                        if (xmlSchemaInfo.Validity == XmlSchemaValidity.Valid) { //It might be valid for unions since we read ahead, but report notknown for consistency
                            return XmlSchemaValidity.NotKnown;
                        }
                        return xmlSchemaInfo.Validity;
 
                    case XmlNodeType.EndElement:
                        return xmlSchemaInfo.Validity;
 
                    case XmlNodeType.Attribute:
                        if (attributePSVI != null) {
                            return AttributeSchemaInfo.Validity;
                        }
                        break;
                }
                return XmlSchemaValidity.NotKnown;
            }
        }
 
        XmlSchemaSimpleType IXmlSchemaInfo.MemberType {
            get {
                switch (NodeType) {
                    case XmlNodeType.Element:
                        if (!coreReader.IsEmptyElement) {
                            GetMemberType();
                        }
                        return xmlSchemaInfo.MemberType;
 
                    case XmlNodeType.EndElement:
                        return xmlSchemaInfo.MemberType;
 
                    case XmlNodeType.Attribute:
                        if (attributePSVI != null) {
                            return AttributeSchemaInfo.MemberType;
                        }
                        return null;
 
                    default:
                        return null; //Text, PI, Comment etc
                }
            }
        }
 
        XmlSchemaType IXmlSchemaInfo.SchemaType {
            get {
                switch (NodeType) {
                    case XmlNodeType.Element:
                    case XmlNodeType.EndElement:
                        return xmlSchemaInfo.SchemaType;
 
                    case XmlNodeType.Attribute:
                        if (attributePSVI != null) {
                            return AttributeSchemaInfo.SchemaType;
                        }
                        return null;
 
                    default:
                        return null; //Text, PI, Comment etc
                }
            }
        }
        XmlSchemaElement IXmlSchemaInfo.SchemaElement {
            get {
                if (NodeType == XmlNodeType.Element || NodeType == XmlNodeType.EndElement) {
                    return xmlSchemaInfo.SchemaElement;
                }
                return null;
            }
        }
 
        XmlSchemaAttribute IXmlSchemaInfo.SchemaAttribute {
            get {
                if (NodeType == XmlNodeType.Attribute) {
                    if (attributePSVI != null) {
                        return AttributeSchemaInfo.SchemaAttribute;
                    }
                }
                return null;
            }
        }
 
        //
        // IXmlLineInfo members
        //
 
        public bool HasLineInfo() {
            return true;
        }
 
        public int LineNumber {
            get {
                if (lineInfo != null) {
                    return lineInfo.LineNumber;
                }
                return 0;
            }
        }
 
        public int LinePosition {
            get {
                if (lineInfo != null) {
                    return lineInfo.LinePosition;
                }
                return 0;
            }
        }
 
        //
        // IXmlNamespaceResolver members
        //
        IDictionary<string, string> IXmlNamespaceResolver.GetNamespacesInScope(XmlNamespaceScope scope) {
            if (coreReaderNSResolver != null) {
                return coreReaderNSResolver.GetNamespacesInScope(scope);
            }
            else {
                return nsManager.GetNamespacesInScope(scope);
            }
        }
 
        string IXmlNamespaceResolver.LookupNamespace(string prefix) {
            if (coreReaderNSResolver != null) {
                return coreReaderNSResolver.LookupNamespace(prefix);
            }
            else {
                return nsManager.LookupNamespace(prefix);
            }
        }
 
        string IXmlNamespaceResolver.LookupPrefix(string namespaceName) {
            if (coreReaderNSResolver != null) {
                return coreReaderNSResolver.LookupPrefix(namespaceName);
            }
            else {
                return nsManager.LookupPrefix(namespaceName);
            }
        }
 
        //Internal / Private methods
 
        private object GetStringValue() {
            return coreReader.Value;
        }
 
        private XmlSchemaType ElementXmlType {
            get {
                return xmlSchemaInfo.XmlType;
            }
        }
 
        private XmlSchemaType AttributeXmlType {
            get {
                if (attributePSVI != null) {
                    return AttributeSchemaInfo.XmlType;
                }
                return null;
            }
        }
 
        private XmlSchemaInfo AttributeSchemaInfo {
            get {
                Debug.Assert(attributePSVI != null);
                return attributePSVI.attributeSchemaInfo;
            }
        }
 
        private void ProcessReaderEvent() {
            if (replayCache) { //if in replay mode, do nothing since nodes have been validated already
                //If NodeType == XmlNodeType.EndElement && if manageNamespaces, may need to pop namespace scope, since scope is not popped in ReadAheadForMemberType
 
                return;
 
            }
            switch (coreReader.NodeType) {
                case XmlNodeType.Element:
 
                    ProcessElementEvent();
                    break;
 
                case XmlNodeType.Whitespace:
                case XmlNodeType.SignificantWhitespace:
                    validator.ValidateWhitespace(GetStringValue);
                    break;
 
                case XmlNodeType.Text:          // text inside a node
                case XmlNodeType.CDATA:         // <![CDATA[...]]>
                    validator.ValidateText(GetStringValue);
                    break;
 
                case XmlNodeType.EndElement:
 
                    ProcessEndElementEvent();
                    break;
 
                case XmlNodeType.EntityReference:
                    throw new InvalidOperationException();
 
                case XmlNodeType.DocumentType:
#if TEMP_HACK_FOR_SCHEMA_INFO
                    validator.SetDtdSchemaInfo((SchemaInfo)coreReader.DtdInfo);
#else
                    validator.SetDtdSchemaInfo(coreReader.DtdInfo);
#endif
                    break;
 
                default:
                    break;
            }
 
        }
 
        // SxS: This function calls ValidateElement on XmlSchemaValidator which is annotated with ResourceExposure attribute.
        // Since the resource names (namespace location) are not provided directly by the user (they are read from the source
        // document) and the function does not expose any resources it is fine to suppress the SxS warning. 
        [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
        [ResourceExposure(ResourceScope.None)]
        private void ProcessElementEvent() {
            if (this.processInlineSchema && IsXSDRoot(coreReader.LocalName, coreReader.NamespaceURI) && coreReader.Depth > 0) {
                xmlSchemaInfo.Clear();
                attributeCount = coreReaderAttributeCount = coreReader.AttributeCount;
                if (!coreReader.IsEmptyElement) { //If its not empty schema, then parse else ignore
                    inlineSchemaParser = new Parser(SchemaType.XSD, coreReaderNameTable, validator.SchemaSet.GetSchemaNames(coreReaderNameTable), validationEvent);
                    inlineSchemaParser.StartParsing(coreReader, null);
                    inlineSchemaParser.ParseReaderNode();
                    validationState = ValidatingReaderState.ParseInlineSchema;
                }
                else {
                    validationState = ValidatingReaderState.ClearAttributes;
                }
            }
            else { //Validate element
 
                //Clear previous data
                atomicValue = null;
                originalAtomicValueString = null;
                xmlSchemaInfo.Clear();
 
                if (manageNamespaces) {
                    nsManager.PushScope();
                }
                //Find Xsi attributes that need to be processed before validating the element
                string xsiSchemaLocation = null;
                string xsiNoNamespaceSL = null;
                string xsiNil = null;
                string xsiType = null;
                if (coreReader.MoveToFirstAttribute()) {
                    do {
                        string objectNs = coreReader.NamespaceURI;
                        string objectName = coreReader.LocalName;
                        if (Ref.Equal(objectNs, NsXsi)) {
                            if (Ref.Equal(objectName, XsiSchemaLocation)) {
                                xsiSchemaLocation = coreReader.Value;
                            }
                            else if (Ref.Equal(objectName, XsiNoNamespaceSchemaLocation)) {
                                xsiNoNamespaceSL = coreReader.Value;
                            }
                            else if (Ref.Equal(objectName, XsiType)) {
                                xsiType = coreReader.Value;
                            }
                            else if (Ref.Equal(objectName, XsiNil)) {
                                xsiNil = coreReader.Value;
                            }
                        }
                        if (manageNamespaces && Ref.Equal(coreReader.NamespaceURI, NsXmlNs)) {
                            nsManager.AddNamespace(coreReader.Prefix.Length == 0 ? string.Empty : coreReader.LocalName, coreReader.Value);
                        }
 
                    } while (coreReader.MoveToNextAttribute());
                    coreReader.MoveToElement();
                }
                validator.ValidateElement(coreReader.LocalName, coreReader.NamespaceURI, xmlSchemaInfo, xsiType, xsiNil, xsiSchemaLocation, xsiNoNamespaceSL);
                ValidateAttributes();
                validator.ValidateEndOfAttributes(xmlSchemaInfo);
                if (coreReader.IsEmptyElement) {
                    ProcessEndElementEvent();
                }
                validationState = ValidatingReaderState.ClearAttributes;
            }
        }
 
        private void ProcessEndElementEvent() {
            atomicValue = validator.ValidateEndElement(xmlSchemaInfo);
            originalAtomicValueString = GetOriginalAtomicValueStringOfElement();
            if (xmlSchemaInfo.IsDefault) { //The atomicValue returned is a default value
                Debug.Assert(atomicValue != null);
                int depth = coreReader.Depth;
                coreReader = GetCachingReader();
                cachingReader.RecordTextNode( xmlSchemaInfo.XmlType.ValueConverter.ToString( atomicValue ), originalAtomicValueString, depth + 1, 0, 0 );
                cachingReader.RecordEndElementNode(); 
                cachingReader.SetToReplayMode();
                replayCache = true;
            }
            else if (manageNamespaces) {
                nsManager.PopScope();
            }
        }
 
        private void ValidateAttributes() {
            attributeCount = coreReaderAttributeCount = coreReader.AttributeCount;
            AttributePSVIInfo attributePSVI;
            int attIndex = 0;
            bool attributeInvalid = false;
            if (coreReader.MoveToFirstAttribute()) {
                do {
                    string localName = coreReader.LocalName;
                    string ns = coreReader.NamespaceURI;
 
                    attributePSVI = AddAttributePSVI(attIndex);
                    attributePSVI.localName = localName;
                    attributePSVI.namespaceUri = ns;
 
                    if ((object)ns == (object)NsXmlNs) {
                        attIndex++;
                        continue;
                    }
                    attributePSVI.typedAttributeValue = validator.ValidateAttribute(localName, ns, valueGetter, attributePSVI.attributeSchemaInfo);
                    if (!attributeInvalid) {
                        attributeInvalid = attributePSVI.attributeSchemaInfo.Validity == XmlSchemaValidity.Invalid;
                    }
                    attIndex++;
 
                } while (coreReader.MoveToNextAttribute());
            }
            coreReader.MoveToElement();
            if (attributeInvalid) { //If any of the attributes are invalid, Need to report element's validity as invalid
                xmlSchemaInfo.Validity = XmlSchemaValidity.Invalid;
            }
            validator.GetUnspecifiedDefaultAttributes(defaultAttributes, true);
            attributeCount += defaultAttributes.Count;
        }
 
        private void ClearAttributesInfo() {
            attributeCount = 0;
            coreReaderAttributeCount = 0;
            currentAttrIndex = -1;
            defaultAttributes.Clear();
            attributePSVI = null;
        }
 
        private AttributePSVIInfo GetAttributePSVI(string name) {
            if (inlineSchemaParser != null) { //Parsing inline schema, no PSVI for schema attributes
                return null;
            }
            string attrLocalName;
            string attrPrefix;
            string ns;
            ValidateNames.SplitQName(name, out attrPrefix, out attrLocalName);
            attrPrefix = coreReaderNameTable.Add(attrPrefix);
            attrLocalName = coreReaderNameTable.Add(attrLocalName);
 
            if (attrPrefix.Length == 0) { //empty prefix, not qualified
                ns = string.Empty;                                
            }
            else {
                ns = thisNSResolver.LookupNamespace(attrPrefix);
            }
            return GetAttributePSVI(attrLocalName, ns);
        }
 
        private AttributePSVIInfo GetAttributePSVI(string localName, string ns) {
            Debug.Assert(coreReaderNameTable.Get(localName) != null);
            Debug.Assert(coreReaderNameTable.Get(ns) != null);
            AttributePSVIInfo attInfo = null;
 
            for (int i = 0; i < coreReaderAttributeCount; i++) {
                attInfo = attributePSVINodes[i];
                if (attInfo != null) { //Will be null for invalid attributes
                    if (Ref.Equal(localName, attInfo.localName) && Ref.Equal(ns, attInfo.namespaceUri)) {
                        currentAttrIndex = i;
                        return attInfo;
                    }
                }
            }
            return null;
        }
 
        private ValidatingReaderNodeData GetDefaultAttribute(string name, bool updatePosition) {
            string attrLocalName;
            string attrPrefix;
            ValidateNames.SplitQName(name, out attrPrefix, out attrLocalName);
 
            //Atomize
            attrPrefix = coreReaderNameTable.Add(attrPrefix);
            attrLocalName = coreReaderNameTable.Add(attrLocalName);
            string ns;
            if (attrPrefix.Length == 0) {
                ns = string.Empty;
            }
            else {
                ns = thisNSResolver.LookupNamespace(attrPrefix);
            }
            return GetDefaultAttribute(attrLocalName, ns, updatePosition);
        }
 
        private ValidatingReaderNodeData GetDefaultAttribute(string attrLocalName, string ns, bool updatePosition) {
            Debug.Assert(coreReaderNameTable.Get(attrLocalName) != null);
            Debug.Assert(coreReaderNameTable.Get(ns) != null);
            ValidatingReaderNodeData defaultNode = null;
 
            for (int i = 0; i < defaultAttributes.Count; i++) {
                defaultNode = (ValidatingReaderNodeData)defaultAttributes[i];
                if (Ref.Equal(defaultNode.LocalName, attrLocalName) && Ref.Equal(defaultNode.Namespace, ns)) {
                    if (updatePosition) {
                        currentAttrIndex = coreReader.AttributeCount + i;
                    }
                    return defaultNode;
                }
            }
            return null;
        }
 
        private AttributePSVIInfo AddAttributePSVI(int attIndex) {
            Debug.Assert(attIndex <= attributePSVINodes.Length);
            AttributePSVIInfo attInfo = attributePSVINodes[attIndex];
            if (attInfo != null) {
                attInfo.Reset();
                return attInfo;
            }
            if (attIndex >= attributePSVINodes.Length - 1) { //reached capacity of PSVIInfo array, Need to increase capacity to twice the initial
                AttributePSVIInfo[] newPSVINodes = new AttributePSVIInfo[attributePSVINodes.Length * 2];
                Array.Copy(attributePSVINodes, 0, newPSVINodes, 0, attributePSVINodes.Length);
                attributePSVINodes = newPSVINodes;
            }
            attInfo = attributePSVINodes[attIndex];
            if (attInfo == null) {
                attInfo = new AttributePSVIInfo();
                attributePSVINodes[attIndex] = attInfo;
            }
            return attInfo;
        }
 
        private bool IsXSDRoot(string localName, string ns) {
            return Ref.Equal(ns, NsXs) && Ref.Equal(localName, XsdSchema);
        }
 
        private void ProcessInlineSchema() {
            Debug.Assert(inlineSchemaParser != null);
            if (coreReader.Read()) {
                if (coreReader.NodeType == XmlNodeType.Element) {
                    attributeCount = coreReaderAttributeCount = coreReader.AttributeCount;
                }
                else { //Clear attributes info if nodeType is not element
                    ClearAttributesInfo();
                }
                if (!inlineSchemaParser.ParseReaderNode()) {
                    inlineSchemaParser.FinishParsing();
                    XmlSchema schema = inlineSchemaParser.XmlSchema;
                    validator.AddSchema(schema);
                    inlineSchemaParser = null;
                    validationState = ValidatingReaderState.Read;
                }
            }
        }
 
        private  object  InternalReadContentAsObject() {
            return InternalReadContentAsObject(false);
        }
 
        private  object  InternalReadContentAsObject(bool unwrapTypedValue) {
 
            string str;
            return InternalReadContentAsObject(unwrapTypedValue, out str);
 
        }
 
        private  object  InternalReadContentAsObject(bool unwrapTypedValue, out string originalStringValue) {
 
            XmlNodeType nodeType = this.NodeType;
            if (nodeType == XmlNodeType.Attribute) {
                originalStringValue = this.Value;
                if ( attributePSVI != null && attributePSVI.typedAttributeValue != null ) {
                    if ( validationState == ValidatingReaderState.OnDefaultAttribute) {
                        XmlSchemaAttribute schemaAttr = attributePSVI.attributeSchemaInfo.SchemaAttribute;
                        originalStringValue = ( schemaAttr.DefaultValue != null ) ? schemaAttr.DefaultValue : schemaAttr.FixedValue;
                    }
 
                    return ReturnBoxedValue( attributePSVI.typedAttributeValue, AttributeSchemaInfo.XmlType, unwrapTypedValue );
 
                }
                else { //return string value
 
                    return this.Value;
 
                }
            }
            else if (nodeType == XmlNodeType.EndElement) {
                if (atomicValue != null) {
                    originalStringValue = originalAtomicValueString;
 
                    return atomicValue;
 
                }
                else {
                    originalStringValue = string.Empty;
 
                    return string.Empty;
 
                }
            }
            else { //Positioned on text, CDATA, PI, Comment etc
                if (validator.CurrentContentType == XmlSchemaContentType.TextOnly) {  //if current element is of simple type
                    object value = ReturnBoxedValue(ReadTillEndElement(), xmlSchemaInfo.XmlType, unwrapTypedValue);
                    originalStringValue = originalAtomicValueString;
 
                    return value;
 
                }
                else {
                    XsdCachingReader cachingReader = this.coreReader as XsdCachingReader;
                    if ( cachingReader != null ) {
                        originalStringValue = cachingReader.ReadOriginalContentAsString();
                    }
                    else {
                        originalStringValue = InternalReadContentAsString();
                    }
 
                    return originalStringValue;
 
                }
            }
        }
 
        private  object  InternalReadElementContentAsObject(out XmlSchemaType xmlType) {
 
            return InternalReadElementContentAsObject(out xmlType, false);
 
        }
 
        private  object  InternalReadElementContentAsObject(out XmlSchemaType xmlType, bool unwrapTypedValue) {
 
            string tmpString;
            return InternalReadElementContentAsObject(out xmlType, unwrapTypedValue, out tmpString);
 
        }
 
        private  object  InternalReadElementContentAsObject(out XmlSchemaType xmlType, bool unwrapTypedValue, out string originalString) {
 
            Debug.Assert(this.NodeType == XmlNodeType.Element);
            object typedValue = null;
            xmlType = null;
            //If its an empty element, can have default/fixed value
            if (this.IsEmptyElement) {
                if (xmlSchemaInfo.ContentType == XmlSchemaContentType.TextOnly) {
                    typedValue = ReturnBoxedValue(atomicValue, xmlSchemaInfo.XmlType, unwrapTypedValue);
                }
                else {
                    typedValue = atomicValue;
                }
                originalString = originalAtomicValueString;
                xmlType = ElementXmlType; //Set this for default values 
                this.Read();
 
                return typedValue;
 
            }
            // move to content and read typed value
            this.Read();
 
            if (this.NodeType == XmlNodeType.EndElement) { //If IsDefault is true, the next node will be EndElement
                if (xmlSchemaInfo.IsDefault) {
                    if (xmlSchemaInfo.ContentType == XmlSchemaContentType.TextOnly) {
                        typedValue = ReturnBoxedValue(atomicValue, xmlSchemaInfo.XmlType, unwrapTypedValue);
                    }
                    else { //anyType has default value
                        typedValue = atomicValue;
                    }
                    originalString = originalAtomicValueString;
                }
                else { //Empty content
                    typedValue = string.Empty;
                    originalString = string.Empty;  
                }
            }
            else if (this.NodeType == XmlNodeType.Element) { //the first child is again element node
                throw new XmlException(Res.Xml_MixedReadElementContentAs, string.Empty, this as IXmlLineInfo);
            }
            else {
 
                typedValue = InternalReadContentAsObject(unwrapTypedValue, out originalString);
 
                // ReadElementContentAsXXX cannot be called on mixed content, if positioned on node other than EndElement, Error
                if (this.NodeType != XmlNodeType.EndElement) {
                    throw new XmlException(Res.Xml_MixedReadElementContentAs, string.Empty, this as IXmlLineInfo);
                }
            }
            xmlType = ElementXmlType; //Set this as we are moving ahead to the next node
 
            // move to next node
            this.Read();
 
            return typedValue;
 
        }
 
        private  object  ReadTillEndElement() {
            if (atomicValue == null) {
                while (coreReader.Read()) {
                    if (replayCache) { //If replaying nodes in the cache, they have already been validated
                        continue;
                    }
                    switch (coreReader.NodeType) {
                        case XmlNodeType.Element:
                            ProcessReaderEvent();
                            goto breakWhile;
 
                        case XmlNodeType.Text:
                        case XmlNodeType.CDATA:
                            validator.ValidateText(GetStringValue);
                            break;
 
                        case XmlNodeType.Whitespace:
                        case XmlNodeType.SignificantWhitespace:
                            validator.ValidateWhitespace(GetStringValue);
                            break;
 
                        case XmlNodeType.Comment:
                        case XmlNodeType.ProcessingInstruction:
                            break;
 
                        case XmlNodeType.EndElement:
                            atomicValue = validator.ValidateEndElement(xmlSchemaInfo);
                            originalAtomicValueString = GetOriginalAtomicValueStringOfElement();
                            if (manageNamespaces) {
                                nsManager.PopScope();
                            }
                            goto breakWhile;
                    }
                    continue;
                breakWhile:
                    break;
                }
            }
            else { //atomicValue != null, meaning already read ahead - Switch reader
                if (atomicValue == this) { //switch back invalid marker; dont need it since coreReader moved to endElement
                    atomicValue = null;
                }
                SwitchReader();
            }
            return atomicValue;
        }
 
        private void SwitchReader() {
            XsdCachingReader cachingReader = this.coreReader as XsdCachingReader;
            if (cachingReader != null) { //Switch back without going over the cached contents again.
                this.coreReader = cachingReader.GetCoreReader();
            }
            Debug.Assert(coreReader.NodeType == XmlNodeType.EndElement);
            replayCache = false;
        }
 
        private void ReadAheadForMemberType() {
            while (coreReader.Read()) {
                switch (coreReader.NodeType) {
                    case XmlNodeType.Element:
                        Debug.Assert(false); //Should not happen as the caching reader does not cache elements in simple content
                        break;
 
                    case XmlNodeType.Text:
                    case XmlNodeType.CDATA:
                        validator.ValidateText(GetStringValue);
                        break;
 
                    case XmlNodeType.Whitespace:
                    case XmlNodeType.SignificantWhitespace:
                        validator.ValidateWhitespace(GetStringValue);
                        break;
 
                    case XmlNodeType.Comment:
                    case XmlNodeType.ProcessingInstruction:
                        break;
 
                    case XmlNodeType.EndElement:
                        atomicValue = validator.ValidateEndElement(xmlSchemaInfo); //?? pop namespaceManager scope
                        originalAtomicValueString = GetOriginalAtomicValueStringOfElement();
                        if (atomicValue == null) { //Invalid marker
                            atomicValue = this;
                        }
                        else if (xmlSchemaInfo.IsDefault) { //The atomicValue returned is a default value
                            cachingReader.SwitchTextNodeAndEndElement(xmlSchemaInfo.XmlType.ValueConverter.ToString(atomicValue), originalAtomicValueString);
                        }
                        goto breakWhile;
                }
                continue;
            breakWhile:
                break;
            }
        }
 
        private void GetIsDefault() {
            XsdCachingReader cachedReader = coreReader as XsdCachingReader;
            if (cachedReader == null && xmlSchemaInfo.HasDefaultValue) { //Get Isdefault
                coreReader = GetCachingReader();
                if (xmlSchemaInfo.IsUnionType && !xmlSchemaInfo.IsNil) { //If it also union, get the memberType as well
                    ReadAheadForMemberType();
                }
                else {
                    if (coreReader.Read()) {
                        switch (coreReader.NodeType) {
                            case XmlNodeType.Element:
                                Debug.Assert(false); //Should not happen as the caching reader does not cache elements in simple content
                                break;
 
                            case XmlNodeType.Text:
                            case XmlNodeType.CDATA:
                                validator.ValidateText(GetStringValue);
                                break;
 
                            case XmlNodeType.Whitespace:
                            case XmlNodeType.SignificantWhitespace:
                                validator.ValidateWhitespace(GetStringValue);
                                break;
 
                            case XmlNodeType.Comment:
                            case XmlNodeType.ProcessingInstruction:
                                break;
 
                            case XmlNodeType.EndElement:
                                atomicValue = validator.ValidateEndElement(xmlSchemaInfo); //?? pop namespaceManager scope
                                originalAtomicValueString = GetOriginalAtomicValueStringOfElement();
                                if (xmlSchemaInfo.IsDefault) { //The atomicValue returned is a default value
                                    cachingReader.SwitchTextNodeAndEndElement(xmlSchemaInfo.XmlType.ValueConverter.ToString(atomicValue), originalAtomicValueString);
                                }
                                break;
 
                            default:
                                break;
                        }
                    }
                }
                cachingReader.SetToReplayMode();
                replayCache = true;
            }
        }
 
        private void GetMemberType() {
            if (xmlSchemaInfo.MemberType != null || atomicValue == this) {
                return;
            }
            XsdCachingReader cachedReader = coreReader as XsdCachingReader;
            if (cachedReader == null && xmlSchemaInfo.IsUnionType && !xmlSchemaInfo.IsNil) {
                coreReader = GetCachingReader();
                ReadAheadForMemberType();
                cachingReader.SetToReplayMode();
                replayCache = true;
            }
        }
 
        private object ReturnBoxedValue(object typedValue, XmlSchemaType xmlType, bool unWrap) {
            if (typedValue != null) {
                if (unWrap) { //convert XmlAtomicValue[] to object[] for list of unions; The other cases return typed value of the valueType anyway
                    Debug.Assert(xmlType != null && xmlType.Datatype != null);
                    if (xmlType.Datatype.Variety == XmlSchemaDatatypeVariety.List) {
                        Datatype_List listType = xmlType.Datatype as Datatype_List;
                        if (listType.ItemType.Variety == XmlSchemaDatatypeVariety.Union) {
                            typedValue = xmlType.ValueConverter.ChangeType(typedValue, xmlType.Datatype.ValueType, thisNSResolver);
                        }
                    }
                }
                return typedValue;
            }
            else { //return the original string value of the element or attribute
                Debug.Assert(NodeType != XmlNodeType.Attribute);
                typedValue = validator.GetConcatenatedValue();
            }
            return typedValue;
        }
 
        private XsdCachingReader GetCachingReader() {
            if (cachingReader == null) {
                cachingReader = new XsdCachingReader(coreReader, lineInfo, new CachingEventHandler(CachingCallBack));
            }
            else {
                cachingReader.Reset(coreReader);
            }
            this.lineInfo = cachingReader as IXmlLineInfo;
            return cachingReader;
        }
 
        internal ValidatingReaderNodeData CreateDummyTextNode(string attributeValue, int depth) {
            if (textNode == null) {
                textNode = new ValidatingReaderNodeData(XmlNodeType.Text);
            }
            textNode.Depth = depth;
            textNode.RawValue = attributeValue;
            return textNode;
        }
 
        internal void CachingCallBack(XsdCachingReader cachingReader) {
            this.coreReader = cachingReader.GetCoreReader(); //re-switch the core-reader after caching reader is done
            this.lineInfo = cachingReader.GetLineInfo();
            replayCache = false;
        }
 
        private string GetOriginalAtomicValueStringOfElement() {
            if ( xmlSchemaInfo.IsDefault ) {
                XmlSchemaElement schemaElem = xmlSchemaInfo.SchemaElement;
                if ( schemaElem != null ) {
                    return ( schemaElem.DefaultValue != null ) ? schemaElem.DefaultValue : schemaElem.FixedValue;
                }
            }
            else {
                return validator.GetConcatenatedValue();
            }
            return string.Empty;
        }
 
    }
}