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