private void LoadTopMostTable(DataTable table)
{
// /------------------------------- This one is in topMostNode (backed up to XML DOM)
// <Table> /----------------------------- We are here on entrance
// <Column>Value</Column>
// <AnotherColumn>Value</AnotherColumn>
// </Table> ...
// \------------------------------ We are here on exit
Debug.Assert(table != null, "Table to be loaded is null on LoadTopMostTable() entry");
Debug.Assert(_topMostNode != null, "topMostNode is null on LoadTopMostTable() entry");
Debug.Assert(!_isDiffgram, "Diffgram mode is on while we have topMostNode table. This is bad.");
bool topNodeIsTable = _isTableLevel || (_dataSet.DataSetName != table.TableName);
// If table name we have matches dataset
// name top node could be a DataSet OR a table.
// It's a table overwise.
DataRow row = null; // Data row we're going to add to this table
bool matchFound = false; // Assume we found no matching elements
int entryDepth = _dataReader.Depth - 1; // Store current reader depth so we know when to stop reading
// Adjust depth by one as we've read top most element
// outside this method.
string textNodeValue; // Value of a text node we might have
Debug.Assert(entryDepth >= 0, "Wrong entry Depth for top most element.");
int entryChild = _childRowsStack.Count; // Memorize child stack level on entry
DataColumn c; // Hold column here
DataColumnCollection collection = table.Columns; // Hold column collectio here
object[] foundColumns = new object[collection.Count];
// This is the columns data we might find
XmlNode n; // Need this to pass by reference
foreach (XmlAttribute attr in _topMostNode.Attributes)
{
// Check all attributes in this node
c = _nodeToSchemaMap.GetColumnSchema(attr, FIgnoreNamespace(attr)) as DataColumn;
// Try to mach attribute to column
if ((c != null) && (c.ColumnMapping == MappingType.Attribute))
{
// If it's a column with attribute mapping
n = attr.FirstChild;
foundColumns[c.Ordinal] = c.ConvertXmlToObject(GetInitialTextFromNodes(ref n));
// Get value
matchFound = true; // and note we found a matching element
}
}
// Now handle elements. This could be columns or nested tables
// We'll skip the rest as we have no idea what to do with it.
// Note: we do not need to read first as we're already as it has been done by caller.
while (entryDepth < _dataReader.Depth)
{
switch (_dataReader.NodeType)
{ // Process nodes based on type
case XmlNodeType.Element: // It's an element
object o = _nodeToSchemaMap.GetColumnSchema(table, _dataReader, FIgnoreNamespace(_dataReader));
// Get dataset element for this XML element
c = o as DataColumn; // Perhaps, it's a column?
if (c != null)
{ // Do we have matched column in this table?
// Let's load column data
if (foundColumns[c.Ordinal] == null)
{
// If this column was not found before
LoadColumn(c, foundColumns); // Get column value.
matchFound = true; // Got matched row.
}
else
{
_dataReader.Read(); // Advance to next element.
}
}
else
{
DataTable nestedTable = o as DataTable;
// Perhaps, it's a nested table ?
if (nestedTable != null)
{ // Do we have matched table in DataSet ?
LoadTable(nestedTable, true /* isNested */);
// Yes. Load nested table (recursive)
matchFound = true; // Got matched nested table
}
else if (ProcessXsdSchema())
{ // Check for schema. Skip or load if found.
continue; // Schema has been found. Process the next element
// we're already at (done by schema processing).
}
else
{ // Not a table or column in this table ?
if (!(matchFound || topNodeIsTable))
{
// Could top node be a DataSet?
return; // Assume top node is DataSet
// and stop top node processing
}
_dataReader.Read(); // Continue to the next element.
}
}
break;
// Oops. Not supported
case XmlNodeType.EntityReference: // Oops. No support for Entity Reference
throw ExceptionBuilder.FoundEntity();
case XmlNodeType.Text: // It looks like a text.
case XmlNodeType.Whitespace: // This actually could be
case XmlNodeType.CDATA: // if we have XmlText in our table
case XmlNodeType.SignificantWhitespace:
textNodeValue = _dataReader.ReadString();
// Get text node value.
c = table._xmlText; // Get XML Text column from our table
if (c != null && foundColumns[c.Ordinal] == null)
{
// If XmlText Column is set
// and we do not have data already
foundColumns[c.Ordinal] = c.ConvertXmlToObject(textNodeValue);
// Read and store the data
}
break;
default:
_dataReader.Read(); // We don't process that, skip to the next element.
break;
}
}
_dataReader.Read(); // Proceed to the next element.
// It's the time to populate row with loaded data and add it to the table we'we just read to the table
for (int i = foundColumns.Length - 1; i >= 0; --i)
{
// Check all columns
if (null == foundColumns[i])
{ // Got data for this column ?
c = collection[i]; // No. Get column for this index
if (c.AllowDBNull && c.ColumnMapping != MappingType.Hidden && !c.AutoIncrement)
{
foundColumns[i] = DBNull.Value; // Assign DBNull if possible
// table.Rows.Add() below will deal
// with default values and autoincrement
}
}
}
row = table.Rows.AddWithColumnEvents(foundColumns); // Create, populate and add row
while (entryChild < _childRowsStack.Count)
{ // Process child rows we might have
DataRow childRow = (DataRow)_childRowsStack.Pop();
// Get row from the stack
bool unchanged = (childRow.RowState == DataRowState.Unchanged);
// Is data the same as before?
childRow.SetNestedParentRow(row, /*setNonNested*/ false);
// Set parent row
if (unchanged) // Restore record if child row's unchanged
childRow._oldRecord = childRow._newRecord;
}
}