2 // mcs/class/System.Data/System.Data/XmlDiffLoader.cs
4 // Purpose: Loads XmlDiffGrams to DataSet
6 // class: XmlDiffLoader
7 // assembly: System.Data.dll
8 // namespace: System.Data
11 // Ville Palo <vi64pa@koti.soon.fi>
12 // Lluis Sanchez Gual (lluis@ximian.com)
14 // (c)copyright 2003 Ville Palo
18 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
20 // Permission is hereby granted, free of charge, to any person obtaining
21 // a copy of this software and associated documentation files (the
22 // "Software"), to deal in the Software without restriction, including
23 // without limitation the rights to use, copy, modify, merge, publish,
24 // distribute, sublicense, and/or sell copies of the Software, and to
25 // permit persons to whom the Software is furnished to do so, subject to
26 // the following conditions:
28 // The above copyright notice and this permission notice shall be
29 // included in all copies or substantial portions of the Software.
31 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
32 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
33 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
34 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
35 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
36 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
37 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
42 using System.Xml.Schema;
43 using System.Xml.XPath;
44 using System.Collections;
45 using System.Globalization;
47 namespace System.Data {
49 internal class XmlDiffLoader
54 private DataTable table;
55 private Hashtable DiffGrRows = new Hashtable ();
56 private Hashtable ErrorRows = new Hashtable ();
62 public XmlDiffLoader (DataSet DSet)
67 public XmlDiffLoader (DataTable table)
74 #region Public methods
76 public void Load (XmlReader reader)
78 bool origEnforceConstraint = false;
80 origEnforceConstraint = DSet.EnforceConstraints;
81 DSet.EnforceConstraints = false;
84 reader.MoveToContent ();
85 if (reader.IsEmptyElement) {
90 reader.ReadStartElement ("diffgram", XmlConstants.DiffgrNamespace);
91 reader.MoveToContent ();
93 while (reader.NodeType != XmlNodeType.EndElement)
95 if (reader.NodeType == XmlNodeType.Element)
97 if (reader.LocalName == "before" && reader.NamespaceURI == XmlConstants.DiffgrNamespace)
99 else if (reader.LocalName == "errors" && reader.NamespaceURI == XmlConstants.DiffgrNamespace)
102 LoadCurrent (reader);
108 reader.ReadEndElement ();
111 DSet.EnforceConstraints = origEnforceConstraint;
114 #endregion // Public methods
116 #region Private methods
118 private void LoadCurrent (XmlReader reader)
120 if (reader.IsEmptyElement) {
124 reader.ReadStartElement (); // Dataset root
125 reader.MoveToContent ();
127 while (reader.NodeType != XmlNodeType.EndElement)
129 if (reader.NodeType == XmlNodeType.Element)
131 DataTable t = GetTable (reader.LocalName);
133 LoadCurrentTable (t, reader);
139 throw new DataException (Locale.GetText ("Cannot load diffGram. Table '" + reader.LocalName + "' is missing in the destination dataset"));
146 reader.ReadEndElement ();
149 private void LoadBefore (XmlReader reader)
151 if (reader.IsEmptyElement) {
155 reader.ReadStartElement ();
156 reader.MoveToContent ();
158 while (reader.NodeType != XmlNodeType.EndElement)
160 if (reader.NodeType == XmlNodeType.Element)
162 DataTable t = GetTable (reader.LocalName);
164 LoadBeforeTable(t, reader);
166 throw new DataException (Locale.GetText ("Cannot load diffGram. Table '" + reader.LocalName + "' is missing in the destination dataset"));
172 reader.ReadEndElement ();
176 private void LoadErrors (XmlReader reader)
178 if (reader.IsEmptyElement) {
182 reader.ReadStartElement ();
183 reader.MoveToContent ();
185 while (reader.NodeType != XmlNodeType.EndElement)
187 if (reader.NodeType == XmlNodeType.Element)
191 // find the row in 'current' section
193 string id = reader.GetAttribute ("id", XmlConstants.DiffgrNamespace);
196 Row = (DataRow) ErrorRows [id];
198 if (reader.IsEmptyElement) continue;
199 reader.ReadStartElement ();
200 while (reader.NodeType != XmlNodeType.EndElement)
202 if (reader.NodeType == XmlNodeType.Element) {
203 string error = reader.GetAttribute ("Error", XmlConstants.DiffgrNamespace);
204 Row.SetColumnError (reader.LocalName, error);
212 reader.ReadEndElement ();
215 private void LoadColumns (DataTable Table, DataRow Row,
216 XmlReader reader, DataRowVersion loadType)
219 LoadColumnAttributes (Table, Row, reader, loadType);
220 LoadColumnChildren (Table, Row, reader, loadType);
223 private void LoadColumnAttributes (DataTable Table, DataRow Row,
224 XmlReader reader, DataRowVersion loadType)
226 if (!reader.HasAttributes // this check will be faster
227 || !reader.MoveToFirstAttribute ())
230 switch (reader.NamespaceURI) {
231 case XmlConstants.XmlnsNS:
233 case XmlConstants.XmlNS:
235 case XmlConstants.DiffgrNamespace:
236 case XmlConstants.MsdataNamespace:
237 case XmlConstants.MspropNamespace:
238 case XmlSchema.Namespace:
241 DataColumn c = Table.Columns [XmlHelper.Decode (reader.LocalName)];
243 c.ColumnMapping != MappingType.Attribute) continue;
244 if (c.Namespace == null && reader.NamespaceURI == String.Empty ||
245 c.Namespace == reader.NamespaceURI) {
246 object data = XmlDataLoader.StringToObject (c.DataType, reader.Value);
247 if (loadType == DataRowVersion.Current)
250 Row.SetOriginalValue (c.ColumnName, data);
251 } // otherwise just ignore as well as unknown elements.
252 } while (reader.MoveToNextAttribute ());
253 reader.MoveToElement ();
256 private void LoadColumnChildren (DataTable Table, DataRow Row,
257 XmlReader reader, DataRowVersion loadType)
260 if (reader.IsEmptyElement) {
264 reader.ReadStartElement ();
265 reader.MoveToContent ();
267 while (reader.NodeType != XmlNodeType.EndElement)
269 if (reader.NodeType != XmlNodeType.Element) { reader.Read (); continue; }
271 string colName = XmlHelper.Decode (reader.LocalName);
272 if (Table.Columns.Contains (colName))
274 object data = XmlDataLoader.StringToObject (Table.Columns[colName].DataType, reader.ReadString ());
276 if (loadType == DataRowVersion.Current) Row [colName] = data;
277 else Row.SetOriginalValue (colName, data);
282 DataTable t = GetTable (reader.LocalName);
284 if (loadType == DataRowVersion.Original)
285 LoadBeforeTable (t, reader);
286 else if (loadType == DataRowVersion.Current)
287 LoadCurrentTable (t, reader);
293 reader.ReadEndElement ();
296 private void LoadBeforeTable (DataTable Table, XmlReader reader)
298 string id = reader.GetAttribute ("id", XmlConstants.DiffgrNamespace);
299 string rowOrder = reader.GetAttribute ("rowOrder", XmlConstants.MsdataNamespace);
300 DataRow Row = (DataRow) DiffGrRows [id];
305 Row = Table.NewRow ();
306 LoadColumns (Table, Row, reader, DataRowVersion.Current);
307 Table.Rows.InsertAt (Row, int.Parse (rowOrder));
308 Row.AcceptChanges ();
313 LoadColumns (Table, Row, reader, DataRowVersion.Original);
317 private void LoadCurrentTable (DataTable Table, XmlReader reader)
320 DataRow Row = Table.NewRow ();
322 string id = reader.GetAttribute ("id", XmlConstants.DiffgrNamespace);
323 string error = reader.GetAttribute ("hasErrors");
324 string changes = reader.GetAttribute ("hasChanges", XmlConstants.DiffgrNamespace);
328 if (string.Compare (changes, "modified", true, CultureInfo.InvariantCulture) == 0) {
329 DiffGrRows.Add (id, Row); // for later use
330 state = DataRowState.Modified;
332 else if (string.Compare (changes, "inserted", true, CultureInfo.InvariantCulture) == 0) {
333 state = DataRowState.Added;
336 throw new InvalidOperationException ("Invalid row change state");
339 state = DataRowState.Unchanged;
341 // If row had errors add row to hashtable for later use
342 if (error != null && string.Compare (error, "true", true, CultureInfo.InvariantCulture) == 0)
343 ErrorRows.Add (id, Row);
345 LoadColumns (Table, Row, reader, DataRowVersion.Current);
346 Table.Rows.Add (Row);
348 if (state != DataRowState.Added)
349 Row.AcceptChanges ();
352 DataTable GetTable (string name)
354 name = XmlConvert.DecodeName (name);
356 return DSet.Tables [name];
357 else if (name == table.TableName)
364 #endregion // Private methods