XmlDataDocument.cs 11 KB

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