private void LoadColumn(DataColumn column, object[] foundColumns)
{
// <DataSet> /--------------------------------- We are here on entrance
// <Table> /
// <Column>Value</Column>
// <AnotherColumn>Value</AnotherColumn>
// </Table> \------------------------------ We are here on exit
// </DataSet>
// <Column> If we have something like this
// <Foo>FooVal</Foo> We would grab first text-like node
// Value In this case it would be "FooVal"
// <Bar>BarVal</Bar> And not "Value" as you might think
// </Column> This is how desktop works
string text = string.Empty; // Column text. Assume empty string
string xsiNilString = null; // Possible NIL attribute string
int entryDepth = _dataReader.Depth; // Store depth so we won't read too much
if (_dataReader.AttributeCount > 0) // If have attributes
xsiNilString = _dataReader.GetAttribute(Keywords.XSI_NIL, Keywords.XSINS);
// Try to get NIL attribute
// We have to do it before we move to the next element
if (column.IsCustomType)
{ // Custom type column
object columnValue = null; // Column value we're after. Assume no value.
string xsiTypeString = null; // XSI type name from TYPE attribute
string typeName = null; // Type name from MSD_INSTANCETYPE attribute
XmlRootAttribute xmlAttrib = null; // Might need this attribute for XmlSerializer
if (_dataReader.AttributeCount > 0)
{ // If have attributes, get attributes we'll need
xsiTypeString = _dataReader.GetAttribute(Keywords.TYPE, Keywords.XSINS);
typeName = _dataReader.GetAttribute(Keywords.MSD_INSTANCETYPE, Keywords.MSDNS);
}
// Check if need to use XmlSerializer. We need to do that if type does not implement IXmlSerializable.
// We also need to do that if no polymorphism for this type allowed.
bool useXmlSerializer = !column.ImplementsIXMLSerializable &&
!((column.DataType == typeof(object)) || (typeName != null) || (xsiTypeString != null));
// Check if we have an attribute telling us value is null.
if ((xsiNilString != null) && XmlConvert.ToBoolean(xsiNilString))
{
if (!useXmlSerializer)
{ // See if need to set typed null.
if (typeName != null && typeName.Length > 0)
{
// Got type name
columnValue = SqlUdtStorage.GetStaticNullForUdtType(DataStorage.GetType(typeName));
}
}
if (null == columnValue)
{ // If no value,
columnValue = DBNull.Value; // change to DBNull;
}
if (!_dataReader.IsEmptyElement) // In case element is not empty
while (_dataReader.Read() && (entryDepth < _dataReader.Depth)) ;
// Read current elements
_dataReader.Read(); // And start reading next element.
}
else
{ // No NIL attribute. Get value
bool skipped = false;
if (column.Table.DataSet != null && column.Table.DataSet._udtIsWrapped)
{
_dataReader.Read(); // if UDT is wrapped, skip the wrapper
skipped = true;
}
if (useXmlSerializer)
{ // Create an attribute for XmlSerializer
if (skipped)
{
xmlAttrib = new XmlRootAttribute(_dataReader.LocalName);
xmlAttrib.Namespace = _dataReader.NamespaceURI;
}
else
{
xmlAttrib = new XmlRootAttribute(column.EncodedColumnName);
xmlAttrib.Namespace = column.Namespace;
}
}
columnValue = column.ConvertXmlToObject(_dataReader, xmlAttrib);
// Go get the value
if (skipped)
{
_dataReader.Read(); // if Wrapper is skipped, skip its end tag
}
}
foundColumns[column.Ordinal] = columnValue; // Store value
}
else
{ // Not a custom type.
if (_dataReader.Read() && entryDepth < _dataReader.Depth)
{
// Read to the next element and see if we're inside.
while (entryDepth < _dataReader.Depth)
{
switch (_dataReader.NodeType)
{ // Process nodes based on type
case XmlNodeType.Text: // It looks like a text. And we need it.
case XmlNodeType.Whitespace:
case XmlNodeType.CDATA:
case XmlNodeType.SignificantWhitespace:
if (0 == text.Length)
{ // In case we do not have value already
text = _dataReader.Value; // Get value.
// See if we have other text nodes near. In most cases this loop will not be executed.
StringBuilder builder = null;
while (_dataReader.Read() && entryDepth < _dataReader.Depth && IsTextLikeNode(_dataReader.NodeType))
{
if (builder == null)
{
builder = new StringBuilder(text);
}
builder.Append(_dataReader.Value); // Concatenate other sequential text like
// nodes we might have. This is rare.
// We're using this instead of dataReader.ReadString()
// which would do the same thing but slower.
}
if (builder != null)
{
text = builder.ToString();
}
}
else
{
_dataReader.ReadString(); // We've got column value already. Read this one and ignore it.
}
break;
case XmlNodeType.Element:
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
{
// We've got element which is not supposed to he here.
// That might be table which was misplaced.
// Or it might be a column inside column (also misplaced).
object o = _nodeToSchemaMap.GetColumnSchema(column.Table, _dataReader, FIgnoreNamespace(_dataReader));
// Get dataset element for this XML element
DataColumn 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
}
else
{
_dataReader.Read(); // Already loaded, proceed to the 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)
}
else
{ // Not a nested column nor nested table.
// Let's try other tables in the DataSet
DataTable misplacedTable = _nodeToSchemaMap.GetTableForNode(_dataReader, FIgnoreNamespace(_dataReader));
// Try to get table for node
if (misplacedTable != null)
{
// Got some table to match?
LoadTable(misplacedTable, false /* isNested */);
// While table's XML element is nested,
// the table itself is not. Load it this way.
}
else
{
_dataReader.Read(); // No match? Try next element
}
}
}
}
break;
case XmlNodeType.EntityReference: // Oops. No support for Entity Reference
throw ExceptionBuilder.FoundEntity();
default:
_dataReader.Read(); // We don't process that, skip to the next element.
break;
}
}
_dataReader.Read(); // We're done here. To the next element.
}
if (0 == text.Length && xsiNilString != null && XmlConvert.ToBoolean(xsiNilString))
{
foundColumns[column.Ordinal] = DBNull.Value;
// If no data and NIL attribute is true set value to null
}
else
{
foundColumns[column.Ordinal] = column.ConvertXmlToObject(text);
}
}
}