2002-12-02 Ville Palo <vi64pa@koti.soon.fi>
[mono.git] / mcs / class / System.Data / System.Xml / XmlDataDocument.cs
1 //
2 // mcs/class/System.Data/System.Xml/XmlDataDocument.cs
3 //
4 // Purpose: Provides a W3C XML DOM Document to interact with
5 //          relational data in a DataSet
6 //
7 // class: XmlDataDocument
8 // assembly: System.Data.dll
9 // namespace: System.Xml
10 //
11 // Author:
12 //     Daniel Morgan <danmorg@sc.rr.com>
13 //     Ville Palo <vi64pa@koti.soon.fi>
14 //
15 // (c)copyright 2002 Daniel Morgan
16 //
17 // XmlDataDocument is included within the Mono Class Library.
18 //
19
20 using System;
21 using System.Data;
22 using System.IO;
23 using System.Text;
24 using System.Xml.XPath;
25 using System.Collections;
26
27 namespace System.Xml {
28
29         public class XmlDataDocument : XmlDocument {
30
31                 #region Fields
32
33                 private DataSet dataSet;
34                 private bool isReadOnly = false;
35
36                 private int dataRowID = 1;
37                 private ArrayList dataRowIDList = new ArrayList ();
38
39                 #endregion // Fields
40
41                 #region Constructors
42
43                 public XmlDataDocument() {
44                         dataSet = new DataSet();                        
45                 }
46
47                 public XmlDataDocument(DataSet dataset) {
48                         this.dataSet = dataset;
49                 }
50
51                 #endregion // Constructors
52
53                 #region Public Properties
54
55                 public override string BaseURI {
56                         [MonoTODO]
57                         get {
58                                 // TODO: why are we overriding?
59                                 return base.BaseURI;
60                         }
61                 }
62
63                 public DataSet DataSet {
64                         [MonoTODO]
65                         get {
66                                 return dataSet;
67                         }
68                 }
69
70                 // override inheritted method from XmlDocument
71                 public override string InnerXml {
72                         [MonoTODO]
73                         get {
74                                 throw new NotImplementedException();
75                         }
76                                  
77                         [MonoTODO]
78                         set {
79                                 throw new NotImplementedException();
80                         }
81                 }
82
83                 public override bool IsReadOnly {
84                         [MonoTODO]
85                         get {
86                                 return isReadOnly;
87                         }
88
89                 }
90
91                 // Item indexer
92                 public override XmlElement this[string name] {
93                         [MonoTODO]
94                         get {
95                                 throw new NotImplementedException();
96                         }
97                 }
98
99                 // Item indexer
100                 public override XmlElement this[string localname, string ns] {
101                         [MonoTODO]
102                         get {
103                                 throw new NotImplementedException();
104                         }
105                 }
106
107                 public override string LocalName {
108                         [MonoTODO]
109                         get {
110                                 throw new NotImplementedException();
111                         }
112                 }
113
114                 public override string Name {
115                         [MonoTODO]
116                         get {
117                                 throw new NotImplementedException();
118                         }
119                 }
120
121                 public override XmlDocument OwnerDocument {
122                         [MonoTODO]
123                         get {
124                                 return null;
125                         }
126                 }
127
128                 #endregion // Public Properties
129
130                 #region Public Methods
131
132                 [MonoTODO]
133                 public override XmlNode CloneNode(bool deep) 
134                 {
135                         throw new NotImplementedException();
136                 }
137
138                 #region overloaded CreateElement methods
139
140                 [MonoTODO]
141                 public override XmlElement CreateElement(string prefix,
142                                 string localName, string namespaceURI) 
143                 {
144                         if ((localName == null) || (localName == String.Empty))
145                                 throw new ArgumentException ("The local name for elements or attributes cannot be null" +
146                                                              "or an empty string.");
147                         string pref = prefix != null ? prefix : String.Empty;
148                         return base.CreateElement (pref, localName, namespaceURI != null ? namespaceURI : String.Empty);
149
150                 }
151
152                 #endregion // overloaded CreateElement Methods
153                         
154                 // will not be supported
155                 public override XmlEntityReference CreateEntityReference(string name) 
156                 {
157                         throw new NotSupportedException();
158                 }
159                 
160                 // will not be supported
161                 public override XmlElement GetElementById(string elemId) 
162                 {
163                         throw new NotSupportedException();
164                 }
165
166                 // get the XmlElement associated with the DataRow
167                 public XmlElement GetElementFromRow(DataRow r) 
168                 {
169                         throw new NotImplementedException();
170                 }
171
172                 // get the DataRow associated with the XmlElement
173                 [MonoTODO]
174                 public DataRow GetRowFromElement(XmlElement e)
175                 {
176                         throw new NotImplementedException();
177                 }
178
179                 #region overload Load methods
180
181                 public override void Load(Stream inStream) {
182                         Load (new XmlTextReader (inStream));
183                 }
184
185                 public override void Load(string filename) {
186                         Load (new XmlTextReader (filename));
187                 }
188
189                 public override void Load(TextReader txtReader) {
190                         Load (new XmlTextReader (txtReader));
191                 }
192
193                 public override void Load(XmlReader reader) {
194                         
195                         DataTable dt = null;
196
197                         // For reading xml to XmlDocument
198                         XmlTextReader textReader = new XmlTextReader (
199                                 reader.BaseURI);
200
201                         if (reader.NodeType != XmlNodeType.Element)
202                                 reader.MoveToContent ();
203
204                         // TODO: Findout which exception should be throwen
205                         if (reader.NodeType != XmlNodeType.Element)
206                                 throw new Exception ();
207
208                         if (dataSet.DataSetName != reader.Name)
209                                 throw new Exception ();
210
211                         // read to next element
212                         while (reader.Read () && reader.NodeType != XmlNodeType.Element);
213
214                         do {
215
216                                 // Find right table from tablecollection
217                                 for (int i = 0; i < DataSet.Tables.Count && dt == null; i++) {
218
219                                         if (reader.Name == DataSet.Tables [i].TableName) {
220
221                                                 dt = DataSet.Tables [i];
222                                                 dt.ColumnChanged += new DataColumnChangeEventHandler (OnDataTableColumnChanged);
223                                                 dt.RowDeleted += new DataRowChangeEventHandler (OnDataTableRowDeleted);
224                                                 dt.RowChanged += new DataRowChangeEventHandler (OnDataTableRowChanged);
225                                         }
226                                 }
227                                 
228                                 // TODO: Findout what kind of exception 
229                                 if (dt == null) 
230                                         throw new Exception (); // there were no correct table
231
232                                 // Read rows to table
233                                 DataRow tempRow = dt.NewRow ();
234                                 while ((reader.NodeType != XmlNodeType.EndElement ||
235                                         reader.Name != dt.TableName) && reader.Read()) {
236                                         
237                                         switch (reader.NodeType) {
238                                                 
239                                         case XmlNodeType.Element:
240                                                 // Add column to DataRow
241                                                 LoadRow (reader, ref tempRow);
242                                                 break;
243                                         default:
244                                                 break;
245                                         }                       
246                                 }
247
248                                 // Every row must have unique id.
249                                 tempRow.XmlRowID = dataRowID;
250                                 dataRowIDList.Add (dataRowID);
251                                 dt.Rows.Add (tempRow);
252                                 dataRowID++;                                    
253                                 
254                                 
255                         } while (reader.Read ());
256
257                         base.Load (textReader);
258                 }
259                 
260                 #endregion // overloaded Load methods
261
262                 [MonoTODO]
263                 public override void WriteContentTo(XmlWriter xw) {
264                         base.WriteContentTo (xw);
265                 }
266
267                 [MonoTODO]
268                 public override void WriteTo(XmlWriter w) {
269                         base.WriteTo (w);
270                 }
271
272                 #endregion // Public Methods
273
274                 #region Protected Methods
275
276                 //FIXME: how do you handle this?
277                 //[MonoTODO]
278                 //protected internal override XPathNavigator CreateNavigator(XmlNode node) {
279                 //      throw new NotImplementedException();
280                 //}
281
282                 [MonoTODO]
283                 public new XPathNavigator CreateNavigator() {
284                         throw new NotImplementedException();
285                 }
286
287                 #endregion // Protected Methods
288                 
289                 #region DataSet event handlers
290
291                 [MonoTODO]
292                 private void OnDataTableColumnChanged(object sender, 
293                                                              DataColumnChangeEventArgs eventArgs)
294                 {
295                         // row is not yet in datatable
296                         if (eventArgs.Row.XmlRowID == 0)
297                                 return;
298
299                         // TODO: Here should be some kind of error checking.
300                         GetElementsByTagName (eventArgs.Column.ToString ()) [dataRowIDList.IndexOf (
301                                 eventArgs.Row.XmlRowID)].InnerText = (string)eventArgs.ProposedValue;
302                         
303                         
304                 }
305         
306                 [MonoTODO]
307                 private void OnDataTableRowDeleted(object sender,
308                                                           DataRowChangeEventArgs eventArgs)
309                 {
310                         DataRow deletedRow = null;
311                         deletedRow = eventArgs.Row;
312
313                         if (eventArgs.Row.XmlRowID == 0)
314                                 return;
315
316                         int rowIndex = dataRowIDList.IndexOf (eventArgs.Row.XmlRowID);
317
318                         // Remove element from xmldocument and row indexlist
319                         GetElementsByTagName (deletedRow.Table.TableName) [rowIndex].RemoveAll ();
320                         dataRowIDList.RemoveAt (rowIndex);
321                 }
322                 
323                 [MonoTODO]
324                 private void OnDataTableRowChanged(object sender, DataRowChangeEventArgs eventArgs)
325                 {
326                         switch (eventArgs.Action) {
327
328                                 case DataRowAction.Delete:
329                                         OnDataTableRowDeleted (sender, eventArgs);
330                                         break;
331
332                                 case DataRowAction.Add:
333                                         OnDataTableRowAdded (eventArgs);
334                                         break;
335
336                                 case DataRowAction.Rollback:
337                                         OnDataTableRowRollback (eventArgs);
338                                         break;
339                                 default:
340                                         break;
341                         } 
342                 }
343
344                 // Added
345                 [MonoTODO]
346                 private void OnDataTableRowAdded (DataRowChangeEventArgs args)
347                 {
348                         // If XmlRowID is != 0 then it is already added
349                         if (args.Row.XmlRowID != 0)
350                                 return;
351                         
352                         // Create row element. Row's name same as TableName                                     
353                         DataRow row = args.Row;
354                         row.XmlRowID = dataRowID;
355                         dataRowID++;
356                         XmlElement element = CreateElement (args.Row.Table.TableName);
357                         DocumentElement.AppendChild (element);
358                         
359                         XmlElement rowElement = null;
360                         for (int i = 0; i < row.Table.Columns.Count; i++) {
361
362                                 rowElement = CreateElement (row.Table.Columns [i].ToString ());
363                                 rowElement.InnerText = (string)row [i];
364                                 element.AppendChild (rowElement);
365                         }
366                 }
367
368                 // Rollback
369                 [MonoTODO]
370                 private void OnDataTableRowRollback (DataRowChangeEventArgs args)
371                 {
372                         DataRow row = args.Row;
373                         
374                         int rowid = dataRowIDList.IndexOf (row.XmlRowID);
375                         
376                         // find right element in xmldocument
377                         XmlNode node = GetElementsByTagName (row.Table.TableName) [rowid];
378
379                         int rowValue = 0;
380                         for (int i = 0; i < node.ChildNodes.Count; i++) {
381
382                                 XmlNode child = node.ChildNodes [i];
383                                 if (child.NodeType != XmlNodeType.Whitespace)                           
384                                         child.InnerText = (string)row [rowValue++];
385                                 
386                         }
387                         
388                 }
389
390                 #endregion // DataSet event handlers
391
392                 #region Private methods
393
394                 [MonoTODO]
395                 private void LoadRow (XmlReader reader, ref DataRow row)
396                 {                       
397                         // dt.Rows.Add (LoadRow (reader, dt.NewRow ()));
398                         // This method returns DataRow filled by values
399                         // from xmldocument
400                         string rowname = reader.Name;
401                         string column = "";
402                         
403                         if (reader.NodeType == XmlNodeType.Element)
404                                 column = reader.Name;
405                         
406                         reader.Read ();
407                         
408                         if (reader.NodeType == XmlNodeType.Text) {
409                                 
410                                 string val = reader.Value;
411                                 if (row.Table.Columns.Contains (column))
412                                         row [column] = val;
413                         }
414                 }
415                 
416                 #endregion // Private methods
417         }
418 }
419