DataSetMappper.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / Data / System / NewXml / DataSetMappper.cs / 1305376 / DataSetMappper.cs

                            //------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// [....] 
// [....]
//----------------------------------------------------------------------------- 
#pragma warning disable 618 // ignore obsolete warning about XmlDataDocument 
namespace System.Xml {
 
    using System.Collections;
    using System.Data;
    using System.Diagnostics;
 

    // 
    // Maps XML nodes to schema 
    //
    // With the exception of some functions (the most important is SearchMatchingTableSchema) all functions expect that each region rowElem is already associated 
    // w/ it's DataRow (basically the test to determine a rowElem is based on a != null associated DataRow). As a result of this, some functions will NOT work properly
    // when they are used on a tree for which rowElem's are not associated w/ a DataRow.
    //
 
    internal sealed class DataSetMapper {
        Hashtable tableSchemaMap;   // maps an string (currently this is localName:nsURI) to a DataTable. Used to quickly find if a bound-elem matches any data-table metadata.. 
        Hashtable columnSchemaMap;  // maps a string (table localName:nsURI) to a Hashtable. The 2nd hastable (the one that is stored as data in columnSchemaMap, maps a string to a DataColumn. 

        XmlDataDocument doc;        // The document this mapper is related to 
        DataSet   dataSet;          // The dataset this mapper is related to
        internal const string strReservedXmlns = "http://www.w3.org/2000/xmlns/";

 
        internal DataSetMapper() {
            Debug.Assert( this.dataSet == null ); 
            this.tableSchemaMap = new Hashtable(); 
            this.columnSchemaMap = new Hashtable();
        } 

        internal void SetupMapping( XmlDataDocument xd, DataSet ds ) {
            // If are already mapped, forget about our current mapping and re-do it again.
            if ( IsMapped() ) { 
                this.tableSchemaMap = new Hashtable();
                this.columnSchemaMap = new Hashtable(); 
            } 
            doc = xd;
            dataSet = ds; 
            foreach( DataTable t in dataSet.Tables ) {
                AddTableSchema( t );

                foreach( DataColumn c in t.Columns ) { 
                    // don't include auto-generated PK & FK to be part of mapping
                    if ( ! IsNotMapped(c) ) { 
                        AddColumnSchema( c ); 
                    }
                } 
            }
        }

        internal bool IsMapped() { 
            return dataSet != null;
        } 
 
        internal DataTable SearchMatchingTableSchema( string localName, string namespaceURI ) {
            object tid = GetIdentity( localName, namespaceURI ); 
            return (DataTable)(tableSchemaMap[ tid ]);

        }
        // SearchMatchingTableSchema function works only when the elem has not been bound to a DataRow. If you want to get the table associated w/ an element after 
        // it has been associated w/ a DataRow use GetTableSchemaForElement function.
        // rowElem is the parent region rowElem or null if there is no parent region (in case elem is a row elem, then rowElem will be the parent region; if elem is not 
        //    mapped to a DataRow, then rowElem is the region elem is part of) 
        //
        // Those are the rules for determing if elem is a row element: 
        //  1. node is an element (already meet, since elem is of type XmlElement)
        //  2. If the node is already associated w/ a DataRow, then the node is a row element - not applicable, b/c this function is intended to be called on a
        //    to find out if the node s/b associated w/ a DataRow (see XmlDataDocument.LoadRows)
        //  3. If the node localName/ns matches a DataTable then 
        //      3.1 Take the parent region DataTable (in our case rowElem.Row.DataTable)
        //          3.2 If no parent region, then the node is associated w/ a DataTable 
        //          3.3 If there is a parent region 
        //              3.3.1 If the node has no elem children and no attr other than namespace declaration, and the node can match
        //                  a column from the parent region table, then the node is NOT associated w/ a DataTable (it is a potential DataColumn in the parent region) 
        //              3.3.2 Else the node is a row-element (and associated w/ a DataTable / DataRow )
        //
        internal DataTable SearchMatchingTableSchema( XmlBoundElement rowElem, XmlBoundElement elem ) {
            Debug.Assert( elem != null ); 

            DataTable t = SearchMatchingTableSchema( elem.LocalName, elem.NamespaceURI ); 
            if ( t == null ) 
                return null;
 
            if ( rowElem == null )
                return t;
            // Currently we expect we map things from top of the tree to the bottom
            Debug.Assert( rowElem.Row != null ); 

            DataColumn col = GetColumnSchemaForNode( rowElem, elem ); 
            if ( col == null ) 
                return t;
 
            foreach ( XmlAttribute a in elem.Attributes ) {
#if DEBUG
                // Some sanity check to catch errors like namespace attributes have the right localName/namespace value, but a wrong atomized namespace value
                if ( a.LocalName == "xmlns" ) { 
                    Debug.Assert( a.Prefix != null && a.Prefix.Length == 0 );
                    Debug.Assert( (object)a.NamespaceURI == (object)strReservedXmlns ); 
                } 
                if ( a.Prefix == "xmlns" ) {
                    Debug.Assert( (object)a.NamespaceURI == (object)strReservedXmlns ); 
                }
                if ( a.NamespaceURI == strReservedXmlns )
                    Debug.Assert( (object)a.NamespaceURI == (object)strReservedXmlns );
#endif 
                // No namespace attribute found, so elem cannot be a potential DataColumn, therefore is a row-elem
                if ( (object)(a.NamespaceURI) != (object)strReservedXmlns ) 
                    return t; 
            }
 
            for ( XmlNode n = elem.FirstChild; n != null; n = n.NextSibling ) {
                if ( n.NodeType == XmlNodeType.Element ) {
                    // elem has an element child, so elem cannot be a potential DataColumn, therefore is a row-elem
                    return t; 
                }
            } 
            // Node is a potential DataColumn in rowElem region 
            return null;
        } 

        internal DataColumn GetColumnSchemaForNode( XmlBoundElement rowElem, XmlNode node ) {
            //
            Debug.Assert( rowElem != null ); 
            // The caller must make sure that node is not a row-element
            Debug.Assert( (node is XmlBoundElement) ? ((XmlBoundElement)node).Row == null : true ); 
 
            object tid = GetIdentity( rowElem.LocalName, rowElem.NamespaceURI );
            object cid = GetIdentity( node.LocalName, node.NamespaceURI ); 

            Hashtable columns = (Hashtable) columnSchemaMap[ tid ];
            if ( columns != null ) {
                DataColumn col = (DataColumn)(columns[ cid ]); 
                if ( col == null )
                    return null; 
 
                MappingType mt = col.ColumnMapping;
 
                if ( node.NodeType == XmlNodeType.Attribute && mt == MappingType.Attribute )
                    return col;
                if ( node.NodeType == XmlNodeType.Element && mt == MappingType.Element )
                    return col; 
                // node's (localName, ns) matches a column, but the MappingType is different (i.e. node is elem, MT is attr)
                return null; 
            } 
            return null;
        } 
        internal DataTable GetTableSchemaForElement( XmlElement elem ) {
            //
            XmlBoundElement be = elem as XmlBoundElement;
            if ( be == null ) 
                return null;
 
            return GetTableSchemaForElement( be ); 
        }
 
        internal DataTable GetTableSchemaForElement( XmlBoundElement be ) {
            // if bound to a row, must be a table.
            DataRow row = be.Row;
            if ( row != null ) 
                return row.Table;
 
            return null; 
        }
 
        internal static bool IsNotMapped( DataColumn c ) {
            return c.ColumnMapping == MappingType.Hidden;
        }
 
        // ATTENTION: GetRowFromElement( XmlElement ) and GetRowFromElement( XmlBoundElement ) should have the same functionality and side effects.
        // See this code fragment for why: 
        //     XmlBoundElement be = ...; 
        //     XmlElement e = be;
        //     GetRowFromElement( be ); // Calls GetRowFromElement( XmlBoundElement ) 
        //     GetRowFromElement( e );  // Calls GetRowFromElement( XmlElement ), in spite of e beeing an instance of XmlBoundElement
        internal DataRow GetRowFromElement( XmlElement e ) {
            XmlBoundElement be = e as XmlBoundElement;
            if ( be != null ) 
                return be.Row;
            return null; 
        } 
        internal DataRow GetRowFromElement( XmlBoundElement be ) {
            return be.Row; 
        }

        // Get the row-elem associatd w/ the region node is in.
        // If node is in a region not mapped (like document element node) the function returns false and sets elem to null) 
        // This function does not work if the region is not associated w/ a DataRow (it uses DataRow association to know what is the row element associated w/ the region)
        internal bool GetRegion( XmlNode node, out XmlBoundElement rowElem ) { 
            while ( node != null ) { 
                XmlBoundElement be = node as XmlBoundElement;
                // Break if found a region 
                if ( be != null && GetRowFromElement( be ) != null ) {
                    rowElem = be;
                    return true;
                } 

                if ( node.NodeType == XmlNodeType.Attribute ) 
                    node = ((XmlAttribute)node).OwnerElement; 
                else
                    node = node.ParentNode; 
            }

            rowElem = null;
            return false; 
        }
 
        internal bool IsRegionRadical( XmlBoundElement rowElem ) { 
            // You must pass a row element (which s/b associated w/ a DataRow)
            Debug.Assert( rowElem.Row != null ); 

            if ( rowElem.ElementState == ElementState.Defoliated )
                return true;
 
            DataTable table = GetTableSchemaForElement( rowElem );
            DataColumnCollection columns = table.Columns; 
            int iColumn = 0; 

            // check column attributes... 
            int cAttrs = rowElem.Attributes.Count;
            for ( int iAttr = 0; iAttr < cAttrs; iAttr++ ) {
                XmlAttribute attr = rowElem.Attributes[iAttr];
 
                // only specified attributes are radical
                if ( !attr.Specified ) 
                    return false; 

                // only mapped attrs are valid 
                DataColumn schema = GetColumnSchemaForNode( rowElem, attr );
                if ( schema == null ) {
                    //Console.WriteLine("Region has unmapped attribute");
                    return false; 
                }
 
                // check to see if column is in order 
                if ( !IsNextColumn( columns, ref iColumn, schema ) ) {
                    //Console.WriteLine("Region has attribute columns out of order or duplicate"); 
                    return false;
                }

                // must have exactly one text node (XmlNodeType.Text) child 
                //
                XmlNode fc = attr.FirstChild; 
                if ( fc == null || fc.NodeType != XmlNodeType.Text || fc.NextSibling != null ) { 
                    //Console.WriteLine("column element has other than a single child text node");
                    return false; 
                }
            }

            // check column elements 
            iColumn = 0;
            XmlNode n = rowElem.FirstChild; 
            for ( ; n != null; n = n.NextSibling ) { 
                // only elements can exist in radically structured data
                if ( n.NodeType != XmlNodeType.Element ) { 
                    //Console.WriteLine("Region has non-element child");
                    return false;
                }
                XmlElement e = n as XmlElement; 

                // only checking for column mappings in this loop 
                if ( GetRowFromElement( e ) != null ) 
                    break;
 
                // element's must have schema to be radically structured
                DataColumn schema = GetColumnSchemaForNode( rowElem, e );
                if ( schema == null ) {
                    //Console.WriteLine("Region has unmapped child element"); 
                    return false;
                } 
 
                // check to see if column is in order
                if ( !IsNextColumn( columns, ref iColumn, schema ) ) { 
                    //Console.WriteLine("Region has element columns out of order or duplicate");
                    return false;
                }
 
                // must have no attributes
                if ( e.HasAttributes ) 
                    return false; 

                // must have exactly one text node child 
                XmlNode fc = e.FirstChild;
                if ( fc == null || fc.NodeType != XmlNodeType.Text || fc.NextSibling != null ) {
                    //Console.WriteLine("column element has other than a single child text node");
                    return false; 
                }
            } 
 
            // check for remaining sub-regions
            for (; n != null; n = n.NextSibling ) { 
                // only elements can exist in radically structured data
                if ( n.NodeType != XmlNodeType.Element ) {
                    //Console.WriteLine("Region has non-element child");
                    return false; 
                }
 
                // element's must be regions in order to be radially structured 
                DataRow row = GetRowFromElement( (XmlElement)n );
                if ( row == null ) { 
                    //Console.WriteLine("Region has unmapped element");
                    return false;
                }
            } 

            return true; 
        } 

        private void AddTableSchema( DataTable table ) { 
            object idTable = GetIdentity( table.EncodedTableName, table.Namespace );
            tableSchemaMap[ idTable ] = table;
        }
        private void AddColumnSchema( DataColumn col ) { 
            DataTable table = col.Table;
            object idTable = GetIdentity( table.EncodedTableName, table.Namespace ); 
            object idColumn = GetIdentity( col.EncodedColumnName, col.Namespace ); 

            Hashtable columns = (Hashtable) columnSchemaMap[ idTable ]; 
            if ( columns == null ) {
                columns = new Hashtable();
                columnSchemaMap[ idTable ] = columns;
            } 
            columns[ idColumn ] = col;
        } 
        private static object GetIdentity( string localName, string namespaceURI ) { 
            // we need access to XmlName to make this faster
            return localName+":"+namespaceURI; 
        }

        private bool IsNextColumn( DataColumnCollection columns, ref int iColumn, DataColumn col ) {
            for ( ; iColumn < columns.Count; iColumn++ ) { 
                if ( columns[iColumn] == col ) {
                    iColumn++; // advance before we return... 
                    return true; 
                }
            } 

            return false;
        }
 
    }
} 
 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK