* DataRow.cs : Throw exceptions if Row is Detached.
[mono.git] / mcs / class / System.Data / System.Data / XmlSchemaMapper.cs
1 //
2 // mcs/class/System.Data/System.Data/XmlSchemaMapper.cs
3 //
4 // Purpose: Maps XmlSchema to DataSet 
5 //
6 // class: XmlSchemaMapper
7 // assembly: System.Data.dll
8 // namespace: System.Data
9 //
10 // Author:
11 //     Ville Palo <vi64pa@koti.soon.fi>
12 //
13 // (C) 2002 Ville Palo
14 //
15 // TODO: Relations
16 //
17
18 using System;
19 using System.Data;
20 using System.Xml;
21 using System.Xml.Schema;
22 using System.Collections;
23 using System.Globalization;
24
25 namespace System.Data {
26
27         internal class XmlSchemaMapper
28         {       
29                 #region Fields
30
31                 private DataSet DSet;
32                 enum ElementType {ELEMENT_UNDEFINED, ELEMENT_TABLE, ELEMENT_COLUMN};
33                 private Hashtable TypeCollection = new Hashtable ();
34                 private Hashtable ElementCollection = new Hashtable ();
35
36                 #endregion // Fields
37
38                 #region Constructors
39
40                 public XmlSchemaMapper (DataSet dataset)
41                 {
42                         DSet = dataset;
43                 }
44
45                 #endregion // Constructors
46
47                 #region Public methods
48
49                 public void Read (XmlReader Reader)
50                 {
51                         XmlSchema Schema = XmlSchema.Read (Reader, new ValidationEventHandler (OnXmlSchemaValidation));
52                         
53                         // read items
54                         foreach (XmlSchemaObject Item in Schema.Items)
55                                 ReadXmlSchemaItem (Item);
56                 }
57
58                 #endregion // Public methods
59
60                 #region Private methods
61
62                 private void ReadXmlSchemaItem (XmlSchemaObject Item)
63                 {
64                         XmlSchemaObject SchemaObject;
65                         
66                         if (Item is XmlSchemaType)
67                                 ReadXmlSchemaType ((XmlSchemaType)Item);
68                         else if (Item is XmlSchemaElement)
69                                 ReadXmlSchemaElement (Item as XmlSchemaElement, ElementType.ELEMENT_UNDEFINED);
70                 }
71
72                 private void ReadXmlSchemaSequence (XmlSchemaSequence Sequence)
73                 {
74                         ReadXmlSchemaSequence (Sequence, null);
75                 }
76
77                 private void ReadXmlSchemaSequence (XmlSchemaSequence Sequence, DataTable Table)
78                 {
79                         foreach (XmlSchemaObject TempObj in Sequence.Items) {
80                                 
81                                 if (TempObj is XmlSchemaElement)
82                                         ReadXmlSchemaElement (TempObj as XmlSchemaElement, ElementType.ELEMENT_COLUMN, Table);
83                                 
84                         }
85                 }
86
87                 private void ReadXmlSchemaChoice (XmlSchemaChoice Choice)
88                 {
89                         XmlSchemaObject SchemaObject;
90                         foreach (XmlSchemaObject TempObject in Choice.Items) {
91                                 
92                                 if ((SchemaObject = TempObject as XmlSchemaElement) != null)
93                                         ReadXmlSchemaElement ((XmlSchemaElement)SchemaObject, ElementType.ELEMENT_TABLE);
94                         }                               
95                 }
96
97                 private void ReadXmlSchemaElement (XmlSchemaElement Element)
98                 {
99                         ReadXmlSchemaElement (Element, ElementType.ELEMENT_UNDEFINED);
100                 }
101
102                 private void ReadXmlSchemaElement (XmlSchemaElement Element, ElementType ElType)
103                 {
104                         ReadXmlSchemaElement (Element, ElType, null);
105                 }
106
107                 private void ReadXmlSchemaElement (XmlSchemaElement Element, ElementType ElType, DataTable Table)
108                 {
109                         Hashtable Attributes = ReadUnhandledAttributes (Element.UnhandledAttributes);
110                         DataTable Table2 = null;
111
112                         if (Attributes.Contains ("IsDataSet")) { // DataSet -elemt
113
114                                 if (String.Compare (Attributes ["IsDataSet"].ToString (), "true", true) == 0)
115                                         DSet.DataSetName = Element.Name;
116                         }
117                         else if (Element.SchemaTypeName != null && Element.SchemaTypeName.Namespace != XmlConstants.SchemaNamespace 
118                                  && Element.SchemaTypeName.Name != String.Empty) {
119
120                                 //
121                                 // If type is not standard type
122                                 //
123
124                                 DataTable TempTable = new DataTable (Element.Name);
125                                 DSet.Tables.Add (TempTable);
126                                 
127                                 // If type is already defined in schema read it...                              
128                                 if (TypeCollection.Contains (Element.SchemaTypeName.ToString ()))
129                                         ReadXmlSchemaType ((XmlSchemaType)TypeCollection [Element.SchemaTypeName.ToString ()], TempTable);
130                                 else // but if it's not yet defined put it safe to wait if we need it later. 
131                                         ElementCollection.Add (Element.SchemaTypeName.Name, TempTable);
132
133                         }
134                         else if (Element.RefName != null && Element.RefName.Name != string.Empty) { // if there is a ref=
135
136                                 if (ElementCollection.Contains (Element.RefName.Name))
137                                         ReadXmlSchemaElement ((XmlSchemaElement)ElementCollection [Element.RefName.Name], ElementType.ELEMENT_TABLE);
138                         }
139                         else if (ElementType.ELEMENT_UNDEFINED != ElType) {
140
141                                 if (ElType == ElementType.ELEMENT_TABLE)
142                                         ReadTable (Element);
143                                 else if (ElType == ElementType.ELEMENT_COLUMN && Table != null)
144                                         ReadColumn (Element, Table);
145                         }
146                         else {
147                                 // this element is undefined, for now
148                                 ElementCollection.Add (Element.Name, Element);
149                         }
150
151                         // Read Element type
152                         if (Element.SchemaType != null)
153                                 ReadXmlSchemaType (Element.SchemaType);
154
155                         // Read possible constraints
156                         if (Element.Constraints != null && Element.Constraints.Count > 0)
157                                 ReadXmlSchemaConstraints (Element.Constraints);
158                 }
159
160                 private void ReadTable (XmlSchemaElement Element)
161                 {
162                         DataTable TempTable = new DataTable (Element.Name);
163                         DSet.Tables.Add (TempTable);
164                         ReadXmlSchemaType (Element.SchemaType, TempTable);                      
165                 }
166
167                 private void ReadColumn (XmlSchemaElement Element, DataTable Table)
168                 {
169                         DataColumn Column = new DataColumn (Element.Name);
170                         Table.Columns.Add (Column);
171
172                         if (Element.UnhandledAttributes != null) {
173
174                                 foreach (XmlAttribute Attr in Element.UnhandledAttributes) {
175                                         
176                                         switch (Attr.LocalName) {
177                                                 
178                                         case "Caption":
179                                                 Column.Caption = Attr.Value;
180                                                 break;
181                                         case "DataType":
182                                                 Column.DataType = Type.GetType (Attr.Value);
183                                                 break;
184                                         case "type":
185                                                 // FIXME:
186                                                 break;                                          
187                                         default:
188                                                 break;
189                                         }
190                                 }
191                         }
192
193                         //
194                         // Handel rest of the parameters
195                         //
196
197                         if (Column.DataType == null)
198                                 Column.DataType = Type.GetType ("System.String");
199                         
200                         if (Element.DefaultValue != null)
201                                 Column.DefaultValue = Element.DefaultValue;
202
203                         // If Element have type
204                         if (Element.SchemaType != null)
205                                 ReadXmlSchemaType (Element.SchemaType, Column);
206                 }
207
208                 // Makes new Hashtable of the attributes.
209                 private Hashtable ReadUnhandledAttributes (XmlAttribute [] Attributes)
210                 {
211                         Hashtable Result = new Hashtable ();
212
213                         if (Attributes == null)
214                                 return Result;
215
216                         foreach (XmlAttribute attribute in Attributes) {
217                                 Result.Add (attribute.LocalName, attribute.Value);
218                         }
219                         
220                         return Result;
221                 }
222
223                 private void ReadXmlSchemaConstraints (XmlSchemaObjectCollection Constraints)
224                 {
225                         foreach (XmlSchemaObject Constraint in Constraints) {
226                                 
227                                 if (Constraint is XmlSchemaUnique)
228                                         ReadXmlSchemaUnique ((XmlSchemaUnique)Constraint);
229                         }
230                 }
231
232                 [MonoTODO()]
233                 private void ReadXmlSchemaUnique (XmlSchemaUnique Unique)
234                 {
235                         // FIXME: Parsing XPath
236                         
237                         string TableName = Unique.Selector.XPath;
238                         if (TableName.StartsWith (".//"))
239                                 TableName = TableName.Substring (3);
240                         
241                         DataColumn [] Columns;
242                         if (DSet.Tables.Contains (TableName)) {
243                                 
244                                 DataTable Table = DSet.Tables [TableName];
245                                 Columns = new DataColumn [Unique.Fields.Count];
246                                 int i = 0;
247                                 foreach (XmlSchemaXPath Field in Unique.Fields) {
248
249                                         if (Table.Columns.Contains (Field.XPath)) {
250                                                 Table.Columns [Field.XPath].Unique = true;
251                                                 Columns [i] = Table.Columns [Field.XPath];
252                                                 i++;
253                                         }
254                                 }
255
256                                 UniqueConstraint Constraint = new UniqueConstraint (Unique.Name, Columns);
257                         }
258                 }
259
260                 #endregion // Private methods
261
262                 #region Private listeners
263
264                 private void OnXmlSchemaValidation (object sender, ValidationEventArgs args)
265                 {
266                         ;
267                 }
268
269                 #endregion // Private listeners
270
271                 #region Private TypeReaders
272
273                 // Reads XmlSchemaType
274                 private void ReadXmlSchemaType (XmlSchemaType SchemaType)
275                 {
276                         ReadXmlSchemaType (SchemaType, (DataTable)null);
277                 }
278
279                 // Reads XmlSchemaType and decides is it Complex or Simple and continue reading those types
280                 private void ReadXmlSchemaType (XmlSchemaType SchemaType, DataTable Table)
281                 {
282                         if (SchemaType is XmlSchemaComplexType)
283                                 ReadXmlSchemaComplexType ((XmlSchemaComplexType)SchemaType, Table);
284                         else if (SchemaType is XmlSchemaSimpleType)
285                                 ReadXmlSchemaSimpleType ((XmlSchemaSimpleType)SchemaType, Table);
286                 }
287
288                 // Same as above but with DataColumn
289                 private void ReadXmlSchemaType (XmlSchemaType SchemaType, DataColumn Column)
290                 {
291                         if (SchemaType is XmlSchemaComplexType)
292                                 ReadXmlSchemaComplexType ((XmlSchemaComplexType)SchemaType, Column);
293                         else if (SchemaType is XmlSchemaSimpleType)
294                                 ReadXmlSchemaSimpleType ((XmlSchemaSimpleType)SchemaType, Column);
295                 }
296
297                 #endregion // PrivateTypeReader
298
299                 #region TypeReaderHelppers
300
301                 private void ReadXmlSchemaSimpleType (XmlSchemaSimpleType SimpleType, DataColumn Column)
302                 {                       
303                         // Read Contents
304                         if (SimpleType.Content is XmlSchemaSimpleTypeRestriction)
305                                 ReadXmlSchemaSimpleTypeRestriction ((XmlSchemaSimpleTypeRestriction)SimpleType.Content, Column);
306                 }
307
308                 [MonoTODO]
309                 private void ReadXmlSchemaSimpleType (XmlSchemaSimpleType SimpleType, DataTable Table)
310                 {
311                         // TODO: Is it possible that Table-element have simpletype???
312                 }
313
314                 [MonoTODO]
315                 private void ReadXmlSchemaSimpleTypeRestriction (XmlSchemaSimpleTypeRestriction Restriction, DataColumn Column)
316                 {
317                         foreach (XmlSchemaObject Facet in Restriction.Facets) {
318                                 
319                                 // FIXME: I dont know are everyone of these needed but, let them be here for now
320                                 if (Facet is XmlSchemaMaxLengthFacet) 
321                                         Column.MaxLength = Int32.Parse(((XmlSchemaFacet)Facet).Value);
322                                 //else if (Facet is XmlSchemaMinLengthFacet) 
323                                 //      ;
324                                 //else if (Facet is XmlSchemaLengthFacet)
325                                 //      ;
326                                 //else if (Facet is XmlSchemaPatternFacet)
327                                 //      ;
328                                 //else if (Facet is XmlSchemaEnumerationFacet)
329                                 //      ;
330                                 //else if (Facet is XmlSchemaMaxInclusiveFacet)
331                                 //      ;
332                                 //else if (Facet is XmlSchemaMaxExclusiveFacet)
333                                 //      ;
334                                 //else if (Facet is XmlSchemaMinInclusiveFacet)
335                                 //      ;
336                                 //else if (Facet is XmlSchemaMinExclusiveFacet)
337                                 //      ;
338                                 //else if (Facet is XmlSchemaFractionDigitsFacet)
339                                 //      ;
340                                 //else if (Facet is XmlSchemaTotalDigitsFacet)
341                                 //      ;
342                                 //else if (Facet is XmlSchemaWhiteSpaceFacet)
343                                 //      ;
344                         }
345                 }
346
347                 [MonoTODO]
348                 private void ReadXmlSchemaComplexType (XmlSchemaComplexType Type, DataColumn Column)
349                 {
350                         // TODO: is it possible that column-element have complextype
351                 }
352
353                 // Reads XmlSchemaComplexType with DataTable
354                 private void ReadXmlSchemaComplexType (XmlSchemaComplexType Type, DataTable Table)
355                 {
356                         XmlSchemaComplexType ComplexType = Type as XmlSchemaComplexType;
357                         
358                         if (ComplexType.Name != null && ComplexType.Name != string.Empty) {
359
360                                 if (ElementCollection.Contains (ComplexType.Name)) {
361
362                                         if (ComplexType.Particle is XmlSchemaChoice) {
363                                                 ReadXmlSchemaChoice (ComplexType.Particle as XmlSchemaChoice);
364                                         }
365                                         else if (ComplexType.Particle is XmlSchemaSequence) {
366
367                                                 DataTable TempTable = ElementCollection [ComplexType.Name] as DataTable;
368                                                 ElementCollection.Remove (ComplexType.Name);
369                                                 ReadXmlSchemaSequence (ComplexType.Particle as XmlSchemaSequence, TempTable);
370                                         }
371                                 }
372                                 else if (ComplexType.Name != null && !TypeCollection.Contains (ComplexType.Name)) {
373                                         TypeCollection.Add (ComplexType.Name, ComplexType);
374                                 } 
375                                 else {
376
377                                         // If we are here it means that types of elements are Tables :-P
378                                         if (ComplexType.Particle is XmlSchemaSequence)
379                                                 ReadXmlSchemaSequence (ComplexType.Particle as XmlSchemaSequence, Table);
380                                 }
381
382                         }
383                         else {
384                                 XmlSchemaParticle Particle;
385                                 if ((Particle = ComplexType.Particle as XmlSchemaChoice) != null) {
386                                         ReadXmlSchemaChoice (Particle as XmlSchemaChoice);
387                                 }
388                                 else if ((Particle = ComplexType.Particle as XmlSchemaSequence) != null) {
389                                         ReadXmlSchemaSequence (Particle as XmlSchemaSequence, Table);
390                                 }
391                         }                               
392                 }
393                 
394                 #endregion // TypeReaderHelppers
395         }
396 }
397