Tuesday, November 3, 2009

Generating XML from a DataTable











 < Day Day Up > 





Generating XML from a DataTable



One question I receive quite often regarding serializing ADO.NET objects to XML format is how to generate XML from a standalone DataTable, or one that is not included in a parent DataSet object. If you look up the GetXml or WriteXml method in online help, you'll find that while both methods are implemented by the DataSet class, neither is implemented by the DataTable class. This is a bit confusing at first because, as you've seen, calling and using these methods against a DataSet containing multiple DataTable objects does result in each table being processed. After exchanging a couple of e-mails with friends on the .NET development team, I've found that the DataSet does define methods to serialize a specified DataTable, but that these methods are not exposed. However, this limitation is very easy to circumvent with the following generic function�WriteDataTableToXml�which serializes a specified DataTable object to XML.





void WriteDataTableToXml(

DataTable* table,

String* filename,

XmlWriteMode mode)

{

#pragma push_macro("new")

#undef new

try

{

// Create a temporary dataset

DataSet* dataset = new DataSet();



// Does table belong to a dataset already?

if (NULL == table->DataSet)

{

// Add it to the temporary DataSet

dataset->Tables->Add(table);

}

else

{

// Make a copy of the DataTable and

// add it to the temporary DataSet

dataset->Tables->Add(table->Copy());

}



dataset->WriteXml(filename, mode);

}

catch(Exception* e)

{

Console::WriteLine(e->Message);

}

#pragma pop_macro("new")

}



The WriteDataTableToXml function takes three parameters�a DataTable object, a String that's used as a file name, and an XmlWriteMode enumeration value. After the function constructs an empty DataSet, it checks to see if the DataTable already belongs to a DataSet by inspecting the DataTable::DataSet property. This is done due to the restriction that a single instance of a DataTable cannot simultaneously belong to more than one DataSet. If the DataTable does not belong to a DataSet, it is added to the temporary DataSet. If the table does belong to a DataSet, then a temporary copy of the DataTable is made and added to the temporary DataSet. Finally, the DataSet::WriteXml is called, passing it the specified file name and XmlWriteNode parameter values. The following test function programmatically constructs a DataTable, defining its columns and adding a couple of rows of test data before calling the WriteDataTableToXml function.





void TestWriteDataTableToXml()

{

#pragma push_macro("new")

#undef new

try

{

// Define a DataTable

DataTable* table = new DataTable(S"Players");



// Define the table's columns

table->Columns->Add(S"FirstName", __typeof(String));

table->Columns->Add(S"LastName", __typeof(String));



DataRow* newRow;

Object* values[] = new Object*[table->Columns->Count];



// Add test rows to the DataTable object

values[0] = S"Yao";

values[1] = S"Ming";

newRow = table->Rows->Add(values);



values[0] = S"Steve";

values[1] = S"Francis";

newRow = table->Rows->Add(values);



WriteDataTableToXml(table,

S"Players.xml",

XmlWriteMode::WriteSchema);

}

catch(Exception* e)

{

Console::WriteLine(e->Message);

}

#pragma pop_macro("new")

}



As the following output indicates, our little helper function now enables us to serialize DataTable objects with or without the accompanying schema information.





<?xml version="1.0" standalone="yes"?>

<NewDataSet>

<xs:schema id="NewDataSet"

xmlns=""

xmlns:xs="http://www.w3.org/2001/XMLSchema"

xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">

<xs:element name="NewDataSet" msdata:IsDataSet="true">

<xs:complexType>

<xs:choice maxOccurs="unbounded">

<xs:element name="Players">

<xs:complexType>

<xs:sequence>

<xs:element name="FirstName"

type="xs:string" minOccurs="0" />

<xs:element name="LastName"

type="xs:string" minOccurs="0" />

</xs:sequence>

</xs:complexType>

</xs:element>

</xs:choice>

</xs:complexType>

</xs:element>

</xs:schema>

<Players>

<FirstName>Yao</FirstName>

<LastName>Ming</LastName>

</Players>

<Players>

<FirstName>Steve</FirstName>

<LastName>Francis</LastName>

</Players>

</NewDataSet>













     < Day Day Up > 



    No comments: