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
15 // Copyright 2011 Xamarin Inc.
19 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
21 // Permission is hereby granted, free of charge, to any person obtaining
22 // a copy of this software and associated documentation files (the
23 // "Software"), to deal in the Software without restriction, including
24 // without limitation the rights to use, copy, modify, merge, publish,
25 // distribute, sublicense, and/or sell copies of the Software, and to
26 // permit persons to whom the Software is furnished to do so, subject to
27 // the following conditions:
29 // The above copyright notice and this permission notice shall be
30 // included in all copies or substantial portions of the Software.
32 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
33 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
34 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
35 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
36 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
37 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
38 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
43 using System.Xml.Schema;
44 using System.Xml.XPath;
45 using System.Collections;
46 using System.Globalization;
48 namespace System.Data {
50 internal class XmlDiffLoader
55 private DataTable table;
56 private Hashtable DiffGrRows = new Hashtable ();
57 private Hashtable ErrorRows = new Hashtable ();
63 public XmlDiffLoader (DataSet DSet)
68 public XmlDiffLoader (DataTable table)
75 #region Public methods
77 public void Load (XmlReader reader)
79 bool origEnforceConstraint = false;
81 origEnforceConstraint = DSet.EnforceConstraints;
82 DSet.EnforceConstraints = false;
85 reader.MoveToContent ();
86 if (reader.IsEmptyElement) {
91 reader.ReadStartElement ("diffgram", XmlConstants.DiffgrNamespace);
92 reader.MoveToContent ();
94 while (reader.NodeType != XmlNodeType.EndElement)
96 if (reader.NodeType == XmlNodeType.Element)
98 if (reader.LocalName == "before" && reader.NamespaceURI == XmlConstants.DiffgrNamespace)
100 else if (reader.LocalName == "errors" && reader.NamespaceURI == XmlConstants.DiffgrNamespace)
103 LoadCurrent (reader);
109 reader.ReadEndElement ();
112 DSet.EnforceConstraints = origEnforceConstraint;
115 #endregion // Public methods
117 #region Private methods
119 private void LoadCurrent (XmlReader reader)
121 if (reader.IsEmptyElement) {
125 reader.ReadStartElement (); // Dataset root
126 reader.MoveToContent ();
128 while (reader.NodeType != XmlNodeType.EndElement)
130 if (reader.NodeType == XmlNodeType.Element)
132 DataTable t = GetTable (reader.LocalName);
134 LoadCurrentTable (t, reader);
140 throw new DataException (Locale.GetText ("Cannot load diffGram. Table '" + reader.LocalName + "' is missing in the destination dataset"));
147 reader.ReadEndElement ();
150 private void LoadBefore (XmlReader reader)
152 if (reader.IsEmptyElement) {
156 reader.ReadStartElement ();
157 reader.MoveToContent ();
159 while (reader.NodeType != XmlNodeType.EndElement)
161 if (reader.NodeType == XmlNodeType.Element)
163 DataTable t = GetTable (reader.LocalName);
165 LoadBeforeTable(t, reader);
167 throw new DataException (Locale.GetText ("Cannot load diffGram. Table '" + reader.LocalName + "' is missing in the destination dataset"));
173 reader.ReadEndElement ();
177 private void LoadErrors (XmlReader reader)
179 if (reader.IsEmptyElement) {
183 reader.ReadStartElement ();
184 reader.MoveToContent ();
186 while (reader.NodeType != XmlNodeType.EndElement)
188 if (reader.NodeType == XmlNodeType.Element)
192 // find the row in 'current' section
194 string id = reader.GetAttribute ("id", XmlConstants.DiffgrNamespace);
197 Row = (DataRow) ErrorRows [id];
199 if (reader.IsEmptyElement) continue;
200 reader.ReadStartElement ();
201 while (reader.NodeType != XmlNodeType.EndElement)
203 if (reader.NodeType == XmlNodeType.Element) {
204 string error = reader.GetAttribute ("Error", XmlConstants.DiffgrNamespace);
205 Row.SetColumnError (reader.LocalName, error);
213 reader.ReadEndElement ();
216 private void LoadColumns (DataTable Table, DataRow Row,
217 XmlReader reader, DataRowVersion loadType)
220 LoadColumnAttributes (Table, Row, reader, loadType);
221 LoadColumnChildren (Table, Row, reader, loadType);
224 private void LoadColumnAttributes (DataTable Table, DataRow Row,
225 XmlReader reader, DataRowVersion loadType)
227 if (!reader.HasAttributes // this check will be faster
228 || !reader.MoveToFirstAttribute ())
231 switch (reader.NamespaceURI) {
232 case XmlConstants.XmlnsNS:
233 case XmlConstants.XmlNS:
234 case XmlConstants.DiffgrNamespace:
235 case XmlConstants.MsdataNamespace:
236 case XmlConstants.MspropNamespace:
237 case XmlSchema.Namespace:
240 DataColumn c = Table.Columns [XmlHelper.Decode (reader.LocalName)];
242 c.ColumnMapping != MappingType.Attribute) continue;
243 if (c.Namespace == null && reader.NamespaceURI == String.Empty ||
244 c.Namespace == reader.NamespaceURI) {
245 object data = XmlDataLoader.StringToObject (c.DataType, reader.Value);
246 if (loadType == DataRowVersion.Current)
249 Row.SetOriginalValue (c.ColumnName, data);
250 } // otherwise just ignore as well as unknown elements.
251 } while (reader.MoveToNextAttribute ());
252 reader.MoveToElement ();
255 private void LoadColumnChildren (DataTable Table, DataRow Row,
256 XmlReader reader, DataRowVersion loadType)
259 if (reader.IsEmptyElement) {
263 reader.ReadStartElement ();
264 reader.MoveToContent ();
266 while (reader.NodeType != XmlNodeType.EndElement)
268 if (reader.NodeType != XmlNodeType.Element) { reader.Read (); continue; }
270 string colName = XmlHelper.Decode (reader.LocalName);
271 if (Table.Columns.Contains (colName))
273 object data = XmlDataLoader.StringToObject (Table.Columns[colName].DataType, reader.ReadString ());
275 if (loadType == DataRowVersion.Current) Row [colName] = data;
276 else Row.SetOriginalValue (colName, data);
281 DataTable t = GetTable (reader.LocalName);
283 if (loadType == DataRowVersion.Original)
284 LoadBeforeTable (t, reader);
285 else if (loadType == DataRowVersion.Current)
286 LoadCurrentTable (t, reader);
292 reader.ReadEndElement ();
295 private void LoadBeforeTable (DataTable Table, XmlReader reader)
297 string id = reader.GetAttribute ("id", XmlConstants.DiffgrNamespace);
298 string rowOrder = reader.GetAttribute ("rowOrder", XmlConstants.MsdataNamespace);
299 DataRow Row = (DataRow) DiffGrRows [id];
304 Row = Table.NewRow ();
305 LoadColumns (Table, Row, reader, DataRowVersion.Current);
306 Table.Rows.InsertAt (Row, int.Parse (rowOrder));
307 Row.AcceptChanges ();
312 LoadColumns (Table, Row, reader, DataRowVersion.Original);
316 private void LoadCurrentTable (DataTable Table, XmlReader reader)
319 DataRow Row = Table.NewRow ();
321 string id = reader.GetAttribute ("id", XmlConstants.DiffgrNamespace);
322 string error = reader.GetAttribute ("hasErrors");
323 string changes = reader.GetAttribute ("hasChanges", XmlConstants.DiffgrNamespace);
327 if (string.Compare (changes, "modified", true, CultureInfo.InvariantCulture) == 0) {
328 DiffGrRows.Add (id, Row); // for later use
329 state = DataRowState.Modified;
331 else if (string.Compare (changes, "inserted", true, CultureInfo.InvariantCulture) == 0) {
332 state = DataRowState.Added;
335 throw new InvalidOperationException ("Invalid row change state");
338 state = DataRowState.Unchanged;
340 // If row had errors add row to hashtable for later use
341 if (error != null && string.Compare (error, "true", true, CultureInfo.InvariantCulture) == 0)
342 ErrorRows.Add (id, Row);
344 LoadColumns (Table, Row, reader, DataRowVersion.Current);
345 Table.Rows.Add (Row);
347 if (state != DataRowState.Added)
348 Row.AcceptChanges ();
351 DataTable GetTable (string name)
353 name = XmlConvert.DecodeName (name);
355 return DSet.Tables [name];
356 else if (name == table.TableName)
363 #endregion // Private methods