* DataSet.cs: Implemented support for runtime serialization. Fixed support
[mono.git] / mcs / class / System.Data / System.Data / XmlDiffLoader.cs
1 //
2 // mcs/class/System.Data/System.Data/XmlDiffLoader.cs
3 //
4 // Purpose: Loads XmlDiffGrams to DataSet 
5 //
6 // class: XmlDiffLoader
7 // assembly: System.Data.dll
8 // namespace: System.Data
9 //
10 // Author:
11 //     Ville Palo <vi64pa@koti.soon.fi>
12 //     Lluis Sanchez Gual (lluis@ximian.com)
13 //
14 // (c)copyright 2003 Ville Palo
15 //
16 using System;
17 using System.Data;
18 using System.Xml;
19 using System.Xml.XPath;
20 using System.Collections;
21 using System.Globalization;
22
23 namespace System.Data {
24
25         internal class XmlDiffLoader 
26         {
27
28                 #region Fields
29                 private DataSet DSet;
30                 private DataTable table;
31                 private Hashtable DiffGrRows = new Hashtable ();
32                 private Hashtable ErrorRows = new Hashtable ();
33
34                 #endregion // Fields
35
36                 #region ctors
37
38                 public XmlDiffLoader (DataSet DSet) 
39                 {
40                         this.DSet = DSet;
41                 }
42
43                 public XmlDiffLoader (DataTable table) 
44                 {
45                         this.table = table;
46                 }
47
48                 #endregion //ctors
49
50                 #region Public methods
51
52                 public void Load (XmlReader reader) 
53                 {
54                         bool origEnforceConstraint = false;
55                         if (DSet != null) {
56                                 origEnforceConstraint = DSet.EnforceConstraints;
57                                 DSet.EnforceConstraints = false;
58                         }
59                         
60                         reader.MoveToContent ();
61                         if (reader.IsEmptyElement) {
62                                 reader.Skip ();
63                                 return;
64                         }
65                         
66                         reader.ReadStartElement ("diffgram", XmlConstants.DiffgrNamespace);
67                         reader.MoveToContent ();
68                         
69                         while (reader.NodeType != XmlNodeType.EndElement)
70                         {
71                                 if (reader.NodeType == XmlNodeType.Element)
72                                 {
73                                         if (reader.LocalName == "before" && reader.NamespaceURI == XmlConstants.DiffgrNamespace)
74                                                 LoadBefore (reader);
75                                         else if (reader.LocalName == "errors" && reader.NamespaceURI == XmlConstants.DiffgrNamespace)
76                                                 LoadErrors (reader);
77                                         else
78                                                 LoadCurrent (reader);
79                                 }
80                                 else
81                                         reader.Skip ();
82                         }
83                         
84                         reader.ReadEndElement ();
85                         
86                         if (DSet != null)
87                                 DSet.EnforceConstraints = origEnforceConstraint;
88                 }
89
90                 #endregion // Public methods
91
92                 #region Private methods
93
94                 private void LoadCurrent (XmlReader reader) 
95                 {
96                         if (reader.IsEmptyElement) return;
97                         
98                         reader.ReadStartElement ();             // Dataset root
99                         reader.MoveToContent ();
100
101                         while (reader.NodeType != XmlNodeType.EndElement)
102                         {
103                                 if (reader.NodeType == XmlNodeType.Element)
104                                 {
105                                         DataTable t = GetTable (reader.LocalName);
106                                         if (t != null)
107                                                 LoadCurrentTable (t, reader);
108 #if true
109                                         else
110                                                 reader.Skip ();
111 #else
112                                         else 
113                                                 throw new DataException (Locale.GetText ("Cannot load diffGram. Table '" + reader.LocalName + "' is missing in the destination dataset"));      
114 #endif
115                                 }
116                                 else
117                                         reader.Skip ();
118                         }
119                         
120                         reader.ReadEndElement ();
121                 }
122
123                 private void LoadBefore (XmlReader reader) 
124                 {
125                         if (reader.IsEmptyElement) return;
126                         
127                         reader.ReadStartElement ();
128                         reader.MoveToContent ();
129
130                         while (reader.NodeType != XmlNodeType.EndElement)
131                         {
132                                 if (reader.NodeType == XmlNodeType.Element)
133                                 {
134                                         DataTable t = GetTable (reader.LocalName);
135                                         if (t != null)
136                                                 LoadBeforeTable(t, reader);
137                                         else
138                                                 throw new DataException (Locale.GetText ("Cannot load diffGram. Table '" + reader.LocalName + "' is missing in the destination dataset"));
139                                 }
140                                 else
141                                         reader.Skip ();
142                         }
143                         
144                         reader.ReadEndElement ();
145                 }                                
146                                 
147                                            
148                 private void LoadErrors (XmlReader reader) 
149                 {
150                         if (reader.IsEmptyElement) return;
151                         
152                         reader.ReadStartElement ();
153                         reader.MoveToContent ();
154
155                         while (reader.NodeType != XmlNodeType.EndElement)
156                         {
157                                 if (reader.NodeType == XmlNodeType.Element)
158                                 {
159                                         DataRow Row = null;
160                 
161                                         // find the row in 'current' section
162                                         
163                                         string id = reader.GetAttribute ("id", XmlConstants.DiffgrNamespace);
164                                         
165                                         if (id != null)
166                                                 Row = (DataRow) ErrorRows [id];
167                 
168                                         if (reader.IsEmptyElement) continue;
169                                         reader.ReadStartElement ();
170                                         while (reader.NodeType != XmlNodeType.EndElement)
171                                         {
172                                                 if (reader.NodeType == XmlNodeType.Element) {
173                                                         string error = reader.GetAttribute ("Error", XmlConstants.DiffgrNamespace);
174                                                         Row.SetColumnError (reader.LocalName, error);
175                                                 }
176                                                 reader.Read ();
177                                         }
178                                 }
179                                 else
180                                         reader.Skip ();
181                         }
182                         reader.ReadEndElement ();
183                 }
184
185                 private void LoadColumns (DataTable Table, DataRow Row, XmlReader reader, DataRowVersion loadType) 
186                 {
187                         if (reader.IsEmptyElement) return;
188                         
189                         reader.ReadStartElement ();
190                         reader.MoveToContent ();
191                         
192                         while (reader.NodeType != XmlNodeType.EndElement)
193                         {
194                                 if (reader.NodeType != XmlNodeType.Element) { reader.Read (); continue; }
195                                 
196                                 if (Table.Columns.Contains (reader.LocalName)) 
197                                 {
198                                         string colName = reader.LocalName;
199                                         object data = XmlDataLoader.StringToObject (Table.Columns[colName].DataType, reader.ReadString ());
200                                         
201                                         if (loadType == DataRowVersion.Current) Row [colName] = data;
202                                         else Row.SetOriginalValue (colName, data);
203                                         reader.Read ();
204                                 }
205                                 else 
206                                 {
207                                         DataTable t = GetTable (reader.LocalName);
208                                         if (t != null) {
209                                                 if (loadType == DataRowVersion.Original)
210                                                         LoadBeforeTable (t, reader);
211                                                 else if (loadType == DataRowVersion.Current)
212                                                         LoadCurrentTable (t, reader);
213                                         }
214                                 }
215                         }
216                         
217                         reader.ReadEndElement ();
218                 }
219
220                 private void LoadBeforeTable (DataTable Table, XmlReader reader) 
221                 {
222                         string id = reader.GetAttribute ("id", XmlConstants.DiffgrNamespace);
223                         string rowOrder = reader.GetAttribute ("rowOrder", XmlConstants.MsdataNamespace);
224                         DataRow Row = (DataRow) DiffGrRows [id];
225                         
226                         if (Row == null)
227                         {
228                                 // Deleted row
229                                 Row = Table.NewRow ();
230                                 LoadColumns (Table, Row, reader, DataRowVersion.Current);
231                                 Table.Rows.InsertAt (Row, int.Parse (rowOrder));
232                                 Row.AcceptChanges ();
233                                 Row.Delete ();
234                         }
235                         else
236                         {
237                                 LoadColumns (Table, Row, reader, DataRowVersion.Original);
238                         }
239                 }
240
241                 private void LoadCurrentTable (DataTable Table, XmlReader reader) 
242                 {
243                         DataRowState state;
244                         DataRow Row = Table.NewRow ();
245
246                         string id = reader.GetAttribute  ("id", XmlConstants.DiffgrNamespace);
247                         string error = reader.GetAttribute ("hasErrors");
248                         string changes = reader.GetAttribute ("hasChanges", XmlConstants.DiffgrNamespace);
249                         
250                         if (changes != null)
251                         {
252                                 if (string.Compare (changes, "modified", true) == 0) {
253                                         DiffGrRows.Add (id, Row); // for later use
254                                         state = DataRowState.Modified;
255                                 }
256                                 else if (string.Compare (changes, "inserted", true) == 0) {
257                                         state = DataRowState.Added;
258                                 }
259                                 else
260                                         throw new InvalidOperationException ("Invalid row change state");
261                         }
262                         else
263                                 state = DataRowState.Unchanged;
264                         
265                         // If row had errors add row to hashtable for later use
266                         if (error != null && string.Compare (error, "true", true) == 0)
267                                 ErrorRows.Add (id, Row);
268                 
269                         LoadColumns (Table, Row, reader, DataRowVersion.Current);
270                         Table.Rows.Add (Row);
271                         
272                         if (state != DataRowState.Added)
273                                 Row.AcceptChanges ();
274                 }
275
276                 DataTable GetTable (string name)
277                 {
278                         if (DSet != null) 
279                                 return DSet.Tables [name];
280                         else if (name == table.TableName) 
281                                 return table;
282                         else
283                                 return null;
284                 }
285
286
287                 #endregion // Private methods
288         }
289 }