|
//------------------------------------------------------------------------------
// <copyright file="DataPointer.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
// <owner current="true" primary="true">Microsoft</owner>
// <owner current="true" primary="false">Microsoft</owner>
//------------------------------------------------------------------------------
#pragma warning disable 618 // ignore obsolete warning about XmlDataDocument
namespace System.Xml {
using System;
using System.Data;
using System.Diagnostics;
internal sealed class DataPointer : IXmlDataVirtualNode {
private XmlDataDocument doc;
private XmlNode node;
private DataColumn column;
private bool fOnValue;
private bool bNeedFoliate = false;
private bool _isInUse;
internal DataPointer( XmlDataDocument doc, XmlNode node ) {
this.doc = doc;
this.node = node;
this.column = null;
this.fOnValue = false;
bNeedFoliate = false;
this._isInUse = true;
AssertValid();
}
internal DataPointer( DataPointer pointer ) {
this.doc = pointer.doc;
this.node = pointer.node;
this.column = pointer.column;
this.fOnValue = pointer.fOnValue;
this.bNeedFoliate = false;
this._isInUse = true;
AssertValid();
}
internal void AddPointer() {
this.doc.AddPointer( (IXmlDataVirtualNode)this );
}
// Returns the row element of the region that the pointer points into
private XmlBoundElement GetRowElement() {
//AssertValid();
XmlBoundElement rowElem;
if ( this.column != null ) {
rowElem = this.node as XmlBoundElement;
Debug.Assert( rowElem != null );
Debug.Assert( rowElem.Row != null );
return rowElem;
}
doc.Mapper.GetRegion( this.node, out rowElem );
return rowElem;
}
private DataRow Row {
get {
//AssertValid();
XmlBoundElement rowElem = GetRowElement();
if ( rowElem == null )
return null;
Debug.Assert( rowElem.Row != null );
return rowElem.Row;
}
}
private static bool IsFoliated( XmlNode node ) {
if (node != null && node is XmlBoundElement)
return((XmlBoundElement)node).IsFoliated;
return true;
}
internal void MoveTo( DataPointer pointer ) {
AssertValid();
// You should not move outside of this document
Debug.Assert( node == this.doc || node.OwnerDocument == this.doc );
this.doc = pointer.doc;
this.node = pointer.node;
this.column = pointer.column;
this.fOnValue = pointer.fOnValue;
AssertValid();
}
private void MoveTo( XmlNode node ) {
//AssertValid();
// You should not move outside of this document
Debug.Assert( node == this.doc || node.OwnerDocument == this.doc );
this.node = node;
this.column = null;
this.fOnValue = false;
AssertValid();
}
private void MoveTo( XmlNode node, DataColumn column, bool fOnValue ) {
//AssertValid();
// You should not move outside of this document
Debug.Assert( node == this.doc || node.OwnerDocument == this.doc );
this.node = node;
this.column = column;
this.fOnValue = fOnValue;
AssertValid();
}
private DataColumn NextColumn( DataRow row, DataColumn col, bool fAttribute, bool fNulls ) {
if (row.RowState == DataRowState.Deleted)
return null;
DataTable table = row.Table;
DataColumnCollection columns = table.Columns;
int iColumn = (col != null) ? col.Ordinal + 1 : 0;
int cColumns = columns.Count;
DataRowVersion rowVersion = ( row.RowState == DataRowState.Detached ) ? DataRowVersion.Proposed : DataRowVersion.Current;
for (; iColumn < cColumns; iColumn++) {
DataColumn c = columns[iColumn];
if (!doc.IsNotMapped( c ) && (c.ColumnMapping == MappingType.Attribute) == fAttribute && (fNulls || ! Convert.IsDBNull( row[c, rowVersion] ) ) )
return c;
}
return null;
}
private DataColumn NthColumn( DataRow row, bool fAttribute, int iColumn, bool fNulls ) {
DataColumn c = null;
while ((c = NextColumn( row, c, fAttribute, fNulls )) != null) {
if (iColumn == 0)
return c;
iColumn = checked((int)iColumn-1);
}
return null;
}
private int ColumnCount( DataRow row, bool fAttribute, bool fNulls ) {
DataColumn c = null;
int count = 0;
while ((c = NextColumn( row, c, fAttribute, fNulls )) != null) {
count++;
}
return count;
}
internal bool MoveToFirstChild() {
RealFoliate();
AssertValid();
if (node == null)
return false;
if (column != null) {
if (fOnValue)
return false;
fOnValue = true;
return true;
}
else if (!IsFoliated( node )) {
// find virtual column elements first
DataColumn c = NextColumn( Row, null, false, false );
if (c != null) {
MoveTo( node, c, doc.IsTextOnly(c) );
return true;
}
}
// look for anything
XmlNode n = doc.SafeFirstChild( node );
if (n != null) {
MoveTo(n);
return true;
}
return false;
}
internal bool MoveToNextSibling() {
RealFoliate();
AssertValid();
if (node != null) {
if (column != null) {
if (fOnValue && !doc.IsTextOnly(column))
return false;
DataColumn c = NextColumn( Row, column, false, false );
if (c != null) {
MoveTo( this.node, c, false );
return true;
}
XmlNode n = doc.SafeFirstChild( node );
if (n != null) {
MoveTo( n );
return true;
}
}
else {
XmlNode n = doc.SafeNextSibling( node );
if (n != null) {
MoveTo(n);
return true;
}
}
}
return false;
}
internal bool MoveToParent() {
RealFoliate();
AssertValid();
if (node != null) {
if (column != null) {
if (fOnValue && !doc.IsTextOnly(column)) {
MoveTo( node, column, false );
return true;
}
if (column.ColumnMapping != MappingType.Attribute) {
MoveTo( node, null, false );
return true;
}
}
else {
XmlNode n = node.ParentNode;
if (n != null) {
MoveTo(n);
return true;
}
}
}
return false;
}
internal bool MoveToOwnerElement() {
RealFoliate();
AssertValid();
if (node != null) {
if (column != null) {
if (fOnValue || doc.IsTextOnly(column) || column.ColumnMapping != MappingType.Attribute)
return false;
MoveTo( node, null, false );
return true;
}
else if (node.NodeType == XmlNodeType.Attribute) {
XmlNode n = ((XmlAttribute)node).OwnerElement;
if (n != null) {
MoveTo( n, null, false );
return true;
}
}
}
return false;
}
internal int AttributeCount {
get {
RealFoliate();
AssertValid();
if (node != null) {
if (column == null && node.NodeType == XmlNodeType.Element) {
if (!IsFoliated( node )) {
return ColumnCount( Row, true, false );
}
else
return node.Attributes.Count;
}
}
return 0;
}
}
internal bool MoveToAttribute( int i ) {
RealFoliate();
AssertValid();
if ( i < 0 )
return false;
if (node != null) {
if ((column == null || column.ColumnMapping == MappingType.Attribute) && node.NodeType == XmlNodeType.Element) {
if (!IsFoliated( node )) {
DataColumn c = NthColumn( Row, true, i, false );
if (c != null) {
MoveTo( node, c, false );
return true;
}
}
else {
XmlNode n = node.Attributes.Item(i);
if (n != null) {
MoveTo( n, null, false );
return true;
}
}
}
}
return false;
}
internal XmlNodeType NodeType {
get {
RealFoliate();
AssertValid();
if (this.node == null) {
return XmlNodeType.None;
}
else if (this.column == null) {
return this.node.NodeType;
}
else if (this.fOnValue) {
return XmlNodeType.Text;
}
else if (this.column.ColumnMapping == MappingType.Attribute) {
return XmlNodeType.Attribute;
}
else {
return XmlNodeType.Element;
}
}
}
internal string LocalName {
get {
RealFoliate();
AssertValid();
if (this.node == null) {
return string.Empty;
}else if (this.column == null) {
String name = node.LocalName;
Debug.Assert( name != null );
if ( IsLocalNameEmpty( this.node.NodeType ) )
return String.Empty;
return name;
}
else if (this.fOnValue) {
return String.Empty;
}
else {
return doc.NameTable.Add(column.EncodedColumnName);
}
}
}
internal string NamespaceURI {
get {
RealFoliate();
AssertValid();
if (this.node == null) {
return string.Empty;
}
else if (this.column == null) {
return node.NamespaceURI;
}
else if (this.fOnValue) {
return string.Empty;
}
else {
return doc.NameTable.Add(column.Namespace);
}
}
}
internal string Name {
get {
RealFoliate();
AssertValid();
if (this.node == null) {
return string.Empty;
}
else if (this.column == null) {
String name = node.Name;
//Again it could be String.Empty at null position
Debug.Assert( name != null );
if ( IsLocalNameEmpty( this.node.NodeType ) )
return String.Empty;
return name;
}
else {
string prefix = Prefix;
string lname = LocalName;
if (prefix != null && prefix.Length > 0) {
if (lname != null && lname.Length > 0) {
return doc.NameTable.Add( prefix + ":" + lname );
}
else {
return prefix;
}
}
else {
return lname;
}
}
}
}
private bool IsLocalNameEmpty ( XmlNodeType nt) {
switch ( nt ) {
case XmlNodeType.None :
case XmlNodeType.Text :
case XmlNodeType.CDATA :
case XmlNodeType.Comment :
case XmlNodeType.Document :
case XmlNodeType.DocumentFragment :
case XmlNodeType.Whitespace :
case XmlNodeType.SignificantWhitespace :
case XmlNodeType.EndElement :
case XmlNodeType.EndEntity :
return true;
case XmlNodeType.Element :
case XmlNodeType.Attribute :
case XmlNodeType.EntityReference :
case XmlNodeType.Entity :
case XmlNodeType.ProcessingInstruction :
case XmlNodeType.DocumentType :
case XmlNodeType.Notation :
case XmlNodeType.XmlDeclaration :
return false;
default :
return true;
}
}
internal string Prefix {
get {
RealFoliate();
AssertValid();
if (this.node == null) {
return string.Empty;
}
else if (this.column == null) {
return node.Prefix;
}
else {
return string.Empty;
}
}
}
internal string Value {
get {
RealFoliate();
AssertValid();
if (this.node == null) {
return null;
}
else if (this.column == null) {
return this.node.Value;
}
else if (this.column.ColumnMapping == MappingType.Attribute || this.fOnValue) {
DataRow row = this.Row;
DataRowVersion rowVersion = ( row.RowState == DataRowState.Detached ) ? DataRowVersion.Proposed : DataRowVersion.Current;
object value = row[ this.column, rowVersion ];
if ( ! Convert.IsDBNull( value ) )
return this.column.ConvertObjectToXml( value );
return null;
}
else {
// column element has no value
return null;
}
}
}
bool IXmlDataVirtualNode.IsOnNode( XmlNode nodeToCheck ) {
RealFoliate();
return nodeToCheck == this.node;
}
bool IXmlDataVirtualNode.IsOnColumn( DataColumn col ) {
RealFoliate();
return col == this.column;
}
internal XmlNode GetNode() {
return this.node;
}
internal bool IsEmptyElement {
get {
RealFoliate();
AssertValid();
if (node != null && column == null) {
//
if (node.NodeType == XmlNodeType.Element) {
return((XmlElement)node).IsEmpty;
}
}
return false;
}
}
internal bool IsDefault {
get {
RealFoliate();
AssertValid();
if (node != null && column == null && node.NodeType == XmlNodeType.Attribute) {
return !((XmlAttribute)node).Specified;
}
return false;
}
}
void IXmlDataVirtualNode.OnFoliated( XmlNode foliatedNode ) {
// update the pointer if the element node has been foliated
if (node == foliatedNode) {
// if already on this node, nothing to do!
if (column == null)
return;
bNeedFoliate = true;
}
}
internal void RealFoliate() {
if ( !bNeedFoliate )
return;
XmlNode n = null;
if (doc.IsTextOnly( column )) {
n = node.FirstChild;
}
else {
if (column.ColumnMapping == MappingType.Attribute) {
n = node.Attributes.GetNamedItem( column.EncodedColumnName, column.Namespace );
}
else {
for (n = node.FirstChild; n != null; n = n.NextSibling) {
if (n.LocalName == column.EncodedColumnName && n.NamespaceURI == column.Namespace)
break;
}
}
if (n != null && fOnValue)
n = n.FirstChild;
}
if (n == null)
throw new InvalidOperationException(Res.GetString(Res.DataDom_Foliation));
// Cannot use MoveTo( n ); b/c the initial state for MoveTo is invalid (region is foliated but this is not)
this.node = n;
this.column = null;
this.fOnValue = false;
AssertValid();
bNeedFoliate = false;
}
//for the 6 properties below, only when the this.column == null that the nodetype could be XmlDeclaration node
internal String PublicId {
get {
XmlNodeType nt = NodeType;
switch ( nt ) {
case XmlNodeType.DocumentType : {
Debug.Assert( this.column == null );
return ( ( XmlDocumentType ) (this.node)).PublicId;
}
case XmlNodeType.Entity : {
Debug.Assert( this.column == null );
return ( ( XmlEntity ) (this.node)).PublicId;
}
case XmlNodeType.Notation : {
Debug.Assert( this.column == null );
return ( ( XmlNotation ) (this.node)).PublicId;
}
}
return null;
}
}
internal String SystemId {
get {
XmlNodeType nt = NodeType;
switch ( nt ) {
case XmlNodeType.DocumentType : {
Debug.Assert( this.column == null );
return ( ( XmlDocumentType ) (this.node)).SystemId;
}
case XmlNodeType.Entity : {
Debug.Assert( this.column == null );
return ( ( XmlEntity ) (this.node)).SystemId;
}
case XmlNodeType.Notation : {
Debug.Assert( this.column == null );
return ( ( XmlNotation ) (this.node)).SystemId;
}
}
return null;
}
}
internal String InternalSubset {
get {
if ( NodeType == XmlNodeType.DocumentType ) {
Debug.Assert( this.column == null );
return ( ( XmlDocumentType ) (this.node)).InternalSubset;
}
return null;
}
}
internal XmlDeclaration Declaration {
get {
XmlNode child = doc.SafeFirstChild(doc);
if ( child != null && child.NodeType == XmlNodeType.XmlDeclaration )
return (XmlDeclaration)child;
return null;
}
}
internal String Encoding {
get {
if ( NodeType == XmlNodeType.XmlDeclaration ) {
Debug.Assert( this.column == null );
return ( ( XmlDeclaration ) (this.node)).Encoding;
} else if ( NodeType == XmlNodeType.Document ) {
XmlDeclaration dec = Declaration;
if ( dec != null )
return dec.Encoding;
}
return null;
}
}
internal String Standalone {
get {
if ( NodeType == XmlNodeType.XmlDeclaration ) {
Debug.Assert( this.column == null );
return ( ( XmlDeclaration ) (this.node)).Standalone;
} else if ( NodeType == XmlNodeType.Document ) {
XmlDeclaration dec = Declaration;
if ( dec != null )
return dec.Standalone;
}
return null;
}
}
internal String Version {
get {
if ( NodeType == XmlNodeType.XmlDeclaration ) {
Debug.Assert( this.column == null );
return ( ( XmlDeclaration ) (this.node)).Version;
} else if ( NodeType == XmlNodeType.Document ) {
XmlDeclaration dec = Declaration;
if ( dec != null )
return dec.Version;
}
return null;
}
}
[System.Diagnostics.Conditional("DEBUG")]
private void AssertValid() {
// This pointer must be int the document list
if ( this.column != null ) {
// We must be on a de-foliated region
XmlBoundElement rowElem = this.node as XmlBoundElement;
Debug.Assert( rowElem != null );
DataRow row = rowElem.Row;
Debug.Assert( row != null );
ElementState state = rowElem.ElementState;
Debug.Assert( state == ElementState.Defoliated, "Region is accessed using column, but it's state is FOLIATED" );
// We cannot be on a column for which the value is DBNull
DataRowVersion rowVersion = ( row.RowState == DataRowState.Detached ) ? DataRowVersion.Proposed : DataRowVersion.Current;
Debug.Assert( ! Convert.IsDBNull( row[ this.column, rowVersion ] ) );
// If we are on the Text column, we should always have fOnValue == true
Debug.Assert( (this.column.ColumnMapping == MappingType.SimpleContent) ? (this.fOnValue == true) : true );
}
}
bool IXmlDataVirtualNode.IsInUse() {
return _isInUse;
}
internal void SetNoLongerUse() {
this.node = null;
this.column = null;
this.fOnValue = false;
this.bNeedFoliate = false;
this._isInUse = false;
}
}
}
|