[ Team LiB ] |
Recipe 8.2 Saving and Loading a DataSet from XMLProblemYou need to save a DataSet as an XML file and create a DataSet from an XML file. SolutionUse the XmlTextWriter and XmlTextReader classes. The sample code contains three event handlers:
The C# code is shown in Example 8-3. Example 8-3. File: XmlFileForm.cs// Namespaces, variables, and constants using System; using System.Configuration; using System.Windows.Forms; using System.Text; using System.IO; using System.Xml; using System.Xml.Schema; using System.Data; using System.Data.SqlClient; // Table name constants private const String ORDERS_TABLE = "Orders"; private const String ORDERDETAILS_TABLE = "OrderDetails"; // Relation name constants private const String ORDERS_ORDERDETAILS_RELATION = "Orders_OrderDetails_Relation"; // Field name constants private const String ORDERID_FIELD = "OrderID"; // . . . private void writeXmlButton_Click(object sender, System.EventArgs e) { DataSet ds = new DataSet( ); SqlDataAdapter da; // Fill the Order table and add it to the DataSet. da = new SqlDataAdapter("SELECT * FROM Orders", ConfigurationSettings.AppSettings["Sql_ConnectString"]); DataTable orderTable = new DataTable(ORDERS_TABLE); da.FillSchema(orderTable, SchemaType.Source); da.Fill(orderTable); ds.Tables.Add(orderTable); // Fill the OrderDetails table and add it to the DataSet. da = new SqlDataAdapter("SELECT * FROM [Order Details]", ConfigurationSettings.AppSettings["Sql_ConnectString"]); DataTable orderDetailTable = new DataTable(ORDERDETAILS_TABLE); da.FillSchema(orderDetailTable, SchemaType.Source); da.Fill(orderDetailTable); ds.Tables.Add(orderDetailTable); // Create a relation between the tables. ds.Relations.Add(ORDERS_ORDERDETAILS_RELATION, ds.Tables[ORDERS_TABLE].Columns[ORDERID_FIELD], ds.Tables[ORDERDETAILS_TABLE].Columns[ORDERID_FIELD], true); // Bind the default view of the Orders table to the grid. resultDataGrid.DataSource = ds.Tables[ORDERS_TABLE].DefaultView; // Write the XSD schema and data to a file. // Display file dialog to select XML file to write. SaveFileDialog sfd = new SaveFileDialog( ); sfd.InitialDirectory = System.IO.Path.GetTempPath( ); sfd.Filter = "XML Files (*.xml)|*.xml|All files (*.*)|*.*"; sfd.FilterIndex = 1; if (sfd.ShowDialog( ) == DialogResult.OK) { FileStream fs = new FileStream(sfd.FileName, FileMode.Create, FileAccess.Write); // Create an XmlTextWriter using the file stream. XmlTextWriter xtw = new XmlTextWriter(fs, Encoding.Unicode); try { // Write the XML to the file. ds.WriteXml(xtw, XmlWriteMode.WriteSchema); resultTextBox.Text = "XML file written."; } catch(Exception ex) { MessageBox.Show(ex.Message); } finally { xtw.Close( ); } } } private void readXmlButton_Click(object sender, System.EventArgs e) { // Write the XML schema from a file. // Display file dialog to select XML file to read. OpenFileDialog ofd = new OpenFileDialog( ); ofd.InitialDirectory = System.IO.Path.GetTempPath( ); ofd.Filter = "XML Files (*.xml)|*.xml|All files (*.*)|*.*"; ofd.FilterIndex = 1; if (ofd.ShowDialog( ) == DialogResult.OK) { FileStream fs = new FileStream(ofd.FileName, FileMode.Open, FileAccess.Read); // Create an XmlTextReader using the file stream. XmlTextReader xtr = new XmlTextReader(fs); try { // Read the schema into the DataSet. DataSet ds = new DataSet( ); ds.ReadXml(xtr, XmlReadMode.ReadSchema); // Bind the default view of the Orders table to the grid. resultDataGrid.DataSource = ds.Tables[ORDERS_TABLE].DefaultView; // Write the XML to a memory stream and display it. MemoryStream ms = new MemoryStream( ); ds.WriteXml(ms, XmlWriteMode.WriteSchema); byte[] result = ms.ToArray( ); ms.Close( ); resultTextBox.Text = Encoding.UTF8.GetString(result, 0, result.Length); } catch(Exception ex) { MessageBox.Show(ex.Message); } finally { xtr.Close( ); } } } private void clearButton_Click(object sender, System.EventArgs e) { // Clear the data grid and the result text box. resultDataGrid.DataSource = null; resultTextBox.Clear( ); } DiscussionThe solution uses the XmlTextWriter and XmlTextReader classes to write and read the XML data for the DataSet. For more information about these classes, see the Discussion for Recipe 8.1 and the MSDN Library. The WriteXml( ) and ReadXml( ) methods of the DataSet are used to write and read the XML for the DataSet. The WriteXml( ) method takes an optional argument that specifies a value from the XmlWriteMode enumeration described in Table 8-2.
If an in-line schema is not written, the ReadXml( ) method can still be used to read the data into a DataSet, but the method will not be able to completely recreate the schema for the DataSet. The XmlRead( ) method takes an optional argument that specifies a value from the XmlReadMode enumeration described in Table 8-3.
Example 8-4 shows the XML file with inline schema written by this solution. Example 8-4. Orders with order details XML file, with schema<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="Orders"> <xs:complexType> <xs:sequence> <xs:element name="OrderID" msdata:ReadOnly="true" msdata:AutoIncrement="true" type="xs:int" /> <xs:element name="CustomerID" minOccurs="0"> <xs:simpleType> <xs:restriction base="xs:string"> <xs:maxLength value="5" /> </xs:restriction> </xs:simpleType> </xs:element> <xs:element name="EmployeeID" type="xs:int" minOccurs="0" /> <xs:element name="OrderDate" type="xs:dateTime" minOccurs="0" /> <xs:element name="RequiredDate" type="xs:dateTime" minOccurs="0" /> <xs:element name="ShippedDate" type="xs:dateTime" minOccurs="0" /> <xs:element name="ShipVia" type="xs:int" minOccurs="0" /> <xs:element name="Freight" type="xs:decimal" minOccurs="0" /> <xs:element name="ShipName" minOccurs="0"> <xs:simpleType> <xs:restriction base="xs:string"> <xs:maxLength value="40" /> </xs:restriction> </xs:simpleType> </xs:element> <xs:element name="ShipAddress" minOccurs="0"> <xs:simpleType> <xs:restriction base="xs:string"> <xs:maxLength value="60" /> </xs:restriction> </xs:simpleType> </xs:element> <xs:element name="ShipCity" minOccurs="0"> <xs:simpleType> <xs:restriction base="xs:string"> <xs:maxLength value="15" /> </xs:restriction> </xs:simpleType> </xs:element> <xs:element name="ShipRegion" minOccurs="0"> <xs:simpleType> <xs:restriction base="xs:string"> <xs:maxLength value="15" /> </xs:restriction> </xs:simpleType> </xs:element> <xs:element name="ShipPostalCode" minOccurs="0"> <xs:simpleType> <xs:restriction base="xs:string"> <xs:maxLength value="10" /> </xs:restriction> </xs:simpleType> </xs:element> <xs:element name="ShipCountry" minOccurs="0"> <xs:simpleType> <xs:restriction base="xs:string"> <xs:maxLength value="15" /> </xs:restriction> </xs:simpleType> </xs:element> </xs:sequence> </xs:complexType> </xs:element> <xs:element name="OrderDetails"> <xs:complexType> <xs:sequence> <xs:element name="OrderID" type="xs:int" /> <xs:element name="ProductID" type="xs:int" /> <xs:element name="UnitPrice" type="xs:decimal" /> <xs:element name="Quantity" type="xs:short" /> <xs:element name="Discount" type="xs:float" /> </xs:sequence> </xs:complexType> </xs:element> </xs:choice> </xs:complexType> <xs:unique name="Constraint1" msdata:PrimaryKey="true"> <xs:selector xpath=".//Orders" /> <xs:field xpath="OrderID" /> </xs:unique> <xs:unique name="OrderDetails_Constraint1" msdata:ConstraintName="Constraint1" msdata:PrimaryKey="true"> <xs:selector xpath=".//OrderDetails" /> <xs:field xpath="OrderID" /> <xs:field xpath="ProductID" /> </xs:unique> <xs:keyref name="Orders_OrderDetails_Relation" refer="Constraint1"> <xs:selector xpath=".//OrderDetails" /> <xs:field xpath="OrderID" /> </xs:keyref> </xs:element> </xs:schema> <Orders> <OrderID>10248</OrderID> <CustomerID>VINET</CustomerID> <EmployeeID>5</EmployeeID> <OrderDate>1996-07-04T00:00:00.0000000-04:00</OrderDate> <RequiredDate>1996-08-01T00:00:00.0000000-04:00</RequiredDate> <ShippedDate>1996-07-16T00:00:00.0000000-04:00</ShippedDate> <ShipVia>3</ShipVia> <Freight>32.38</Freight> <ShipName>Vins et alcools Chevalier</ShipName> <ShipAddress>59 rue de l'Abbaye</ShipAddress> <ShipCity>Reims</ShipCity> <ShipPostalCode>51100</ShipPostalCode> <ShipCountry>France</ShipCountry> </Orders> <Orders> <OrderID>10249</OrderID> <CustomerID>TOMSP</CustomerID> <EmployeeID>6</EmployeeID> <OrderDate>1996-07-05T00:00:00.0000000-04:00</OrderDate> <RequiredDate>1996-08-16T00:00:00.0000000-04:00</RequiredDate> <ShippedDate>1996-07-10T00:00:00.0000000-04:00</ShippedDate> <ShipVia>1</ShipVia> <Freight>11.61</Freight> <ShipName>Toms Spezialitäten</ShipName> <ShipAddress>Luisenstr. 48</ShipAddress> <ShipCity>Münster</ShipCity> <ShipPostalCode>44087</ShipPostalCode> <ShipCountry>Germany</ShipCountry> </Orders> <!-- . . . --> <Orders> <OrderID>11076</OrderID> <CustomerID>BONAP</CustomerID> <EmployeeID>4</EmployeeID> <OrderDate>1998-05-06T00:00:00.0000000-04:00</OrderDate> <RequiredDate>1998-06-03T00:00:00.0000000-04:00</RequiredDate> <ShipVia>2</ShipVia> <Freight>38.28</Freight> <ShipName>Bon app'</ShipName> <ShipAddress>12, rue des Bouchers</ShipAddress> <ShipCity>Marseille</ShipCity> <ShipPostalCode>13008</ShipPostalCode> <ShipCountry>France</ShipCountry> </Orders> <Orders> <OrderID>11077</OrderID> <CustomerID>RATTC</CustomerID> <EmployeeID>1</EmployeeID> <OrderDate>1998-05-06T00:00:00.0000000-04:00</OrderDate> <RequiredDate>1998-06-03T00:00:00.0000000-04:00</RequiredDate> <ShipVia>2</ShipVia> <Freight>8.53</Freight> <ShipName>Rattlesnake Canyon Grocery</ShipName> <ShipAddress>2817 Milton Dr.</ShipAddress> <ShipCity>Albuquerque</ShipCity> <ShipRegion>NM</ShipRegion> <ShipPostalCode>87110</ShipPostalCode> <ShipCountry>USA</ShipCountry> </Orders> <OrderDetails> <OrderID>10248</OrderID> <ProductID>11</ProductID> <UnitPrice>14</UnitPrice> <Quantity>12</Quantity> <Discount>0</Discount> </OrderDetails> <OrderDetails> <OrderID>10248</OrderID> <ProductID>42</ProductID> <UnitPrice>9.8</UnitPrice> <Quantity>10</Quantity> <Discount>0</Discount> </OrderDetails> <!-- . . . --> <OrderDetails> <OrderID>11077</OrderID> <ProductID>75</ProductID> <UnitPrice>7.75</UnitPrice> <Quantity>4</Quantity> <Discount>0</Discount> </OrderDetails> <OrderDetails> <OrderID>11077</OrderID> <ProductID>77</ProductID> <UnitPrice>13</UnitPrice> <Quantity>2</Quantity> <Discount>0</Discount> </OrderDetails> </NewDataSet> Use the WriteXmlSchema( ) and ReadXmlSchema( ) methods of the DataSet to write and read just the XSD schema information. |
[ Team LiB ] |