2003-11-25 Tim Coleman <tim@timcoleman.com>
[mono.git] / mcs / class / System.Data / System.Data / XmlDataLoader.cs
1 //
2 // mcs/class/System.Data/System.Data/XmlDataLoader.cs
3 //
4 // Purpose: Loads XmlDocument to DataSet 
5 //
6 // class: XmlDataLoader
7 // assembly: System.Data.dll
8 // namespace: System.Data
9 //
10 // Author:
11 //     Ville Palo <vi64pa@koti.soon.fi>
12 //
13 // (c)copyright 2002 Ville Palo
14 //
15 // XmlDataLoader is included within the Mono Class Library.
16 //
17
18 using System;
19 using System.Data;
20 using System.Xml;
21 using System.Xml.XPath;
22 using System.Collections;
23 using System.Globalization;
24
25 namespace System.Data {
26
27         internal class XmlDataLoader
28         {
29         
30                 private DataSet DSet;
31                 Hashtable DiffGrRows = new Hashtable ();
32
33                 public XmlDataLoader (DataSet set) 
34                 {
35                         DSet = set;
36                 }
37
38                 public XmlReadMode LoadData (XmlReader reader, XmlReadMode mode)
39                 {
40                         XmlReadMode Result = XmlReadMode.Auto;
41
42                         switch (mode) {
43
44                                 case XmlReadMode.Fragment:
45                                         break;
46                                 case XmlReadMode.ReadSchema:
47                                         Result = XmlReadMode.ReadSchema;
48                                         ReadModeSchema (reader, false);
49                                         break;
50                                 case XmlReadMode.IgnoreSchema:
51                                         Result = XmlReadMode.IgnoreSchema;
52                                         ReadModeSchema (reader, true);
53                                         break;
54                                 case XmlReadMode.InferSchema:
55                                         Result = XmlReadMode.InferSchema;
56                                         ReadModeInferSchema (reader);
57                                         break;
58                                 default:
59                                         break;
60                         }
61
62                         return Result;
63                 }
64
65                 #region reading
66
67                 // XmlReadMode.InferSchema
68                 [MonoTODO]
69                 private void ReadModeInferSchema (XmlReader reader)
70                 {
71                         // root element is DataSets name
72                         reader.MoveToContent ();
73
74                         DSet.DataSetName = reader.LocalName;
75
76                         // And now comes tables
77                         while (reader.Read ()) {
78
79                                 // skip possible inline-schema
80                                 if (String.Compare (reader.LocalName, "schema", true) == 0 && reader.NodeType == XmlNodeType.Element) {
81                                         while (reader.Read () && (reader.NodeType != XmlNodeType.EndElement 
82                                                                   || String.Compare (reader.LocalName, "schema", true) != 0));
83                                 }
84
85
86                                 if (reader.NodeType == XmlNodeType.Element) {
87                                         
88                                         string datatablename = reader.LocalName;
89                                         DataTable table;
90                                         bool NewTable = false;
91
92                                         if (!DSet.Tables.Contains (datatablename)) {
93                                                 table = new DataTable (reader.LocalName);
94                                                 DSet.Tables.Add (table);
95                                                 NewTable = true;
96                                         }
97                                         else {
98                                                 table = DSet.Tables [datatablename];
99                                         }
100
101                                         Hashtable rowValue = new Hashtable ();
102
103                                         while (reader.Read () && (reader.NodeType != XmlNodeType.EndElement 
104                                                                   || reader.LocalName != datatablename))
105                                         {
106                                                 if (reader.NodeType == XmlNodeType.Element) {
107
108                                                         string dataColumnName = reader.LocalName;
109                                                         if (NewTable)
110                                                                 table.Columns.Add (dataColumnName);
111
112                                                         // FIXME: exception?
113                                                         if (!reader.Read ())
114                                                                 return;
115
116                                                         rowValue.Add (dataColumnName, reader.Value);
117                                                 }
118                                         }
119                                         
120                                         DataRow row = table.NewRow ();
121                                         
122                                         IDictionaryEnumerator enumerator = rowValue.GetEnumerator ();
123                                         while (enumerator.MoveNext ()) {
124                                                 row [enumerator.Key.ToString ()] = enumerator.Value.ToString ();
125                                         }
126
127                                         table.Rows.Add (row);
128                                 }
129                         }                       
130                 }
131
132                 // Read Xmldocument. XmlReadMode.ReadSchema and XmlReadMode.IgnoreSchema
133                 [MonoTODO]
134                 private void ReadModeSchema (XmlReader reader, bool IgnoreSchema)
135                 {
136                         /*\
137                          *  Reads any inline schema, but an exception is thrown 
138                          *  if any tables in the inline schema already exist in the DataSet.
139                         \*/
140
141                         reader.MoveToContent ();
142                         reader.ReadStartElement ();
143                         reader.MoveToContent ();
144
145                         while (reader.NodeType != XmlNodeType.EndElement) 
146                         {
147                                 if (reader.NodeType == XmlNodeType.Element)
148                                 {
149                                         // FIXME: possible inline-schema should be readed here
150                                         if (String.Compare (reader.LocalName, "schema", true) == 0) \r
151                                         {
152                                                 if (!IgnoreSchema)
153                                                         DSet.ReadXmlSchema (reader);
154                                         }
155
156                                         // find table
157                                         if (DSet.Tables.Contains (reader.LocalName)) \r
158                                         {
159                                                 DataTable table = DSet.Tables [reader.LocalName];
160                                                 DataRow row = table.NewRow ();
161
162                                                 reader.ReadStartElement ();
163                                                 ReadColumns (reader, row, table, reader.LocalName);                                     
164                                                 reader.ReadEndElement ();
165
166                                                 table.Rows.Add (row);
167                                         }
168                                 }
169                                 reader.MoveToContent ();
170                         }
171                 }
172
173                 #endregion // reading
174
175                 #region Private helper methods
176                 
177                 private void ReadColumns (XmlReader reader, DataRow row, DataTable table, string TableName)
178                 {
179                         do {
180                                 if (reader.NodeType == XmlNodeType.Element) {
181                                         DataColumn col = table.Columns [reader.LocalName];
182                                         if (col != null) {
183                                                 reader.Read ();
184                                                 row [col] = StringToObject (col.DataType, reader.Value);
185                                         }
186                                 }
187                                 else {
188                                         reader.Read ();
189                                 }
190                                 
191                         } while (table.TableName != reader.LocalName 
192                                  || reader.NodeType != XmlNodeType.EndElement);
193                 }
194
195                 internal static object StringToObject (Type type, string value)
196                 {
197                         if (type == null) return value;
198
199                         switch (Type.GetTypeCode (type))
200                         {
201                                 case TypeCode.Boolean: return XmlConvert.ToBoolean (value);
202                                 case TypeCode.Byte: return XmlConvert.ToByte (value);
203                                 case TypeCode.Char: return (char)XmlConvert.ToInt32 (value);
204                                 case TypeCode.DateTime: return XmlConvert.ToDateTime (value);
205                                 case TypeCode.Decimal: return XmlConvert.ToDecimal (value);
206                                 case TypeCode.Double: return XmlConvert.ToDouble (value);
207                                 case TypeCode.Int16: return XmlConvert.ToInt16 (value);
208                                 case TypeCode.Int32: return XmlConvert.ToInt32 (value);
209                                 case TypeCode.Int64: return XmlConvert.ToInt64 (value);
210                                 case TypeCode.SByte: return XmlConvert.ToSByte (value);
211                                 case TypeCode.Single: return XmlConvert.ToSingle (value);
212                                 case TypeCode.UInt16: return XmlConvert.ToUInt16 (value);
213                                 case TypeCode.UInt32: return XmlConvert.ToUInt32 (value);
214                                 case TypeCode.UInt64: return XmlConvert.ToUInt64 (value);
215                         }\r
216 \r
217                         if (type == typeof (TimeSpan)) return XmlConvert.ToTimeSpan (value);\r
218                         if (type == typeof (byte[])) return Convert.FromBase64String (value);\r
219
220                         return Convert.ChangeType (value, type);
221                 }
222
223                 #endregion // Private helper methods
224         }
225 }