(DISTFILES): Comment out a few missing files.
[mono-project.git] / mcs / class / System.Data / System.Data / XmlDataReader.cs
bloba3d3cdd970cb2106ebc5e54fca2906848137653a
2 //
3 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
4 //
5 // Permission is hereby granted, free of charge, to any person obtaining
6 // a copy of this software and associated documentation files (the
7 // "Software"), to deal in the Software without restriction, including
8 // without limitation the rights to use, copy, modify, merge, publish,
9 // distribute, sublicense, and/or sell copies of the Software, and to
10 // permit persons to whom the Software is furnished to do so, subject to
11 // the following conditions:
12 //
13 // The above copyright notice and this permission notice shall be
14 // included in all copies or substantial portions of the Software.
15 //
16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 using System;
26 using System.IO;
27 using System.Data;
28 using System.Xml;
31 namespace System.Data
33 #if STANDALONE_DRIVER_TEST
34 public class Driver
36 public static void Main (string [] args)
38 if (args.Length == 0) {
39 Console.WriteLine ("usage: mono xmldatareader.exe filename");
40 return;
43 Console.WriteLine ("Target file: " + args [0]);
45 DataSet ds = new DataSet ();
46 // ds.InferXmlSchema (args [0], null);
48 try {
49 ds.ReadXml (args [0]);
50 } catch (Exception ex) {
51 Console.WriteLine ("ReadXml() borked: " + ex.Message);
52 return;
54 Console.WriteLine ("---- DataSet ----------------");
55 StringWriter sw = new StringWriter ();
56 PrintDataSet (ds, sw);
57 PrintDataSet (ds, Console.Out);
59 ds = new DataSet ();
60 ds.InferXmlSchema (args [0], null);
61 XmlDataReader.ReadXml (ds, new XmlTextReader (args [0]));
62 Console.WriteLine ("---- XmlDataReader ----------------");
63 StringWriter sw2 = new StringWriter ();
64 PrintDataSet (ds, sw2);
66 if (sw.ToString () == sw2.ToString ())
67 Console.WriteLine ("Successful.");
68 else
69 Console.WriteLine ("Different *************************************************\n" + sw2);
72 private static void PrintDataSet (DataSet ds, TextWriter tw)
74 tw.WriteLine ("DS::" + ds.DataSetName + ", " + ds.Tables.Count + ", " + ds.Relations.Count);
75 foreach (DataTable dt in ds.Tables)
76 tw.WriteLine ("DT:" + dt.TableName + ", " + dt.Columns.Count + ", " + dt.Rows.Count);
78 ds.WriteXml (tw);
79 tw.WriteLine ();
82 #endif
84 internal class XmlDataReader
86 const string xmlnsNS = "http://www.w3.org/2000/xmlns/";
88 public static void ReadXml (
89 DataSet dataset, XmlReader reader, XmlReadMode mode)
91 new XmlDataReader (dataset, reader, mode).Process ();
94 DataSet dataset;
95 XmlReader reader;
96 XmlReadMode mode;
98 public XmlDataReader (DataSet ds, XmlReader xr, XmlReadMode m)
100 dataset = ds;
101 reader =xr;
102 mode = m;
105 private void Process ()
107 // set EnforceConstraint to false during load time.
108 bool savedEnforceConstraints =
109 dataset.EnforceConstraints;
110 dataset.EnforceConstraints = false;
112 reader.MoveToContent ();
114 if (mode == XmlReadMode.Fragment) {
115 do {
116 if (XmlConvert.DecodeName (reader.LocalName) == dataset.DataSetName && reader.NamespaceURI == dataset.Namespace)
117 ReadTopLevelElement ();
118 else
119 reader.Skip ();
120 } while (!reader.EOF);
121 } else {
122 // Top level element can be ignored, being regarded
123 // just as a wrapper (even it is not dataset element).
124 DataTable tab = dataset.Tables [XmlConvert.DecodeName (reader.LocalName)];
125 if (tab != null && tab.Namespace == reader.NamespaceURI)
126 ReadDataSetContent ();
127 else
128 ReadTopLevelElement ();
129 reader.MoveToContent ();
132 dataset.EnforceConstraints = savedEnforceConstraints;
135 private void ReadTopLevelElement ()
137 int depth = reader.Depth;
138 reader.Read ();
139 reader.MoveToContent ();
140 do {
141 ReadDataSetContent ();
142 } while (reader.Depth > depth && !reader.EOF);
144 if (reader.IsEmptyElement)
145 reader.Read ();
146 if (reader.NodeType == XmlNodeType.EndElement)
147 reader.ReadEndElement ();
148 reader.MoveToContent ();
151 private void ReadDataSetContent ()
153 DataTable table = dataset.Tables [XmlConvert.DecodeName (reader.LocalName)];
154 if (table == null || table.Namespace != reader.NamespaceURI) {
155 reader.Skip ();
156 reader.MoveToContent ();
157 return; // skip if there is no matching table
160 // skip if namespace does not match.
161 // TODO: This part is suspicious for MS compatibility
162 // (test required)
163 if (table.Namespace != reader.NamespaceURI) {
164 reader.Skip ();
165 reader.MoveToContent ();
166 return; // skip if there is no matching table
169 DataRow row = table.NewRow ();
170 ReadElement (row);
171 table.Rows.Add (row);
174 private void ReadElement (DataRow row)
176 // Consume attributes
177 if (reader.MoveToFirstAttribute ()) {
178 do {
179 if (reader.NamespaceURI == xmlnsNS)
180 continue;
181 ReadElementAttribute (row);
182 } while (reader.MoveToNextAttribute ());
183 reader.MoveToElement ();
186 // If not empty element, read content.
187 if (reader.IsEmptyElement) {
188 reader.Skip ();
189 reader.MoveToContent ();
190 } else {
191 int depth = reader.Depth;
192 reader.Read ();
193 reader.MoveToContent ();
194 do {
195 ReadElementContent (row);
196 } while (reader.Depth > depth && !reader.EOF);
197 if (reader.IsEmptyElement)
198 reader.Read ();
199 if (reader.NodeType == XmlNodeType.EndElement)
200 reader.ReadEndElement ();
201 reader.MoveToContent ();
205 private void ReadElementAttribute (DataRow row)
207 DataColumn col = row.Table.Columns [XmlConvert.DecodeName (reader.LocalName)];
208 if (col == null || col.Namespace != reader.NamespaceURI)
209 return;
210 row [col] = StringToObject (col.DataType, reader.Value);
213 private void ReadElementContent (DataRow row)
215 switch (reader.NodeType) {
217 case XmlNodeType.EndElement:
218 // This happens when the content was only whitespace (and skipped by MoveToContent()).
219 return;
221 case XmlNodeType.Element:
222 ReadElementElement (row);
223 break;
225 case XmlNodeType.Text:
226 case XmlNodeType.CDATA:
227 case XmlNodeType.SignificantWhitespace:
228 DataColumn simple = null;
229 DataColumnCollection cols = row.Table.Columns;
230 for (int i = 0; i < cols.Count; i++) {
231 DataColumn col = cols [i];
232 if (col.ColumnMapping ==
233 MappingType.SimpleContent) {
234 simple = col;
235 break;
238 string s = reader.ReadString ();
239 reader.MoveToContent ();
240 #if SILLY_MS_COMPATIBLE
241 // As to MS, "test string" and "test <!-- comment -->string" are different :P
242 if (simple != null && row.IsNull (simple))
243 row [simple] = StringToObject (simple.DataType, s);
244 #else
245 // But it does not mean we support "123<!-- comment -->456". just allowed for string
246 if (simple != null)
247 row [simple] += s;
248 #endif
249 break;
250 case XmlNodeType.Whitespace:
251 reader.ReadString ();
252 break;
256 private void ReadElementElement (DataRow row)
258 // This child element (for row) might be either simple
259 // content element, or child element
261 // MS.NET crashes here... but it seems just a bug.
262 // DataColumn col = row.Table.Columns [XmlConvert.DecodeName (reader.LocalName)];
263 DataColumn col = null;
264 DataColumnCollection cols = row.Table.Columns;
265 for (int i = 0; i < cols.Count; i++) {
266 if (cols [i].ColumnName == XmlConvert.DecodeName (reader.LocalName) && cols [i].Namespace == reader.NamespaceURI) {
267 col = cols [i];
268 break;
273 // if col exists, then it should be MappingType.Element
274 if (col != null
275 && col.ColumnMapping == MappingType.Element) {
277 // TODO: This part is suspicious for
278 // MS compatibility (test required)
279 if (col.Namespace != reader.NamespaceURI) {
280 reader.Skip ();
281 return;
284 bool wasEmpty = reader.IsEmptyElement;
285 int depth = reader.Depth;
286 row [col] = StringToObject (col.DataType, reader.ReadElementString ());
287 if (!wasEmpty && reader.Depth > depth) {
288 // This means, instance does not match with
289 // the schema (because the instance element
290 // contains complex content, while specified as
291 // simple), so just skip to the end of the
292 // element.
293 while (reader.Depth > depth)
294 reader.Read ();
295 reader.Read ();
297 reader.MoveToContent ();
298 return;
299 } else if (col != null) {
300 // Mismatch column type. Just skip
301 reader.Skip ();
302 reader.MoveToContent ();
303 return;
306 // Otherwise, it might be child table element
307 DataRelationCollection rels = row.Table.ChildRelations;
308 for (int i = 0; i < rels.Count; i++) {
309 DataRelation rel = rels [i];
310 if (!rel.Nested)
311 continue;
312 DataTable ct = rel.ChildTable;
313 if (ct.TableName != XmlConvert.DecodeName (reader.LocalName) || ct.Namespace != reader.NamespaceURI)
314 continue;
316 DataRow childRow = rel.ChildTable.NewRow ();
317 ReadElement (childRow);
319 for (int c = 0; c < rel.ChildColumns.Length; c++) {
320 childRow [rel.ChildColumns [c]]
321 = row [rel.ParentColumns [c]];
323 rel.ChildTable.Rows.Add (childRow);
324 return;
327 // Matched neither of the above: just skip
328 reader.Skip ();
329 reader.MoveToContent ();
332 internal static object StringToObject (Type type, string value)
334 if (type == null) return value;
336 switch (Type.GetTypeCode (type)) {
337 case TypeCode.Boolean: return XmlConvert.ToBoolean (value);
338 case TypeCode.Byte: return XmlConvert.ToByte (value);
339 case TypeCode.Char: return (char)XmlConvert.ToInt32 (value);
340 case TypeCode.DateTime: return XmlConvert.ToDateTime (value);
341 case TypeCode.Decimal: return XmlConvert.ToDecimal (value);
342 case TypeCode.Double: return XmlConvert.ToDouble (value);
343 case TypeCode.Int16: return XmlConvert.ToInt16 (value);
344 case TypeCode.Int32: return XmlConvert.ToInt32 (value);
345 case TypeCode.Int64: return XmlConvert.ToInt64 (value);
346 case TypeCode.SByte: return XmlConvert.ToSByte (value);
347 case TypeCode.Single: return XmlConvert.ToSingle (value);
348 case TypeCode.UInt16: return XmlConvert.ToUInt16 (value);
349 case TypeCode.UInt32: return XmlConvert.ToUInt32 (value);
350 case TypeCode.UInt64: return XmlConvert.ToUInt64 (value);
353 if (type == typeof (TimeSpan)) return XmlConvert.ToTimeSpan (value);
354 if (type == typeof (Guid)) return XmlConvert.ToGuid (value);
355 if (type == typeof (byte[])) return Convert.FromBase64String (value);
357 return Convert.ChangeType (value, type);