You've already forked linux-packaging-mono
Imported Upstream version 4.6.0.125
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
This commit is contained in:
parent
a569aebcfd
commit
e79aa3c0ed
@ -0,0 +1,484 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <copyright file="XmlToDatasetMap.cs" company="Microsoft">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
// <owner current="true" primary="true">[....]</owner>
|
||||
// <owner current="true" primary="false">[....]</owner>
|
||||
// <owner current="false" primary="false">[....]</owner>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace System.Data {
|
||||
using System;
|
||||
using System.Xml;
|
||||
using System.Collections;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
|
||||
// This is an internal helper class used during Xml load to DataSet/DataDocument.
|
||||
// XmlToDatasetMap class provides functionality for binding elemants/atributes
|
||||
// to DataTable / DataColumn
|
||||
internal sealed class XmlToDatasetMap {
|
||||
|
||||
private sealed class XmlNodeIdentety {
|
||||
public string LocalName;
|
||||
public string NamespaceURI;
|
||||
public XmlNodeIdentety(string localName, string namespaceURI) {
|
||||
this.LocalName = localName;
|
||||
this.NamespaceURI = namespaceURI;
|
||||
}
|
||||
override public int GetHashCode() {
|
||||
return ((object) LocalName).GetHashCode();
|
||||
}
|
||||
override public bool Equals(object obj) {
|
||||
XmlNodeIdentety id = (XmlNodeIdentety) obj;
|
||||
return (
|
||||
(String.Compare(this.LocalName, id.LocalName, StringComparison.OrdinalIgnoreCase) == 0) &&
|
||||
(String.Compare(this.NamespaceURI, id.NamespaceURI, StringComparison.OrdinalIgnoreCase) == 0)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// This class exist to avoid alocatin of XmlNodeIdentety to every acces to the hash table.
|
||||
// Unfortunetely XmlNode doesn't export single identety object.
|
||||
internal sealed class XmlNodeIdHashtable : Hashtable {
|
||||
private XmlNodeIdentety id = new XmlNodeIdentety(string.Empty, string.Empty);
|
||||
public XmlNodeIdHashtable(Int32 capacity)
|
||||
: base(capacity) {}
|
||||
public object this[XmlNode node] {
|
||||
get {
|
||||
id.LocalName = node.LocalName;
|
||||
id.NamespaceURI = node.NamespaceURI;
|
||||
return this[id];
|
||||
}
|
||||
}
|
||||
|
||||
public object this[XmlReader dataReader] {
|
||||
get {
|
||||
id.LocalName = dataReader.LocalName;
|
||||
id.NamespaceURI = dataReader.NamespaceURI;
|
||||
return this[id];
|
||||
}
|
||||
}
|
||||
|
||||
public object this[DataTable table] {
|
||||
get {
|
||||
id.LocalName = table.EncodedTableName;
|
||||
id.NamespaceURI = table.Namespace;
|
||||
return this[id];
|
||||
}
|
||||
}
|
||||
|
||||
public object this[string name] {
|
||||
get {
|
||||
id.LocalName = name;
|
||||
id.NamespaceURI = String.Empty;
|
||||
return this[id];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class TableSchemaInfo {
|
||||
public DataTable TableSchema;
|
||||
public XmlNodeIdHashtable ColumnsSchemaMap;
|
||||
public TableSchemaInfo(DataTable tableSchema) {
|
||||
this.TableSchema = tableSchema;
|
||||
this.ColumnsSchemaMap = new XmlNodeIdHashtable(tableSchema.Columns.Count);
|
||||
}
|
||||
}
|
||||
|
||||
XmlNodeIdHashtable tableSchemaMap; // Holds all the tables information
|
||||
|
||||
TableSchemaInfo lastTableSchemaInfo = null;
|
||||
|
||||
// Used to infer schema
|
||||
|
||||
public XmlToDatasetMap(DataSet dataSet, XmlNameTable nameTable) {
|
||||
Debug.Assert(dataSet != null, "DataSet can't be null");
|
||||
Debug.Assert(nameTable != null, "NameTable can't be null");
|
||||
BuildIdentityMap(dataSet, nameTable);
|
||||
}
|
||||
|
||||
// Used to read data with known schema
|
||||
|
||||
public XmlToDatasetMap(XmlNameTable nameTable, DataSet dataSet) {
|
||||
Debug.Assert(dataSet != null, "DataSet can't be null");
|
||||
Debug.Assert(nameTable != null, "NameTable can't be null");
|
||||
BuildIdentityMap(nameTable, dataSet);
|
||||
}
|
||||
|
||||
// Used to infer schema
|
||||
|
||||
public XmlToDatasetMap(DataTable dataTable, XmlNameTable nameTable) {
|
||||
Debug.Assert(dataTable != null, "DataTable can't be null");
|
||||
Debug.Assert(nameTable != null, "NameTable can't be null");
|
||||
BuildIdentityMap(dataTable, nameTable);
|
||||
}
|
||||
|
||||
// Used to read data with known schema
|
||||
|
||||
public XmlToDatasetMap(XmlNameTable nameTable, DataTable dataTable) {
|
||||
Debug.Assert(dataTable != null, "DataTable can't be null");
|
||||
Debug.Assert(nameTable != null, "NameTable can't be null");
|
||||
BuildIdentityMap(nameTable, dataTable);
|
||||
}
|
||||
static internal bool IsMappedColumn(DataColumn c) {
|
||||
return (c.ColumnMapping != MappingType.Hidden);
|
||||
}
|
||||
|
||||
// Used to infere schema
|
||||
|
||||
private TableSchemaInfo AddTableSchema(DataTable table, XmlNameTable nameTable) {
|
||||
// [....]: Because in our case reader already read the document all names that we can meet in the
|
||||
// document already has an entry in NameTable.
|
||||
// If in future we will build identity map before reading XML we can replace Get() to Add()
|
||||
// [....]: GetIdentity is called from two places: BuildIdentityMap() and LoadRows()
|
||||
// First case deals with decoded names; Second one with encoded names.
|
||||
// We decided encoded names in first case (instead of decoding them in second)
|
||||
// because it save us time in LoadRows(). We have, as usual, more data them schemas
|
||||
string tableLocalName = nameTable.Get(table.EncodedTableName);
|
||||
string tableNamespace = nameTable.Get(table.Namespace );
|
||||
if(tableLocalName == null) {
|
||||
// because name of this table isn't present in XML we don't need mapping for it.
|
||||
// Less mapping faster we work.
|
||||
return null;
|
||||
}
|
||||
TableSchemaInfo tableSchemaInfo = new TableSchemaInfo(table);
|
||||
tableSchemaMap[new XmlNodeIdentety(tableLocalName, tableNamespace)] = tableSchemaInfo;
|
||||
return tableSchemaInfo;
|
||||
}
|
||||
|
||||
private TableSchemaInfo AddTableSchema(XmlNameTable nameTable, DataTable table) {
|
||||
// [....]:This is the opposite of the previous function:
|
||||
// we populate the nametable so that the hash comparison can happen as
|
||||
// object comparison instead of strings.
|
||||
// [....]: GetIdentity is called from two places: BuildIdentityMap() and LoadRows()
|
||||
// First case deals with decoded names; Second one with encoded names.
|
||||
// We decided encoded names in first case (instead of decoding them in second)
|
||||
// because it save us time in LoadRows(). We have, as usual, more data them schemas
|
||||
|
||||
string _tableLocalName = table.EncodedTableName; // Table name
|
||||
|
||||
string tableLocalName = nameTable.Get(_tableLocalName); // Look it up in nametable
|
||||
|
||||
if(tableLocalName == null) { // If not found
|
||||
tableLocalName = nameTable.Add(_tableLocalName); // Add it
|
||||
}
|
||||
|
||||
table.encodedTableName = tableLocalName; // And set it back
|
||||
|
||||
string tableNamespace = nameTable.Get(table.Namespace); // Look ip table namespace
|
||||
|
||||
if (tableNamespace == null) { // If not found
|
||||
tableNamespace = nameTable.Add(table.Namespace); // Add it
|
||||
}
|
||||
else {
|
||||
if (table.tableNamespace != null) // Update table namespace
|
||||
table.tableNamespace = tableNamespace;
|
||||
}
|
||||
|
||||
|
||||
TableSchemaInfo tableSchemaInfo = new TableSchemaInfo(table);
|
||||
// Create new table schema info
|
||||
tableSchemaMap[new XmlNodeIdentety(tableLocalName, tableNamespace)] = tableSchemaInfo;
|
||||
// And add it to the hashtable
|
||||
return tableSchemaInfo; // Return it as we have to populate
|
||||
// Column schema map and Child table
|
||||
// schema map in it
|
||||
}
|
||||
|
||||
private bool AddColumnSchema(DataColumn col, XmlNameTable nameTable, XmlNodeIdHashtable columns) {
|
||||
string columnLocalName = nameTable.Get(col.EncodedColumnName );
|
||||
string columnNamespace = nameTable.Get(col.Namespace );
|
||||
if(columnLocalName == null) {
|
||||
return false;
|
||||
}
|
||||
XmlNodeIdentety idColumn = new XmlNodeIdentety(columnLocalName, columnNamespace);
|
||||
|
||||
columns[idColumn] = col;
|
||||
|
||||
if (col.ColumnName.StartsWith("xml", StringComparison.OrdinalIgnoreCase)) {
|
||||
HandleSpecialColumn(col, nameTable, columns);
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool AddColumnSchema(XmlNameTable nameTable, DataColumn col, XmlNodeIdHashtable columns) {
|
||||
string _columnLocalName = XmlConvert.EncodeLocalName(col.ColumnName);
|
||||
string columnLocalName = nameTable.Get(_columnLocalName); // Look it up in a name table
|
||||
|
||||
if(columnLocalName == null) { // Not found?
|
||||
columnLocalName = nameTable.Add(_columnLocalName); // Add it
|
||||
}
|
||||
|
||||
col.encodedColumnName = columnLocalName; // And set it back
|
||||
|
||||
string columnNamespace = nameTable.Get(col.Namespace ); // Get column namespace from nametable
|
||||
|
||||
if(columnNamespace == null) { // Not found ?
|
||||
columnNamespace = nameTable.Add(col.Namespace); // Add it
|
||||
}
|
||||
else {
|
||||
if (col._columnUri != null ) // Update namespace
|
||||
col._columnUri = columnNamespace;
|
||||
}
|
||||
// Create XmlNodeIdentety
|
||||
// for this column
|
||||
XmlNodeIdentety idColumn = new XmlNodeIdentety(columnLocalName, columnNamespace);
|
||||
columns[idColumn] = col; // And add it to hashtable
|
||||
|
||||
if (col.ColumnName.StartsWith("xml", StringComparison.OrdinalIgnoreCase)) {
|
||||
HandleSpecialColumn(col, nameTable, columns);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void BuildIdentityMap(DataSet dataSet, XmlNameTable nameTable) {
|
||||
|
||||
this.tableSchemaMap = new XmlNodeIdHashtable(dataSet.Tables.Count);
|
||||
|
||||
foreach(DataTable t in dataSet.Tables) {
|
||||
TableSchemaInfo tableSchemaInfo = AddTableSchema(t, nameTable);
|
||||
if(tableSchemaInfo != null) {
|
||||
foreach( DataColumn c in t.Columns ) {
|
||||
// don't include auto-generated PK, FK and any hidden columns to be part of mapping
|
||||
if (IsMappedColumn(c)) {
|
||||
AddColumnSchema(c, nameTable, tableSchemaInfo.ColumnsSchemaMap);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This one is used while reading data with preloaded schema
|
||||
|
||||
private void BuildIdentityMap(XmlNameTable nameTable, DataSet dataSet) {
|
||||
this.tableSchemaMap = new XmlNodeIdHashtable(dataSet.Tables.Count);
|
||||
// This hash table contains
|
||||
// tables schemas as TableSchemaInfo objects
|
||||
// These objects holds reference to the table.
|
||||
// Hash tables with columns schema maps
|
||||
// and child tables schema maps
|
||||
|
||||
string dsNamespace = nameTable.Get(dataSet.Namespace); // Attept to look up DataSet namespace
|
||||
// in the name table
|
||||
|
||||
if (dsNamespace == null) { // Found ?
|
||||
dsNamespace = nameTable.Add(dataSet.Namespace); // Nope. Add it
|
||||
}
|
||||
dataSet.namespaceURI = dsNamespace; // Set a DataSet namespace URI
|
||||
|
||||
|
||||
foreach(DataTable t in dataSet.Tables) { // For each table
|
||||
|
||||
TableSchemaInfo tableSchemaInfo = AddTableSchema(nameTable, t);
|
||||
// Add table schema info to hash table
|
||||
|
||||
if(tableSchemaInfo != null) {
|
||||
foreach( DataColumn c in t.Columns ) { // Add column schema map
|
||||
// don't include auto-generated PK, FK and any hidden columns to be part of mapping
|
||||
if (IsMappedColumn(c)) { // If mapped column
|
||||
AddColumnSchema(nameTable, c, tableSchemaInfo.ColumnsSchemaMap);
|
||||
} // Add it to the map
|
||||
}
|
||||
|
||||
// Add child nested tables to the schema
|
||||
|
||||
foreach( DataRelation r in t.ChildRelations ) { // Do we have a child tables ?
|
||||
if (r.Nested) { // Is it nested?
|
||||
// don't include non nested tables
|
||||
|
||||
// Handle namespaces and names as usuall
|
||||
|
||||
string _tableLocalName = XmlConvert.EncodeLocalName(r.ChildTable.TableName);
|
||||
string tableLocalName = nameTable.Get(_tableLocalName);
|
||||
|
||||
if(tableLocalName == null) {
|
||||
tableLocalName = nameTable.Add(_tableLocalName);
|
||||
}
|
||||
|
||||
string tableNamespace = nameTable.Get(r.ChildTable.Namespace );
|
||||
|
||||
if(tableNamespace == null) {
|
||||
tableNamespace = nameTable.Add(r.ChildTable.Namespace);
|
||||
}
|
||||
|
||||
XmlNodeIdentety idTable = new XmlNodeIdentety(tableLocalName, tableNamespace);
|
||||
tableSchemaInfo.ColumnsSchemaMap[idTable] = r.ChildTable;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Used for inference
|
||||
|
||||
private void BuildIdentityMap(DataTable dataTable, XmlNameTable nameTable) {
|
||||
this.tableSchemaMap = new XmlNodeIdHashtable(1);
|
||||
|
||||
TableSchemaInfo tableSchemaInfo = AddTableSchema(dataTable, nameTable);
|
||||
if(tableSchemaInfo != null) {
|
||||
foreach( DataColumn c in dataTable.Columns ) {
|
||||
// don't include auto-generated PK, FK and any hidden columns to be part of mapping
|
||||
if (IsMappedColumn(c)) {
|
||||
AddColumnSchema(c, nameTable, tableSchemaInfo.ColumnsSchemaMap);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// This one is used while reading data with preloaded schema
|
||||
|
||||
private void BuildIdentityMap(XmlNameTable nameTable, DataTable dataTable) {
|
||||
|
||||
ArrayList tableList = GetSelfAndDescendants(dataTable); // Get list of tables we're loading
|
||||
// This includes our table and
|
||||
// related tables tree
|
||||
|
||||
this.tableSchemaMap = new XmlNodeIdHashtable( tableList.Count );
|
||||
// Create hash table to hold all
|
||||
// tables to load.
|
||||
|
||||
foreach (DataTable t in tableList) { // For each table
|
||||
|
||||
TableSchemaInfo tableSchemaInfo = AddTableSchema(nameTable, t );
|
||||
// Create schema info
|
||||
if(tableSchemaInfo != null) {
|
||||
foreach( DataColumn c in t.Columns ) { // Add column information
|
||||
// don't include auto-generated PK, FK and any hidden columns to be part of mapping
|
||||
if (IsMappedColumn(c)) {
|
||||
AddColumnSchema(nameTable, c, tableSchemaInfo.ColumnsSchemaMap);
|
||||
}
|
||||
}
|
||||
|
||||
foreach( DataRelation r in t.ChildRelations ) { // Add nested tables information
|
||||
if (r.Nested) { // Is it nested?
|
||||
// don't include non nested tables
|
||||
|
||||
// Handle namespaces and names as usuall
|
||||
|
||||
string _tableLocalName = XmlConvert.EncodeLocalName(r.ChildTable.TableName);
|
||||
string tableLocalName = nameTable.Get(_tableLocalName);
|
||||
|
||||
if(tableLocalName == null) {
|
||||
tableLocalName = nameTable.Add(_tableLocalName);
|
||||
}
|
||||
|
||||
string tableNamespace = nameTable.Get(r.ChildTable.Namespace );
|
||||
|
||||
if(tableNamespace == null) {
|
||||
tableNamespace = nameTable.Add(r.ChildTable.Namespace);
|
||||
}
|
||||
|
||||
XmlNodeIdentety idTable = new XmlNodeIdentety(tableLocalName, tableNamespace);
|
||||
tableSchemaInfo.ColumnsSchemaMap[idTable] = r.ChildTable;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private ArrayList GetSelfAndDescendants(DataTable dt) { // breadth-first
|
||||
ArrayList tableList = new ArrayList();
|
||||
tableList.Add(dt);
|
||||
int nCounter = 0;
|
||||
|
||||
while (nCounter < tableList.Count) {
|
||||
foreach(DataRelation childRelations in ((DataTable)tableList[nCounter]).ChildRelations) {
|
||||
if (!tableList.Contains(childRelations.ChildTable))
|
||||
tableList.Add(childRelations.ChildTable);
|
||||
}
|
||||
nCounter++;
|
||||
}
|
||||
|
||||
return tableList;
|
||||
}
|
||||
// Used to infer schema and top most node
|
||||
|
||||
public object GetColumnSchema(XmlNode node, bool fIgnoreNamespace) {
|
||||
Debug.Assert(node != null, "Argument validation");
|
||||
TableSchemaInfo tableSchemaInfo = null;
|
||||
|
||||
XmlNode nodeRegion = (node.NodeType == XmlNodeType.Attribute) ? ((XmlAttribute)node).OwnerElement : node.ParentNode;
|
||||
|
||||
do {
|
||||
if(nodeRegion == null || nodeRegion.NodeType != XmlNodeType.Element) {
|
||||
return null;
|
||||
}
|
||||
tableSchemaInfo = (TableSchemaInfo) (fIgnoreNamespace ? tableSchemaMap[nodeRegion.LocalName] : tableSchemaMap[nodeRegion]);
|
||||
|
||||
nodeRegion = nodeRegion.ParentNode;
|
||||
} while(tableSchemaInfo == null);
|
||||
|
||||
if (fIgnoreNamespace)
|
||||
return tableSchemaInfo.ColumnsSchemaMap[node.LocalName];
|
||||
else
|
||||
return tableSchemaInfo.ColumnsSchemaMap[node];
|
||||
|
||||
}
|
||||
|
||||
|
||||
public object GetColumnSchema(DataTable table, XmlReader dataReader, bool fIgnoreNamespace){
|
||||
if ((lastTableSchemaInfo == null) || (lastTableSchemaInfo.TableSchema != table)) {
|
||||
lastTableSchemaInfo = (TableSchemaInfo)(fIgnoreNamespace ? tableSchemaMap[table.EncodedTableName] : tableSchemaMap[table]);
|
||||
}
|
||||
|
||||
if (fIgnoreNamespace)
|
||||
return lastTableSchemaInfo.ColumnsSchemaMap[dataReader.LocalName];
|
||||
return lastTableSchemaInfo.ColumnsSchemaMap[dataReader];
|
||||
}
|
||||
|
||||
// Used to infer schema
|
||||
|
||||
public object GetSchemaForNode(XmlNode node, bool fIgnoreNamespace) {
|
||||
TableSchemaInfo tableSchemaInfo = null;
|
||||
|
||||
if (node.NodeType == XmlNodeType.Element) { // If element
|
||||
tableSchemaInfo = (TableSchemaInfo) (fIgnoreNamespace ? tableSchemaMap[node.LocalName] : tableSchemaMap[node]);
|
||||
} // Look up table schema info for it
|
||||
|
||||
if (tableSchemaInfo != null) { // Got info ?
|
||||
return tableSchemaInfo.TableSchema; // Yes, Return table
|
||||
}
|
||||
|
||||
return GetColumnSchema(node, fIgnoreNamespace); // Attempt to locate column
|
||||
}
|
||||
|
||||
public DataTable GetTableForNode(XmlReader node, bool fIgnoreNamespace) {
|
||||
TableSchemaInfo tableSchemaInfo = (TableSchemaInfo) (fIgnoreNamespace ? tableSchemaMap[node.LocalName] : tableSchemaMap[node]);
|
||||
if (tableSchemaInfo != null) {
|
||||
lastTableSchemaInfo = tableSchemaInfo;
|
||||
return lastTableSchemaInfo.TableSchema;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void HandleSpecialColumn(DataColumn col, XmlNameTable nameTable, XmlNodeIdHashtable columns) {
|
||||
// if column name starts with xml, we encode it manualy and add it for look up
|
||||
Debug.Assert(col.ColumnName.StartsWith("xml", StringComparison.OrdinalIgnoreCase), "column name should start with xml");
|
||||
string tempColumnName;
|
||||
|
||||
if ('x' == col.ColumnName[0]) {
|
||||
tempColumnName = "_x0078_"; // lower case xml... -> _x0078_ml...
|
||||
}
|
||||
else {
|
||||
tempColumnName = "_x0058_"; // upper case Xml... -> _x0058_ml...
|
||||
}
|
||||
|
||||
tempColumnName += col.ColumnName.Substring(1);
|
||||
|
||||
if(nameTable.Get(tempColumnName) == null) {
|
||||
nameTable.Add(tempColumnName);
|
||||
}
|
||||
string columnNamespace = nameTable.Get(col.Namespace);
|
||||
XmlNodeIdentety idColumn = new XmlNodeIdentety(tempColumnName, columnNamespace);
|
||||
columns[idColumn] = col;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user