2 // mcs/class/System.Data/System.Xml/XmlDataDocument.cs
4 // Purpose: Provides a W3C XML DOM Document to interact with
5 // relational data in a DataSet
7 // class: XmlDataDocument
8 // assembly: System.Data.dll
9 // namespace: System.Xml
12 // Daniel Morgan <danmorg@sc.rr.com>
13 // Ville Palo <vi64pa@koti.soon.fi>
15 // (c)copyright 2002 Daniel Morgan
17 // XmlDataDocument is included within the Mono Class Library.
24 using System.Xml.XPath;
25 using System.Collections;
27 namespace System.Xml {
29 public class XmlDataDocument : XmlDocument {
33 private DataSet dataSet;
34 private bool isReadOnly = false;
36 private int dataRowID = 1;
37 private ArrayList dataRowIDList = new ArrayList ();
43 public XmlDataDocument() {
44 dataSet = new DataSet();
47 public XmlDataDocument(DataSet dataset) {
48 this.dataSet = dataset;
51 #endregion // Constructors
53 #region Public Properties
55 public override string BaseURI {
58 // TODO: why are we overriding?
63 public DataSet DataSet {
70 // override inheritted method from XmlDocument
71 public override string InnerXml {
74 throw new NotImplementedException();
79 throw new NotImplementedException();
83 public override bool IsReadOnly {
92 public override XmlElement this[string name] {
95 throw new NotImplementedException();
100 public override XmlElement this[string localname, string ns] {
103 throw new NotImplementedException();
107 public override string LocalName {
110 throw new NotImplementedException();
114 public override string Name {
117 throw new NotImplementedException();
121 public override XmlDocument OwnerDocument {
128 #endregion // Public Properties
130 #region Public Methods
133 public override XmlNode CloneNode(bool deep)
135 throw new NotImplementedException();
138 #region overloaded CreateElement methods
141 public override XmlElement CreateElement(string prefix,
142 string localName, string namespaceURI)
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);
152 #endregion // overloaded CreateElement Methods
154 // will not be supported
155 public override XmlEntityReference CreateEntityReference(string name)
157 throw new NotSupportedException();
160 // will not be supported
161 public override XmlElement GetElementById(string elemId)
163 throw new NotSupportedException();
166 // get the XmlElement associated with the DataRow
167 public XmlElement GetElementFromRow(DataRow r)
169 throw new NotImplementedException();
172 // get the DataRow associated with the XmlElement
174 public DataRow GetRowFromElement(XmlElement e)
176 throw new NotImplementedException();
179 #region overload Load methods
181 public override void Load(Stream inStream) {
182 Load (new XmlTextReader (inStream));
185 public override void Load(string filename) {
186 Load (new XmlTextReader (filename));
189 public override void Load(TextReader txtReader) {
190 Load (new XmlTextReader (txtReader));
193 public override void Load(XmlReader reader) {
197 // For reading xml to XmlDocument
198 XmlTextReader textReader = new XmlTextReader (
201 if (reader.NodeType != XmlNodeType.Element)
202 reader.MoveToContent ();
204 // TODO: Findout which exception should be throwen
205 if (reader.NodeType != XmlNodeType.Element)
206 throw new Exception ();
208 if (dataSet.DataSetName != reader.Name)
209 throw new Exception ();
211 // read to next element
212 while (reader.Read () && reader.NodeType != XmlNodeType.Element);
216 // Find right table from tablecollection
217 for (int i = 0; i < DataSet.Tables.Count && dt == null; i++) {
219 if (reader.Name == DataSet.Tables [i].TableName) {
221 dt = DataSet.Tables [i];
222 dt.ColumnChanged += new DataColumnChangeEventHandler (OnDataTableColumnChanged);
223 dt.RowDeleted += new DataRowChangeEventHandler (OnDataTableRowDeleted);
224 dt.RowChanged += new DataRowChangeEventHandler (OnDataTableRowChanged);
228 // TODO: Findout what kind of exception
230 throw new Exception (); // there were no correct table
232 // Read rows to table
233 DataRow tempRow = dt.NewRow ();
234 while ((reader.NodeType != XmlNodeType.EndElement ||
235 reader.Name != dt.TableName) && reader.Read()) {
237 switch (reader.NodeType) {
239 case XmlNodeType.Element:
240 // Add column to DataRow
241 LoadRow (reader, ref tempRow);
248 // Every row must have unique id.
249 tempRow.XmlRowID = dataRowID;
250 dataRowIDList.Add (dataRowID);
251 dt.Rows.Add (tempRow);
255 } while (reader.Read ());
257 base.Load (textReader);
260 #endregion // overloaded Load methods
263 public override void WriteContentTo(XmlWriter xw) {
264 base.WriteContentTo (xw);
268 public override void WriteTo(XmlWriter w) {
272 #endregion // Public Methods
274 #region Protected Methods
276 //FIXME: how do you handle this?
278 //protected internal override XPathNavigator CreateNavigator(XmlNode node) {
279 // throw new NotImplementedException();
283 public new XPathNavigator CreateNavigator() {
284 throw new NotImplementedException();
287 #endregion // Protected Methods
289 #region DataSet event handlers
292 private void OnDataTableColumnChanged(object sender,
293 DataColumnChangeEventArgs eventArgs)
295 // row is not yet in datatable
296 if (eventArgs.Row.XmlRowID == 0)
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;
307 private void OnDataTableRowDeleted(object sender,
308 DataRowChangeEventArgs eventArgs)
310 DataRow deletedRow = null;
311 deletedRow = eventArgs.Row;
313 if (eventArgs.Row.XmlRowID == 0)
316 int rowIndex = dataRowIDList.IndexOf (eventArgs.Row.XmlRowID);
318 // Remove element from xmldocument and row indexlist
319 GetElementsByTagName (deletedRow.Table.TableName) [rowIndex].RemoveAll ();
320 dataRowIDList.RemoveAt (rowIndex);
324 private void OnDataTableRowChanged(object sender, DataRowChangeEventArgs eventArgs)
326 switch (eventArgs.Action) {
328 case DataRowAction.Delete:
329 OnDataTableRowDeleted (sender, eventArgs);
332 case DataRowAction.Add:
333 OnDataTableRowAdded (eventArgs);
336 case DataRowAction.Rollback:
337 OnDataTableRowRollback (eventArgs);
346 private void OnDataTableRowAdded (DataRowChangeEventArgs args)
348 // If XmlRowID is != 0 then it is already added
349 if (args.Row.XmlRowID != 0)
352 // Create row element. Row's name same as TableName
353 DataRow row = args.Row;
354 row.XmlRowID = dataRowID;
356 XmlElement element = CreateElement (args.Row.Table.TableName);
357 DocumentElement.AppendChild (element);
359 XmlElement rowElement = null;
360 for (int i = 0; i < row.Table.Columns.Count; i++) {
362 rowElement = CreateElement (row.Table.Columns [i].ToString ());
363 rowElement.InnerText = (string)row [i];
364 element.AppendChild (rowElement);
370 private void OnDataTableRowRollback (DataRowChangeEventArgs args)
372 DataRow row = args.Row;
374 int rowid = dataRowIDList.IndexOf (row.XmlRowID);
376 // find right element in xmldocument
377 XmlNode node = GetElementsByTagName (row.Table.TableName) [rowid];
380 for (int i = 0; i < node.ChildNodes.Count; i++) {
382 XmlNode child = node.ChildNodes [i];
383 if (child.NodeType != XmlNodeType.Whitespace)
384 child.InnerText = (string)row [rowValue++];
390 #endregion // DataSet event handlers
392 #region Private methods
395 private void LoadRow (XmlReader reader, ref DataRow row)
397 // dt.Rows.Add (LoadRow (reader, dt.NewRow ()));
398 // This method returns DataRow filled by values
400 string rowname = reader.Name;
403 if (reader.NodeType == XmlNodeType.Element)
404 column = reader.Name;
408 if (reader.NodeType == XmlNodeType.Text) {
410 string val = reader.Value;
411 if (row.Table.Columns.Contains (column))
416 #endregion // Private methods