Updates referencesource to .NET 4.7
[mono-project.git] / mcs / class / referencesource / System.Xml / System / Xml / XPath / XPathNavigatorReader.cs
blob12226d2052b6149c548c3422ffe49373b17721d2
1 //------------------------------------------------------------------------------
2 // <copyright file="XmlNavigatorReader.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
4 // </copyright>
5 // <owner current="true" primary="true">Microsoft</owner>
6 //------------------------------------------------------------------------------
8 using System.IO;
9 using System.Xml.Schema;
10 using System.Collections;
11 using System.Diagnostics;
12 using System.Collections.Generic;
15 namespace System.Xml.XPath {
17 /// <summary>
18 /// Reader that traverses the subtree rooted at the current position of the specified navigator.
19 /// </summary>
20 internal class XPathNavigatorReader : XmlReader, IXmlNamespaceResolver {
21 enum State {
22 Initial,
23 Content,
24 EndElement,
25 Attribute,
26 AttrVal,
27 InReadBinary,
28 EOF,
29 Closed,
30 Error,
33 private XPathNavigator nav;
34 private XPathNavigator navToRead;
35 private int depth;
36 private State state;
37 private XmlNodeType nodeType;
38 private int attrCount;
39 private bool readEntireDocument;
41 protected IXmlLineInfo lineInfo;
42 protected IXmlSchemaInfo schemaInfo;
44 private ReadContentAsBinaryHelper readBinaryHelper;
45 private State savedState;
47 internal const string space = "space";
49 internal static XmlNodeType[] convertFromXPathNodeType = {
50 XmlNodeType.Document, // XPathNodeType.Root
51 XmlNodeType.Element, // XPathNodeType.Element
52 XmlNodeType.Attribute, // XPathNodeType.Attribute
53 XmlNodeType.Attribute, // XPathNodeType.Namespace
54 XmlNodeType.Text, // XPathNodeType.Text
55 XmlNodeType.SignificantWhitespace, // XPathNodeType.SignificantWhitespace
56 XmlNodeType.Whitespace, // XPathNodeType.Whitespace
57 XmlNodeType.ProcessingInstruction, // XPathNodeType.ProcessingInstruction
58 XmlNodeType.Comment, // XPathNodeType.Comment
59 XmlNodeType.None // XPathNodeType.All
62 /// <summary>
63 /// Translates an XPathNodeType value into the corresponding XmlNodeType value.
64 /// XPathNodeType.Whitespace and XPathNodeType.SignificantWhitespace are mapped into XmlNodeType.Text.
65 /// </summary>
66 internal static XmlNodeType ToXmlNodeType( XPathNodeType typ ) {
67 return XPathNavigatorReader.convertFromXPathNodeType[(int) typ];
70 internal object UnderlyingObject {
71 get {
72 return this.nav.UnderlyingObject;
76 static public XPathNavigatorReader Create(XPathNavigator navToRead ) {
77 XPathNavigator nav = navToRead.Clone();
78 IXmlLineInfo xli = nav as IXmlLineInfo;
79 IXmlSchemaInfo xsi = nav as IXmlSchemaInfo;
80 #if NAVREADER_SUPPORTSLINEINFO
81 if (null == xsi) {
82 if (null == xli) {
83 return new XPathNavigatorReader(nav, xli, xsi);
85 else {
86 return new XPathNavigatorReaderWithLI(nav, xli, xsi);
89 else {
90 if (null == xli) {
91 return new XPathNavigatorReaderWithSI(nav, xli, xsi);
93 else {
94 return new XPathNavigatorReaderWithLIAndSI(nav, xli, xsi);
97 #else
98 if (null == xsi) {
99 return new XPathNavigatorReader(nav, xli, xsi);
101 else {
102 return new XPathNavigatorReaderWithSI(nav, xli, xsi);
104 #endif
107 protected XPathNavigatorReader( XPathNavigator navToRead, IXmlLineInfo xli, IXmlSchemaInfo xsi ) {
108 // Need clone that can be moved independently of original navigator
109 this.navToRead = navToRead;
110 this.lineInfo = xli;
111 this.schemaInfo = xsi;
112 this.nav = XmlEmptyNavigator.Singleton;
113 this.state = State.Initial;
114 this.depth = 0;
115 this.nodeType = XPathNavigatorReader.ToXmlNodeType( this.nav.NodeType );
118 protected bool IsReading {
119 get { return this.state > State.Initial && this.state < State.EOF; }
122 internal override XmlNamespaceManager NamespaceManager {
123 get { return XPathNavigator.GetNamespaces( this ); }
127 //-----------------------------------------------
128 // IXmlNamespaceResolver -- pass through to Navigator
129 //-----------------------------------------------
130 public override XmlNameTable NameTable {
131 get {
132 return this.navToRead.NameTable;
136 IDictionary<string,string> IXmlNamespaceResolver.GetNamespacesInScope(XmlNamespaceScope scope) {
137 return this.nav.GetNamespacesInScope(scope);
140 string IXmlNamespaceResolver.LookupNamespace(string prefix) {
141 return this.nav.LookupNamespace(prefix);
144 string IXmlNamespaceResolver.LookupPrefix(string namespaceName) {
145 return this.nav.LookupPrefix(namespaceName);
148 //-----------------------------------------------
149 // XmlReader -- pass through to Navigator
150 //-----------------------------------------------
152 public override XmlReaderSettings Settings {
153 get {
154 XmlReaderSettings rs = new XmlReaderSettings();
155 rs.NameTable = this.NameTable;
156 rs.ConformanceLevel = ConformanceLevel.Fragment;
157 rs.CheckCharacters = false;
158 rs.ReadOnly = true;
159 return rs;
163 public override IXmlSchemaInfo SchemaInfo {
164 get {
165 // Special case attribute text (this.nav points to attribute even though current state is Text)
166 if ( this.nodeType == XmlNodeType.Text )
167 return null;
168 return this.nav.SchemaInfo;
172 public override System.Type ValueType {
173 get { return this.nav.ValueType; }
176 public override XmlNodeType NodeType {
177 get { return this.nodeType; }
180 public override string NamespaceURI {
181 get {
182 //NamespaceUri for namespace nodes is different in case of XPathNavigator and Reader
183 if (this.nav.NodeType == XPathNodeType.Namespace)
184 return this.NameTable.Add(XmlReservedNs.NsXmlNs);
185 //Special case attribute text node
186 if (this.NodeType == XmlNodeType.Text)
187 return string.Empty;
188 return this.nav.NamespaceURI;
192 public override string LocalName {
193 get {
194 //Default namespace in case of reader has a local name value of 'xmlns'
195 if (this.nav.NodeType == XPathNodeType.Namespace && this.nav.LocalName.Length == 0)
196 return this.NameTable.Add("xmlns");
197 //Special case attribute text node
198 if (this.NodeType == XmlNodeType.Text)
199 return string.Empty;
200 return this.nav.LocalName;
204 public override string Prefix {
205 get {
206 //Prefix for namespace nodes is different in case of XPathNavigator and Reader
207 if (this.nav.NodeType == XPathNodeType.Namespace && this.nav.LocalName.Length != 0)
208 return this.NameTable.Add("xmlns");
209 //Special case attribute text node
210 if (this.NodeType == XmlNodeType.Text)
211 return string.Empty;
212 return this.nav.Prefix;
216 public override string BaseURI {
217 get {
218 //reader returns BaseUri even before read method is called.
219 if( this.state == State.Initial )
220 return this.navToRead.BaseURI;
221 return this.nav.BaseURI;
225 public override bool IsEmptyElement {
226 get {
227 return this.nav.IsEmptyElement;
231 public override XmlSpace XmlSpace {
232 get {
233 XPathNavigator tempNav = this.nav.Clone();
234 do {
235 if (tempNav.MoveToAttribute(XPathNavigatorReader.space, XmlReservedNs.NsXml)) {
236 switch (XmlConvert.TrimString(tempNav.Value)) {
237 case "default":
238 return XmlSpace.Default;
239 case "preserve":
240 return XmlSpace.Preserve;
241 default:
242 break;
244 tempNav.MoveToParent();
247 while (tempNav.MoveToParent());
248 return XmlSpace.None;
252 public override string XmlLang {
253 get {
254 return this.nav.XmlLang;
258 public override bool HasValue {
259 get {
260 if( ( this.nodeType != XmlNodeType.Element )
261 && ( this.nodeType !=XmlNodeType.Document )
262 && ( this.nodeType !=XmlNodeType.EndElement )
263 && ( this.nodeType !=XmlNodeType.None ) )
264 return true;
265 return false;
269 public override string Value {
270 get {
271 if( ( this.nodeType != XmlNodeType.Element )
272 && ( this.nodeType !=XmlNodeType.Document )
273 && ( this.nodeType !=XmlNodeType.EndElement )
274 && ( this.nodeType !=XmlNodeType.None ) )
275 return this.nav.Value;
276 return string.Empty;
280 private XPathNavigator GetElemNav() {
281 XPathNavigator tempNav;
282 switch (this.state) {
283 case State.Content:
284 return this.nav.Clone();
285 case State.Attribute:
286 case State.AttrVal:
287 tempNav = this.nav.Clone();
288 if (tempNav.MoveToParent())
289 return tempNav;
290 break;
291 case State.InReadBinary:
292 state = savedState;
293 XPathNavigator nav = GetElemNav();
294 state = State.InReadBinary;
295 return nav;
297 return null;
300 private XPathNavigator GetElemNav(out int depth) {
301 XPathNavigator nav = null;
302 switch (this.state) {
303 case State.Content:
304 if (this.nodeType == XmlNodeType.Element)
305 nav = this.nav.Clone();
306 depth = this.depth;
307 break;
308 case State.Attribute:
309 nav = this.nav.Clone();
310 nav.MoveToParent();
311 depth = this.depth - 1;
312 break;
313 case State.AttrVal:
314 nav = this.nav.Clone();
315 nav.MoveToParent();
316 depth = this.depth - 2;
317 break;
318 case State.InReadBinary:
319 state = savedState;
320 nav = GetElemNav(out depth);
321 state = State.InReadBinary;
322 break;
323 default:
324 depth = this.depth;
325 break;
327 return nav;
330 private void MoveToAttr(XPathNavigator nav, int depth) {
331 this.nav.MoveTo( nav );
332 this.depth = depth;
333 this.nodeType = XmlNodeType.Attribute;
334 this.state = State.Attribute;
337 public override int AttributeCount {
338 get {
339 if ( this.attrCount < 0 ) {
340 // attribute count works for element, regardless of where you are in start tag
341 XPathNavigator tempNav = GetElemNav();
342 int count = 0;
343 if ( null != tempNav ) {
344 if( tempNav.MoveToFirstNamespace( XPathNamespaceScope.Local ) ) {
345 do {
346 count++;
347 } while( tempNav.MoveToNextNamespace( ( XPathNamespaceScope.Local ) ) );
348 tempNav.MoveToParent();
350 if( tempNav.MoveToFirstAttribute() ) {
351 do {
352 count++;
353 } while( tempNav.MoveToNextAttribute() );
356 this.attrCount = count;
358 return this.attrCount;
362 public override string GetAttribute( string name ) {
363 // reader allows calling GetAttribute, even when positioned inside attributes
364 XPathNavigator nav = this.nav;
365 switch (nav.NodeType) {
366 case XPathNodeType.Element:
367 break;
368 case XPathNodeType.Attribute:
369 nav = nav.Clone();
370 if (!nav.MoveToParent())
371 return null;
372 break;
373 default:
374 return null;
376 string prefix, localname;
377 ValidateNames.SplitQName( name, out prefix, out localname );
378 if ( 0 == prefix.Length ) {
379 if( localname == "xmlns" )
380 return nav.GetNamespace( string.Empty );
381 if ( (object)nav == (object)this.nav )
382 nav = nav.Clone();
383 if ( nav.MoveToAttribute( localname, string.Empty ) )
384 return nav.Value;
386 else {
387 if( prefix == "xmlns" )
388 return nav.GetNamespace( localname );
389 if ((object)nav == (object)this.nav)
390 nav = nav.Clone();
391 if (nav.MoveToFirstAttribute()) {
392 do {
393 if (nav.LocalName == localname && nav.Prefix == prefix)
394 return nav.Value;
395 } while (nav.MoveToNextAttribute());
398 return null;
401 public override string GetAttribute( string localName, string namespaceURI ) {
402 if ( null == localName )
403 throw new ArgumentNullException("localName");
404 // reader allows calling GetAttribute, even when positioned inside attributes
405 XPathNavigator nav = this.nav;
406 switch (nav.NodeType) {
407 case XPathNodeType.Element:
408 break;
409 case XPathNodeType.Attribute:
410 nav = nav.Clone();
411 if (!nav.MoveToParent())
412 return null;
413 break;
414 default:
415 return null;
417 // are they really looking for a namespace-decl?
418 if( namespaceURI == XmlReservedNs.NsXmlNs ) {
419 if (localName == "xmlns")
420 localName = string.Empty;
421 return nav.GetNamespace( localName );
423 if ( null == namespaceURI )
424 namespaceURI = string.Empty;
425 // We need to clone the navigator and move the clone to the attribute to see whether the attribute exists,
426 // because XPathNavigator.GetAttribute return string.Empty for both when the the attribute is not there or when
427 // it has an empty value. XmlReader.GetAttribute must return null if the attribute does not exist.
428 if ((object)nav == (object)this.nav)
429 nav = nav.Clone();
430 if ( nav.MoveToAttribute( localName, namespaceURI ) ) {
431 return nav.Value;
433 else {
434 return null;
438 private static string GetNamespaceByIndex( XPathNavigator nav, int index, out int count ) {
439 string thisValue = nav.Value;
440 string value = null;
441 if ( nav.MoveToNextNamespace( XPathNamespaceScope.Local ) ) {
442 value = GetNamespaceByIndex( nav, index, out count );
444 else {
445 count = 0;
447 if ( count == index ) {
448 Debug.Assert( value == null );
449 value = thisValue;
451 count++;
452 return value;
455 public override string GetAttribute( int index ) {
456 if (index < 0)
457 goto Error;
458 XPathNavigator nav = GetElemNav();
459 if (null == nav)
460 goto Error;
461 if ( nav.MoveToFirstNamespace( XPathNamespaceScope.Local ) ) {
462 // namespaces are returned in reverse order,
463 // but we want to return them in the correct order,
464 // so first count the namespaces
465 int nsCount;
466 string value = GetNamespaceByIndex( nav, index, out nsCount );
467 if ( null != value ) {
468 return value;
470 index -= nsCount;
471 nav.MoveToParent();
473 if ( nav.MoveToFirstAttribute() ) {
474 do {
475 if (index == 0)
476 return nav.Value;
477 index--;
478 } while ( nav.MoveToNextAttribute() );
480 // can't find it... error
481 Error:
482 throw new ArgumentOutOfRangeException("index");
486 public override bool MoveToAttribute( string localName, string namespaceName ) {
487 if ( null == localName )
488 throw new ArgumentNullException("localName");
489 int depth = this.depth;
490 XPathNavigator nav = GetElemNav(out depth);
491 if (null != nav) {
492 if ( namespaceName == XmlReservedNs.NsXmlNs ) {
493 if (localName == "xmlns")
494 localName = string.Empty;
495 if( nav.MoveToFirstNamespace( XPathNamespaceScope.Local ) ) {
496 do {
497 if ( nav.LocalName == localName )
498 goto FoundMatch;
499 } while( nav.MoveToNextNamespace( XPathNamespaceScope.Local ) );
502 else {
503 if (null == namespaceName)
504 namespaceName = string.Empty;
505 if ( nav.MoveToAttribute( localName, namespaceName ) )
506 goto FoundMatch;
509 return false;
511 FoundMatch:
512 if ( state == State.InReadBinary ) {
513 readBinaryHelper.Finish();
514 state = savedState;
516 MoveToAttr(nav, depth+1);
517 return true;
520 public override bool MoveToFirstAttribute() {
521 int depth;
522 XPathNavigator nav = GetElemNav(out depth);
523 if (null != nav) {
524 if ( nav.MoveToFirstNamespace( XPathNamespaceScope.Local ) ) {
525 // attributes are in reverse order
526 while ( nav.MoveToNextNamespace( XPathNamespaceScope.Local ) )
528 goto FoundMatch;
530 if ( nav.MoveToFirstAttribute() ) {
531 goto FoundMatch;
534 return false;
535 FoundMatch:
536 if ( state == State.InReadBinary ) {
537 readBinaryHelper.Finish();
538 state = savedState;
540 MoveToAttr(nav, depth+1);
541 return true;
544 public override bool MoveToNextAttribute() {
545 switch (this.state) {
546 case State.Content:
547 return MoveToFirstAttribute();
549 case State.Attribute: {
550 if (XPathNodeType.Attribute == this.nav.NodeType)
551 return this.nav.MoveToNextAttribute();
553 // otherwise it is on a namespace... namespace are in reverse order
554 Debug.Assert( XPathNodeType.Namespace == this.nav.NodeType );
555 XPathNavigator nav = this.nav.Clone();
556 if ( !nav.MoveToParent() )
557 return false; // shouldn't happen
558 if ( !nav.MoveToFirstNamespace( XPathNamespaceScope.Local ) )
559 return false; // shouldn't happen
560 if ( nav.IsSamePosition( this.nav ) ) {
561 // this was the last one... start walking attributes
562 nav.MoveToParent();
563 if (!nav.MoveToFirstAttribute())
564 return false;
565 // otherwise we are there
566 this.nav.MoveTo(nav);
567 return true;
569 else {
570 XPathNavigator prev = nav.Clone();
571 for (;;) {
572 if ( !nav.MoveToNextNamespace( XPathNamespaceScope.Local ) ) {
573 Debug.Fail( "Couldn't find Namespace Node! Should not happen!" );
574 return false;
576 if ( nav.IsSamePosition( this.nav ) ) {
577 this.nav.MoveTo(prev);
578 return true;
580 prev.MoveTo( nav );
582 // found previous namespace position
585 case State.AttrVal:
586 depth--;
587 this.state = State.Attribute;
588 if (!MoveToNextAttribute()) {
589 depth++;
590 this.state = State.AttrVal;
591 return false;
593 this.nodeType = XmlNodeType.Attribute;
594 return true;
596 case State.InReadBinary:
597 state = savedState;
598 if (!MoveToNextAttribute()) {
599 state = State.InReadBinary;
600 return false;
602 readBinaryHelper.Finish();
603 return true;
605 default:
606 return false;
610 public override bool MoveToAttribute( string name ) {
611 int depth;
612 XPathNavigator nav = GetElemNav(out depth);
613 if (null == nav)
614 return false;
616 string prefix, localname;
617 ValidateNames.SplitQName( name, out prefix, out localname );
619 // watch for a namespace name
620 bool IsXmlnsNoPrefix = false;
621 if ( ( IsXmlnsNoPrefix = ( 0 == prefix.Length && localname == "xmlns" ) )
622 || ( prefix == "xmlns" ) ) {
623 if ( IsXmlnsNoPrefix )
624 localname = string.Empty;
625 if ( nav.MoveToFirstNamespace(XPathNamespaceScope.Local) ) {
626 do {
627 if (nav.LocalName == localname)
628 goto FoundMatch;
629 } while ( nav.MoveToNextNamespace(XPathNamespaceScope.Local) );
632 else if ( 0 == prefix.Length ) {
633 // the empty prefix always means empty namespaceUri for attributes
634 if ( nav.MoveToAttribute( localname, string.Empty ) )
635 goto FoundMatch;
637 else {
638 if ( nav.MoveToFirstAttribute() ) {
639 do {
640 if (nav.LocalName == localname && nav.Prefix == prefix)
641 goto FoundMatch;
642 } while (nav.MoveToNextAttribute());
645 return false;
647 FoundMatch:
648 if ( state == State.InReadBinary ) {
649 readBinaryHelper.Finish();
650 state = savedState;
652 MoveToAttr(nav, depth+1);
653 return true;
656 public override bool MoveToElement() {
657 switch (this.state) {
658 case State.Attribute:
659 case State.AttrVal:
660 if (!nav.MoveToParent())
661 return false;
662 this.depth--;
663 if (this.state == State.AttrVal)
664 this.depth--;
665 this.state = State.Content;
666 this.nodeType = XmlNodeType.Element;
667 return true;
668 case State.InReadBinary:
669 state = savedState;
670 if (!MoveToElement()) {
671 state = State.InReadBinary;
672 return false;
674 readBinaryHelper.Finish();
675 break;
677 return false;
680 public override bool EOF {
681 get {
682 return this.state == State.EOF;
686 public override ReadState ReadState {
687 get {
688 switch (this.state) {
689 case State.Initial:
690 return ReadState.Initial;
691 case State.Content:
692 case State.EndElement:
693 case State.Attribute:
694 case State.AttrVal:
695 case State.InReadBinary:
696 return ReadState.Interactive;
697 case State.EOF:
698 return ReadState.EndOfFile;
699 case State.Closed:
700 return ReadState.Closed;
701 default:
702 return ReadState.Error;
707 public override void ResolveEntity() {
708 throw new InvalidOperationException( Res.GetString( Res.Xml_InvalidOperation ) );
711 public override bool ReadAttributeValue() {
712 if ( state == State.InReadBinary ) {
713 readBinaryHelper.Finish();
714 state = savedState;
716 if ( this.state == State.Attribute ) {
717 this.state = State.AttrVal;
718 this.nodeType = XmlNodeType.Text;
719 this.depth++;
720 return true;
722 return false;
725 public override bool CanReadBinaryContent {
726 get {
727 return true;
731 public override int ReadContentAsBase64( byte[] buffer, int index, int count ) {
732 if ( ReadState != ReadState.Interactive ) {
733 return 0;
736 // init ReadContentAsBinaryHelper when called first time
737 if ( state != State.InReadBinary ) {
738 readBinaryHelper = ReadContentAsBinaryHelper.CreateOrReset( readBinaryHelper, this );
739 savedState = state;
742 // turn off InReadBinary state in order to have a normal Read() behavior when called from readBinaryHelper
743 state = savedState;
745 // call to the helper
746 int readCount = readBinaryHelper.ReadContentAsBase64( buffer, index, count );
748 // turn on InReadBinary state again and return
749 savedState = state;
750 state = State.InReadBinary;
751 return readCount;
754 public override int ReadContentAsBinHex( byte[] buffer, int index, int count ) {
755 if ( ReadState != ReadState.Interactive ) {
756 return 0;
759 // init ReadContentAsBinaryHelper when called first time
760 if ( state != State.InReadBinary ) {
761 readBinaryHelper = ReadContentAsBinaryHelper.CreateOrReset( readBinaryHelper, this );
762 savedState = state;
765 // turn off InReadBinary state in order to have a normal Read() behavior when called from readBinaryHelper
766 state = savedState;
768 // call to the helper
769 int readCount = readBinaryHelper.ReadContentAsBinHex( buffer, index, count );
771 // turn on InReadBinary state again and return
772 savedState = state;
773 state = State.InReadBinary;
774 return readCount;
777 public override int ReadElementContentAsBase64( byte[] buffer, int index, int count ) {
778 if ( ReadState != ReadState.Interactive ) {
779 return 0;
782 // init ReadContentAsBinaryHelper when called first time
783 if ( state != State.InReadBinary ) {
784 readBinaryHelper = ReadContentAsBinaryHelper.CreateOrReset( readBinaryHelper, this );
785 savedState = state;
788 // turn off InReadBinary state in order to have a normal Read() behavior when called from readBinaryHelper
789 state = savedState;
791 // call to the helper
792 int readCount = readBinaryHelper.ReadElementContentAsBase64( buffer, index, count );
794 // turn on InReadBinary state again and return
795 savedState = state;
796 state = State.InReadBinary;
797 return readCount;
800 public override int ReadElementContentAsBinHex( byte[] buffer, int index, int count ) {
801 if ( ReadState != ReadState.Interactive ) {
802 return 0;
805 // init ReadContentAsBinaryHelper when called first time
806 if ( state != State.InReadBinary ) {
807 readBinaryHelper = ReadContentAsBinaryHelper.CreateOrReset( readBinaryHelper, this );
808 savedState = state;
811 // turn off InReadBinary state in order to have a normal Read() behavior when called from readBinaryHelper
812 state = savedState;
814 // call to the helper
815 int readCount = readBinaryHelper.ReadElementContentAsBinHex( buffer, index, count );
817 // turn on InReadBinary state again and return
818 savedState = state;
819 state = State.InReadBinary;
820 return readCount;
823 public override string LookupNamespace( string prefix ) {
824 return this.nav.LookupNamespace( prefix );
827 /// <summary>
828 /// Current depth in subtree.
829 /// </summary>
830 public override int Depth {
831 get { return this.depth; }
834 /// <summary>
835 /// Move to the next reader state. Return false if that is ReaderState.Closed.
836 /// </summary>
837 public override bool Read() {
838 this.attrCount = -1;
839 switch (this.state) {
840 case State.Error:
841 case State.Closed:
842 case State.EOF:
843 return false;
845 case State.Initial:
846 // Starting state depends on the navigator's item type
847 this.nav = this.navToRead;
848 this.state = State.Content;
849 if ( XPathNodeType.Root == this.nav.NodeType ) {
850 if( !nav.MoveToFirstChild() ) {
851 SetEOF();
852 return false;
854 this.readEntireDocument = true;
856 else if ( XPathNodeType.Attribute == this.nav.NodeType ) {
857 this.state = State.Attribute;
859 this.nodeType = ToXmlNodeType( this.nav.NodeType );
860 break;
862 case State.Content:
863 if ( this.nav.MoveToFirstChild() ) {
864 this.nodeType = ToXmlNodeType( this.nav.NodeType );
865 this.depth++;
866 this.state = State.Content;
868 else if ( this.nodeType == XmlNodeType.Element
869 && !this.nav.IsEmptyElement ) {
870 this.nodeType = XmlNodeType.EndElement;
871 this.state = State.EndElement;
873 else
874 goto case State.EndElement;
875 break;
877 case State.EndElement:
878 if ( 0 == depth && !this.readEntireDocument ) {
879 SetEOF();
880 return false;
882 else if ( this.nav.MoveToNext() ) {
883 this.nodeType = ToXmlNodeType( this.nav.NodeType );
884 this.state = State.Content;
886 else if ( depth > 0 && this.nav.MoveToParent() ) {
887 Debug.Assert( this.nav.NodeType == XPathNodeType.Element, this.nav.NodeType.ToString() + " == XPathNodeType.Element" );
888 this.nodeType = XmlNodeType.EndElement;
889 this.state = State.EndElement;
890 depth--;
892 else {
893 SetEOF();
894 return false;
896 break;
898 case State.Attribute:
899 case State.AttrVal:
900 if ( !this.nav.MoveToParent() ) {
901 SetEOF();
902 return false;
904 this.nodeType = ToXmlNodeType( this.nav.NodeType );
905 this.depth--;
906 if (state == State.AttrVal)
907 this.depth--;
908 goto case State.Content;
909 case State.InReadBinary:
910 state = savedState;
911 readBinaryHelper.Finish();
912 return Read();
914 return true;
918 /// <summary>
919 /// End reading by transitioning into the Closed state.
920 /// </summary>
921 public override void Close() {
922 this.nav = XmlEmptyNavigator.Singleton;
923 this.nodeType = XmlNodeType.None;
924 this.state = State.Closed;
925 this.depth = 0;
928 /// <summary>
929 /// set reader to EOF state
930 /// </summary>
931 private void SetEOF() {
932 this.nav = XmlEmptyNavigator.Singleton;
933 this.nodeType = XmlNodeType.None;
934 this.state = State.EOF;
935 this.depth = 0;
939 #if NAVREADER_SUPPORTSLINEINFO
940 internal class XPathNavigatorReaderWithLI : XPathNavigatorReader, System.Xml.IXmlLineInfo {
941 internal XPathNavigatorReaderWithLI( XPathNavigator navToRead, IXmlLineInfo xli, IXmlSchemaInfo xsi )
942 : base( navToRead, xli, xsi ) {
945 //-----------------------------------------------
946 // IXmlLineInfo
947 //-----------------------------------------------
949 public virtual bool HasLineInfo() { return IsReading ? this.lineInfo.HasLineInfo() : false; }
950 public virtual int LineNumber { get { return IsReading ? this.lineInfo.LineNumber : 0; } }
951 public virtual int LinePosition { get { return IsReading ? this.lineInfo.LinePosition : 0; } }
954 internal class XPathNavigatorReaderWithLIAndSI : XPathNavigatorReaderWithLI, System.Xml.IXmlLineInfo, System.Xml.Schema.IXmlSchemaInfo {
955 internal XPathNavigatorReaderWithLIAndSI( XPathNavigator navToRead, IXmlLineInfo xli, IXmlSchemaInfo xsi )
956 : base( navToRead, xli, xsi ) {
959 //-----------------------------------------------
960 // IXmlSchemaInfo
961 //-----------------------------------------------
963 public virtual XmlSchemaValidity Validity { get { return IsReading ? this.schemaInfo.Validity : XmlSchemaValidity.NotKnown; } }
964 public override bool IsDefault { get { return IsReading ? this.schemaInfo.IsDefault : false; } }
965 public virtual bool IsNil { get { return IsReading ? this.schemaInfo.IsNil : false; } }
966 public virtual XmlSchemaSimpleType MemberType { get { return IsReading ? this.schemaInfo.MemberType : null; } }
967 public virtual XmlSchemaType SchemaType { get { return IsReading ? this.schemaInfo.SchemaType : null; } }
968 public virtual XmlSchemaElement SchemaElement { get { return IsReading ? this.schemaInfo.SchemaElement : null; } }
969 public virtual XmlSchemaAttribute SchemaAttribute { get { return IsReading ? this.schemaInfo.SchemaAttribute : null; } }
971 #endif
973 internal class XPathNavigatorReaderWithSI : XPathNavigatorReader, System.Xml.Schema.IXmlSchemaInfo {
974 internal XPathNavigatorReaderWithSI( XPathNavigator navToRead, IXmlLineInfo xli, IXmlSchemaInfo xsi )
975 : base( navToRead, xli, xsi ) {
978 //-----------------------------------------------
979 // IXmlSchemaInfo
980 //-----------------------------------------------
982 public virtual XmlSchemaValidity Validity { get { return IsReading ? this.schemaInfo.Validity : XmlSchemaValidity.NotKnown; } }
983 public override bool IsDefault { get { return IsReading ? this.schemaInfo.IsDefault : false; } }
984 public virtual bool IsNil { get { return IsReading ? this.schemaInfo.IsNil : false; } }
985 public virtual XmlSchemaSimpleType MemberType { get { return IsReading ? this.schemaInfo.MemberType : null; } }
986 public virtual XmlSchemaType SchemaType { get { return IsReading ? this.schemaInfo.SchemaType : null; } }
987 public virtual XmlSchemaElement SchemaElement { get { return IsReading ? this.schemaInfo.SchemaElement : null; } }
988 public virtual XmlSchemaAttribute SchemaAttribute { get { return IsReading ? this.schemaInfo.SchemaAttribute : null; } }
991 /// <summary>
992 /// The XmlEmptyNavigator exposes a document node with no children.
993 /// Only one XmlEmptyNavigator exists per AppDomain (Singleton). That's why the constructor is private.
994 /// Use the Singleton property to get the EmptyNavigator.
995 /// </summary>
996 internal class XmlEmptyNavigator : XPathNavigator {
997 private static volatile XmlEmptyNavigator singleton;
999 private XmlEmptyNavigator() {
1002 public static XmlEmptyNavigator Singleton {
1003 get {
1004 if (XmlEmptyNavigator.singleton == null)
1005 XmlEmptyNavigator.singleton = new XmlEmptyNavigator();
1006 return XmlEmptyNavigator.singleton;
1010 //-----------------------------------------------
1011 // XmlReader
1012 //-----------------------------------------------
1014 public override XPathNodeType NodeType {
1015 get { return XPathNodeType.All; }
1018 public override string NamespaceURI {
1019 get { return string.Empty; }
1022 public override string LocalName {
1023 get { return string.Empty; }
1026 public override string Name {
1027 get { return string.Empty; }
1030 public override string Prefix {
1031 get { return string.Empty; }
1034 public override string BaseURI {
1035 get { return string.Empty; }
1038 public override string Value {
1039 get { return string.Empty; }
1042 public override bool IsEmptyElement {
1043 get { return false; }
1046 public override string XmlLang {
1047 get { return string.Empty; }
1050 public override bool HasAttributes {
1051 get { return false; }
1054 public override bool HasChildren {
1055 get { return false; }
1059 //-----------------------------------------------
1060 // IXmlNamespaceResolver
1061 //-----------------------------------------------
1063 public override XmlNameTable NameTable {
1064 get { return new NameTable(); }
1067 public override bool MoveToFirstChild() {
1068 return false;
1071 public override void MoveToRoot() {
1072 //always on root
1073 return;
1076 public override bool MoveToNext() {
1077 return false;
1080 public override bool MoveToPrevious() {
1081 return false;
1084 public override bool MoveToFirst() {
1085 return false;
1088 public override bool MoveToFirstAttribute() {
1089 return false;
1092 public override bool MoveToNextAttribute() {
1093 return false;
1096 public override bool MoveToId(string id) {
1097 return false;
1100 public override string GetAttribute(string localName, string namespaceName) {
1101 return null;
1104 public override bool MoveToAttribute(string localName, string namespaceName) {
1105 return false;
1108 public override string GetNamespace( string name ) {
1109 return null;
1112 public override bool MoveToNamespace( string prefix ) {
1113 return false;
1117 public override bool MoveToFirstNamespace(XPathNamespaceScope scope) {
1118 return false;
1121 public override bool MoveToNextNamespace(XPathNamespaceScope scope) {
1122 return false;
1125 public override bool MoveToParent() {
1126 return false;
1129 public override bool MoveTo(XPathNavigator other) {
1130 // Only one instance of XmlEmptyNavigator exists on the system
1131 return (object) this == (object) other;
1134 public override XmlNodeOrder ComparePosition(XPathNavigator other) {
1135 // Only one instance of XmlEmptyNavigator exists on the system
1136 return ((object) this == (object) other) ? XmlNodeOrder.Same : XmlNodeOrder.Unknown;
1139 public override bool IsSamePosition(XPathNavigator other) {
1140 // Only one instance of XmlEmptyNavigator exists on the system
1141 return (object) this == (object) other;
1145 //-----------------------------------------------
1146 // XPathNavigator2
1147 //-----------------------------------------------
1148 public override XPathNavigator Clone() {
1149 // Singleton, so clone just returns this
1150 return this;