XPathNodePointer.cs 68 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508
  1. //------------------------------------------------------------------------------
  2. // <copyright file="XPathNodePointer.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.Data;
  12. using System.Diagnostics;
  13. using System.Xml.XPath;
  14. internal sealed class XPathNodePointer : IXmlDataVirtualNode {
  15. private WeakReference _owner; // Owner of this pointer (an DataDocumentXPathNavigator). When the associated DataDocumentXPathNavigator (the owner) goes away, this XPathNodePointer can go away as well.
  16. private XmlDataDocument _doc;
  17. private XmlNode _node;
  18. private DataColumn _column;
  19. private bool _fOnValue;
  20. internal XmlBoundElement _parentOfNS;
  21. internal static int[] xmlNodeType_To_XpathNodeType_Map;
  22. internal static string s_strReservedXmlns = "http://www.w3.org/2000/xmlns/";
  23. internal static string s_strReservedXml = "http://www.w3.org/XML/1998/namespace";
  24. internal static string s_strXmlNS = "xmlns";
  25. private bool _bNeedFoliate;
  26. static XPathNodePointer(){
  27. #if DEBUG
  28. int max=0, tempVal=0;
  29. Array enumValues = Enum.GetValues(typeof(XmlNodeType));
  30. for ( int i = 0; i < enumValues.Length; i++) {
  31. tempVal = (int)enumValues.GetValue(i);
  32. if ( tempVal > max )
  33. max = tempVal;
  34. }
  35. Debug.Assert( max == (int) XmlNodeType.XmlDeclaration );
  36. #endif
  37. xmlNodeType_To_XpathNodeType_Map = new int[20];
  38. xmlNodeType_To_XpathNodeType_Map[(int)(XmlNodeType.None)] = -1;
  39. xmlNodeType_To_XpathNodeType_Map[(int)(XmlNodeType.Element)] = (int)XPathNodeType.Element;
  40. xmlNodeType_To_XpathNodeType_Map[(int)(XmlNodeType.Attribute)] = (int)XPathNodeType.Attribute;
  41. xmlNodeType_To_XpathNodeType_Map[(int)(XmlNodeType.Text)] = (int)XPathNodeType.Text;
  42. xmlNodeType_To_XpathNodeType_Map[(int)(XmlNodeType.CDATA)] = (int)XPathNodeType.Text;
  43. xmlNodeType_To_XpathNodeType_Map[(int)(XmlNodeType.EntityReference)] = -1;
  44. xmlNodeType_To_XpathNodeType_Map[(int)(XmlNodeType.Entity)] = -1;
  45. xmlNodeType_To_XpathNodeType_Map[(int)(XmlNodeType.ProcessingInstruction)] = (int)XPathNodeType.ProcessingInstruction;
  46. xmlNodeType_To_XpathNodeType_Map[(int)(XmlNodeType.Comment)] = (int)XPathNodeType.Comment;
  47. xmlNodeType_To_XpathNodeType_Map[(int)(XmlNodeType.Document)] = (int)XPathNodeType.Root;
  48. xmlNodeType_To_XpathNodeType_Map[(int)(XmlNodeType.DocumentType)] = -1;
  49. xmlNodeType_To_XpathNodeType_Map[(int)(XmlNodeType.DocumentFragment)] = (int)XPathNodeType.Root;
  50. xmlNodeType_To_XpathNodeType_Map[(int)(XmlNodeType.Notation)] = -1;
  51. xmlNodeType_To_XpathNodeType_Map[(int)(XmlNodeType.Whitespace)] = (int)XPathNodeType.Whitespace;
  52. xmlNodeType_To_XpathNodeType_Map[(int)(XmlNodeType.SignificantWhitespace)] = (int)XPathNodeType.SignificantWhitespace;
  53. xmlNodeType_To_XpathNodeType_Map[(int)(XmlNodeType.EndElement)] = -1;
  54. xmlNodeType_To_XpathNodeType_Map[(int)(XmlNodeType.EndEntity)] = -1;
  55. xmlNodeType_To_XpathNodeType_Map[(int)(XmlNodeType.XmlDeclaration)] = -1;
  56. // xmlNodeType_To_XpathNodeType_Map[(int)(XmlNodeType.All)] = -1;
  57. }
  58. private XPathNodeType DecideXPNodeTypeForTextNodes( XmlNode node ) {
  59. //the function can only be called on text like nodes.
  60. Debug.Assert( XmlDataDocument.IsTextNode( node.NodeType ) );
  61. XPathNodeType xnt = XPathNodeType.Whitespace;
  62. while( node != null ) {
  63. switch( node.NodeType ) {
  64. case XmlNodeType.Whitespace :
  65. break;
  66. case XmlNodeType.SignificantWhitespace :
  67. xnt = XPathNodeType.SignificantWhitespace;
  68. break;
  69. case XmlNodeType.Text :
  70. case XmlNodeType.CDATA :
  71. return XPathNodeType.Text;
  72. default :
  73. return xnt;
  74. }
  75. node = this._doc.SafeNextSibling(node);
  76. }
  77. return xnt;
  78. }
  79. private XPathNodeType ConvertNodeType( XmlNode node ) {
  80. int xnt = -1;
  81. if ( XmlDataDocument.IsTextNode( node.NodeType ) )
  82. return DecideXPNodeTypeForTextNodes( node );
  83. xnt = xmlNodeType_To_XpathNodeType_Map[(int)(node.NodeType)];
  84. if ( xnt == (int) XPathNodeType.Attribute ) {
  85. if ( node.NamespaceURI == s_strReservedXmlns )
  86. return XPathNodeType.Namespace;
  87. else
  88. return XPathNodeType.Attribute;
  89. }
  90. Debug.Assert( xnt != -1 );
  91. return (XPathNodeType)xnt;
  92. }
  93. private bool IsNamespaceNode( XmlNodeType nt, string ns ) {
  94. if ( nt == XmlNodeType.Attribute && ns == s_strReservedXmlns )
  95. return true;
  96. return false;
  97. }
  98. //when the constructor is called, the node has to be a valid XPath node at the valid location ( for example, the first
  99. //text/WS/SWS/CData nodes of a series continuous text-like nodes.
  100. internal XPathNodePointer( DataDocumentXPathNavigator owner, XmlDataDocument doc, XmlNode node )
  101. : this ( owner, doc, node, null, false, null ){
  102. }
  103. internal XPathNodePointer( DataDocumentXPathNavigator owner, XPathNodePointer pointer )
  104. : this ( owner, pointer._doc, pointer._node, pointer._column, pointer._fOnValue, pointer._parentOfNS ) {
  105. }
  106. private XPathNodePointer( DataDocumentXPathNavigator owner, XmlDataDocument doc, XmlNode node, DataColumn c, bool bOnValue, XmlBoundElement parentOfNS ) {
  107. Debug.Assert( owner != null );
  108. this._owner = new WeakReference( owner );
  109. this._doc = doc;
  110. this._node = node;
  111. this._column = c;
  112. this._fOnValue = bOnValue;
  113. this._parentOfNS = parentOfNS;
  114. // Add this pointer to the document so it will be updated each time region changes it's foliation state.
  115. this._doc.AddPointer( (IXmlDataVirtualNode)this );
  116. _bNeedFoliate = false;
  117. AssertValid();
  118. }
  119. internal XPathNodePointer Clone( DataDocumentXPathNavigator owner ){
  120. //Debug.WriteLineIf( XmlTrace.traceXPathNodePointerFunctions.Enabled, "XPathNodePointer:Clone");
  121. RealFoliate();
  122. return new XPathNodePointer( owner, this ) ;
  123. }
  124. internal bool IsEmptyElement {
  125. get {
  126. //Debug.WriteLineIf( XmlTrace.traceXPathNodePointerFunctions.Enabled, "XPathNodePointer:IsEmptyElement");
  127. AssertValid();
  128. if (_node != null && _column == null) {
  129. if (_node.NodeType == XmlNodeType.Element) {
  130. return((XmlElement)_node).IsEmpty;
  131. }
  132. }
  133. return false;
  134. }
  135. }
  136. internal XPathNodeType NodeType {
  137. get {
  138. //Debug.WriteLineIf( XmlTrace.traceXPathNodePointerFunctions.Enabled, "XPathNodePointer:NodeType");
  139. RealFoliate();
  140. AssertValid();
  141. if (this._node == null) {
  142. return XPathNodeType.All;
  143. }
  144. else if (this._column == null) {
  145. return ConvertNodeType(this._node);
  146. }
  147. else if (this._fOnValue) {
  148. return XPathNodeType.Text;
  149. }
  150. else if (this._column.ColumnMapping == MappingType.Attribute) {
  151. if ( this._column.Namespace == s_strReservedXmlns )
  152. return XPathNodeType.Namespace;
  153. else
  154. return XPathNodeType.Attribute;
  155. }
  156. else //
  157. return XPathNodeType.Element;
  158. }
  159. }
  160. //Microsoft: From CodeReview: Perf: We should have another array similar w/
  161. // xmlNodeType_To_XpathNodeType_Map that will return String.Empty for everything but the element and
  162. // attribute case.
  163. internal string LocalName {
  164. get {
  165. //Debug.WriteLineIf( XmlTrace.traceXPathNodePointerFunctions.Enabled, "XPathNodePointer:LocalName");
  166. RealFoliate();
  167. AssertValid();
  168. if (this._node == null) {
  169. return string.Empty;
  170. }
  171. else if (this._column == null) {
  172. XmlNodeType nt = this._node.NodeType;
  173. if ( IsNamespaceNode( nt, this._node.NamespaceURI ) && this._node.LocalName == s_strXmlNS )
  174. return string.Empty;
  175. if ( nt == XmlNodeType.Element || nt == XmlNodeType.Attribute || nt == XmlNodeType.ProcessingInstruction )
  176. return _node.LocalName;
  177. return string.Empty;
  178. }
  179. else if (this._fOnValue) {
  180. return String.Empty;
  181. }
  182. else //when column is not null
  183. return _doc.NameTable.Add(_column.EncodedColumnName);
  184. }
  185. }
  186. //note that, we've have lost the prefix in this senario ( defoliation will toss prefix away. )
  187. internal string Name {
  188. get {
  189. //Debug.WriteLineIf( XmlTrace.traceXPathNodePointerFunctions.Enabled, "XPathNodePointer:Name");
  190. RealFoliate();
  191. AssertValid();
  192. if (this._node == null) {
  193. return string.Empty;
  194. }
  195. else if (this._column == null) {
  196. XmlNodeType nt = this._node.NodeType;
  197. if ( IsNamespaceNode( nt, this._node.NamespaceURI ) ) {
  198. if ( this._node.LocalName == s_strXmlNS )
  199. return string.Empty;
  200. else
  201. return this._node.LocalName;
  202. }
  203. if ( nt == XmlNodeType.Element || nt == XmlNodeType.Attribute || nt == XmlNodeType.ProcessingInstruction )
  204. return _node.Name;
  205. return string.Empty;
  206. }
  207. else if (this._fOnValue) {
  208. return String.Empty;
  209. }
  210. else { //when column is not null
  211. //we've lost prefix in this senario.
  212. return _doc.NameTable.Add(_column.EncodedColumnName);
  213. }
  214. }
  215. }
  216. internal string NamespaceURI {
  217. get {
  218. //Debug.WriteLineIf( XmlTrace.traceXPathNodePointerFunctions.Enabled, "XPathNodePointer:NamespaceURI");
  219. RealFoliate();
  220. AssertValid();
  221. if (this._node == null) {
  222. return string.Empty;
  223. }
  224. else if (this._column == null) {
  225. XPathNodeType xnt = ConvertNodeType( this._node );
  226. if ( xnt == XPathNodeType.Element || xnt == XPathNodeType.Root || xnt == XPathNodeType.Attribute )
  227. return _node.NamespaceURI;
  228. return string.Empty;
  229. }
  230. else if (this._fOnValue) {
  231. return string.Empty;
  232. }
  233. else { //When column is not null
  234. if ( _column.Namespace == s_strReservedXmlns )
  235. //namespace nodes has empty string as namespaceURI
  236. return string.Empty;
  237. return _doc.NameTable.Add(_column.Namespace);
  238. }
  239. }
  240. }
  241. //
  242. internal string Prefix {
  243. get {
  244. //Debug.WriteLineIf( XmlTrace.traceXPathNodePointerFunctions.Enabled, "XPathNodePointer:Prefix");
  245. RealFoliate();
  246. AssertValid();
  247. if (this._node == null) {
  248. return string.Empty;
  249. }
  250. else if (this._column == null) {
  251. if ( IsNamespaceNode( this._node.NodeType, this._node.NamespaceURI ) )
  252. return string.Empty;
  253. return _node.Prefix;
  254. }
  255. return string.Empty;
  256. }
  257. }
  258. internal string Value {
  259. get {
  260. //Debug.WriteLineIf( XmlTrace.traceXPathNodePointerFunctions.Enabled, "XPathNodePointer:Value");
  261. RealFoliate();
  262. AssertValid();
  263. if (this._node == null)
  264. return null;
  265. else if (this._column == null) {
  266. string strRet = this._node.Value;
  267. if ( XmlDataDocument.IsTextNode( this._node.NodeType ) ) {
  268. //concatenate adjacent textlike nodes
  269. XmlNode parent = this._node.ParentNode;
  270. if ( parent == null )
  271. return strRet;
  272. XmlNode n = _doc.SafeNextSibling(this._node);
  273. while ( n != null && XmlDataDocument.IsTextNode( n.NodeType ) ) {
  274. strRet += n.Value;
  275. n = _doc.SafeNextSibling(n);
  276. }
  277. }
  278. return strRet;
  279. }
  280. else if (this._column.ColumnMapping == MappingType.Attribute || this._fOnValue) {
  281. DataRow row = this.Row;
  282. DataRowVersion rowVersion = ( row.RowState == DataRowState.Detached ) ? DataRowVersion.Proposed : DataRowVersion.Current;
  283. object value = row[ this._column, rowVersion ];
  284. if ( ! Convert.IsDBNull( value ) )
  285. return this._column.ConvertObjectToXml( value );
  286. return null;
  287. }
  288. else
  289. //
  290. return null;
  291. }
  292. }
  293. internal string InnerText {
  294. get {
  295. //Debug.WriteLineIf( XmlTrace.traceXPathNodePointerFunctions.Enabled, "XPathNodePointer:InnerText");
  296. RealFoliate();
  297. AssertValid();
  298. if (this._node == null) {
  299. return string.Empty;
  300. }
  301. else if (this._column == null) {
  302. //
  303. if ( this._node.NodeType == XmlNodeType.Document ) {
  304. //document node's region should always be uncompressed
  305. XmlElement rootElem = ((XmlDocument)this._node).DocumentElement;
  306. if ( rootElem != null )
  307. return rootElem.InnerText;
  308. return string.Empty;
  309. }
  310. else
  311. return this._node.InnerText;
  312. }
  313. else {
  314. DataRow row = this.Row;
  315. DataRowVersion rowVersion = ( row.RowState == DataRowState.Detached ) ? DataRowVersion.Proposed : DataRowVersion.Current;
  316. object value = row[ this._column, rowVersion ];
  317. if ( ! Convert.IsDBNull( value ) )
  318. return this._column.ConvertObjectToXml( value );
  319. return string.Empty;
  320. }
  321. }
  322. }
  323. internal String BaseURI {
  324. get {
  325. //Debug.WriteLineIf( XmlTrace.traceXPathNodePointerFunctions.Enabled, "XPathNodePointer:BaseURI");
  326. RealFoliate();
  327. if ( this._node != null )
  328. return this._node.BaseURI;
  329. return String.Empty;
  330. }
  331. }
  332. internal String XmlLang {
  333. get {
  334. //Debug.WriteLineIf( XmlTrace.traceXPathNodePointerFunctions.Enabled, "XPathNodePointer:XmlLang");
  335. RealFoliate();
  336. XmlNode curNode = this._node;
  337. XmlBoundElement curBoundElem = null;
  338. object colVal = null;
  339. while ( curNode != null ) {
  340. //
  341. curBoundElem = curNode as XmlBoundElement;
  342. if ( curBoundElem != null ) {
  343. //this._doc.Foliate( curBoundElem, ElementState.WeakFoliation );
  344. if ( curBoundElem.ElementState == ElementState.Defoliated ) {
  345. //if not foliated, going through the columns to get the xml:lang
  346. DataRow row = curBoundElem.Row;
  347. foreach( DataColumn col in row.Table.Columns ) {
  348. if ( col.Prefix == "xml" && col.EncodedColumnName == "lang" ) {
  349. colVal = row[col];
  350. if ( colVal == DBNull.Value )
  351. break; //goto its ancesstors
  352. return (String) colVal;
  353. }
  354. }
  355. }
  356. else {
  357. //if folicated, get the attribute directly
  358. if ( curBoundElem.HasAttribute( "xml:lang" ) )
  359. return curBoundElem.GetAttribute( "xml:lang" );
  360. }
  361. }
  362. if ( curNode.NodeType == XmlNodeType.Attribute )
  363. curNode = ((XmlAttribute)curNode).OwnerElement;
  364. else
  365. curNode = curNode.ParentNode;
  366. }
  367. return String.Empty;
  368. }
  369. }
  370. private XmlBoundElement GetRowElement() {
  371. //Debug.WriteLineIf( XmlTrace.traceXPathNodePointerFunctions.Enabled, "XPathNodePointer:GetRowElement()");
  372. //AssertValid();
  373. XmlBoundElement rowElem;
  374. if ( this._column != null ) {
  375. rowElem = this._node as XmlBoundElement;
  376. Debug.Assert( rowElem != null );
  377. Debug.Assert( rowElem.Row != null );
  378. return rowElem;
  379. }
  380. _doc.Mapper.GetRegion( this._node, out rowElem );
  381. return rowElem;
  382. }
  383. //
  384. private DataRow Row {
  385. get {
  386. //Debug.WriteLineIf( XmlTrace.traceXPathNodePointerFunctions.Enabled, "XPathNodePointer:Row");
  387. //AssertValid();
  388. XmlBoundElement rowElem = GetRowElement();
  389. if ( rowElem == null )
  390. return null;
  391. Debug.Assert( rowElem.Row != null );
  392. return rowElem.Row;
  393. }
  394. }
  395. internal bool MoveTo( XPathNodePointer pointer ) {
  396. //Debug.WriteLineIf( XmlTrace.traceXPathNodePointerFunctions.Enabled, "XPathNodePointer:MoveTo(pointer)");
  397. AssertValid();
  398. if ( this._doc != pointer._doc )
  399. return false;
  400. /*
  401. XmlDataDocument docOld = this._doc;
  402. XmlDataDocument docNew = pointer._doc;
  403. if ( docNew != docOld ) {
  404. this._doc.RemovePointer( this );
  405. this._doc = pointer._doc;
  406. this._doc.AddPointer( this );
  407. }
  408. */
  409. this._node = pointer._node;
  410. this._column = pointer._column;
  411. this._fOnValue = pointer._fOnValue;
  412. this._bNeedFoliate = pointer._bNeedFoliate;
  413. AssertValid();
  414. return true;
  415. }
  416. private void MoveTo( XmlNode node ) {
  417. //Debug.WriteLineIf( XmlTrace.traceXPathNodePointerFunctions.Enabled, "XPathNodePointer:MoveTo(node)");
  418. //AssertValid();
  419. // Should not move outside of this document
  420. Debug.Assert( node == this._doc || node.OwnerDocument == this._doc );
  421. this._node = node;
  422. this._column = null;
  423. this._fOnValue = false;
  424. //AssertValid();
  425. }
  426. private void MoveTo( XmlNode node, DataColumn column, bool _fOnValue ) {
  427. //Debug.WriteLineIf( XmlTrace.traceXPathNodePointerFunctions.Enabled, "XPathNodePointer:MoveTo(node, column, fOnValue)");
  428. //AssertValid();
  429. // Should not move outside of this document
  430. Debug.Assert( node == this._doc || node.OwnerDocument == this._doc );
  431. this._node = node;
  432. this._column = column;
  433. this._fOnValue = _fOnValue;
  434. //AssertValid();
  435. }
  436. private bool IsFoliated( XmlNode node ) {
  437. //Debug.WriteLineIf( XmlTrace.traceXPathNodePointerFunctions.Enabled, "XPathNodePointer:IsFoliated(node)");
  438. //AssertValid();
  439. if (node != null && node is XmlBoundElement)
  440. return((XmlBoundElement)node).IsFoliated;
  441. return true;
  442. }
  443. private int ColumnCount( DataRow row, bool fAttribute ) {
  444. //Debug.WriteLineIf( XmlTrace.traceXPathNodePointerFunctions.Enabled, "XPathNodePointer:ColumnCount(row,fAttribute)");
  445. DataColumn c = null;
  446. int count = 0;
  447. while ((c = NextColumn( row, c, fAttribute )) != null) {
  448. if ( c.Namespace != s_strReservedXmlns )
  449. count++;
  450. }
  451. return count;
  452. }
  453. internal int AttributeCount {
  454. get {
  455. //Debug.WriteLineIf( XmlTrace.traceXPathNodePointerFunctions.Enabled, "XPathNodePointer:AttributeCount");
  456. RealFoliate();
  457. AssertValid();
  458. if (_node != null) {
  459. if (_column == null && _node.NodeType == XmlNodeType.Element) {
  460. if (!IsFoliated( _node ))
  461. return ColumnCount( Row, true );
  462. else {
  463. int nc = 0;
  464. foreach ( XmlAttribute attr in _node.Attributes ) {
  465. if ( attr.NamespaceURI != s_strReservedXmlns )
  466. nc++;
  467. }
  468. return nc;
  469. }
  470. }
  471. }
  472. return 0;
  473. }
  474. }
  475. internal DataColumn NextColumn( DataRow row, DataColumn col, bool fAttribute ) {
  476. //Debug.WriteLineIf( XmlTrace.traceXPathNodePointerFunctions.Enabled, "XPathNodePointer:NextColumn(row,col,fAttribute)");
  477. if (row.RowState == DataRowState.Deleted)
  478. return null;
  479. DataTable table = row.Table;
  480. DataColumnCollection columns = table.Columns;
  481. int iColumn = (col != null) ? col.Ordinal + 1 : 0;
  482. int cColumns = columns.Count;
  483. DataRowVersion rowVersion = ( row.RowState == DataRowState.Detached ) ? DataRowVersion.Proposed : DataRowVersion.Current;
  484. for (; iColumn < cColumns; iColumn++) {
  485. DataColumn c = columns[iColumn];
  486. if (!_doc.IsNotMapped( c ) && (c.ColumnMapping == MappingType.Attribute) == fAttribute && ! Convert.IsDBNull( row[c, rowVersion] ) )
  487. return c;
  488. }
  489. return null;
  490. }
  491. internal DataColumn PreviousColumn( DataRow row, DataColumn col, bool fAttribute ) {
  492. //Debug.WriteLineIf( XmlTrace.traceXPathNodePointerFunctions.Enabled, "XPathNodePointer:PreviousColumn(row,col,fAttribute)");
  493. if (row.RowState == DataRowState.Deleted)
  494. return null;
  495. DataTable table = row.Table;
  496. DataColumnCollection columns = table.Columns;
  497. int iColumn = (col != null) ? col.Ordinal - 1 : columns.Count - 1;
  498. int cColumns = columns.Count;
  499. DataRowVersion rowVersion = ( row.RowState == DataRowState.Detached ) ? DataRowVersion.Proposed : DataRowVersion.Current;
  500. for (; iColumn >= 0; iColumn--) {
  501. DataColumn c = columns[iColumn];
  502. if (!_doc.IsNotMapped( c ) && (c.ColumnMapping == MappingType.Attribute) == fAttribute && !Convert.IsDBNull( row[c, rowVersion] ) )
  503. return c;
  504. }
  505. return null;
  506. }
  507. internal bool MoveToAttribute( string localName, string namespaceURI ) {
  508. //Debug.WriteLineIf( XmlTrace.traceXPathNodePointerFunctions.Enabled, "XPathNodePointer:MoveToAttribute(localName, namespaceURI)");
  509. RealFoliate();
  510. AssertValid();
  511. if ( namespaceURI == s_strReservedXmlns )
  512. return false;
  513. if (_node != null) {
  514. //_column.ColumnMapping checkin below is not really needed since the pointer should be pointing at the node before this
  515. // function should even be called ( there is always a call MoveToOwnerElement() before MoveToAttribute(..)
  516. if ((_column == null || _column.ColumnMapping == MappingType.Attribute) && _node.NodeType == XmlNodeType.Element) {
  517. if (!IsFoliated( _node )) {
  518. DataColumn c = null;
  519. while ((c = NextColumn( Row, c, true )) != null) {
  520. if (c.EncodedColumnName == localName && c.Namespace == namespaceURI) {
  521. MoveTo( _node, c, false );
  522. return true;
  523. }
  524. }
  525. }
  526. else {
  527. Debug.Assert( _node.Attributes != null );
  528. XmlNode n = _node.Attributes.GetNamedItem(localName, namespaceURI);
  529. if (n != null) {
  530. MoveTo( n, null, false );
  531. return true;
  532. }
  533. }
  534. }
  535. }
  536. return false;
  537. }
  538. internal bool MoveToNextAttribute( bool bFirst ) {
  539. //Debug.WriteLineIf( XmlTrace.traceXPathNodePointerFunctions.Enabled, "XPathNodePointer:MoveToNextAttribute(bFirst)");
  540. //
  541. RealFoliate();
  542. AssertValid();
  543. if (_node != null) {
  544. if ( bFirst && ( _column != null || _node.NodeType != XmlNodeType.Element ) )
  545. return false;
  546. if ( !bFirst ) {
  547. if ( _column != null && _column.ColumnMapping != MappingType.Attribute )
  548. return false;
  549. if ( _column == null && _node.NodeType != XmlNodeType.Attribute )
  550. return false;
  551. }
  552. if ( !IsFoliated( _node ) ) {
  553. DataColumn c = _column;
  554. while ( ( c = NextColumn( Row, c, true ) ) != null ) {
  555. if ( c.Namespace != s_strReservedXmlns ) {
  556. MoveTo( _node, c, false );
  557. return true;
  558. }
  559. }
  560. return false;
  561. }
  562. else {
  563. if ( bFirst ) {
  564. XmlAttributeCollection attrs = _node.Attributes;
  565. foreach ( XmlAttribute attr in attrs ) {
  566. if ( attr.NamespaceURI != s_strReservedXmlns ) {
  567. MoveTo( attr, null, false );
  568. return true;
  569. }
  570. }
  571. }
  572. else {
  573. XmlAttributeCollection attrs = ((XmlAttribute)_node).OwnerElement.Attributes;
  574. bool bFound = false;
  575. foreach ( XmlAttribute attr in attrs ) {
  576. if ( bFound && attr.NamespaceURI != s_strReservedXmlns ) {
  577. MoveTo( attr, null, false );
  578. return true;
  579. }
  580. if ( attr == _node )
  581. bFound = true;
  582. }
  583. }
  584. }
  585. }
  586. return false;
  587. }
  588. private bool IsValidChild( XmlNode parent, XmlNode child ) {
  589. //Debug.WriteLineIf( XmlTrace.traceXPathNodePointerFunctions.Enabled, "XPathNodePointer:IsValidChild(parent,child)");
  590. int xntChildInt = xmlNodeType_To_XpathNodeType_Map[(int)(child.NodeType)];
  591. if ( xntChildInt == -1 )
  592. return false;
  593. int xntInt = xmlNodeType_To_XpathNodeType_Map[(int)(parent.NodeType)];
  594. Debug.Assert( xntInt != -1 );
  595. switch ( xntInt ) {
  596. case (int)XPathNodeType.Root:
  597. return ( xntChildInt == (int)XPathNodeType.Element ||
  598. xntChildInt == (int)XPathNodeType.Comment ||
  599. xntChildInt == (int)XPathNodeType.ProcessingInstruction );
  600. case (int)XPathNodeType.Element:
  601. return ( xntChildInt == (int)XPathNodeType.Element ||
  602. xntChildInt == (int)XPathNodeType.Text ||
  603. xntChildInt == (int)XPathNodeType.Comment ||
  604. xntChildInt == (int)XPathNodeType.Whitespace ||
  605. xntChildInt == (int)XPathNodeType.SignificantWhitespace ||
  606. xntChildInt == (int)XPathNodeType.ProcessingInstruction );
  607. default :
  608. return false;
  609. }
  610. }
  611. private bool IsValidChild( XmlNode parent, DataColumn c ) {
  612. //Debug.WriteLineIf( XmlTrace.traceXPathNodePointerFunctions.Enabled, "XPathNodePointer:IsValidChild(parent,c)");
  613. int xntInt = xmlNodeType_To_XpathNodeType_Map[(int)(parent.NodeType)];
  614. Debug.Assert( xntInt != -1 );
  615. switch ( xntInt ) {
  616. case (int)XPathNodeType.Root:
  617. return c.ColumnMapping == MappingType.Element;
  618. case (int)XPathNodeType.Element:
  619. return ( c.ColumnMapping == MappingType.Element || c.ColumnMapping == MappingType.SimpleContent );
  620. default :
  621. return false;
  622. }
  623. }
  624. internal bool MoveToNextSibling() {
  625. //Debug.WriteLineIf( XmlTrace.traceXPathNodePointerFunctions.Enabled, "XPathNodePointer:MoveToNextSibling()");
  626. RealFoliate();
  627. AssertValid();
  628. if (_node != null) {
  629. if ( _column != null ) {
  630. if ( _fOnValue ) {
  631. // _fOnValue could be true only when the column is mapped as simplecontent or element
  632. Debug.Assert( _column.ColumnMapping != MappingType.Attribute && _column.ColumnMapping != MappingType.Hidden );
  633. return false;
  634. }
  635. DataRow curRow = Row;
  636. DataColumn c = NextColumn( curRow, _column, false );
  637. while ( c != null ) {
  638. if ( IsValidChild( _node, c ) ) {
  639. MoveTo( this._node, c, _doc.IsTextOnly(c));
  640. return true;
  641. }
  642. c = NextColumn( curRow, c, false );
  643. }
  644. XmlNode n = _doc.SafeFirstChild( _node );
  645. if (n != null) {
  646. MoveTo( n );
  647. return true;
  648. }
  649. }
  650. else {
  651. XmlNode n = _node;
  652. XmlNode parent = _node.ParentNode;
  653. if ( parent == null )
  654. return false;
  655. bool bTextLike = XmlDataDocument.IsTextNode( _node.NodeType );
  656. do {
  657. do {
  658. n = _doc.SafeNextSibling(n);
  659. } while ( n != null && bTextLike && XmlDataDocument.IsTextNode( n.NodeType ));
  660. } while ( n != null && !IsValidChild(parent, n) );
  661. if (n != null) {
  662. MoveTo(n);
  663. return true;
  664. }
  665. }
  666. }
  667. return false;
  668. }
  669. internal bool MoveToPreviousSibling() {
  670. //Debug.WriteLineIf( XmlTrace.traceXPathNodePointerFunctions.Enabled, "XPathNodePointer:MoveToPreviousSibling()");
  671. RealFoliate();
  672. AssertValid();
  673. if (_node != null) {
  674. if (_column != null) {
  675. if (_fOnValue)
  676. return false;
  677. DataRow curRow = Row;
  678. DataColumn c = PreviousColumn( curRow, _column, false );
  679. while ( c != null ) {
  680. if ( IsValidChild(_node,c)) {
  681. MoveTo( _node, c, _doc.IsTextOnly(c) );
  682. return true;
  683. }
  684. c = PreviousColumn( curRow, c , false );
  685. }
  686. }
  687. else {
  688. XmlNode n = _node;
  689. XmlNode parent = _node.ParentNode;
  690. if ( parent == null )
  691. return false;
  692. bool bTextLike = XmlDataDocument.IsTextNode( _node.NodeType );
  693. do {
  694. do {
  695. n = _doc.SafePreviousSibling( n );
  696. } while ( n != null && bTextLike && XmlDataDocument.IsTextNode( n.NodeType ) );
  697. } while ( n != null && !IsValidChild(parent, n) );
  698. if (n != null) {
  699. MoveTo(n);
  700. return true;
  701. }
  702. if (!IsFoliated( parent ) && (parent is XmlBoundElement)) {
  703. DataRow row = ((XmlBoundElement)parent).Row;
  704. if (row != null) {
  705. DataColumn c = PreviousColumn( row, null, false );
  706. if (c != null) {
  707. MoveTo( parent, c, _doc.IsTextOnly(c) );
  708. return true;
  709. }
  710. }
  711. }
  712. }
  713. }
  714. return false;
  715. }
  716. internal bool MoveToFirst() {
  717. //Debug.WriteLineIf( XmlTrace.traceXPathNodePointerFunctions.Enabled, "XPathNodePointer:MoveToFirst()");
  718. RealFoliate();
  719. AssertValid();
  720. if (_node != null) {
  721. DataRow curRow = null;
  722. XmlNode parent = null;
  723. if (_column != null) {
  724. curRow = Row;
  725. parent = _node;
  726. }
  727. else {
  728. parent = _node.ParentNode;
  729. if ( parent == null )
  730. return false;
  731. if ( !IsFoliated( parent ) && (parent is XmlBoundElement) )
  732. curRow = ((XmlBoundElement)parent).Row;
  733. }
  734. //first check with the columns in the row
  735. if ( curRow != null ) {
  736. DataColumn c = NextColumn( curRow, null, false );
  737. while ( c != null ) {
  738. if ( IsValidChild( _node, c ) ) {
  739. MoveTo( _node, c, _doc.IsTextOnly( c ) );
  740. return true;
  741. }
  742. c = NextColumn( curRow, c, false );
  743. }
  744. }
  745. //didn't find a valid column or maybe already Foliated, go through its children nodes
  746. XmlNode n = _doc.SafeFirstChild( parent );
  747. while ( n != null ) {
  748. if ( IsValidChild( parent, n ) ) {
  749. MoveTo( n );
  750. return true;
  751. }
  752. n = _doc.SafeNextSibling( n );
  753. }
  754. }
  755. return false;
  756. }
  757. internal bool HasChildren {
  758. get {
  759. //Debug.WriteLineIf( XmlTrace.traceXPathNodePointerFunctions.Enabled, "XPathNodePointer:HasChildren");
  760. RealFoliate();
  761. AssertValid();
  762. if (_node == null)
  763. return false;
  764. if (_column != null) {
  765. if ( _column.ColumnMapping == MappingType.Attribute || _column.ColumnMapping == MappingType.Hidden )
  766. return false;
  767. return !_fOnValue;
  768. }
  769. if (!IsFoliated( _node )) {
  770. // find virtual column elements first
  771. DataRow curRow = Row;
  772. DataColumn c = NextColumn( curRow, null, false );
  773. while ( c != null ) {
  774. if ( IsValidChild( _node, c) )
  775. return true;
  776. c = NextColumn( curRow, c, false );
  777. }
  778. }
  779. // look for anything
  780. XmlNode n = _doc.SafeFirstChild( _node );
  781. while ( n != null ) {
  782. if ( IsValidChild( _node, n ) )
  783. return true;
  784. n = _doc.SafeNextSibling( n );
  785. }
  786. return false;
  787. }
  788. }
  789. internal bool MoveToFirstChild() {
  790. //Debug.WriteLineIf( XmlTrace.traceXPathNodePointerFunctions.Enabled, "XPathNodePointer:MoveToFirstChild()");
  791. RealFoliate();
  792. AssertValid();
  793. if (_node == null)
  794. return false;
  795. if (_column != null) {
  796. if ( _column.ColumnMapping == MappingType.Attribute || _column.ColumnMapping == MappingType.Hidden )
  797. return false;
  798. if (_fOnValue) //text node has no children to move to
  799. return false;
  800. _fOnValue = true;
  801. return true;
  802. }
  803. if (!IsFoliated( _node )) {
  804. // find virtual column elements first
  805. DataRow curRow = Row;
  806. DataColumn c = NextColumn( curRow, null, false );
  807. while ( c != null ) {
  808. if ( IsValidChild( _node, c) ) {
  809. MoveTo( _node, c, _doc.IsTextOnly(c) );
  810. return true;
  811. }
  812. c = NextColumn( curRow, c, false );
  813. }
  814. }
  815. // look for anything
  816. XmlNode n = _doc.SafeFirstChild( _node );
  817. while ( n != null ) {
  818. if ( IsValidChild( _node, n ) ) {
  819. MoveTo(n);
  820. return true;
  821. }
  822. n = _doc.SafeNextSibling( n );
  823. }
  824. return false;
  825. }
  826. //this version of MoveToParent will consider Attribute type position and move to its owner element
  827. //
  828. internal bool MoveToParent() {
  829. //Debug.WriteLineIf( XmlTrace.traceXPathNodePointerFunctions.Enabled, "XPathNodePointer:MoveToParent()");
  830. RealFoliate();
  831. AssertValid();
  832. if ( NodeType == XPathNodeType.Namespace ) {
  833. MoveTo( _parentOfNS );
  834. return true;
  835. }
  836. if (_node != null) {
  837. if (_column != null) {
  838. if (_fOnValue && !_doc.IsTextOnly(_column)) {
  839. MoveTo( _node, _column, false );
  840. return true;
  841. }
  842. MoveTo( _node, null, false );
  843. return true;
  844. }
  845. else {
  846. XmlNode n = null;
  847. if ( _node.NodeType == XmlNodeType.Attribute )
  848. n = ((XmlAttribute)_node).OwnerElement;
  849. else
  850. n = _node.ParentNode;
  851. if (n != null) {
  852. MoveTo(n);
  853. return true;
  854. }
  855. }
  856. }
  857. return false;
  858. }
  859. private XmlNode GetParent( XmlNode node ) {
  860. //Debug.WriteLineIf( XmlTrace.traceXPathNodePointerFunctions.Enabled, "XPathNodePointer:GetParent(node)");
  861. XPathNodeType xnt = ConvertNodeType( node );
  862. if ( xnt == XPathNodeType.Namespace ) {
  863. Debug.Assert( _parentOfNS != null );
  864. return _parentOfNS;
  865. }
  866. if ( xnt == XPathNodeType.Attribute )
  867. return ((XmlAttribute)node).OwnerElement;
  868. return node.ParentNode;
  869. }
  870. internal void MoveToRoot() {
  871. //Debug.WriteLineIf( XmlTrace.traceXPathNodePointerFunctions.Enabled, "XPathNodePointer:MoveToRoot()");
  872. XmlNode node = this._node;
  873. XmlNode parent = this._node;
  874. while ( parent != null ) {
  875. node = parent;
  876. parent = GetParent(parent);
  877. }
  878. this._node = node;
  879. this._column = null;
  880. this._fOnValue = false;
  881. AssertValid();
  882. }
  883. internal bool IsSamePosition( XPathNodePointer pointer ) {
  884. //Debug.WriteLineIf( XmlTrace.traceXPathNodePointerFunctions.Enabled, "XPathNodePointer:IsSamePosition(pointer)");
  885. RealFoliate();
  886. pointer.RealFoliate();
  887. AssertValid();
  888. pointer.AssertValid();
  889. if (_column == null && pointer._column == null)
  890. return ( pointer._node == this._node && pointer._parentOfNS == this._parentOfNS );
  891. return ( pointer._doc == this._doc
  892. && pointer._node == this._node
  893. && pointer._column == this._column
  894. && pointer._fOnValue == this._fOnValue
  895. && pointer._parentOfNS == this._parentOfNS );
  896. }
  897. private XmlNodeOrder CompareNamespacePosition( XPathNodePointer other ) {
  898. //Debug.WriteLineIf( XmlTrace.traceXPathNodePointerFunctions.Enabled, "XPathNodePointer:CompareNamespacePostion(other)");
  899. XPathNodePointer xp1 = this.Clone((DataDocumentXPathNavigator)(this._owner.Target));
  900. XPathNodePointer xp2 = other.Clone((DataDocumentXPathNavigator)(other._owner.Target));
  901. while ( xp1.MoveToNextNamespace(XPathNamespaceScope.All) ) {
  902. if ( xp1.IsSamePosition( other ) )
  903. return XmlNodeOrder.Before;
  904. }
  905. return XmlNodeOrder.After;
  906. }
  907. private static XmlNode GetRoot( XmlNode node, ref int depth ) {
  908. //Debug.WriteLineIf( XmlTrace.traceXPathNodePointerFunctions.Enabled, "XPathNodePointer:GetRoot(node, depth)");
  909. depth = 0;
  910. XmlNode curNode = node;
  911. XmlNode parent = ( ( curNode.NodeType == XmlNodeType.Attribute ) ? ( ((XmlAttribute)curNode).OwnerElement ) : ( curNode.ParentNode ) );
  912. for ( ; parent != null; depth++ ) {
  913. curNode = parent;
  914. parent = curNode.ParentNode; // no need to check for attribute since navigator can't be built on its children or navigate to its children
  915. }
  916. return curNode;
  917. }
  918. internal XmlNodeOrder ComparePosition( XPathNodePointer other ) {
  919. //Debug.WriteLineIf( XmlTrace.traceXPathNodePointerFunctions.Enabled, "XPathNodePointer:ComparePosition(other)");
  920. RealFoliate();
  921. other.RealFoliate();
  922. Debug.Assert( other != null );
  923. if ( IsSamePosition( other ) )
  924. return XmlNodeOrder.Same;
  925. XmlNode curNode1 = null, curNode2 = null;
  926. //deal with namespace node first
  927. if ( this.NodeType == XPathNodeType.Namespace && other.NodeType == XPathNodeType.Namespace ) {
  928. if ( this._parentOfNS == other._parentOfNS )
  929. return this.CompareNamespacePosition( other );
  930. //if not from the same parent
  931. curNode1 = this._parentOfNS;
  932. curNode2 = other._parentOfNS;
  933. }
  934. else if ( this.NodeType == XPathNodeType.Namespace ) {
  935. Debug.Assert( other.NodeType != XPathNodeType.Namespace );
  936. if ( this._parentOfNS == other._node ) {
  937. //from the same region, NS nodes come before all other nodes
  938. if ( other._column == null )
  939. return XmlNodeOrder.After;
  940. else
  941. return XmlNodeOrder.Before;
  942. }
  943. //if not from the same region
  944. curNode1 = this._parentOfNS;
  945. curNode2 = other._node;
  946. }
  947. else if ( other.NodeType == XPathNodeType.Namespace ) {
  948. Debug.Assert( this.NodeType != XPathNodeType.Namespace );
  949. if ( this._node == other._parentOfNS ) {
  950. //from the same region
  951. if ( this._column == null )
  952. return XmlNodeOrder.Before;
  953. else
  954. return XmlNodeOrder.After;
  955. }
  956. //if not from the same region
  957. curNode1 = this._node;
  958. curNode2 = other._parentOfNS;
  959. }
  960. else {
  961. if ( this._node == other._node ) {
  962. //compare within the same region
  963. if ( this._column == other._column ) {
  964. //one is the children of the other
  965. Debug.Assert( this._fOnValue != other._fOnValue );
  966. if ( this._fOnValue )
  967. return XmlNodeOrder.After;
  968. else
  969. return XmlNodeOrder.Before;
  970. }
  971. else {
  972. Debug.Assert( this.Row == other.Row ); //in the same row
  973. if ( this._column == null )
  974. return XmlNodeOrder.Before;
  975. else if ( other._column == null )
  976. return XmlNodeOrder.After;
  977. else if ( this._column.Ordinal < other._column.Ordinal )
  978. return XmlNodeOrder.Before;
  979. else
  980. return XmlNodeOrder.After;
  981. }
  982. }
  983. curNode1 = this._node;
  984. curNode2 = other._node;
  985. }
  986. Debug.Assert( curNode1 != null );
  987. Debug.Assert( curNode2 != null );
  988. if (curNode1 == null || curNode2 == null) {
  989. return XmlNodeOrder.Unknown;
  990. }
  991. int depth1 = -1, depth2 = -1;
  992. XmlNode root1 = XPathNodePointer.GetRoot( curNode1, ref depth1 );
  993. XmlNode root2 = XPathNodePointer.GetRoot( curNode2, ref depth2 );
  994. if ( root1 != root2 )
  995. return XmlNodeOrder.Unknown;
  996. if ( depth1 > depth2 ) {
  997. while ( curNode1 != null && depth1 > depth2 ) {
  998. curNode1 = ( ( curNode1.NodeType == XmlNodeType.Attribute ) ? ( ((XmlAttribute)curNode1).OwnerElement ) : ( curNode1.ParentNode ) );
  999. depth1--;
  1000. }
  1001. if ( curNode1 == curNode2 )
  1002. return XmlNodeOrder.After;
  1003. }
  1004. else if ( depth2 > depth1 ) {
  1005. while ( curNode2 != null && depth2 > depth1 ) {
  1006. curNode2 = ( ( curNode2.NodeType == XmlNodeType.Attribute ) ? ( ((XmlAttribute)curNode2).OwnerElement ) : ( curNode2.ParentNode ) );
  1007. depth2--;
  1008. }
  1009. if ( curNode1 == curNode2 )
  1010. return XmlNodeOrder.Before;
  1011. }
  1012. XmlNode parent1 = GetParent(curNode1);
  1013. XmlNode parent2 = GetParent(curNode2);
  1014. XmlNode nextNode = null;
  1015. while ( parent1 != null && parent2 != null ) {
  1016. if ( parent1 == parent2 ) {
  1017. while (curNode1 != null ) {
  1018. nextNode = curNode1.NextSibling;
  1019. if ( nextNode == curNode2 )
  1020. return XmlNodeOrder.Before;
  1021. curNode1 = nextNode;
  1022. }
  1023. return XmlNodeOrder.After;
  1024. }
  1025. curNode1 = parent1;
  1026. curNode2 = parent2;
  1027. parent1 = curNode1.ParentNode;
  1028. parent2 = curNode2.ParentNode;
  1029. }
  1030. //logically, we shouldn't reach here
  1031. Debug.Assert( false );
  1032. return XmlNodeOrder.Unknown;
  1033. }
  1034. internal XmlNode Node {
  1035. get {
  1036. //Debug.WriteLineIf( XmlTrace.traceXPathNodePointerFunctions.Enabled, "XPathNodePointer:Node");
  1037. RealFoliate();
  1038. AssertValid();
  1039. if ( this._node == null )
  1040. return null;
  1041. XmlBoundElement rowElem = GetRowElement();
  1042. if ( rowElem != null ) {
  1043. //lock ( this._doc.pointers ) {
  1044. bool wasFoliationEnabled = this._doc.IsFoliationEnabled;
  1045. this._doc.IsFoliationEnabled = true;
  1046. this._doc.Foliate( rowElem, ElementState.StrongFoliation );
  1047. this._doc.IsFoliationEnabled = wasFoliationEnabled;
  1048. //}
  1049. }
  1050. RealFoliate();
  1051. AssertValid();
  1052. return this._node;
  1053. }
  1054. }
  1055. bool IXmlDataVirtualNode.IsOnNode( XmlNode nodeToCheck ) {
  1056. //Debug.WriteLineIf( XmlTrace.traceXPathNodePointerFunctions.Enabled, "XPathNodePointer:IsOnNode(nodeToCheck)");
  1057. RealFoliate();
  1058. return nodeToCheck == this._node;
  1059. }
  1060. bool IXmlDataVirtualNode.IsOnColumn( DataColumn col ) {
  1061. //Debug.WriteLineIf( XmlTrace.traceXPathNodePointerFunctions.Enabled, "XPathNodePointer:IsOnColumn(col)");
  1062. RealFoliate();
  1063. return col == this._column;
  1064. }
  1065. void IXmlDataVirtualNode.OnFoliated( XmlNode foliatedNode ) {
  1066. //Debug.WriteLineIf( XmlTrace.traceXPathNodePointerFunctions.Enabled, "XPathNodePointer:OnFoliated(foliatedNode)");
  1067. // update the pointer if the element node has been foliated
  1068. if (_node == foliatedNode) {
  1069. // if already on this node, nothing to do!
  1070. if (_column == null)
  1071. return;
  1072. _bNeedFoliate = true;
  1073. }
  1074. }
  1075. private void RealFoliate() {
  1076. if ( !_bNeedFoliate )
  1077. return;
  1078. //Debug.WriteLineIf( XmlTrace.traceXPathNodePointerFunctions.Enabled, "XPathNodePointer:RealFoliate()");
  1079. _bNeedFoliate = false;
  1080. Debug.Assert( this._column != null );
  1081. XmlNode n = null;
  1082. if (_doc.IsTextOnly( _column ))
  1083. n = _node.FirstChild;
  1084. else {
  1085. if (_column.ColumnMapping == MappingType.Attribute) {
  1086. n = _node.Attributes.GetNamedItem( _column.EncodedColumnName, _column.Namespace );
  1087. }
  1088. else {
  1089. for (n = _node.FirstChild; n != null; n = n.NextSibling) {
  1090. if (n.LocalName == _column.EncodedColumnName && n.NamespaceURI == _column.Namespace)
  1091. break;
  1092. }
  1093. }
  1094. if (n != null && _fOnValue)
  1095. n = n.FirstChild;
  1096. }
  1097. if (n == null)
  1098. throw new InvalidOperationException(Res.GetString(Res.DataDom_Foliation));
  1099. // Cannot use MoveTo( n ); b/c the initial state for MoveTo is invalid (region is foliated but this is not)
  1100. this._node = n;
  1101. this._column = null;
  1102. this._fOnValue = false;
  1103. AssertValid();
  1104. _bNeedFoliate = false;
  1105. }
  1106. //The function only helps to find out if there is a namespace declaration of given name is defined on the given node
  1107. //It will not check the accestors of the given node.
  1108. private string GetNamespace( XmlBoundElement be, string name ) {
  1109. //Debug.WriteLineIf( XmlTrace.traceXPathNodePointerFunctions.Enabled, "XPathNodePointer:GetNamespace(be,name)");
  1110. if ( be == null )
  1111. return null;
  1112. XmlAttribute attr = null;
  1113. if ( be.IsFoliated ) {
  1114. attr = be.GetAttributeNode ( name, s_strReservedXmlns );
  1115. if ( attr != null )
  1116. return attr.Value;
  1117. else
  1118. return null;
  1119. }
  1120. else { //defoliated so that we need to search through its column
  1121. DataRow curRow = be.Row;
  1122. if ( curRow == null )
  1123. return null;
  1124. //going through its attribute columns
  1125. DataColumn curCol = PreviousColumn( curRow, null, true );
  1126. while ( curCol != null ) {
  1127. if ( curCol.Namespace == s_strReservedXmlns ) {
  1128. //
  1129. DataRowVersion rowVersion = ( curRow.RowState == DataRowState.Detached ) ? DataRowVersion.Proposed : DataRowVersion.Current;
  1130. return curCol.ConvertObjectToXml( curRow[curCol,rowVersion] );
  1131. }
  1132. curCol = PreviousColumn( curRow, curCol, true );
  1133. }
  1134. return null;
  1135. }
  1136. }
  1137. internal string GetNamespace(string name) {
  1138. //Debug.WriteLineIf( XmlTrace.traceXPathNodePointerFunctions.Enabled, "XPathNodePointer:GetNamespace(name)");
  1139. //we are checking the namespace nodes backwards comparing its normal order in DOM tree
  1140. if ( name == "xml" )
  1141. return s_strReservedXml;
  1142. if ( name == "xmlns" )
  1143. return s_strReservedXmlns;
  1144. if ( name != null && name.Length == 0 )
  1145. name = "xmlns";
  1146. RealFoliate();
  1147. XmlNode node = _node;
  1148. XmlNodeType nt = node.NodeType;
  1149. String retVal = null;
  1150. while ( node != null ) {
  1151. //first identify an element node in the ancestor + itself
  1152. while ( node != null && ( ( nt = node.NodeType ) != XmlNodeType.Element ) ) {
  1153. if ( nt == XmlNodeType.Attribute )
  1154. node = ((XmlAttribute)node).OwnerElement;
  1155. else
  1156. node = node.ParentNode;
  1157. }
  1158. //found one -- inside if
  1159. if ( node != null ) {
  1160. //must be element node
  1161. retVal = GetNamespace((XmlBoundElement)node, name);
  1162. if ( retVal != null )
  1163. return retVal;
  1164. //didn't find it, try the next parentnode
  1165. node = node.ParentNode;
  1166. }
  1167. }
  1168. //nothing happens, then return string.empty.
  1169. return string.Empty;
  1170. }
  1171. internal bool MoveToNamespace(string name) {
  1172. //Debug.WriteLineIf( XmlTrace.traceXPathNodePointerFunctions.Enabled, "XPathNodePointer:MoveToNamespace(name)");
  1173. _parentOfNS = this._node as XmlBoundElement;
  1174. //only need to check with _node, even if _column is not null and its mapping type is element, it can't have attributes
  1175. if ( _parentOfNS == null )
  1176. return false;
  1177. string attrName = name;
  1178. if ( attrName == "xmlns" )
  1179. attrName = "xmlns:xmlns";
  1180. if ( attrName != null && attrName.Length == 0 )
  1181. attrName = "xmlns";
  1182. RealFoliate();
  1183. XmlNode node = this._node;
  1184. XmlNodeType nt = node.NodeType;
  1185. XmlAttribute attr = null;
  1186. XmlBoundElement be = null;
  1187. while ( node != null ) {
  1188. //check current element node
  1189. be = node as XmlBoundElement;
  1190. if ( be != null ) {
  1191. if ( be.IsFoliated ) {
  1192. attr = be.GetAttributeNode ( name, s_strReservedXmlns );
  1193. if ( attr != null ) {
  1194. MoveTo( attr );
  1195. return true;
  1196. }
  1197. }
  1198. else {//defoliated so that we need to search through its column
  1199. DataRow curRow = be.Row;
  1200. if ( curRow == null )
  1201. return false;
  1202. //going through its attribute columns
  1203. DataColumn curCol = PreviousColumn( curRow, null, true );
  1204. while ( curCol != null ) {
  1205. if ( curCol.Namespace == s_strReservedXmlns && curCol.ColumnName == name ) {
  1206. MoveTo( be, curCol, false );
  1207. return true;
  1208. }
  1209. curCol = PreviousColumn( curRow, curCol, true );
  1210. }
  1211. }
  1212. }
  1213. //didn't find it, try the next element anccester.
  1214. do {
  1215. node = node.ParentNode;
  1216. } while ( node != null && node.NodeType != XmlNodeType.Element );
  1217. }
  1218. //nothing happens, the name doesn't exist as a namespace node.
  1219. _parentOfNS = null;
  1220. return false;
  1221. }
  1222. //the function will find the next namespace node on the given bound element starting with the given column or attribte
  1223. // wether to use column or attribute depends on if the bound element is folicated or not.
  1224. private bool MoveToNextNamespace( XmlBoundElement be, DataColumn col, XmlAttribute curAttr ) {
  1225. //Debug.WriteLineIf( XmlTrace.traceXPathNodePointerFunctions.Enabled, "XPathNodePointer:MoveToNextNamespace(be,col,curAttr)");
  1226. if ( be != null ) {
  1227. if ( be.IsFoliated ) {
  1228. XmlAttributeCollection attrs = be.Attributes;
  1229. XmlAttribute attr = null;
  1230. bool bFound = false;
  1231. if ( curAttr == null )
  1232. bFound = true; //the first namespace will be the one
  1233. #if DEBUG
  1234. if ( curAttr != null )
  1235. Debug.Assert( curAttr.NamespaceURI == s_strReservedXmlns );
  1236. #endif
  1237. Debug.Assert( attrs!=null );
  1238. int attrInd = attrs.Count;
  1239. while ( attrInd > 0 ) {
  1240. attrInd--;
  1241. attr = attrs[attrInd];
  1242. if ( bFound && attr.NamespaceURI == s_strReservedXmlns && !DuplicateNS( be, attr.LocalName ) ) {
  1243. MoveTo(attr);
  1244. return true;
  1245. }
  1246. if ( attr == curAttr )
  1247. bFound = true;
  1248. }
  1249. }
  1250. else {//defoliated so that we need to search through its column
  1251. DataRow curRow = be.Row;
  1252. if ( curRow == null )
  1253. return false;
  1254. //going through its attribute columns
  1255. DataColumn curCol = PreviousColumn( curRow, col, true );
  1256. while ( curCol != null ) {
  1257. if ( curCol.Namespace == s_strReservedXmlns && !DuplicateNS( be, curCol.ColumnName ) ) {
  1258. MoveTo( be, curCol, false );
  1259. return true;
  1260. }
  1261. curCol = PreviousColumn( curRow, curCol, true );
  1262. }
  1263. }
  1264. }
  1265. return false;
  1266. }
  1267. //Caller( DataDocumentXPathNavigator will make sure that the node is at the right position for this call )
  1268. internal bool MoveToFirstNamespace(XPathNamespaceScope namespaceScope) {
  1269. //Debug.WriteLineIf( XmlTrace.traceXPathNodePointerFunctions.Enabled, "XPathNodePointer:MoveToFirstNamespace(namespaceScope)");
  1270. RealFoliate();
  1271. _parentOfNS = this._node as XmlBoundElement;
  1272. //only need to check with _node, even if _column is not null and its mapping type is element, it can't have attributes
  1273. if ( _parentOfNS == null )
  1274. return false;
  1275. XmlNode node = this._node;
  1276. XmlBoundElement be = null;
  1277. while ( node != null ) {
  1278. be = node as XmlBoundElement;
  1279. if ( MoveToNextNamespace( be, null, null ) )
  1280. return true;
  1281. //didn't find it
  1282. if ( namespaceScope == XPathNamespaceScope.Local )
  1283. goto labelNoNS;
  1284. //try the next element anccestor.
  1285. do {
  1286. node = node.ParentNode;
  1287. } while ( node != null && node.NodeType != XmlNodeType.Element );
  1288. }
  1289. if ( namespaceScope == XPathNamespaceScope.All ) {
  1290. MoveTo( this._doc.attrXml, null, false );
  1291. return true;
  1292. }
  1293. labelNoNS:
  1294. //didn't find one namespace node
  1295. _parentOfNS = null;
  1296. return false;
  1297. }
  1298. //endElem is on the path from startElem to root is enforced by the caller
  1299. private bool DuplicateNS( XmlBoundElement endElem, string lname) {
  1300. //Debug.WriteLineIf( XmlTrace.traceXPathNodePointerFunctions.Enabled, "XPathNodePointer:DuplicateNS(endElem, lname)");
  1301. if ( this._parentOfNS == null || endElem == null )
  1302. return false;
  1303. XmlBoundElement be = this._parentOfNS;
  1304. XmlNode node = null;
  1305. while ( be != null && be != endElem ) {
  1306. if ( GetNamespace( be, lname ) != null )
  1307. return true;
  1308. node = (XmlNode)be;
  1309. do {
  1310. node = node.ParentNode;
  1311. } while ( node != null && node.NodeType != XmlNodeType.Element );
  1312. be = node as XmlBoundElement;
  1313. }
  1314. return false;
  1315. }
  1316. //Caller( DataDocumentXPathNavigator will make sure that the node is at the right position for this call )
  1317. internal bool MoveToNextNamespace(XPathNamespaceScope namespaceScope) {
  1318. //Debug.WriteLineIf( XmlTrace.traceXPathNodePointerFunctions.Enabled, "XPathNodePointer:MoveToNextNamespace(namespaceScope)");
  1319. RealFoliate();
  1320. Debug.Assert( _parentOfNS != null );
  1321. XmlNode node = this._node;
  1322. //first check within the same boundelement
  1323. if ( this._column != null ) {
  1324. Debug.Assert( this._column.Namespace == s_strReservedXmlns );
  1325. if ( namespaceScope == XPathNamespaceScope.Local && _parentOfNS != this._node ) //already outside scope
  1326. return false;
  1327. XmlBoundElement be = this._node as XmlBoundElement;
  1328. Debug.Assert( be != null );
  1329. DataRow curRow = be.Row;
  1330. Debug.Assert( curRow != null );
  1331. DataColumn curCol = PreviousColumn( curRow, this._column, true );
  1332. while ( curCol != null ) {
  1333. if ( curCol.Namespace == s_strReservedXmlns ) {
  1334. MoveTo( be, curCol, false );
  1335. return true;
  1336. }
  1337. curCol = PreviousColumn( curRow, curCol, true );
  1338. }
  1339. //didn't find it in this loop
  1340. if ( namespaceScope == XPathNamespaceScope.Local )
  1341. return false;
  1342. //try its ancesstor
  1343. do {
  1344. node = node.ParentNode;
  1345. } while ( node != null && node.NodeType != XmlNodeType.Element );
  1346. }
  1347. else if ( this._node.NodeType == XmlNodeType.Attribute ) {
  1348. XmlAttribute attr = (XmlAttribute)(this._node);
  1349. Debug.Assert( attr != null );
  1350. node = attr.OwnerElement;
  1351. if ( node == null )
  1352. return false;
  1353. if ( namespaceScope == XPathNamespaceScope.Local && _parentOfNS != node ) //already outside scope
  1354. return false;
  1355. if ( MoveToNextNamespace( (XmlBoundElement)node, null, (XmlAttribute)attr ) )
  1356. return true;
  1357. //didn't find it
  1358. if ( namespaceScope == XPathNamespaceScope.Local )
  1359. return false;
  1360. do {
  1361. node = node.ParentNode;
  1362. } while ( node != null && node.NodeType != XmlNodeType.Element );
  1363. }
  1364. // till now, node should be the next accesstor (bound) element of the element parent of current namespace node (attribute or data column)
  1365. while ( node != null ) {
  1366. //try the namespace attributes from the same element
  1367. XmlBoundElement be = node as XmlBoundElement;
  1368. if ( MoveToNextNamespace( be, null, null ) )
  1369. return true;
  1370. //no more namespace attribute under the same element
  1371. do {
  1372. node = node.ParentNode;
  1373. } while ( node != null && node.NodeType == XmlNodeType.Element );
  1374. }
  1375. //didn't find the next namespace, thus return
  1376. if ( namespaceScope == XPathNamespaceScope.All ) {
  1377. MoveTo( this._doc.attrXml, null, false );
  1378. return true;
  1379. }
  1380. return false;
  1381. }
  1382. [System.Diagnostics.Conditional("DEBUG")]
  1383. private void AssertValid() {
  1384. // This pointer must be int the document list
  1385. //RealFoliate();
  1386. this._doc.AssertPointerPresent( this );
  1387. if ( this._column != null ) {
  1388. // We must be on a de-foliated region
  1389. XmlBoundElement rowElem = this._node as XmlBoundElement;
  1390. Debug.Assert( rowElem != null );
  1391. DataRow row = rowElem.Row;
  1392. Debug.Assert( row != null );
  1393. //ElementState state = rowElem.ElementState;
  1394. //Debug.Assert( state == ElementState.Defoliated || _bNeedFoliated, "Region is accessed using column, but it's state is FOLIATED" );
  1395. // We cannot be on a column for which the value is DBNull
  1396. DataRowVersion rowVersion = ( row.RowState == DataRowState.Detached ) ? DataRowVersion.Proposed : DataRowVersion.Current;
  1397. Debug.Assert( ! Convert.IsDBNull( row[ this._column, rowVersion ] ) );
  1398. // If we are on the Text column, we should always have _fOnValue == true
  1399. Debug.Assert( (this._column.ColumnMapping == MappingType.SimpleContent) ? (this._fOnValue == true) : true );
  1400. }
  1401. if ( this._column == null )
  1402. Debug.Assert( !this._fOnValue );
  1403. }
  1404. internal XmlDataDocument Document { get { return _doc; } }
  1405. bool IXmlDataVirtualNode.IsInUse() {
  1406. //Debug.WriteLineIf( XmlTrace.traceXPathNodePointerFunctions.Enabled, "XPathNodePointer:IsInUse()");
  1407. return _owner.IsAlive;
  1408. }
  1409. }
  1410. }