//------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. // // Microsoft //------------------------------------------------------------------------------ using System.IO; using System.Xml.Schema; using System.Collections; using System.Diagnostics; using System.Collections.Generic; namespace System.Xml.XPath { /// /// Reader that traverses the subtree rooted at the current position of the specified navigator. /// internal class XPathNavigatorReader : XmlReader, IXmlNamespaceResolver { enum State { Initial, Content, EndElement, Attribute, AttrVal, InReadBinary, EOF, Closed, Error, } private XPathNavigator nav; private XPathNavigator navToRead; private int depth; private State state; private XmlNodeType nodeType; private int attrCount; private bool readEntireDocument; protected IXmlLineInfo lineInfo; protected IXmlSchemaInfo schemaInfo; private ReadContentAsBinaryHelper readBinaryHelper; private State savedState; internal const string space = "space"; internal static XmlNodeType[] convertFromXPathNodeType = { XmlNodeType.Document, // XPathNodeType.Root XmlNodeType.Element, // XPathNodeType.Element XmlNodeType.Attribute, // XPathNodeType.Attribute XmlNodeType.Attribute, // XPathNodeType.Namespace XmlNodeType.Text, // XPathNodeType.Text XmlNodeType.SignificantWhitespace, // XPathNodeType.SignificantWhitespace XmlNodeType.Whitespace, // XPathNodeType.Whitespace XmlNodeType.ProcessingInstruction, // XPathNodeType.ProcessingInstruction XmlNodeType.Comment, // XPathNodeType.Comment XmlNodeType.None // XPathNodeType.All }; /// /// Translates an XPathNodeType value into the corresponding XmlNodeType value. /// XPathNodeType.Whitespace and XPathNodeType.SignificantWhitespace are mapped into XmlNodeType.Text. /// internal static XmlNodeType ToXmlNodeType( XPathNodeType typ ) { return XPathNavigatorReader.convertFromXPathNodeType[(int) typ]; } internal object UnderlyingObject { get { return this.nav.UnderlyingObject; } } static public XPathNavigatorReader Create(XPathNavigator navToRead ) { XPathNavigator nav = navToRead.Clone(); IXmlLineInfo xli = nav as IXmlLineInfo; IXmlSchemaInfo xsi = nav as IXmlSchemaInfo; #if NAVREADER_SUPPORTSLINEINFO if (null == xsi) { if (null == xli) { return new XPathNavigatorReader(nav, xli, xsi); } else { return new XPathNavigatorReaderWithLI(nav, xli, xsi); } } else { if (null == xli) { return new XPathNavigatorReaderWithSI(nav, xli, xsi); } else { return new XPathNavigatorReaderWithLIAndSI(nav, xli, xsi); } } #else if (null == xsi) { return new XPathNavigatorReader(nav, xli, xsi); } else { return new XPathNavigatorReaderWithSI(nav, xli, xsi); } #endif } protected XPathNavigatorReader( XPathNavigator navToRead, IXmlLineInfo xli, IXmlSchemaInfo xsi ) { // Need clone that can be moved independently of original navigator this.navToRead = navToRead; this.lineInfo = xli; this.schemaInfo = xsi; this.nav = XmlEmptyNavigator.Singleton; this.state = State.Initial; this.depth = 0; this.nodeType = XPathNavigatorReader.ToXmlNodeType( this.nav.NodeType ); } protected bool IsReading { get { return this.state > State.Initial && this.state < State.EOF; } } internal override XmlNamespaceManager NamespaceManager { get { return XPathNavigator.GetNamespaces( this ); } } //----------------------------------------------- // IXmlNamespaceResolver -- pass through to Navigator //----------------------------------------------- public override XmlNameTable NameTable { get { return this.navToRead.NameTable; } } IDictionary IXmlNamespaceResolver.GetNamespacesInScope(XmlNamespaceScope scope) { return this.nav.GetNamespacesInScope(scope); } string IXmlNamespaceResolver.LookupNamespace(string prefix) { return this.nav.LookupNamespace(prefix); } string IXmlNamespaceResolver.LookupPrefix(string namespaceName) { return this.nav.LookupPrefix(namespaceName); } //----------------------------------------------- // XmlReader -- pass through to Navigator //----------------------------------------------- public override XmlReaderSettings Settings { get { XmlReaderSettings rs = new XmlReaderSettings(); rs.NameTable = this.NameTable; rs.ConformanceLevel = ConformanceLevel.Fragment; rs.CheckCharacters = false; rs.ReadOnly = true; return rs; } } public override IXmlSchemaInfo SchemaInfo { get { // Special case attribute text (this.nav points to attribute even though current state is Text) if ( this.nodeType == XmlNodeType.Text ) return null; return this.nav.SchemaInfo; } } public override System.Type ValueType { get { return this.nav.ValueType; } } public override XmlNodeType NodeType { get { return this.nodeType; } } public override string NamespaceURI { get { //NamespaceUri for namespace nodes is different in case of XPathNavigator and Reader if (this.nav.NodeType == XPathNodeType.Namespace) return this.NameTable.Add(XmlReservedNs.NsXmlNs); //Special case attribute text node if (this.NodeType == XmlNodeType.Text) return string.Empty; return this.nav.NamespaceURI; } } public override string LocalName { get { //Default namespace in case of reader has a local name value of 'xmlns' if (this.nav.NodeType == XPathNodeType.Namespace && this.nav.LocalName.Length == 0) return this.NameTable.Add("xmlns"); //Special case attribute text node if (this.NodeType == XmlNodeType.Text) return string.Empty; return this.nav.LocalName; } } public override string Prefix { get { //Prefix for namespace nodes is different in case of XPathNavigator and Reader if (this.nav.NodeType == XPathNodeType.Namespace && this.nav.LocalName.Length != 0) return this.NameTable.Add("xmlns"); //Special case attribute text node if (this.NodeType == XmlNodeType.Text) return string.Empty; return this.nav.Prefix; } } public override string BaseURI { get { //reader returns BaseUri even before read method is called. if( this.state == State.Initial ) return this.navToRead.BaseURI; return this.nav.BaseURI; } } public override bool IsEmptyElement { get { return this.nav.IsEmptyElement; } } public override XmlSpace XmlSpace { get { XPathNavigator tempNav = this.nav.Clone(); do { if (tempNav.MoveToAttribute(XPathNavigatorReader.space, XmlReservedNs.NsXml)) { switch (XmlConvert.TrimString(tempNav.Value)) { case "default": return XmlSpace.Default; case "preserve": return XmlSpace.Preserve; default: break; } tempNav.MoveToParent(); } } while (tempNav.MoveToParent()); return XmlSpace.None; } } public override string XmlLang { get { return this.nav.XmlLang; } } public override bool HasValue { get { if( ( this.nodeType != XmlNodeType.Element ) && ( this.nodeType !=XmlNodeType.Document ) && ( this.nodeType !=XmlNodeType.EndElement ) && ( this.nodeType !=XmlNodeType.None ) ) return true; return false; } } public override string Value { get { if( ( this.nodeType != XmlNodeType.Element ) && ( this.nodeType !=XmlNodeType.Document ) && ( this.nodeType !=XmlNodeType.EndElement ) && ( this.nodeType !=XmlNodeType.None ) ) return this.nav.Value; return string.Empty; } } private XPathNavigator GetElemNav() { XPathNavigator tempNav; switch (this.state) { case State.Content: return this.nav.Clone(); case State.Attribute: case State.AttrVal: tempNav = this.nav.Clone(); if (tempNav.MoveToParent()) return tempNav; break; case State.InReadBinary: state = savedState; XPathNavigator nav = GetElemNav(); state = State.InReadBinary; return nav; } return null; } private XPathNavigator GetElemNav(out int depth) { XPathNavigator nav = null; switch (this.state) { case State.Content: if (this.nodeType == XmlNodeType.Element) nav = this.nav.Clone(); depth = this.depth; break; case State.Attribute: nav = this.nav.Clone(); nav.MoveToParent(); depth = this.depth - 1; break; case State.AttrVal: nav = this.nav.Clone(); nav.MoveToParent(); depth = this.depth - 2; break; case State.InReadBinary: state = savedState; nav = GetElemNav(out depth); state = State.InReadBinary; break; default: depth = this.depth; break; } return nav; } private void MoveToAttr(XPathNavigator nav, int depth) { this.nav.MoveTo( nav ); this.depth = depth; this.nodeType = XmlNodeType.Attribute; this.state = State.Attribute; } public override int AttributeCount { get { if ( this.attrCount < 0 ) { // attribute count works for element, regardless of where you are in start tag XPathNavigator tempNav = GetElemNav(); int count = 0; if ( null != tempNav ) { if( tempNav.MoveToFirstNamespace( XPathNamespaceScope.Local ) ) { do { count++; } while( tempNav.MoveToNextNamespace( ( XPathNamespaceScope.Local ) ) ); tempNav.MoveToParent(); } if( tempNav.MoveToFirstAttribute() ) { do { count++; } while( tempNav.MoveToNextAttribute() ); } } this.attrCount = count; } return this.attrCount; } } public override string GetAttribute( string name ) { // reader allows calling GetAttribute, even when positioned inside attributes XPathNavigator nav = this.nav; switch (nav.NodeType) { case XPathNodeType.Element: break; case XPathNodeType.Attribute: nav = nav.Clone(); if (!nav.MoveToParent()) return null; break; default: return null; } string prefix, localname; ValidateNames.SplitQName( name, out prefix, out localname ); if ( 0 == prefix.Length ) { if( localname == "xmlns" ) return nav.GetNamespace( string.Empty ); if ( (object)nav == (object)this.nav ) nav = nav.Clone(); if ( nav.MoveToAttribute( localname, string.Empty ) ) return nav.Value; } else { if( prefix == "xmlns" ) return nav.GetNamespace( localname ); if ((object)nav == (object)this.nav) nav = nav.Clone(); if (nav.MoveToFirstAttribute()) { do { if (nav.LocalName == localname && nav.Prefix == prefix) return nav.Value; } while (nav.MoveToNextAttribute()); } } return null; } public override string GetAttribute( string localName, string namespaceURI ) { if ( null == localName ) throw new ArgumentNullException("localName"); // reader allows calling GetAttribute, even when positioned inside attributes XPathNavigator nav = this.nav; switch (nav.NodeType) { case XPathNodeType.Element: break; case XPathNodeType.Attribute: nav = nav.Clone(); if (!nav.MoveToParent()) return null; break; default: return null; } // are they really looking for a namespace-decl? if( namespaceURI == XmlReservedNs.NsXmlNs ) { if (localName == "xmlns") localName = string.Empty; return nav.GetNamespace( localName ); } if ( null == namespaceURI ) namespaceURI = string.Empty; // We need to clone the navigator and move the clone to the attribute to see whether the attribute exists, // because XPathNavigator.GetAttribute return string.Empty for both when the the attribute is not there or when // it has an empty value. XmlReader.GetAttribute must return null if the attribute does not exist. if ((object)nav == (object)this.nav) nav = nav.Clone(); if ( nav.MoveToAttribute( localName, namespaceURI ) ) { return nav.Value; } else { return null; } } private static string GetNamespaceByIndex( XPathNavigator nav, int index, out int count ) { string thisValue = nav.Value; string value = null; if ( nav.MoveToNextNamespace( XPathNamespaceScope.Local ) ) { value = GetNamespaceByIndex( nav, index, out count ); } else { count = 0; } if ( count == index ) { Debug.Assert( value == null ); value = thisValue; } count++; return value; } public override string GetAttribute( int index ) { if (index < 0) goto Error; XPathNavigator nav = GetElemNav(); if (null == nav) goto Error; if ( nav.MoveToFirstNamespace( XPathNamespaceScope.Local ) ) { // namespaces are returned in reverse order, // but we want to return them in the correct order, // so first count the namespaces int nsCount; string value = GetNamespaceByIndex( nav, index, out nsCount ); if ( null != value ) { return value; } index -= nsCount; nav.MoveToParent(); } if ( nav.MoveToFirstAttribute() ) { do { if (index == 0) return nav.Value; index--; } while ( nav.MoveToNextAttribute() ); } // can't find it... error Error: throw new ArgumentOutOfRangeException("index"); } public override bool MoveToAttribute( string localName, string namespaceName ) { if ( null == localName ) throw new ArgumentNullException("localName"); int depth = this.depth; XPathNavigator nav = GetElemNav(out depth); if (null != nav) { if ( namespaceName == XmlReservedNs.NsXmlNs ) { if (localName == "xmlns") localName = string.Empty; if( nav.MoveToFirstNamespace( XPathNamespaceScope.Local ) ) { do { if ( nav.LocalName == localName ) goto FoundMatch; } while( nav.MoveToNextNamespace( XPathNamespaceScope.Local ) ); } } else { if (null == namespaceName) namespaceName = string.Empty; if ( nav.MoveToAttribute( localName, namespaceName ) ) goto FoundMatch; } } return false; FoundMatch: if ( state == State.InReadBinary ) { readBinaryHelper.Finish(); state = savedState; } MoveToAttr(nav, depth+1); return true; } public override bool MoveToFirstAttribute() { int depth; XPathNavigator nav = GetElemNav(out depth); if (null != nav) { if ( nav.MoveToFirstNamespace( XPathNamespaceScope.Local ) ) { // attributes are in reverse order while ( nav.MoveToNextNamespace( XPathNamespaceScope.Local ) ) ; goto FoundMatch; } if ( nav.MoveToFirstAttribute() ) { goto FoundMatch; } } return false; FoundMatch: if ( state == State.InReadBinary ) { readBinaryHelper.Finish(); state = savedState; } MoveToAttr(nav, depth+1); return true; } public override bool MoveToNextAttribute() { switch (this.state) { case State.Content: return MoveToFirstAttribute(); case State.Attribute: { if (XPathNodeType.Attribute == this.nav.NodeType) return this.nav.MoveToNextAttribute(); // otherwise it is on a namespace... namespace are in reverse order Debug.Assert( XPathNodeType.Namespace == this.nav.NodeType ); XPathNavigator nav = this.nav.Clone(); if ( !nav.MoveToParent() ) return false; // shouldn't happen if ( !nav.MoveToFirstNamespace( XPathNamespaceScope.Local ) ) return false; // shouldn't happen if ( nav.IsSamePosition( this.nav ) ) { // this was the last one... start walking attributes nav.MoveToParent(); if (!nav.MoveToFirstAttribute()) return false; // otherwise we are there this.nav.MoveTo(nav); return true; } else { XPathNavigator prev = nav.Clone(); for (;;) { if ( !nav.MoveToNextNamespace( XPathNamespaceScope.Local ) ) { Debug.Fail( "Couldn't find Namespace Node! Should not happen!" ); return false; } if ( nav.IsSamePosition( this.nav ) ) { this.nav.MoveTo(prev); return true; } prev.MoveTo( nav ); } // found previous namespace position } } case State.AttrVal: depth--; this.state = State.Attribute; if (!MoveToNextAttribute()) { depth++; this.state = State.AttrVal; return false; } this.nodeType = XmlNodeType.Attribute; return true; case State.InReadBinary: state = savedState; if (!MoveToNextAttribute()) { state = State.InReadBinary; return false; } readBinaryHelper.Finish(); return true; default: return false; } } public override bool MoveToAttribute( string name ) { int depth; XPathNavigator nav = GetElemNav(out depth); if (null == nav) return false; string prefix, localname; ValidateNames.SplitQName( name, out prefix, out localname ); // watch for a namespace name bool IsXmlnsNoPrefix = false; if ( ( IsXmlnsNoPrefix = ( 0 == prefix.Length && localname == "xmlns" ) ) || ( prefix == "xmlns" ) ) { if ( IsXmlnsNoPrefix ) localname = string.Empty; if ( nav.MoveToFirstNamespace(XPathNamespaceScope.Local) ) { do { if (nav.LocalName == localname) goto FoundMatch; } while ( nav.MoveToNextNamespace(XPathNamespaceScope.Local) ); } } else if ( 0 == prefix.Length ) { // the empty prefix always means empty namespaceUri for attributes if ( nav.MoveToAttribute( localname, string.Empty ) ) goto FoundMatch; } else { if ( nav.MoveToFirstAttribute() ) { do { if (nav.LocalName == localname && nav.Prefix == prefix) goto FoundMatch; } while (nav.MoveToNextAttribute()); } } return false; FoundMatch: if ( state == State.InReadBinary ) { readBinaryHelper.Finish(); state = savedState; } MoveToAttr(nav, depth+1); return true; } public override bool MoveToElement() { switch (this.state) { case State.Attribute: case State.AttrVal: if (!nav.MoveToParent()) return false; this.depth--; if (this.state == State.AttrVal) this.depth--; this.state = State.Content; this.nodeType = XmlNodeType.Element; return true; case State.InReadBinary: state = savedState; if (!MoveToElement()) { state = State.InReadBinary; return false; } readBinaryHelper.Finish(); break; } return false; } public override bool EOF { get { return this.state == State.EOF; } } public override ReadState ReadState { get { switch (this.state) { case State.Initial: return ReadState.Initial; case State.Content: case State.EndElement: case State.Attribute: case State.AttrVal: case State.InReadBinary: return ReadState.Interactive; case State.EOF: return ReadState.EndOfFile; case State.Closed: return ReadState.Closed; default: return ReadState.Error; } } } public override void ResolveEntity() { throw new InvalidOperationException( Res.GetString( Res.Xml_InvalidOperation ) ); } public override bool ReadAttributeValue() { if ( state == State.InReadBinary ) { readBinaryHelper.Finish(); state = savedState; } if ( this.state == State.Attribute ) { this.state = State.AttrVal; this.nodeType = XmlNodeType.Text; this.depth++; return true; } 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 ( state != State.InReadBinary ) { readBinaryHelper = ReadContentAsBinaryHelper.CreateOrReset( readBinaryHelper, this ); savedState = state; } // turn off InReadBinary state in order to have a normal Read() behavior when called from readBinaryHelper state = savedState; // call to the helper int readCount = readBinaryHelper.ReadContentAsBase64( buffer, index, count ); // turn on InReadBinary state again and return savedState = state; state = State.InReadBinary; 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 ( state != State.InReadBinary ) { readBinaryHelper = ReadContentAsBinaryHelper.CreateOrReset( readBinaryHelper, this ); savedState = state; } // turn off InReadBinary state in order to have a normal Read() behavior when called from readBinaryHelper state = savedState; // call to the helper int readCount = readBinaryHelper.ReadContentAsBinHex( buffer, index, count ); // turn on InReadBinary state again and return savedState = state; state = State.InReadBinary; 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 ( state != State.InReadBinary ) { readBinaryHelper = ReadContentAsBinaryHelper.CreateOrReset( readBinaryHelper, this ); savedState = state; } // turn off InReadBinary state in order to have a normal Read() behavior when called from readBinaryHelper state = savedState; // call to the helper int readCount = readBinaryHelper.ReadElementContentAsBase64( buffer, index, count ); // turn on InReadBinary state again and return savedState = state; state = State.InReadBinary; 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 ( state != State.InReadBinary ) { readBinaryHelper = ReadContentAsBinaryHelper.CreateOrReset( readBinaryHelper, this ); savedState = state; } // turn off InReadBinary state in order to have a normal Read() behavior when called from readBinaryHelper state = savedState; // call to the helper int readCount = readBinaryHelper.ReadElementContentAsBinHex( buffer, index, count ); // turn on InReadBinary state again and return savedState = state; state = State.InReadBinary; return readCount; } public override string LookupNamespace( string prefix ) { return this.nav.LookupNamespace( prefix ); } /// /// Current depth in subtree. /// public override int Depth { get { return this.depth; } } /// /// Move to the next reader state. Return false if that is ReaderState.Closed. /// public override bool Read() { this.attrCount = -1; switch (this.state) { case State.Error: case State.Closed: case State.EOF: return false; case State.Initial: // Starting state depends on the navigator's item type this.nav = this.navToRead; this.state = State.Content; if ( XPathNodeType.Root == this.nav.NodeType ) { if( !nav.MoveToFirstChild() ) { SetEOF(); return false; } this.readEntireDocument = true; } else if ( XPathNodeType.Attribute == this.nav.NodeType ) { this.state = State.Attribute; } this.nodeType = ToXmlNodeType( this.nav.NodeType ); break; case State.Content: if ( this.nav.MoveToFirstChild() ) { this.nodeType = ToXmlNodeType( this.nav.NodeType ); this.depth++; this.state = State.Content; } else if ( this.nodeType == XmlNodeType.Element && !this.nav.IsEmptyElement ) { this.nodeType = XmlNodeType.EndElement; this.state = State.EndElement; } else goto case State.EndElement; break; case State.EndElement: if ( 0 == depth && !this.readEntireDocument ) { SetEOF(); return false; } else if ( this.nav.MoveToNext() ) { this.nodeType = ToXmlNodeType( this.nav.NodeType ); this.state = State.Content; } else if ( depth > 0 && this.nav.MoveToParent() ) { Debug.Assert( this.nav.NodeType == XPathNodeType.Element, this.nav.NodeType.ToString() + " == XPathNodeType.Element" ); this.nodeType = XmlNodeType.EndElement; this.state = State.EndElement; depth--; } else { SetEOF(); return false; } break; case State.Attribute: case State.AttrVal: if ( !this.nav.MoveToParent() ) { SetEOF(); return false; } this.nodeType = ToXmlNodeType( this.nav.NodeType ); this.depth--; if (state == State.AttrVal) this.depth--; goto case State.Content; case State.InReadBinary: state = savedState; readBinaryHelper.Finish(); return Read(); } return true; } /// /// End reading by transitioning into the Closed state. /// public override void Close() { this.nav = XmlEmptyNavigator.Singleton; this.nodeType = XmlNodeType.None; this.state = State.Closed; this.depth = 0; } /// /// set reader to EOF state /// private void SetEOF() { this.nav = XmlEmptyNavigator.Singleton; this.nodeType = XmlNodeType.None; this.state = State.EOF; this.depth = 0; } } #if NAVREADER_SUPPORTSLINEINFO internal class XPathNavigatorReaderWithLI : XPathNavigatorReader, System.Xml.IXmlLineInfo { internal XPathNavigatorReaderWithLI( XPathNavigator navToRead, IXmlLineInfo xli, IXmlSchemaInfo xsi ) : base( navToRead, xli, xsi ) { } //----------------------------------------------- // IXmlLineInfo //----------------------------------------------- public virtual bool HasLineInfo() { return IsReading ? this.lineInfo.HasLineInfo() : false; } public virtual int LineNumber { get { return IsReading ? this.lineInfo.LineNumber : 0; } } public virtual int LinePosition { get { return IsReading ? this.lineInfo.LinePosition : 0; } } } internal class XPathNavigatorReaderWithLIAndSI : XPathNavigatorReaderWithLI, System.Xml.IXmlLineInfo, System.Xml.Schema.IXmlSchemaInfo { internal XPathNavigatorReaderWithLIAndSI( XPathNavigator navToRead, IXmlLineInfo xli, IXmlSchemaInfo xsi ) : base( navToRead, xli, xsi ) { } //----------------------------------------------- // IXmlSchemaInfo //----------------------------------------------- public virtual XmlSchemaValidity Validity { get { return IsReading ? this.schemaInfo.Validity : XmlSchemaValidity.NotKnown; } } public override bool IsDefault { get { return IsReading ? this.schemaInfo.IsDefault : false; } } public virtual bool IsNil { get { return IsReading ? this.schemaInfo.IsNil : false; } } public virtual XmlSchemaSimpleType MemberType { get { return IsReading ? this.schemaInfo.MemberType : null; } } public virtual XmlSchemaType SchemaType { get { return IsReading ? this.schemaInfo.SchemaType : null; } } public virtual XmlSchemaElement SchemaElement { get { return IsReading ? this.schemaInfo.SchemaElement : null; } } public virtual XmlSchemaAttribute SchemaAttribute { get { return IsReading ? this.schemaInfo.SchemaAttribute : null; } } } #endif internal class XPathNavigatorReaderWithSI : XPathNavigatorReader, System.Xml.Schema.IXmlSchemaInfo { internal XPathNavigatorReaderWithSI( XPathNavigator navToRead, IXmlLineInfo xli, IXmlSchemaInfo xsi ) : base( navToRead, xli, xsi ) { } //----------------------------------------------- // IXmlSchemaInfo //----------------------------------------------- public virtual XmlSchemaValidity Validity { get { return IsReading ? this.schemaInfo.Validity : XmlSchemaValidity.NotKnown; } } public override bool IsDefault { get { return IsReading ? this.schemaInfo.IsDefault : false; } } public virtual bool IsNil { get { return IsReading ? this.schemaInfo.IsNil : false; } } public virtual XmlSchemaSimpleType MemberType { get { return IsReading ? this.schemaInfo.MemberType : null; } } public virtual XmlSchemaType SchemaType { get { return IsReading ? this.schemaInfo.SchemaType : null; } } public virtual XmlSchemaElement SchemaElement { get { return IsReading ? this.schemaInfo.SchemaElement : null; } } public virtual XmlSchemaAttribute SchemaAttribute { get { return IsReading ? this.schemaInfo.SchemaAttribute : null; } } } /// /// The XmlEmptyNavigator exposes a document node with no children. /// Only one XmlEmptyNavigator exists per AppDomain (Singleton). That's why the constructor is private. /// Use the Singleton property to get the EmptyNavigator. /// internal class XmlEmptyNavigator : XPathNavigator { private static volatile XmlEmptyNavigator singleton; private XmlEmptyNavigator() { } public static XmlEmptyNavigator Singleton { get { if (XmlEmptyNavigator.singleton == null) XmlEmptyNavigator.singleton = new XmlEmptyNavigator(); return XmlEmptyNavigator.singleton; } } //----------------------------------------------- // XmlReader //----------------------------------------------- public override XPathNodeType NodeType { get { return XPathNodeType.All; } } public override string NamespaceURI { get { return string.Empty; } } public override string LocalName { get { return string.Empty; } } public override string Name { get { return string.Empty; } } public override string Prefix { get { return string.Empty; } } public override string BaseURI { get { return string.Empty; } } public override string Value { get { return string.Empty; } } public override bool IsEmptyElement { get { return false; } } public override string XmlLang { get { return string.Empty; } } public override bool HasAttributes { get { return false; } } public override bool HasChildren { get { return false; } } //----------------------------------------------- // IXmlNamespaceResolver //----------------------------------------------- public override XmlNameTable NameTable { get { return new NameTable(); } } public override bool MoveToFirstChild() { return false; } public override void MoveToRoot() { //always on root return; } public override bool MoveToNext() { return false; } public override bool MoveToPrevious() { return false; } public override bool MoveToFirst() { return false; } public override bool MoveToFirstAttribute() { return false; } public override bool MoveToNextAttribute() { return false; } public override bool MoveToId(string id) { return false; } public override string GetAttribute(string localName, string namespaceName) { return null; } public override bool MoveToAttribute(string localName, string namespaceName) { return false; } public override string GetNamespace( string name ) { return null; } public override bool MoveToNamespace( string prefix ) { return false; } public override bool MoveToFirstNamespace(XPathNamespaceScope scope) { return false; } public override bool MoveToNextNamespace(XPathNamespaceScope scope) { return false; } public override bool MoveToParent() { return false; } public override bool MoveTo(XPathNavigator other) { // Only one instance of XmlEmptyNavigator exists on the system return (object) this == (object) other; } public override XmlNodeOrder ComparePosition(XPathNavigator other) { // Only one instance of XmlEmptyNavigator exists on the system return ((object) this == (object) other) ? XmlNodeOrder.Same : XmlNodeOrder.Unknown; } public override bool IsSamePosition(XPathNavigator other) { // Only one instance of XmlEmptyNavigator exists on the system return (object) this == (object) other; } //----------------------------------------------- // XPathNavigator2 //----------------------------------------------- public override XPathNavigator Clone() { // Singleton, so clone just returns this return this; } } }