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