RegionIterator.cs 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. //------------------------------------------------------------------------------
  2. // <copyright file="RegionIterator.cs" company="Microsoft">
  3. // Copyright (c) Microsoft Corporation. All rights reserved.
  4. // </copyright>
  5. // <owner current="true" primary="true">Microsoft</owner>
  6. // <owner current="true" primary="false">Microsoft</owner>
  7. //------------------------------------------------------------------------------
  8. #pragma warning disable 618 // ignore obsolete warning about XmlDataDocument
  9. namespace System.Xml {
  10. using System;
  11. using System.Diagnostics;
  12. using System.Text;
  13. internal abstract class BaseRegionIterator : BaseTreeIterator {
  14. internal BaseRegionIterator( DataSetMapper mapper ) : base( mapper ) {
  15. }
  16. }
  17. // Iterates over non-attribute nodes
  18. internal sealed class RegionIterator : BaseRegionIterator {
  19. private XmlBoundElement rowElement;
  20. private XmlNode currentNode;
  21. internal RegionIterator( XmlBoundElement rowElement ) : base( ((XmlDataDocument)(rowElement.OwnerDocument)).Mapper ) {
  22. Debug.Assert( rowElement != null && rowElement.Row != null );
  23. this.rowElement = rowElement;
  24. this.currentNode = rowElement;
  25. }
  26. internal override void Reset() {
  27. currentNode = rowElement;
  28. }
  29. internal override XmlNode CurrentNode {
  30. get {
  31. return currentNode;
  32. }
  33. }
  34. internal override bool Next() {
  35. XmlNode nextNode;
  36. ElementState oldState = rowElement.ElementState;
  37. // We do not want to cause any foliation w/ this iterator or use this iterator once the region was defoliated
  38. Debug.Assert( oldState != ElementState.None );
  39. // Try to move to the first child
  40. nextNode = currentNode.FirstChild;
  41. // No children, try next sibling
  42. if ( nextNode != null ) {
  43. currentNode = nextNode;
  44. // If we have been defoliated, we should have stayed that way
  45. Debug.Assert( (oldState == ElementState.Defoliated) ? (rowElement.ElementState == ElementState.Defoliated) : true );
  46. // Rollback foliation
  47. rowElement.ElementState = oldState;
  48. return true;
  49. }
  50. return NextRight();
  51. }
  52. internal override bool NextRight() {
  53. // Make sure we do not get past the rowElement if we call NextRight on a just initialized iterator and rowElement has no children
  54. if ( currentNode == rowElement ) {
  55. currentNode = null;
  56. return false;
  57. }
  58. ElementState oldState = rowElement.ElementState;
  59. // We do not want to cause any foliation w/ this iterator or use this iterator once the region was defoliated
  60. Debug.Assert( oldState != ElementState.None );
  61. XmlNode nextNode = currentNode.NextSibling;
  62. if ( nextNode != null ) {
  63. currentNode = nextNode;
  64. // If we have been defoliated, we should have stayed that way
  65. Debug.Assert( (oldState == ElementState.Defoliated) ? (rowElement.ElementState == ElementState.Defoliated) : true );
  66. // Rollback foliation
  67. rowElement.ElementState = oldState;
  68. return true;
  69. }
  70. // No next sibling, try the first sibling of from the parent chain
  71. nextNode = currentNode;
  72. while ( nextNode != rowElement && nextNode.NextSibling == null )
  73. nextNode = nextNode.ParentNode;
  74. if ( nextNode == rowElement ) {
  75. currentNode = null;
  76. // If we have been defoliated, we should have stayed that way
  77. Debug.Assert( (oldState == ElementState.Defoliated) ? (rowElement.ElementState == ElementState.Defoliated) : true );
  78. // Rollback foliation
  79. rowElement.ElementState = oldState;
  80. return false;
  81. }
  82. currentNode = nextNode.NextSibling;
  83. Debug.Assert( currentNode != null );
  84. // If we have been defoliated, we should have stayed that way
  85. Debug.Assert( (oldState == ElementState.Defoliated) ? (rowElement.ElementState == ElementState.Defoliated) : true );
  86. // Rollback foliation
  87. rowElement.ElementState = oldState;
  88. return true;
  89. }
  90. // Get the initial text value for the current node. You should be positioned on the node (element) for
  91. // which to get the initial text value, not on the text node.
  92. internal bool NextInitialTextLikeNodes( out String value ) {
  93. Debug.Assert( this.CurrentNode != null );
  94. Debug.Assert( this.CurrentNode.NodeType == XmlNodeType.Element );
  95. #if DEBUG
  96. // It's not OK to try to read the initial text value for sub-regions, because we do not know how to revert their initial state
  97. if ( this.CurrentNode.NodeType == XmlNodeType.Element && mapper.GetTableSchemaForElement( (XmlElement)(this.CurrentNode) ) != null ) {
  98. if ( this.CurrentNode != rowElement )
  99. Debug.Assert( false );
  100. }
  101. #endif
  102. ElementState oldState = rowElement.ElementState;
  103. // We do not want to cause any foliation w/ this iterator or use this iterator once the region was defoliated
  104. Debug.Assert( oldState != ElementState.None );
  105. XmlNode n = this.CurrentNode.FirstChild;
  106. value = GetInitialTextFromNodes( ref n );
  107. if ( n == null ) {
  108. // If we have been defoliated, we should have stayed that way
  109. Debug.Assert( (oldState == ElementState.Defoliated) ? (rowElement.ElementState == ElementState.Defoliated) : true );
  110. // Rollback eventual foliation
  111. rowElement.ElementState = oldState;
  112. return NextRight();
  113. }
  114. Debug.Assert( ! XmlDataDocument.IsTextLikeNode( n ) );
  115. currentNode = n;
  116. // If we have been defoliated, we should have stayed that way
  117. Debug.Assert( (oldState == ElementState.Defoliated) ? (rowElement.ElementState == ElementState.Defoliated) : true );
  118. // Rollback eventual foliation
  119. rowElement.ElementState = oldState;
  120. return true;
  121. }
  122. private static string GetInitialTextFromNodes( ref XmlNode n ) {
  123. string value = null;
  124. if ( n != null ) {
  125. // don't consider whitespace
  126. while ( n.NodeType == XmlNodeType.Whitespace ) {
  127. n = n.NextSibling;
  128. if ( n == null )
  129. return String.Empty;
  130. }
  131. if ( XmlDataDocument.IsTextLikeNode( n ) && (n.NextSibling == null || ! XmlDataDocument.IsTextLikeNode( n.NextSibling )) ) {
  132. // don't use string builder if only one text node exists
  133. value = n.Value;
  134. n = n.NextSibling;
  135. }
  136. else {
  137. StringBuilder sb = new StringBuilder();
  138. while ( n != null && XmlDataDocument.IsTextLikeNode( n ) ) {
  139. // Ignore non-significant whitespace nodes
  140. if ( n.NodeType != XmlNodeType.Whitespace )
  141. sb.Append( n.Value );
  142. n = n.NextSibling;
  143. }
  144. value = sb.ToString();
  145. }
  146. }
  147. if ( value == null )
  148. value = String.Empty;
  149. return value;
  150. }
  151. }
  152. }