1 //------------------------------------------------------------------------------
2 // <copyright file="DataPointer.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
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
12 using System.Diagnostics;
14 internal sealed class DataPointer : IXmlDataVirtualNode {
15 private XmlDataDocument doc;
17 private DataColumn column;
18 private bool fOnValue;
19 private bool bNeedFoliate = false;
20 private bool _isInUse;
22 internal DataPointer( XmlDataDocument doc, XmlNode node ) {
26 this.fOnValue = false;
32 internal DataPointer( DataPointer pointer ) {
33 this.doc = pointer.doc;
34 this.node = pointer.node;
35 this.column = pointer.column;
36 this.fOnValue = pointer.fOnValue;
37 this.bNeedFoliate = false;
42 internal void AddPointer() {
43 this.doc.AddPointer( (IXmlDataVirtualNode)this );
46 // Returns the row element of the region that the pointer points into
47 private XmlBoundElement GetRowElement() {
50 XmlBoundElement rowElem;
51 if ( this.column != null ) {
52 rowElem = this.node as XmlBoundElement;
53 Debug.Assert( rowElem != null );
54 Debug.Assert( rowElem.Row != null );
58 doc.Mapper.GetRegion( this.node, out rowElem );
65 XmlBoundElement rowElem = GetRowElement();
66 if ( rowElem == null )
69 Debug.Assert( rowElem.Row != null );
74 private static bool IsFoliated( XmlNode node ) {
75 if (node != null && node is XmlBoundElement)
76 return((XmlBoundElement)node).IsFoliated;
80 internal void MoveTo( DataPointer pointer ) {
82 // You should not move outside of this document
83 Debug.Assert( node == this.doc || node.OwnerDocument == this.doc );
85 this.doc = pointer.doc;
86 this.node = pointer.node;
87 this.column = pointer.column;
88 this.fOnValue = pointer.fOnValue;
91 private void MoveTo( XmlNode node ) {
93 // You should not move outside of this document
94 Debug.Assert( node == this.doc || node.OwnerDocument == this.doc );
98 this.fOnValue = false;
102 private void MoveTo( XmlNode node, DataColumn column, bool fOnValue ) {
104 // You should not move outside of this document
105 Debug.Assert( node == this.doc || node.OwnerDocument == this.doc );
108 this.column = column;
109 this.fOnValue = fOnValue;
113 private DataColumn NextColumn( DataRow row, DataColumn col, bool fAttribute, bool fNulls ) {
114 if (row.RowState == DataRowState.Deleted)
117 DataTable table = row.Table;
118 DataColumnCollection columns = table.Columns;
119 int iColumn = (col != null) ? col.Ordinal + 1 : 0;
120 int cColumns = columns.Count;
121 DataRowVersion rowVersion = ( row.RowState == DataRowState.Detached ) ? DataRowVersion.Proposed : DataRowVersion.Current;
123 for (; iColumn < cColumns; iColumn++) {
124 DataColumn c = columns[iColumn];
125 if (!doc.IsNotMapped( c ) && (c.ColumnMapping == MappingType.Attribute) == fAttribute && (fNulls || ! Convert.IsDBNull( row[c, rowVersion] ) ) )
132 private DataColumn NthColumn( DataRow row, bool fAttribute, int iColumn, bool fNulls ) {
134 while ((c = NextColumn( row, c, fAttribute, fNulls )) != null) {
138 iColumn = checked((int)iColumn-1);
143 private int ColumnCount( DataRow row, bool fAttribute, bool fNulls ) {
146 while ((c = NextColumn( row, c, fAttribute, fNulls )) != null) {
152 internal bool MoveToFirstChild() {
158 if (column != null) {
165 else if (!IsFoliated( node )) {
166 // find virtual column elements first
167 DataColumn c = NextColumn( Row, null, false, false );
169 MoveTo( node, c, doc.IsTextOnly(c) );
175 XmlNode n = doc.SafeFirstChild( node );
184 internal bool MoveToNextSibling() {
188 if (column != null) {
189 if (fOnValue && !doc.IsTextOnly(column))
192 DataColumn c = NextColumn( Row, column, false, false );
194 MoveTo( this.node, c, false );
198 XmlNode n = doc.SafeFirstChild( node );
205 XmlNode n = doc.SafeNextSibling( node );
216 internal bool MoveToParent() {
220 if (column != null) {
221 if (fOnValue && !doc.IsTextOnly(column)) {
222 MoveTo( node, column, false );
226 if (column.ColumnMapping != MappingType.Attribute) {
227 MoveTo( node, null, false );
232 XmlNode n = node.ParentNode;
242 internal bool MoveToOwnerElement() {
246 if (column != null) {
247 if (fOnValue || doc.IsTextOnly(column) || column.ColumnMapping != MappingType.Attribute)
250 MoveTo( node, null, false );
253 else if (node.NodeType == XmlNodeType.Attribute) {
254 XmlNode n = ((XmlAttribute)node).OwnerElement;
256 MoveTo( n, null, false );
266 internal int AttributeCount {
271 if (column == null && node.NodeType == XmlNodeType.Element) {
272 if (!IsFoliated( node )) {
273 return ColumnCount( Row, true, false );
276 return node.Attributes.Count;
283 internal bool MoveToAttribute( int i ) {
289 if ((column == null || column.ColumnMapping == MappingType.Attribute) && node.NodeType == XmlNodeType.Element) {
290 if (!IsFoliated( node )) {
291 DataColumn c = NthColumn( Row, true, i, false );
293 MoveTo( node, c, false );
298 XmlNode n = node.Attributes.Item(i);
300 MoveTo( n, null, false );
309 internal XmlNodeType NodeType {
313 if (this.node == null) {
314 return XmlNodeType.None;
316 else if (this.column == null) {
317 return this.node.NodeType;
319 else if (this.fOnValue) {
320 return XmlNodeType.Text;
322 else if (this.column.ColumnMapping == MappingType.Attribute) {
323 return XmlNodeType.Attribute;
326 return XmlNodeType.Element;
331 internal string LocalName {
335 if (this.node == null) {
337 }else if (this.column == null) {
338 String name = node.LocalName;
339 Debug.Assert( name != null );
340 if ( IsLocalNameEmpty( this.node.NodeType ) )
344 else if (this.fOnValue) {
348 return doc.NameTable.Add(column.EncodedColumnName);
353 internal string NamespaceURI {
357 if (this.node == null) {
360 else if (this.column == null) {
361 return node.NamespaceURI;
363 else if (this.fOnValue) {
367 return doc.NameTable.Add(column.Namespace);
372 internal string Name {
376 if (this.node == null) {
379 else if (this.column == null) {
380 String name = node.Name;
381 //Again it could be String.Empty at null position
382 Debug.Assert( name != null );
383 if ( IsLocalNameEmpty( this.node.NodeType ) )
388 string prefix = Prefix;
389 string lname = LocalName;
390 if (prefix != null && prefix.Length > 0) {
391 if (lname != null && lname.Length > 0) {
392 return doc.NameTable.Add( prefix + ":" + lname );
406 private bool IsLocalNameEmpty ( XmlNodeType nt) {
408 case XmlNodeType.None :
409 case XmlNodeType.Text :
410 case XmlNodeType.CDATA :
411 case XmlNodeType.Comment :
412 case XmlNodeType.Document :
413 case XmlNodeType.DocumentFragment :
414 case XmlNodeType.Whitespace :
415 case XmlNodeType.SignificantWhitespace :
416 case XmlNodeType.EndElement :
417 case XmlNodeType.EndEntity :
419 case XmlNodeType.Element :
420 case XmlNodeType.Attribute :
421 case XmlNodeType.EntityReference :
422 case XmlNodeType.Entity :
423 case XmlNodeType.ProcessingInstruction :
424 case XmlNodeType.DocumentType :
425 case XmlNodeType.Notation :
426 case XmlNodeType.XmlDeclaration :
433 internal string Prefix {
437 if (this.node == null) {
440 else if (this.column == null) {
449 internal string Value {
453 if (this.node == null) {
456 else if (this.column == null) {
457 return this.node.Value;
459 else if (this.column.ColumnMapping == MappingType.Attribute || this.fOnValue) {
460 DataRow row = this.Row;
461 DataRowVersion rowVersion = ( row.RowState == DataRowState.Detached ) ? DataRowVersion.Proposed : DataRowVersion.Current;
462 object value = row[ this.column, rowVersion ];
463 if ( ! Convert.IsDBNull( value ) )
464 return this.column.ConvertObjectToXml( value );
468 // column element has no value
474 bool IXmlDataVirtualNode.IsOnNode( XmlNode nodeToCheck ) {
476 return nodeToCheck == this.node;
479 bool IXmlDataVirtualNode.IsOnColumn( DataColumn col ) {
481 return col == this.column;
484 internal XmlNode GetNode() {
488 internal bool IsEmptyElement {
492 if (node != null && column == null) {
494 if (node.NodeType == XmlNodeType.Element) {
495 return((XmlElement)node).IsEmpty;
502 internal bool IsDefault {
506 if (node != null && column == null && node.NodeType == XmlNodeType.Attribute) {
507 return !((XmlAttribute)node).Specified;
514 void IXmlDataVirtualNode.OnFoliated( XmlNode foliatedNode ) {
515 // update the pointer if the element node has been foliated
516 if (node == foliatedNode) {
517 // if already on this node, nothing to do!
524 internal void RealFoliate() {
530 if (doc.IsTextOnly( column )) {
534 if (column.ColumnMapping == MappingType.Attribute) {
535 n = node.Attributes.GetNamedItem( column.EncodedColumnName, column.Namespace );
538 for (n = node.FirstChild; n != null; n = n.NextSibling) {
539 if (n.LocalName == column.EncodedColumnName && n.NamespaceURI == column.Namespace)
544 if (n != null && fOnValue)
549 throw new InvalidOperationException(Res.GetString(Res.DataDom_Foliation));
551 // Cannot use MoveTo( n ); b/c the initial state for MoveTo is invalid (region is foliated but this is not)
554 this.fOnValue = false;
557 bNeedFoliate = false;
560 //for the 6 properties below, only when the this.column == null that the nodetype could be XmlDeclaration node
561 internal String PublicId {
563 XmlNodeType nt = NodeType;
565 case XmlNodeType.DocumentType : {
566 Debug.Assert( this.column == null );
567 return ( ( XmlDocumentType ) (this.node)).PublicId;
569 case XmlNodeType.Entity : {
570 Debug.Assert( this.column == null );
571 return ( ( XmlEntity ) (this.node)).PublicId;
573 case XmlNodeType.Notation : {
574 Debug.Assert( this.column == null );
575 return ( ( XmlNotation ) (this.node)).PublicId;
582 internal String SystemId {
584 XmlNodeType nt = NodeType;
586 case XmlNodeType.DocumentType : {
587 Debug.Assert( this.column == null );
588 return ( ( XmlDocumentType ) (this.node)).SystemId;
590 case XmlNodeType.Entity : {
591 Debug.Assert( this.column == null );
592 return ( ( XmlEntity ) (this.node)).SystemId;
594 case XmlNodeType.Notation : {
595 Debug.Assert( this.column == null );
596 return ( ( XmlNotation ) (this.node)).SystemId;
603 internal String InternalSubset {
605 if ( NodeType == XmlNodeType.DocumentType ) {
606 Debug.Assert( this.column == null );
607 return ( ( XmlDocumentType ) (this.node)).InternalSubset;
613 internal XmlDeclaration Declaration {
615 XmlNode child = doc.SafeFirstChild(doc);
616 if ( child != null && child.NodeType == XmlNodeType.XmlDeclaration )
617 return (XmlDeclaration)child;
622 internal String Encoding {
624 if ( NodeType == XmlNodeType.XmlDeclaration ) {
625 Debug.Assert( this.column == null );
626 return ( ( XmlDeclaration ) (this.node)).Encoding;
627 } else if ( NodeType == XmlNodeType.Document ) {
628 XmlDeclaration dec = Declaration;
636 internal String Standalone {
638 if ( NodeType == XmlNodeType.XmlDeclaration ) {
639 Debug.Assert( this.column == null );
640 return ( ( XmlDeclaration ) (this.node)).Standalone;
641 } else if ( NodeType == XmlNodeType.Document ) {
642 XmlDeclaration dec = Declaration;
644 return dec.Standalone;
650 internal String Version {
652 if ( NodeType == XmlNodeType.XmlDeclaration ) {
653 Debug.Assert( this.column == null );
654 return ( ( XmlDeclaration ) (this.node)).Version;
655 } else if ( NodeType == XmlNodeType.Document ) {
656 XmlDeclaration dec = Declaration;
664 [System.Diagnostics.Conditional("DEBUG")]
665 private void AssertValid() {
666 // This pointer must be int the document list
667 if ( this.column != null ) {
668 // We must be on a de-foliated region
669 XmlBoundElement rowElem = this.node as XmlBoundElement;
670 Debug.Assert( rowElem != null );
672 DataRow row = rowElem.Row;
673 Debug.Assert( row != null );
675 ElementState state = rowElem.ElementState;
676 Debug.Assert( state == ElementState.Defoliated, "Region is accessed using column, but it's state is FOLIATED" );
678 // We cannot be on a column for which the value is DBNull
679 DataRowVersion rowVersion = ( row.RowState == DataRowState.Detached ) ? DataRowVersion.Proposed : DataRowVersion.Current;
680 Debug.Assert( ! Convert.IsDBNull( row[ this.column, rowVersion ] ) );
682 // If we are on the Text column, we should always have fOnValue == true
683 Debug.Assert( (this.column.ColumnMapping == MappingType.SimpleContent) ? (this.fOnValue == true) : true );
687 bool IXmlDataVirtualNode.IsInUse() {
691 internal void SetNoLongerUse() {
694 this.fOnValue = false;
695 this.bNeedFoliate = false;
696 this._isInUse = false;