DataSet.cs (ReadXml) : Fix bugs. Read correctly the xml file with XmlReadMode of...
[mono.git] / mcs / class / System.Data / System.Data / DataSet.cs
1 // 
2 // System.Data/DataSet.cs
3 //
4 // Author:
5 //   Christopher Podurgiel <cpodurgiel@msn.com>
6 //   Daniel Morgan <danmorg@sc.rr.com>
7 //   Rodrigo Moya <rodrigo@ximian.com>
8 //   Stuart Caborn <stuart.caborn@virgin.net>
9 //   Tim Coleman (tim@timcoleman.com)
10 //   Ville Palo <vi64pa@koti.soon.fi>
11 //
12 // (C) Ximian, Inc. 2002
13 // Copyright (C) Tim Coleman, 2002, 2003
14 //
15
16 using System;
17 using System.Collections;
18 using System.ComponentModel;
19 using System.Globalization;
20 using System.Threading;
21 using System.IO;
22 using System.Runtime.Serialization;
23 using System.Xml;
24 using System.Xml.Schema;
25 using System.Xml.Serialization;
26 using System.Data.Common;
27
28 namespace System.Data {
29
30         [ToolboxItem (false)]
31         [DefaultProperty ("DataSetName")]
32         [Serializable]
33         public class DataSet : MarshalByValueComponent, IListSource, 
34                 ISupportInitialize, ISerializable, IXmlSerializable 
35         {
36                 private string dataSetName;
37                 private string _namespace = "";
38                 private string prefix;
39                 private bool caseSensitive;
40                 private bool enforceConstraints = true;
41                 private DataTableCollection tableCollection;
42                 private DataRelationCollection relationCollection;
43                 private PropertyCollection properties;
44                 private DataViewManager defaultView;
45                 private CultureInfo locale = System.Threading.Thread.CurrentThread.CurrentCulture;
46                 
47                 #region Constructors
48
49                 public DataSet () : this ("NewDataSet") 
50                 {               
51                 }
52                 
53                 public DataSet (string name)
54                 {
55                         dataSetName = name;
56                         tableCollection = new DataTableCollection (this);
57                         relationCollection = new DataRelationCollection.DataSetRelationCollection (this);
58                         properties = new PropertyCollection ();
59                         this.prefix = String.Empty;
60                         
61                         this.Locale = CultureInfo.CurrentCulture;
62                 }
63
64                 [MonoTODO]
65                 protected DataSet (SerializationInfo info, StreamingContext context) : this ()
66                 {
67                         throw new NotImplementedException ();
68                 }
69
70                 #endregion // Constructors
71
72                 #region Public Properties
73
74                 [DataCategory ("Data")]
75                 [DataSysDescription ("Indicates whether comparing strings within the DataSet is case sensitive.")]
76                 [DefaultValue (false)]
77                 public bool CaseSensitive {
78                         get {
79                                 return caseSensitive;
80                         } 
81                         set {
82                                 foreach (DataTable T in Tables) {
83                                         if (T.VirginCaseSensitive)
84                                                 T.CaseSensitive = value;
85                                 }
86
87                                 caseSensitive = value; 
88                                 if (!caseSensitive) {
89                                         foreach (DataTable table in Tables) {
90                                                 foreach (Constraint c in table.Constraints)
91                                                         c.AssertConstraint ();
92                                         }
93                                 }
94                         }
95                 }
96
97                 [DataCategory ("Data")]
98                 [DataSysDescription ("The name of this DataSet.")]
99                 [DefaultValue ("")]
100                 public string DataSetName {
101                         get { return dataSetName; } 
102                         set { dataSetName = value; }
103                 }
104
105                 [DataSysDescription ("Indicates a custom \"view\" of the data contained by the DataSet. This view allows filtering, searching, and navigating through the custom data view.")]
106                 [Browsable (false)]
107                 public DataViewManager DefaultViewManager {
108                         get {
109                                 if (defaultView == null)
110                                         defaultView = new DataViewManager (this);
111                                 return defaultView;
112                         } 
113                 }
114
115                 [DataSysDescription ("Indicates whether constraint rules are to be followed.")]
116                 [DefaultValue (true)]
117                 public bool EnforceConstraints {
118                         get { return enforceConstraints; } 
119                         set { 
120                                 if (value != enforceConstraints) {
121                                         enforceConstraints = value; 
122                                         if (value) {
123                                                 foreach (DataTable table in Tables) {
124                                                         foreach (Constraint c in table.Constraints)
125                                                                 c.AssertConstraint ();
126                                                 }
127                                         }
128                                 }
129                         }
130                 }
131
132                 [Browsable (false)]
133                 [DataCategory ("Data")]
134                 [DataSysDescription ("The collection that holds custom user information.")]
135                 public PropertyCollection ExtendedProperties {
136                         get { return properties; }
137                 }
138
139                 [Browsable (false)]
140                 [DataSysDescription ("Indicates that the DataSet has errors.")]
141                 public bool HasErrors {
142                         [MonoTODO]
143                         get {
144                                 for (int i = 0; i < Tables.Count; i++) {
145                                         if (Tables[i].HasErrors)
146                                                 return true;
147                                 }
148                                 return false;
149                         }
150                 }
151
152                 [DataCategory ("Data")]
153                 [DataSysDescription ("Indicates a locale under which to compare strings within the DataSet.")]
154                 public CultureInfo Locale {
155                         get {
156                                 return locale;
157                         }
158                         set {
159                                 if (locale == null || !locale.Equals (value)) {
160                                         // TODO: check if the new locale is valid
161                                         // TODO: update locale of all tables
162                                         locale = value;
163                                 }
164                         }
165                 }
166
167                 public void Merge (DataRow[] rows)
168                 {
169                         Merge (rows, false, MissingSchemaAction.Add);
170                 }
171                 
172                 public void Merge (DataSet dataSet)
173                 {
174                         Merge (dataSet, false, MissingSchemaAction.Add);
175                 }
176                 
177                 public void Merge (DataTable table)
178                 {
179                         Merge (table, false, MissingSchemaAction.Add);
180                 }
181                 
182                 public void Merge (DataSet dataSet, bool preserveChanges)
183                 {
184                         Merge (dataSet, preserveChanges, MissingSchemaAction.Add);
185                 }
186                 
187                 [MonoTODO]
188                 public void Merge (DataRow[] rows, bool preserveChanges, MissingSchemaAction missingSchemaAction)
189                 {
190                         if (rows == null)
191                                 throw new ArgumentNullException ("rows");
192                         if (!IsLegalSchemaAction (missingSchemaAction))
193                                 throw new ArgumentOutOfRangeException ("missingSchemaAction");
194                         
195                         MergeManager.Merge (this, rows, preserveChanges, missingSchemaAction);
196                 }
197                 
198                 [MonoTODO]
199                 public void Merge (DataSet dataSet, bool preserveChanges, MissingSchemaAction missingSchemaAction)
200                 {
201                         if (dataSet == null)
202                                 throw new ArgumentNullException ("dataSet");
203                         if (!IsLegalSchemaAction (missingSchemaAction))
204                                 throw new ArgumentOutOfRangeException ("missingSchemaAction");
205                         
206                         MergeManager.Merge (this, dataSet, preserveChanges, missingSchemaAction);
207                 }
208                 
209                 [MonoTODO]
210                 public void Merge (DataTable table, bool preserveChanges, MissingSchemaAction missingSchemaAction)
211                 {
212                         if (table == null)
213                                 throw new ArgumentNullException ("table");
214                         if (!IsLegalSchemaAction (missingSchemaAction))
215                                 throw new ArgumentOutOfRangeException ("missingSchemaAction");
216                         
217                         MergeManager.Merge (this, table, preserveChanges, missingSchemaAction);
218                 }
219
220                 private static bool IsLegalSchemaAction (MissingSchemaAction missingSchemaAction)
221                 {
222                         if (missingSchemaAction == MissingSchemaAction.Add || missingSchemaAction == MissingSchemaAction.AddWithKey
223                                 || missingSchemaAction == MissingSchemaAction.Error || missingSchemaAction == MissingSchemaAction.Ignore)
224                                 return true;
225                         return false;
226                 }
227                 
228                 [DataCategory ("Data")]
229                 [DataSysDescription ("Indicates the XML uri namespace for the root element pointed at by this DataSet.")]
230                 [DefaultValue ("")]
231                 public string Namespace {
232                         [MonoTODO]
233                         get { return _namespace; } 
234                         [MonoTODO]
235                         set {
236                                 //TODO - trigger an event if this happens?
237                                 _namespace = value;
238                         }
239                 }
240
241                 [DataCategory ("Data")]
242                 [DataSysDescription ("Indicates the prefix of the namespace used for this DataSet.")]
243                 [DefaultValue ("")]
244                 public string Prefix {
245                         [MonoTODO]
246                         get { return prefix; } 
247                         [MonoTODO]
248                         set {
249                                 //TODO - trigger an event if this happens?
250
251                                 if (value == null)
252                                         value = string.Empty;
253                                 
254                                 if (value != this.prefix) 
255                                         RaisePropertyChanging ("Prefix");
256                                 prefix = value;
257                         }
258                 }
259
260                 [DataCategory ("Data")]
261                 [DataSysDescription ("The collection that holds the relations for this DatSet.")]
262                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
263                 public DataRelationCollection Relations {
264                         get {
265                                 return relationCollection;              
266                         }
267                 }
268
269                 [Browsable (false)]
270                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
271                 public override ISite Site {
272                         [MonoTODO]
273                         get {
274                                 throw new NotImplementedException ();
275                         } 
276                         
277                         [MonoTODO]
278                         set {
279                                 throw new NotImplementedException ();
280                         }
281                 }
282
283                 [DataCategory ("Data")]
284                 [DataSysDescription ("The collection that holds the tables for this DataSet.")]
285                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
286                 public DataTableCollection Tables {
287                         get { return tableCollection; }
288                 }
289
290                 #endregion // Public Properties
291
292                 #region Public Methods
293
294                 [MonoTODO]
295                 public void AcceptChanges ()
296                 {
297                         foreach (DataTable tempTable in tableCollection)
298                                 tempTable.AcceptChanges ();
299                 }
300
301                 public void Clear ()
302                 {
303                         // TODO: if currently bound to a XmlDataDocument
304                         //       throw a NotSupportedException
305                         for (int t = 0; t < tableCollection.Count; t++) {
306                                 tableCollection[t].Clear ();
307                         }
308                 }
309
310                 public virtual DataSet Clone ()
311                 {
312                         DataSet Copy = new DataSet ();
313                         CopyProperties (Copy);
314
315                         foreach (DataTable Table in Tables) {
316                                 Copy.Tables.Add (Table.Clone ());
317                         }
318
319                         //Copy Relationships between tables after existance of tables
320                         //and setting properties correctly
321                         CopyRelations (Copy);
322                         
323                         return Copy;
324                 }
325
326                 // Copies both the structure and data for this DataSet.
327                 public DataSet Copy ()
328                 {
329                         DataSet Copy = new DataSet ();
330                         CopyProperties (Copy);
331
332                         // Copy DatSet's tables
333                         foreach (DataTable Table in Tables) 
334                                 Copy.Tables.Add (Table.Copy ());
335
336                         //Copy Relationships between tables after existance of tables
337                         //and setting properties correctly
338                         CopyRelations (Copy);
339
340                         return Copy;
341                 }
342
343                 [MonoTODO]
344                 private void CopyProperties (DataSet Copy)
345                 {
346                         Copy.CaseSensitive = CaseSensitive;
347                         //Copy.Container = Container
348                         Copy.DataSetName = DataSetName;
349                         //Copy.DefaultViewManager
350                         //Copy.DesignMode
351                         Copy.EnforceConstraints = EnforceConstraints;
352                         //Copy.ExtendedProperties 
353                         //Copy.HasErrors
354                         //Copy.Locale = Locale;
355                         Copy.Namespace = Namespace;
356                         Copy.Prefix = Prefix;                   
357                         //Copy.Site = Site;
358
359                 }
360                 
361                 
362                 private void CopyRelations (DataSet Copy)
363                 {
364
365                         //Creation of the relation contains some of the properties, and the constructor
366                         //demands these values. instead changing the DataRelation constructor and behaviour the
367                         //parameters are pre-configured and sent to the most general constructor
368
369                         foreach (DataRelation MyRelation in this.Relations) {
370                                 string pTable = MyRelation.ParentTable.TableName;
371                                 string cTable = MyRelation.ChildTable.TableName;
372                                 DataColumn[] P_DC = new DataColumn[MyRelation.ParentColumns.Length]; 
373                                 DataColumn[] C_DC = new DataColumn[MyRelation.ChildColumns.Length];
374                                 int i = 0;
375                                 
376                                 foreach (DataColumn DC in MyRelation.ParentColumns) {
377                                         P_DC[i]=Copy.Tables[pTable].Columns[DC.ColumnName];
378                                         i++;
379                                 }
380
381                                 i = 0;
382
383                                 foreach (DataColumn DC in MyRelation.ChildColumns) {
384                                         C_DC[i]=Copy.Tables[cTable].Columns[DC.ColumnName];
385                                         i++;
386                                 }
387                                 
388                                 DataRelation cRel = new DataRelation (MyRelation.RelationName, P_DC, C_DC);
389                                 //cRel.ChildColumns = MyRelation.ChildColumns;
390                                 //cRel.ChildTable = MyRelation.ChildTable;
391                                 //cRel.ExtendedProperties = cRel.ExtendedProperties; 
392                                 //cRel.Nested = MyRelation.Nested;
393                                 //cRel.ParentColumns = MyRelation.ParentColumns;
394                                 //cRel.ParentTable = MyRelation.ParentTable;
395                                                                 
396                                 Copy.Relations.Add (cRel);
397                         }
398                 }
399
400                 
401
402
403                 public DataSet GetChanges ()
404                 {
405                         return GetChanges (DataRowState.Added | DataRowState.Deleted | DataRowState.Modified);
406                 }
407
408                 
409                 public DataSet GetChanges (DataRowState rowStates)
410                 {
411                         if (!HasChanges (rowStates))
412                                 return null;
413                         
414                         DataSet copySet = Clone ();
415                         IEnumerator tableEnumerator = Tables.GetEnumerator ();
416                         DataTable origTable;
417                         DataTable copyTable;
418                         while (tableEnumerator.MoveNext ()) {
419                                 origTable = (DataTable)tableEnumerator.Current;
420                                 copyTable = copySet.Tables[origTable.TableName];
421
422                                 IEnumerator rowEnumerator = origTable.Rows.GetEnumerator ();
423                                 while (rowEnumerator.MoveNext ()) {
424                                         DataRow row = (DataRow)rowEnumerator.Current;
425                                         if (row.IsRowChanged (rowStates)) {
426                                                 DataRow newRow = copyTable.NewRow ();
427                                                 copyTable.Rows.Add (newRow);
428                                                 row.CopyValuesToRow (newRow);
429                                         }
430                                 }
431                         }
432                         return copySet;
433                 }
434
435 #if NET_1_2
436                 [MonoTODO]
437                 public DataTableReader GetDataReader (DataTable[] dataTables)
438                 {
439                         throw new NotImplementedException ();
440                 }
441
442                 [MonoTODO]
443                 public DataTableReader GetDataReader ()
444                 {
445                         throw new NotImplementedException ();
446                 }
447 #endif
448                 
449                 public string GetXml ()
450                 {
451                         StringWriter Writer = new StringWriter ();
452
453                         // Sending false for not printing the Processing instruction
454                         WriteXml (Writer, XmlWriteMode.IgnoreSchema, false);
455                         return Writer.ToString ();
456                 }
457
458                 public string GetXmlSchema ()
459                 {
460                         StringWriter Writer = new StringWriter ();
461                         WriteXmlSchema (Writer);
462                         return Writer.ToString ();
463                 }
464
465                 [MonoTODO]
466                 public bool HasChanges ()
467                 {
468                         return HasChanges (DataRowState.Added | DataRowState.Deleted | DataRowState.Modified);
469                 }
470
471                 [MonoTODO]
472                 public bool HasChanges (DataRowState rowState)
473                 {
474                         if (((int)rowState & 0xffffffe0) != 0)
475                                 throw new ArgumentOutOfRangeException ("rowState");
476
477                         DataTableCollection tableCollection = Tables;
478                         DataTable table;
479                         DataRowCollection rowCollection;
480                         DataRow row;
481
482                         for (int i = 0; i < tableCollection.Count; i++) {
483                                 table = tableCollection[i];
484                                 rowCollection = table.Rows;
485                                 for (int j = 0; j < rowCollection.Count; j++) {
486                                         row = rowCollection[j];
487                                         if ((row.RowState & rowState) != 0)
488                                                 return true;
489                                 }
490                         }
491
492                         return false;           
493                 }
494
495                 [MonoTODO]
496                 public void InferXmlSchema (XmlReader reader, string[] nsArray)
497                 {
498                 }
499
500                 public void InferXmlSchema (Stream stream, string[] nsArray)
501                 {
502                         InferXmlSchema (new XmlTextReader (stream), nsArray);
503                 }
504
505                 public void InferXmlSchema (TextReader reader, string[] nsArray)
506                 {
507                         InferXmlSchema (new XmlTextReader (reader), nsArray);
508                 }
509
510                 public void InferXmlSchema (string fileName, string[] nsArray)
511                 {
512                         XmlTextReader reader = new XmlTextReader (fileName);
513                         try {
514                                 InferXmlSchema (reader, nsArray);
515                         } finally {
516                                 reader.Close ();
517                         }
518                 }
519
520 #if NET_1_2
521                 [MonoTODO]
522                 public void Load (IDataReader reader, LoadOption loadOption, DataTable[] tables)
523                 {
524                         throw new NotImplementedException ();
525                 }
526
527                 [MonoTODO]
528                 public void Load (IDataReader reader, LoadOption loadOption, string[] tables)
529                 {
530                         throw new NotImplementedException ();
531                 }
532 #endif
533
534                 public virtual void RejectChanges ()
535                 {
536                         int i;
537                         bool oldEnforceConstraints = this.EnforceConstraints;
538                         this.EnforceConstraints = false;
539                         
540                         for (i = 0; i < this.Tables.Count;i++) 
541                                 this.Tables[i].RejectChanges ();
542
543                         this.EnforceConstraints = oldEnforceConstraints;
544                 }
545
546                 public virtual void Reset ()
547                 {
548                         IEnumerator constraintEnumerator;
549
550                         // first we remove all ForeignKeyConstraints (if we will not do that
551                         // we will get an exception when clearing the tables).
552                         for (int i = 0; i < Tables.Count; i++) {
553                                 ConstraintCollection cc = Tables[i].Constraints;
554                                 for (int j = 0; j < cc.Count; j++) {
555                                         if (cc[j] is ForeignKeyConstraint)
556                                                 cc.Remove (cc[j]);
557                                 }
558                         }
559
560                         Clear ();
561                         Relations.Clear ();
562                         Tables.Clear ();
563                 }
564
565                 public void WriteXml (Stream stream)
566                 {
567                         XmlWriter writer = new XmlTextWriter (stream, null);
568                         
569                         WriteXml (writer);
570                 }
571
572                 ///<summary>
573                 /// Writes the current data for the DataSet to the specified file.
574                 /// </summary>
575                 /// <param name="filename">Fully qualified filename to write to</param>
576                 public void WriteXml (string fileName)
577                 {
578                         XmlWriter writer = new XmlTextWriter (fileName, null);
579                         
580                         WriteXml (writer);
581                         
582                         writer.Close ();
583                 }
584
585                 public void WriteXml (TextWriter writer)
586                 {
587                         XmlWriter xwriter = new XmlTextWriter (writer);
588                         
589                         WriteXml (xwriter);
590                 }
591
592                 public void WriteXml (XmlWriter writer)
593                 {
594                         WriteXml (writer, XmlWriteMode.IgnoreSchema, true);
595                 }
596
597                 public void WriteXml (string filename, XmlWriteMode mode)
598                 {
599                         XmlWriter writer = new XmlTextWriter (filename, null);
600                         WriteXml (writer, mode, true);
601                 }
602
603                 public void WriteXml (Stream stream, XmlWriteMode mode)
604                 {
605                         XmlWriter writer = new XmlTextWriter (stream, null);
606
607                         WriteXml (writer, mode, true);
608                 }
609
610                 public void WriteXml (TextWriter writer, XmlWriteMode mode)
611                 {
612                         XmlWriter xwriter = new XmlTextWriter (writer);
613                         WriteXml (xwriter, mode, true);
614                 }
615
616                 public void WriteXml (XmlWriter writer, XmlWriteMode mode)
617                 {
618                         WriteXml (writer, mode, true);
619                 }
620                 
621                 internal void WriteXml (Stream stream, XmlWriteMode mode, bool writePI)
622                 {
623                         XmlWriter writer = new XmlTextWriter (stream, null);
624                         
625                         WriteXml (writer, mode, writePI);
626                 }
627
628                 internal void WriteXml (string fileName, XmlWriteMode mode, bool writePI)
629                 {
630                         XmlWriter writer = new XmlTextWriter (fileName, null);
631                         
632                         WriteXml (writer, mode, writePI);
633                         
634                         writer.Close ();
635                 }
636
637                 internal void WriteXml (TextWriter writer, XmlWriteMode mode, bool writePI)
638                 {
639                         XmlWriter xwriter = new XmlTextWriter (writer);
640                         
641                         WriteXml (xwriter, mode, writePI);
642                 }
643
644                 internal void WriteXml (XmlWriter writer, XmlWriteMode mode, bool writePI)
645                 {
646                         if (writePI && (writer.WriteState == WriteState.Start))
647                                 writer.WriteStartDocument (true);
648
649                         ((XmlTextWriter)writer).Formatting = Formatting.Indented;
650
651                         if (mode == XmlWriteMode.DiffGram) {
652                                 SetRowsID();
653                                 WriteDiffGramElement(writer);
654                         }
655
656                         WriteStartElement (writer, mode, Namespace, Prefix, XmlConvert.EncodeName (DataSetName));
657                         
658                         if (mode == XmlWriteMode.WriteSchema) {
659                                 DoWriteXmlSchema (writer);
660                         }
661                         
662                         WriteTables (writer, mode, Tables, DataRowVersion.Default);
663                         if (mode == XmlWriteMode.DiffGram) {
664                                 writer.WriteEndElement (); //DataSet name
665                                 if (HasChanges(DataRowState.Modified | DataRowState.Deleted)) {
666
667                                         DataSet beforeDS = GetChanges (DataRowState.Modified | DataRowState.Deleted);   
668                                         WriteStartElement (writer, XmlWriteMode.DiffGram, Namespace, Prefix, "diffgr:before");
669                                         WriteTables (writer, mode, beforeDS.Tables, DataRowVersion.Original);
670                                         writer.WriteEndElement ();
671                                 }
672                         }
673                         writer.WriteEndElement (); // DataSet name or diffgr:diffgram
674                 }
675
676                 public void WriteXmlSchema (Stream stream)
677                 {
678                         XmlWriter writer = new XmlTextWriter (stream, null );
679                         
680                         WriteXmlSchema (writer);        
681                 }
682
683                 public void WriteXmlSchema (string fileName)
684                 {
685                         XmlWriter writer = new XmlTextWriter (fileName, null);
686                 
687                         WriteXmlSchema (writer);
688                 }
689
690                 public void WriteXmlSchema (TextWriter writer)
691                 {
692                         XmlWriter xwriter = new XmlTextWriter (writer);
693                         
694                         WriteXmlSchema (xwriter);
695                 }
696
697                 public void WriteXmlSchema (XmlWriter writer)
698                 {
699                         ((XmlTextWriter)writer).Formatting = Formatting.Indented;
700                         //Create a skeleton doc and then write the schema 
701                         //proper which is common to the WriteXml method in schema mode
702                         writer.WriteStartDocument ();
703                         
704                         DoWriteXmlSchema (writer);
705                         
706                         writer.WriteEndDocument ();
707                 }
708
709                 public void ReadXmlSchema (Stream stream)
710                 {
711                         XmlReader reader = new XmlTextReader (stream, null);
712                         ReadXmlSchema (reader);
713                 }
714
715                 public void ReadXmlSchema (string str)
716                 {
717                         XmlReader reader = new XmlTextReader (str);
718                         ReadXmlSchema (reader);
719                 }
720
721                 public void ReadXmlSchema (TextReader treader)
722                 {
723                         XmlReader reader = new XmlTextReader (treader);
724                         ReadXmlSchema (reader);                 
725                 }
726
727                 public void ReadXmlSchema (XmlReader reader)
728                 {
729                         XmlSchemaMapper SchemaMapper = new XmlSchemaMapper (this);
730                         SchemaMapper.Read (reader);
731                 }
732
733                 public XmlReadMode ReadXml (Stream stream)
734                 {
735                         return ReadXml (new XmlTextReader (stream));
736                 }
737
738                 public XmlReadMode ReadXml (string str)
739                 {
740                         return ReadXml (new XmlTextReader (str));
741                 }
742
743                 public XmlReadMode ReadXml (TextReader reader)
744                 {
745                         return ReadXml (new XmlTextReader (reader));
746                 }
747
748                 public XmlReadMode ReadXml (XmlReader r)
749                 {
750                         XmlDataLoader Loader = new XmlDataLoader (this);
751                         // FIXME: somekinda exception?
752                         if (!r.Read ())
753                                 return XmlReadMode.Auto; // FIXME
754                         
755                         // Check if the curent element is the process instruction (PI).
756                         // if it is move to next element.
757                         if (r.LocalName == "xml")
758                                 r.MoveToContent();
759
760                         /*\
761                          *  If document is diffgram we will use diffgram
762                         \*/
763                         if (r.LocalName == "diffgram")
764                                 return ReadXml (r, XmlReadMode.DiffGram);
765                         
766                         // Get the DataSet name.
767                         string dataSetName = XmlConvert.DecodeName (r.LocalName);
768                         DataSetName = dataSetName;
769                         
770                         r.ReadStartElement ();
771                         r.MoveToContent();
772                         
773                         bool schemaRead = false;
774                         // Check if the current element is the schema
775                         if (r.LocalName == "schema") {
776                                 ReadXmlSchema (r);
777                                 r.MoveToContent();
778                                 schemaRead = true;
779                         }
780                         
781                         if (r.LocalName == "diffgram") {
782                                 return ReadXml (r, XmlReadMode.DiffGram);
783                         }
784                         
785                         // If the schema has been read we should read the rest of the document
786                         if (schemaRead) {
787                                 ReadXml (r, XmlReadMode.IgnoreSchema, false);
788                                 return XmlReadMode.ReadSchema;
789                         }
790                         
791                         // Read with inferschema.
792                         return ReadXml (r, XmlReadMode.InferSchema, false);
793
794                 }
795
796                 public XmlReadMode ReadXml (Stream stream, XmlReadMode mode)
797                 {
798                         return ReadXml (new XmlTextReader (stream), mode);
799                 }
800
801                 public XmlReadMode ReadXml (string str, XmlReadMode mode)
802                 {
803                         return ReadXml (new XmlTextReader (str), mode);
804                 }
805
806                 public XmlReadMode ReadXml (TextReader reader, XmlReadMode mode)
807                 {
808                         return ReadXml (new XmlTextReader (reader), mode);
809                 }
810
811                 [MonoTODO]
812                 public XmlReadMode ReadXml (XmlReader reader, XmlReadMode mode)
813                 {
814                         // we have to initiate the reader.
815                         if (reader.ReadState == ReadState.Initial)
816                                 reader.Read();
817                         
818                         // Check if the curent element is the process instruction (PI).
819                         // if it is move to next element.
820                         if (reader.LocalName == "xml")
821                                 reader.MoveToContent();
822
823                         XmlReadMode Result = XmlReadMode.Auto;
824
825                         if (mode == XmlReadMode.DiffGram) {
826                                 if (reader.LocalName != "diffgram"){
827                                         reader.MoveToContent ();
828                                         reader.ReadStartElement ();     // <DataSet>
829
830                                         reader.MoveToContent ();
831                                         if (reader.LocalName == "schema")
832                                                 ReadXmlSchema (reader);
833
834                                         reader.MoveToContent ();
835                                 }
836                                 XmlDiffLoader DiffLoader = new XmlDiffLoader (this);
837                                 DiffLoader.Load (reader);
838                                 Result =  XmlReadMode.DiffGram;
839                         }
840                         else 
841                                 Result = ReadXml(reader, mode, true);
842
843                         return Result;
844                 }
845
846                 private XmlReadMode ReadXml (XmlReader r, XmlReadMode mode, bool readDataSet) {
847                         
848                         if (readDataSet) {
849                                 string dataSetName = XmlConvert.DecodeName (r.LocalName);
850                                 DataSetName = dataSetName;
851                                 // get the Namespace of the DataSet.
852                                 string tmp = r.GetAttribute("xmlns");
853                                 if (tmp != null)
854                                         Namespace = tmp;
855                                 
856                                 r.ReadStartElement ();
857                                 r.MoveToContent();
858                         }
859
860                         XmlDataLoader Loader = new XmlDataLoader (this);
861                         return Loader.LoadData (r, mode);
862                 }
863
864                 #endregion // Public Methods
865
866                 #region Public Events
867
868                 [DataCategory ("Action")]
869                 [DataSysDescription ("Occurs when it is not possible to merge schemas for two tables with the same name.")]
870                 public event MergeFailedEventHandler MergeFailed;
871
872                 #endregion // Public Events
873
874                 #region Destructors
875
876                 ~DataSet ()
877                 {
878                 }
879
880                 #endregion Destructors
881
882                 #region IListSource methods
883                 IList IListSource.GetList ()
884                 {
885                         return DefaultViewManager;
886                 }
887                 
888                 bool IListSource.ContainsListCollection {
889                         get {
890                                 return true;
891                         }
892                 }
893                 #endregion IListSource methods
894                 
895                 #region ISupportInitialize methods
896                 public void BeginInit ()
897                 {
898                 }
899                 
900                 public void EndInit ()
901                 {
902                 }
903                 #endregion
904
905                 #region ISerializable
906                 void ISerializable.GetObjectData (SerializationInfo si, StreamingContext sc)
907                 {
908                         throw new NotImplementedException ();
909                 }
910                 #endregion
911                 
912                 #region Protected Methods
913                 protected void GetSerializationData (SerializationInfo info, StreamingContext context)
914                 {
915                         string s = info.GetValue ("XmlDiffGram", typeof (String)) as String;
916                         if (s != null) ReadXmlSerializable (new XmlTextReader (new StringReader (s)));
917                 }
918                 
919                 
920                 protected virtual System.Xml.Schema.XmlSchema GetSchemaSerializable ()
921                 {
922                         return BuildSchema ();
923                 }
924                 
925                 protected virtual void ReadXmlSerializable (XmlReader reader)
926                 {
927                         ReadXml (reader, XmlReadMode.DiffGram); // FIXME
928                 }
929
930                 void IXmlSerializable.ReadXml (XmlReader reader)
931                 {
932
933                         ReadXmlSerializable(reader);
934                         
935                         // the XmlSerializationReader does this lines!!!
936                         //reader.MoveToContent ();
937                         //reader.ReadEndElement ();     // </DataSet>
938                 }
939                 
940                 void IXmlSerializable.WriteXml (XmlWriter writer)
941                 {
942                         DoWriteXmlSchema (writer);
943                         WriteXml (writer, XmlWriteMode.DiffGram, true);
944                 }
945
946                 protected virtual bool ShouldSerializeRelations ()
947                 {
948                         return true;
949                 }
950                 
951                 protected virtual bool ShouldSerializeTables ()
952                 {
953                         return true;
954                 }
955
956                 [MonoTODO]
957                 protected internal virtual void OnPropertyChanging (PropertyChangedEventArgs pcevent)
958                 {
959                 }
960
961                 [MonoTODO]
962                 protected virtual void OnRemoveRelation (DataRelation relation)
963                 {
964                 }
965
966                 [MonoTODO]
967                 protected virtual void OnRemoveTable (DataTable table)
968                 {
969                 }
970
971                 protected internal virtual void OnMergeFailed (MergeFailedEventArgs e)
972                 {
973                         if (MergeFailed != null)
974                                 MergeFailed (this, e);
975                 }
976
977                 [MonoTODO]
978                 protected internal void RaisePropertyChanging (string name)
979                 {
980                 }
981                 #endregion
982
983                 #region Private Xml Serialisation
984
985                 private string WriteObjectXml (object o)
986                 {
987                         switch (Type.GetTypeCode (o.GetType ())) {
988                                 case TypeCode.Boolean:
989                                         return XmlConvert.ToString ((Boolean) o);
990                                 case TypeCode.Byte:
991                                         return XmlConvert.ToString ((Byte) o);
992                                 case TypeCode.Char:
993                                         return XmlConvert.ToString ((Char) o);
994                                 case TypeCode.DateTime:
995                                         return XmlConvert.ToString ((DateTime) o);
996                                 case TypeCode.Decimal:
997                                         return XmlConvert.ToString ((Decimal) o);
998                                 case TypeCode.Double:
999                                         return XmlConvert.ToString ((Double) o);
1000                                 case TypeCode.Int16:
1001                                         return XmlConvert.ToString ((Int16) o);
1002                                 case TypeCode.Int32:
1003                                         return XmlConvert.ToString ((Int32) o);
1004                                 case TypeCode.Int64:
1005                                         return XmlConvert.ToString ((Int64) o);
1006                                 case TypeCode.SByte:
1007                                         return XmlConvert.ToString ((SByte) o);
1008                                 case TypeCode.Single:
1009                                         return XmlConvert.ToString ((Single) o);
1010                                 case TypeCode.UInt16:
1011                                         return XmlConvert.ToString ((UInt16) o);
1012                                 case TypeCode.UInt32:
1013                                         return XmlConvert.ToString ((UInt32) o);
1014                                 case TypeCode.UInt64:
1015                                         return XmlConvert.ToString ((UInt64) o);
1016                         }
1017                         if (o is TimeSpan) return XmlConvert.ToString ((TimeSpan) o);
1018                         if (o is Guid) return XmlConvert.ToString ((Guid) o);
1019                         return o.ToString ();
1020                 }
1021                 
1022                 private void WriteTables (XmlWriter writer, XmlWriteMode mode, DataTableCollection tableCollection, DataRowVersion version)
1023                 {
1024                         //Write out each table in order, providing it is not
1025                         //part of another table structure via a nested parent relationship
1026                         foreach (DataTable table in tableCollection) {
1027                                 bool isTopLevel = true;
1028                                 foreach (DataRelation rel in table.ParentRelations) {
1029                                         if (rel.Nested) {
1030                                                 isTopLevel = false;
1031                                                 break;
1032                                         }
1033                                 }
1034                                 
1035                                 if (isTopLevel) {
1036                                         WriteTable ( writer, table, mode, version);
1037                                 }
1038                         }
1039                 }
1040
1041                 private void WriteTable (XmlWriter writer, DataTable table, XmlWriteMode mode, DataRowVersion version)
1042                 {
1043                         DataRow[] rows = new DataRow [table.Rows.Count];
1044                         table.Rows.CopyTo (rows, 0);
1045                         WriteTable (writer, rows, mode, version);
1046                 }
1047
1048                 private void WriteTable (XmlWriter writer, DataRow[] rows, XmlWriteMode mode, DataRowVersion version)
1049                 {
1050                         //The columns can be attributes, hidden, elements, or simple content
1051                         //There can be 0-1 simple content cols or 0-* elements
1052                         System.Collections.ArrayList atts;
1053                         System.Collections.ArrayList elements;
1054                         DataColumn simple = null;
1055
1056                         if (rows.Length == 0) return;
1057                         DataTable table = rows[0].Table;
1058                         SplitColumns (table, out atts, out elements, out simple);
1059                         //sort out the namespacing
1060                         string nspc = table.Namespace.Length > 0 ? table.Namespace : Namespace;
1061
1062                         foreach (DataRow row in rows) {
1063                                 if (!row.HasVersion(version))
1064                                         continue;
1065                                 
1066                                 // First check are all the rows null. If they are we just write empty element
1067                                 bool AllNulls = true;
1068                                 foreach (DataColumn dc in table.Columns) {
1069                                 
1070                                         if (row [dc.ColumnName, version] != DBNull.Value) {
1071                                                 AllNulls = false;
1072                                                 break;
1073                                         } 
1074                                 }
1075
1076                                 // If all of the columns were null, we have to write empty element
1077                                 if (AllNulls) {
1078                                         writer.WriteElementString (table.TableName, "");
1079                                         continue;
1080                                 }
1081                                 
1082                                 WriteTableElement (writer, mode, table, row, version);
1083                                 
1084                                 foreach (DataColumn col in atts) {                                      
1085                                         WriteColumnAsAttribute (writer, mode, col, row, version);
1086                                 }
1087                                 
1088                                 if (simple != null) {
1089                                         writer.WriteString (WriteObjectXml (row[simple, version]));
1090                                 }
1091                                 else {                                  
1092                                         foreach (DataColumn col in elements) {
1093                                                 WriteColumnAsElement (writer, mode, nspc, col, row, version);
1094                                         }
1095                                 }
1096                                 
1097                                 foreach (DataRelation relation in table.ChildRelations) {
1098                                         if (relation.Nested) {
1099                                                 WriteTable (writer, row.GetChildRows (relation), mode, version);
1100                                         }
1101                                 }
1102                                 
1103                                 writer.WriteEndElement ();
1104                         }
1105
1106                 }
1107
1108                 private void WriteColumnAsElement (XmlWriter writer, XmlWriteMode mode, string nspc, DataColumn col, DataRow row, DataRowVersion version)
1109                 {
1110                         string colnspc = nspc;
1111                         object rowObject = row [col, version];
1112                                                                         
1113                         if (rowObject == null || rowObject == DBNull.Value)
1114                                 return;
1115
1116                         if (col.Namespace != null) {
1117                                 colnspc = col.Namespace;
1118                         }
1119         
1120                         //TODO check if I can get away with write element string
1121                         WriteStartElement (writer, mode, colnspc, col.Prefix, col.ColumnName);
1122                         writer.WriteString (WriteObjectXml (rowObject));
1123                         writer.WriteEndElement ();
1124                 }
1125
1126                 private void WriteColumnAsAttribute (XmlWriter writer, XmlWriteMode mode, DataColumn col, DataRow row, DataRowVersion version)
1127                 {
1128                         WriteAttributeString (writer, mode, col.Namespace, col.Prefix, col.ColumnName, row[col, version].ToString ());
1129                 }
1130
1131                 private void WriteTableElement (XmlWriter writer, XmlWriteMode mode, DataTable table, DataRow row, DataRowVersion version)
1132                 {
1133                         //sort out the namespacing
1134                         string nspc = table.Namespace.Length > 0 ? table.Namespace : Namespace;
1135
1136                         WriteStartElement (writer, mode, nspc, table.Prefix, table.TableName);
1137
1138                         if (mode == XmlWriteMode.DiffGram) {
1139                                 WriteAttributeString (writer, mode, "", "diffgr", "id", table.TableName + (row.XmlRowID + 1));
1140                                 WriteAttributeString (writer, mode, "", "msdata", "rowOrder", row.XmlRowID.ToString());
1141                                 if (row.RowState == DataRowState.Modified && version != DataRowVersion.Original){
1142                                         WriteAttributeString (writer, mode, "", "diffgr", "hasChanges", "modified");
1143                                 }
1144                         }
1145                 }
1146                     
1147                 private void WriteStartElement (XmlWriter writer, XmlWriteMode mode, string nspc, string prefix, string name)
1148                 {                       
1149                         switch ( mode) {
1150                                 case XmlWriteMode.WriteSchema:
1151                                         if (nspc == null || nspc == "") {
1152                                                 writer.WriteStartElement (name);
1153                                         }
1154                                         else if (prefix != null) {                                                      
1155                                                 writer.WriteStartElement (prefix, name, nspc);
1156                                         }                                               
1157                                         else {                                  
1158                                                 writer.WriteStartElement (writer.LookupPrefix (nspc), name, nspc);
1159                                         }
1160                                         break;
1161                                 case XmlWriteMode.DiffGram:
1162                                         writer.WriteStartElement (name);
1163                                         break;  
1164                                 default:                                               
1165                                         writer.WriteStartElement (name);
1166                                         break;                                  
1167                         };
1168                 }
1169                 
1170                 private void WriteAttributeString (XmlWriter writer, XmlWriteMode mode, string nspc, string prefix, string name, string stringValue)
1171                 {
1172                         switch ( mode) {
1173                                 case XmlWriteMode.WriteSchema:
1174                                         writer.WriteAttributeString (prefix, name, nspc);
1175                                         break;
1176                                 case XmlWriteMode.DiffGram:
1177                                         writer.WriteAttributeString (prefix, name, nspc, stringValue);
1178                                         break;
1179                                 default:
1180                                         writer.WriteAttributeString (name, stringValue);
1181                                         break;                                  
1182                         };
1183                 }
1184
1185                 XmlSchema IXmlSerializable.GetSchema ()
1186                 {
1187                         return BuildSchema ();
1188                 }
1189                 
1190                 XmlSchema BuildSchema ()
1191                 {
1192                         XmlSchema schema = new XmlSchema ();
1193                         schema.AttributeFormDefault = XmlSchemaForm.Qualified;
1194
1195                         XmlSchemaElement elem = new XmlSchemaElement ();
1196                         elem.Name = XmlConvert.EncodeName (DataSetName);
1197
1198                         XmlDocument doc = new XmlDocument ();
1199
1200                         XmlAttribute[] atts = new XmlAttribute [2];
1201                         atts[0] = doc.CreateAttribute (XmlConstants.MsdataPrefix,  XmlConstants.IsDataSet, XmlConstants.MsdataNamespace);
1202                         atts[0].Value = "true";
1203
1204                         atts[1] = doc.CreateAttribute (XmlConstants.MsdataPrefix, XmlConstants.Locale, XmlConstants.MsdataNamespace);
1205                         atts[1].Value = locale.Name;
1206                         elem.UnhandledAttributes = atts;
1207
1208                         schema.Items.Add (elem);
1209
1210                         XmlSchemaComplexType complex = new XmlSchemaComplexType ();
1211                         elem.SchemaType = complex;
1212
1213                         XmlSchemaChoice choice = new XmlSchemaChoice ();
1214                         complex.Particle = choice;
1215                         choice.MaxOccursString = XmlConstants.Unbounded;
1216                         
1217                         //Write out schema for each table in order
1218                         foreach (DataTable table in Tables) {           
1219                                 bool isTopLevel = true;
1220                                 foreach (DataRelation rel in table.ParentRelations) {
1221                                         if (rel.Nested) {
1222                                                 isTopLevel = false;
1223                                                 break;
1224                                         }
1225                                 }
1226                                 
1227                                 if (isTopLevel){
1228                                         choice.Items.Add (GetTableSchema (doc, table));
1229                                 }
1230                         }
1231                         
1232                         bool nameModifier = true;
1233                         foreach (DataRelation rel in Relations) {
1234                                 XmlSchemaUnique uniq = new XmlSchemaUnique();
1235                                 XmlSchemaKeyref keyRef = new XmlSchemaKeyref();
1236                                 ForeignKeyConstraint fkConst = rel.ChildKeyConstraint;
1237                                 UniqueConstraint uqConst = rel.ParentKeyConstraint;
1238                                                                 
1239                                 if (nameModifier) {
1240                                         uniq.Name = uqConst.ConstraintName;
1241                                         keyRef.Name = fkConst.ConstraintName;
1242                                         keyRef.Refer = new XmlQualifiedName(uniq.Name);
1243                                         XmlAttribute[] attrib = null;
1244                                         if (rel.Nested){
1245                                                 attrib = new XmlAttribute [2];
1246                                                 attrib [0] = doc.CreateAttribute (XmlConstants.MsdataPrefix,  XmlConstants.IsNested, XmlConstants.MsdataNamespace);
1247                                                 attrib [0].Value = "true";
1248                 
1249                                                 attrib [1] = doc.CreateAttribute (XmlConstants.MsdataPrefix, XmlConstants.RelationName, XmlConstants.MsdataNamespace);
1250                                                 attrib [1].Value = rel.RelationName;
1251                                         }
1252                                         else {
1253                                                 attrib = new XmlAttribute [1];
1254                                                 attrib[0] = doc.CreateAttribute (XmlConstants.MsdataPrefix, XmlConstants.RelationName, XmlConstants.MsdataNamespace);
1255                                                 attrib[0].Value = rel.RelationName;
1256
1257                                         }
1258                                         keyRef.UnhandledAttributes = attrib;
1259                                         nameModifier = false;
1260                                 }
1261                                 else {
1262                                         uniq.Name = rel.ParentTable.TableName+"_"+uqConst.ConstraintName;
1263                                         keyRef.Name = rel.ChildTable.TableName+"_"+fkConst.ConstraintName;
1264                                         keyRef.Refer = new XmlQualifiedName(uniq.Name);
1265                                         XmlAttribute[] attrib;
1266                                         if (rel.Nested) {
1267                                                 attrib = new XmlAttribute [3];
1268                                                 attrib [0] = doc.CreateAttribute (XmlConstants.MsdataPrefix,  XmlConstants.ConstraintName, XmlConstants.MsdataNamespace);
1269                                                 attrib [0].Value = fkConst.ConstraintName;
1270                                                 attrib [1] = doc.CreateAttribute (XmlConstants.MsdataPrefix,  XmlConstants.IsNested, XmlConstants.MsdataNamespace);
1271                                                 attrib [1].Value = "true";
1272                 
1273                                                 attrib [2] = doc.CreateAttribute (XmlConstants.MsdataPrefix, XmlConstants.RelationName, XmlConstants.MsdataNamespace);
1274                                                 attrib [2].Value = rel.RelationName;
1275                                         }
1276                                         else {
1277                                                 attrib = new XmlAttribute [2];
1278                                                 attrib [0] = doc.CreateAttribute (XmlConstants.MsdataPrefix,  XmlConstants.ConstraintName, XmlConstants.MsdataNamespace);
1279                                                 attrib [0].Value = fkConst.ConstraintName;
1280                                                 attrib [1] = doc.CreateAttribute (XmlConstants.MsdataPrefix, XmlConstants.RelationName, XmlConstants.MsdataNamespace);
1281                                                 attrib [1].Value = rel.RelationName;
1282
1283                                         }
1284                                         keyRef.UnhandledAttributes = attrib;
1285                                         attrib = new XmlAttribute [1];
1286                                         attrib [0] = doc.CreateAttribute (XmlConstants.MsdataPrefix, XmlConstants.ConstraintName, XmlConstants.MsdataNamespace);
1287                                         attrib [0].Value = uqConst.ConstraintName; 
1288                                         uniq.UnhandledAttributes = attrib;
1289                                 }
1290
1291                                 uniq.Selector = new XmlSchemaXPath();
1292                                 uniq.Selector.XPath = ".//"+rel.ParentTable.TableName;
1293                                 XmlSchemaXPath field;
1294                                 foreach (DataColumn column in rel.ParentColumns) {
1295                                         field = new XmlSchemaXPath();
1296                                         field.XPath = column.ColumnName;
1297                                         uniq.Fields.Add(field);
1298                                 }
1299                                 
1300                                 keyRef.Selector = new XmlSchemaXPath();
1301                                 keyRef.Selector.XPath = ".//"+rel.ChildTable.TableName;
1302                                 foreach (DataColumn column in rel.ChildColumns) {
1303                                         field = new XmlSchemaXPath();
1304                                         field.XPath = column.ColumnName;
1305                                         keyRef.Fields.Add(field);
1306                                 }
1307                                 
1308                                 elem.Constraints.Add (uniq);
1309                                 elem.Constraints.Add (keyRef);
1310                         }
1311                         
1312                         return schema;
1313                 }
1314
1315                 private XmlSchemaElement GetTableSchema (XmlDocument doc, DataTable table)
1316                 {
1317                         ArrayList elements;
1318                         ArrayList atts;
1319                         DataColumn simple;
1320                         
1321                         SplitColumns (table, out atts, out elements, out simple);
1322
1323                         XmlSchemaElement elem = new XmlSchemaElement ();
1324                         elem.Name = table.TableName;
1325
1326                         XmlSchemaComplexType complex = new XmlSchemaComplexType ();
1327                         elem.SchemaType = complex;
1328
1329                         //TODO - what about the simple content?
1330                         if (elements.Count == 0) {                              
1331                         }
1332                         else {
1333                                 //A sequence of element types or a simple content node
1334                                 //<xs:sequence>
1335                                 XmlSchemaSequence seq = new XmlSchemaSequence ();
1336                                 complex.Particle = seq;
1337
1338                                 foreach (DataColumn col in elements) {
1339                                         //<xs:element name=ColumnName type=MappedType Ordinal=index>
1340                                         XmlSchemaElement colElem = new XmlSchemaElement ();
1341                                         colElem.Name = col.ColumnName;
1342                                 
1343                                         if (col.ColumnName != col.Caption && col.Caption != string.Empty) {
1344                                                 XmlAttribute[] xatts = new XmlAttribute[1];
1345                                                 xatts[0] = doc.CreateAttribute (XmlConstants.MsdataPrefix, XmlConstants.Caption, XmlConstants.MsdataNamespace);
1346                                                 xatts[0].Value = col.Caption;
1347                                                 colElem.UnhandledAttributes = xatts;
1348                                         }
1349
1350                                         if (col.DefaultValue.ToString () != string.Empty)
1351                                                 colElem.DefaultValue = col.DefaultValue.ToString ();
1352
1353                                         colElem.SchemaTypeName = MapType (col.DataType);
1354
1355                                         if (col.AllowDBNull) {
1356                                                 colElem.MinOccurs = 0;
1357                                         }
1358
1359                                         //writer.WriteAttributeString (XmlConstants.MsdataPrefix, 
1360                                         //                            XmlConstants.Ordinal, 
1361                                         //                            XmlConstants.MsdataNamespace, 
1362                                         //                            col.Ordinal.ToString ());
1363
1364                                         // Write SimpleType if column have MaxLength
1365                                         if (col.MaxLength > -1) {
1366                                                 colElem.SchemaType = GetTableSimpleType (doc, col);
1367                                         }
1368
1369                                         seq.Items.Add (colElem);
1370                                 }
1371
1372                                 foreach (DataRelation rel in table.ChildRelations) {
1373                                         if (rel.Nested) {
1374                                                 seq.Items.Add(GetTableSchema (doc, rel.ChildTable));
1375                                         }
1376                                 }
1377                         }
1378
1379                         //Then a list of attributes
1380                         foreach (DataColumn col in atts) {
1381                                 //<xs:attribute name=col.ColumnName form="unqualified" type=MappedType/>
1382                                 XmlSchemaAttribute att = new XmlSchemaAttribute ();
1383                                 att.Name = col.ColumnName;
1384                                 att.Form = XmlSchemaForm.Unqualified;
1385                                 att.SchemaTypeName = MapType (col.DataType);
1386                                 complex.Attributes.Add (att);
1387                         }
1388
1389                         return elem;
1390                 }
1391
1392                 private XmlSchemaSimpleType GetTableSimpleType (XmlDocument doc, DataColumn col)
1393                 {
1394                         // SimpleType
1395                         XmlSchemaSimpleType simple = new XmlSchemaSimpleType ();
1396
1397                         // Restriction
1398                         XmlSchemaSimpleTypeRestriction restriction = new XmlSchemaSimpleTypeRestriction ();
1399                         restriction.BaseTypeName = MapType (col.DataType);
1400                         
1401                         // MaxValue
1402                         XmlSchemaMaxLengthFacet max = new XmlSchemaMaxLengthFacet ();
1403                         max.Value = XmlConvert.ToString (col.MaxLength);
1404                         restriction.Facets.Add (max);
1405
1406                         return simple;
1407                 }
1408
1409                 private void DoWriteXmlSchema (XmlWriter writer)
1410                 {
1411                         GetSchemaSerializable ().Write (writer);
1412                 }
1413                 
1414                 ///<summary>
1415                 /// Helper function to split columns into attributes elements and simple
1416                 /// content
1417                 /// </summary>
1418                 private void SplitColumns (DataTable table, 
1419                         out ArrayList atts, 
1420                         out ArrayList elements, 
1421                         out DataColumn simple)
1422                 {
1423                         //The columns can be attributes, hidden, elements, or simple content
1424                         //There can be 0-1 simple content cols or 0-* elements
1425                         atts = new System.Collections.ArrayList ();
1426                         elements = new System.Collections.ArrayList ();
1427                         simple = null;
1428                         
1429                         //Sort out the columns
1430                         foreach (DataColumn col in table.Columns) {
1431                                 switch (col.ColumnMapping) {
1432                                         case MappingType.Attribute:
1433                                                 atts.Add (col);
1434                                                 break;
1435                                         case MappingType.Element:
1436                                                 elements.Add (col);
1437                                                 break;
1438                                         case MappingType.SimpleContent:
1439                                                 if (simple != null) {
1440                                                         throw new System.InvalidOperationException ("There may only be one simple content element");
1441                                                 }
1442                                                 simple = col;
1443                                                 break;
1444                                         default:
1445                                                 //ignore Hidden elements
1446                                                 break;
1447                                 }
1448                         }
1449                 }
1450
1451                 private void WriteDiffGramElement(XmlWriter writer)
1452                 {
1453                         WriteStartElement (writer, XmlWriteMode.DiffGram, Namespace, Prefix, "diffgr:diffgram");
1454                         WriteAttributeString(writer, XmlWriteMode.DiffGram, null, "xmlns", XmlConstants.MsdataPrefix, XmlConstants.MsdataNamespace);
1455                         WriteAttributeString(writer, XmlWriteMode.DiffGram, null, "xmlns", XmlConstants.DiffgrPrefix, XmlConstants.DiffgrNamespace);
1456                 }
1457
1458                 private void SetRowsID()
1459                 {
1460                         foreach (DataTable Table in Tables) {
1461                                 int dataRowID = 0;
1462                                 foreach (DataRow Row in Table.Rows) {
1463                                         Row.XmlRowID = dataRowID;
1464                                         dataRowID++;
1465                                 }
1466                         }
1467                 }
1468
1469                 
1470                 private XmlQualifiedName MapType (Type type)
1471                 {
1472                         switch (Type.GetTypeCode (type)) {
1473                                 case TypeCode.String: return XmlConstants.QnString;
1474                                 case TypeCode.Int16: return XmlConstants.QnShort;
1475                                 case TypeCode.Int32: return XmlConstants.QnInt;
1476                                 case TypeCode.Int64: return XmlConstants.QnLong;
1477                                 case TypeCode.Boolean: return XmlConstants.QnBoolean;
1478                                 case TypeCode.Byte: return XmlConstants.QnUnsignedByte;
1479                                 case TypeCode.Char: return XmlConstants.QnChar;
1480                                 case TypeCode.DateTime: return XmlConstants.QnDateTime;
1481                                 case TypeCode.Decimal: return XmlConstants.QnDecimal;
1482                                 case TypeCode.Double: return XmlConstants.QnDouble;
1483                                 case TypeCode.SByte: return XmlConstants.QnSbyte;
1484                                 case TypeCode.Single: return XmlConstants.QnFloat;
1485                                 case TypeCode.UInt16: return XmlConstants.QnUsignedShort;
1486                                 case TypeCode.UInt32: return XmlConstants.QnUnsignedInt;
1487                                 case TypeCode.UInt64: return XmlConstants.QnUnsignedLong;
1488                         }
1489                         
1490                         if (typeof (TimeSpan) == type)
1491                                 return XmlConstants.QnDuration;
1492                         else if (typeof (System.Uri) == type)
1493                                 return XmlConstants.QnUri;
1494                         else if (typeof (byte[]) == type)
1495                                 return XmlConstants.QnBase64Binary;
1496                         else if (typeof (XmlQualifiedName) == type)
1497                                 return XmlConstants.QnXmlQualifiedName;
1498                         else
1499                                 return XmlConstants.QnString;
1500                 }
1501
1502                 #endregion //Private Xml Serialisation
1503         }
1504 }