2004-04-14 Atsushi Enomoto <atsushi@ximian.com>
[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) return;
62                         
63                         reader.ReadStartElement ("diffgram", XmlConstants.DiffgrNamespace);
64                         reader.MoveToContent ();
65                         
66                         while (reader.NodeType != XmlNodeType.EndElement)
67                         {
68                                 if (reader.NodeType == XmlNodeType.Element)
69                                 {
70                                         if (reader.LocalName == "before" && reader.NamespaceURI == XmlConstants.DiffgrNamespace)
71                                                 LoadBefore (reader);
72                                         else if (reader.LocalName == "errors" && reader.NamespaceURI == XmlConstants.DiffgrNamespace)
73                                                 LoadErrors (reader);
74                                         else
75                                                 LoadCurrent (reader);
76                                 }
77                                 else
78                                         reader.Skip ();
79                         }
80                         
81                         reader.ReadEndElement ();
82                         
83                         if (DSet != null)
84                                 DSet.EnforceConstraints = origEnforceConstraint;
85                 }
86
87                 #endregion // Public methods
88
89                 #region Private methods
90
91                 private void LoadCurrent (XmlReader reader) 
92                 {
93                         if (reader.IsEmptyElement) return;
94                         
95                         reader.ReadStartElement ();             // Dataset root
96                         reader.MoveToContent ();
97
98                         while (reader.NodeType != XmlNodeType.EndElement)
99                         {
100                                 if (reader.NodeType == XmlNodeType.Element)
101                                 {
102                                         DataTable t = GetTable (reader.LocalName);
103                                         if (t != null)
104                                                 LoadCurrentTable (t, reader);
105 #if true
106                                         else
107                                                 reader.Skip ();
108 #else
109                                         else 
110                                                 throw new DataException (Locale.GetText ("Cannot load diffGram. Table '" + reader.LocalName + "' is missing in the destination dataset"));      
111 #endif
112                                 }
113                                 else
114                                         reader.Skip ();
115                         }
116                         
117                         reader.ReadEndElement ();
118                 }
119
120                 private void LoadBefore (XmlReader reader) 
121                 {
122                         if (reader.IsEmptyElement) return;
123                         
124                         reader.ReadStartElement ();
125                         reader.MoveToContent ();
126
127                         while (reader.NodeType != XmlNodeType.EndElement)
128                         {
129                                 if (reader.NodeType == XmlNodeType.Element)
130                                 {
131                                         DataTable t = GetTable (reader.LocalName);
132                                         if (t != null)
133                                                 LoadBeforeTable(t, reader);
134                                         else
135                                                 throw new DataException (Locale.GetText ("Cannot load diffGram. Table '" + reader.LocalName + "' is missing in the destination dataset"));
136                                 }
137                                 else
138                                         reader.Skip ();
139                         }
140                         
141                         reader.ReadEndElement ();
142                 }                                
143                                 
144                                            
145                 private void LoadErrors (XmlReader reader) 
146                 {
147                         if (reader.IsEmptyElement) return;
148                         
149                         reader.ReadStartElement ();
150                         reader.MoveToContent ();
151
152                         while (reader.NodeType != XmlNodeType.EndElement)
153                         {
154                                 if (reader.NodeType == XmlNodeType.Element)
155                                 {
156                                         DataRow Row = null;
157                 
158                                         // find the row in 'current' section
159                                         
160                                         string id = reader.GetAttribute ("id", XmlConstants.DiffgrNamespace);
161                                         
162                                         if (id != null)
163                                                 Row = (DataRow) ErrorRows [id];
164                 
165                                         if (reader.IsEmptyElement) continue;
166                                         reader.ReadStartElement ();
167                                         while (reader.NodeType != XmlNodeType.EndElement)
168                                         {
169                                                 if (reader.NodeType == XmlNodeType.Element) {
170                                                         string error = reader.GetAttribute ("Error", XmlConstants.DiffgrNamespace);
171                                                         Row.SetColumnError (reader.LocalName, error);
172                                                 }
173                                                 reader.Read ();
174                                         }
175                                 }
176                                 else
177                                         reader.Skip ();
178                         }
179                         reader.ReadEndElement ();
180                 }
181
182                 private void LoadColumns (DataTable Table, DataRow Row, XmlReader reader, DataRowVersion loadType) 
183                 {
184                         if (reader.IsEmptyElement) return;
185                         
186                         reader.ReadStartElement ();
187                         reader.MoveToContent ();
188                         
189                         while (reader.NodeType != XmlNodeType.EndElement)
190                         {
191                                 if (reader.NodeType != XmlNodeType.Element) { reader.Read (); continue; }
192                                 
193                                 if (Table.Columns.Contains (reader.LocalName)) 
194                                 {
195                                         string colName = reader.LocalName;
196                                         object data = XmlDataLoader.StringToObject (Table.Columns[colName].DataType, reader.ReadString ());
197                                         
198                                         if (loadType == DataRowVersion.Current) Row [colName] = data;
199                                         else Row.SetOriginalValue (colName, data);
200                                         reader.Read ();
201                                 }
202                                 else 
203                                 {
204                                         DataTable t = GetTable (reader.LocalName);
205                                         if (t != null) {
206                                                 if (loadType == DataRowVersion.Original)
207                                                         LoadBeforeTable (t, reader);
208                                                 else if (loadType == DataRowVersion.Current)
209                                                         LoadCurrentTable (t, reader);
210                                         }
211                                 }
212                         }
213                         
214                         reader.ReadEndElement ();
215                 }
216
217                 private void LoadBeforeTable (DataTable Table, XmlReader reader) 
218                 {
219                         string id = reader.GetAttribute ("id", XmlConstants.DiffgrNamespace);
220                         string rowOrder = reader.GetAttribute ("rowOrder", XmlConstants.MsdataNamespace);
221                         DataRow Row = (DataRow) DiffGrRows [id];
222                         
223                         if (Row == null)
224                         {
225                                 // Deleted row
226                                 Row = Table.NewRow ();
227                                 LoadColumns (Table, Row, reader, DataRowVersion.Current);
228                                 Table.Rows.InsertAt (Row, int.Parse (rowOrder));
229                                 Row.AcceptChanges ();
230                                 Row.Delete ();
231                         }
232                         else
233                         {
234                                 LoadColumns (Table, Row, reader, DataRowVersion.Original);
235                         }
236                 }
237
238                 private void LoadCurrentTable (DataTable Table, XmlReader reader) 
239                 {
240                         DataRowState state;
241                         DataRow Row = Table.NewRow ();
242
243                         string id = reader.GetAttribute  ("id", XmlConstants.DiffgrNamespace);
244                         string error = reader.GetAttribute ("hasErrors");
245                         string changes = reader.GetAttribute ("hasChanges", XmlConstants.DiffgrNamespace);
246                         
247                         if (changes != null)
248                         {
249                                 if (string.Compare (changes, "modified", true) == 0) {
250                                         DiffGrRows.Add (id, Row); // for later use
251                                         state = DataRowState.Modified;
252                                 }
253                                 else if (string.Compare (changes, "inserted", true) == 0) {
254                                         state = DataRowState.Added;
255                                 }
256                                 else
257                                         throw new InvalidOperationException ("Invalid row change state");
258                         }
259                         else
260                                 state = DataRowState.Unchanged;
261                         
262                         // If row had errors add row to hashtable for later use
263                         if (error != null && string.Compare (error, "true", true) == 0)
264                                 ErrorRows.Add (id, Row);
265                 
266                         LoadColumns (Table, Row, reader, DataRowVersion.Current);
267                         Table.Rows.Add (Row);
268                         
269                         if (state != DataRowState.Added)
270                                 Row.AcceptChanges ();
271                 }
272
273                 DataTable GetTable (string name)
274                 {
275                         if (DSet != null) 
276                                 return DSet.Tables [name];
277                         else if (name == table.TableName) 
278                                 return table;
279                         else
280                                 return null;
281                 }
282
283
284                 #endregion // Private methods
285         }
286 }