2 // mcs/class/System.Data/System.Data/XmlSchemaMapper.cs
4 // Purpose: Maps XmlSchema to DataSet
6 // class: XmlSchemaMapper
7 // assembly: System.Data.dll
8 // namespace: System.Data
11 // Ville Palo <vi64pa@koti.soon.fi>
13 // (C) 2002 Ville Palo
21 using System.Xml.Schema;
22 using System.Collections;
23 using System.Globalization;
25 namespace System.Data {
27 internal class XmlSchemaMapper
32 enum ElementType {ELEMENT_UNDEFINED, ELEMENT_TABLE, ELEMENT_COLUMN};
33 private Hashtable TypeCollection = new Hashtable ();
34 private Hashtable ElementCollection = new Hashtable ();
40 public XmlSchemaMapper (DataSet dataset)
45 #endregion // Constructors
47 #region Public methods
49 public void Read (XmlReader Reader)
51 XmlSchema Schema = XmlSchema.Read (Reader, new ValidationEventHandler (OnXmlSchemaValidation));
54 foreach (XmlSchemaObject Item in Schema.Items)
55 ReadXmlSchemaItem (Item);
58 #endregion // Public methods
60 #region Private methods
62 private void ReadXmlSchemaItem (XmlSchemaObject Item)
64 XmlSchemaObject SchemaObject;
66 if (Item is XmlSchemaType)
67 ReadXmlSchemaType ((XmlSchemaType)Item);
68 else if (Item is XmlSchemaElement)
69 ReadXmlSchemaElement (Item as XmlSchemaElement, ElementType.ELEMENT_UNDEFINED);
72 private void ReadXmlSchemaSequence (XmlSchemaSequence Sequence)
74 ReadXmlSchemaSequence (Sequence, null);
77 private void ReadXmlSchemaSequence (XmlSchemaSequence Sequence, DataTable Table)
79 foreach (XmlSchemaObject TempObj in Sequence.Items) {
81 if (TempObj is XmlSchemaElement)
82 ReadXmlSchemaElement (TempObj as XmlSchemaElement, ElementType.ELEMENT_COLUMN, Table);
87 private void ReadXmlSchemaChoice (XmlSchemaChoice Choice)
89 XmlSchemaObject SchemaObject;
90 foreach (XmlSchemaObject TempObject in Choice.Items) {
92 if ((SchemaObject = TempObject as XmlSchemaElement) != null)
93 ReadXmlSchemaElement ((XmlSchemaElement)SchemaObject, ElementType.ELEMENT_TABLE);
97 private void ReadXmlSchemaElement (XmlSchemaElement Element)
99 ReadXmlSchemaElement (Element, ElementType.ELEMENT_UNDEFINED);
102 private void ReadXmlSchemaElement (XmlSchemaElement Element, ElementType ElType)
104 ReadXmlSchemaElement (Element, ElType, null);
107 private void ReadXmlSchemaElement (XmlSchemaElement Element, ElementType ElType, DataTable Table)
109 Hashtable Attributes = ReadUnhandledAttributes (Element.UnhandledAttributes);
110 DataTable Table2 = null;
112 if (Attributes.Contains ("IsDataSet")) { // DataSet -elemt
114 if (String.Compare (Attributes ["IsDataSet"].ToString (), "true", true) == 0)
115 DSet.DataSetName = Element.Name;
117 else if (Element.SchemaTypeName != null && Element.SchemaTypeName.Namespace != XmlConstants.SchemaNamespace
118 && Element.SchemaTypeName.Name != String.Empty) {
121 // If type is not standard type
124 DataTable TempTable = new DataTable (Element.Name);
125 DSet.Tables.Add (TempTable);
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);
134 else if (Element.RefName != null && Element.RefName.Name != string.Empty) { // if there is a ref=
136 if (ElementCollection.Contains (Element.RefName.Name))
137 ReadXmlSchemaElement ((XmlSchemaElement)ElementCollection [Element.RefName.Name], ElementType.ELEMENT_TABLE);
139 else if (ElementType.ELEMENT_UNDEFINED != ElType) {
141 if (ElType == ElementType.ELEMENT_TABLE)
143 else if (ElType == ElementType.ELEMENT_COLUMN && Table != null)
144 ReadColumn (Element, Table);
147 // this element is undefined, for now
148 ElementCollection.Add (Element.Name, Element);
152 if (Element.SchemaType != null)
153 ReadXmlSchemaType (Element.SchemaType);
155 // Read possible constraints
156 if (Element.Constraints != null && Element.Constraints.Count > 0)
157 ReadXmlSchemaConstraints (Element.Constraints);
160 private void ReadTable (XmlSchemaElement Element)
162 DataTable TempTable = new DataTable (Element.Name);
163 DSet.Tables.Add (TempTable);
164 ReadXmlSchemaType (Element.SchemaType, TempTable);
167 private void ReadColumn (XmlSchemaElement Element, DataTable Table)
169 DataColumn Column = new DataColumn (Element.Name);
170 Table.Columns.Add (Column);
172 if (Element.UnhandledAttributes != null) {
174 foreach (XmlAttribute Attr in Element.UnhandledAttributes) {
176 switch (Attr.LocalName) {
179 Column.Caption = Attr.Value;
182 Column.DataType = Type.GetType (Attr.Value);
194 // Handel rest of the parameters
197 if (Column.DataType == null)
198 Column.DataType = Type.GetType ("System.String");
200 if (Element.DefaultValue != null)
201 Column.DefaultValue = Element.DefaultValue;
203 // If Element have type
204 if (Element.SchemaType != null)
205 ReadXmlSchemaType (Element.SchemaType, Column);
208 // Makes new Hashtable of the attributes.
209 private Hashtable ReadUnhandledAttributes (XmlAttribute [] Attributes)
211 Hashtable Result = new Hashtable ();
213 if (Attributes == null)
216 foreach (XmlAttribute attribute in Attributes) {
217 Result.Add (attribute.LocalName, attribute.Value);
223 private void ReadXmlSchemaConstraints (XmlSchemaObjectCollection Constraints)
225 foreach (XmlSchemaObject Constraint in Constraints) {
227 if (Constraint is XmlSchemaUnique)
228 ReadXmlSchemaUnique ((XmlSchemaUnique)Constraint);
233 private void ReadXmlSchemaUnique (XmlSchemaUnique Unique)
235 // FIXME: Parsing XPath
237 string TableName = Unique.Selector.XPath;
238 if (TableName.StartsWith (".//"))
239 TableName = TableName.Substring (3);
241 DataColumn [] Columns;
242 if (DSet.Tables.Contains (TableName)) {
244 DataTable Table = DSet.Tables [TableName];
245 Columns = new DataColumn [Unique.Fields.Count];
247 foreach (XmlSchemaXPath Field in Unique.Fields) {
249 if (Table.Columns.Contains (Field.XPath)) {
250 Table.Columns [Field.XPath].Unique = true;
251 Columns [i] = Table.Columns [Field.XPath];
256 UniqueConstraint Constraint = new UniqueConstraint (Unique.Name, Columns);
260 #endregion // Private methods
262 #region Private listeners
264 private void OnXmlSchemaValidation (object sender, ValidationEventArgs args)
269 #endregion // Private listeners
271 #region Private TypeReaders
273 // Reads XmlSchemaType
274 private void ReadXmlSchemaType (XmlSchemaType SchemaType)
276 ReadXmlSchemaType (SchemaType, (DataTable)null);
279 // Reads XmlSchemaType and decides is it Complex or Simple and continue reading those types
280 private void ReadXmlSchemaType (XmlSchemaType SchemaType, DataTable Table)
282 if (SchemaType is XmlSchemaComplexType)
283 ReadXmlSchemaComplexType ((XmlSchemaComplexType)SchemaType, Table);
284 else if (SchemaType is XmlSchemaSimpleType)
285 ReadXmlSchemaSimpleType ((XmlSchemaSimpleType)SchemaType, Table);
288 // Same as above but with DataColumn
289 private void ReadXmlSchemaType (XmlSchemaType SchemaType, DataColumn Column)
291 if (SchemaType is XmlSchemaComplexType)
292 ReadXmlSchemaComplexType ((XmlSchemaComplexType)SchemaType, Column);
293 else if (SchemaType is XmlSchemaSimpleType)
294 ReadXmlSchemaSimpleType ((XmlSchemaSimpleType)SchemaType, Column);
297 #endregion // PrivateTypeReader
299 #region TypeReaderHelppers
301 private void ReadXmlSchemaSimpleType (XmlSchemaSimpleType SimpleType, DataColumn Column)
304 if (SimpleType.Content is XmlSchemaSimpleTypeRestriction)
305 ReadXmlSchemaSimpleTypeRestriction ((XmlSchemaSimpleTypeRestriction)SimpleType.Content, Column);
309 private void ReadXmlSchemaSimpleType (XmlSchemaSimpleType SimpleType, DataTable Table)
311 // TODO: Is it possible that Table-element have simpletype???
315 private void ReadXmlSchemaSimpleTypeRestriction (XmlSchemaSimpleTypeRestriction Restriction, DataColumn Column)
317 foreach (XmlSchemaObject Facet in Restriction.Facets) {
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)
324 //else if (Facet is XmlSchemaLengthFacet)
326 //else if (Facet is XmlSchemaPatternFacet)
328 //else if (Facet is XmlSchemaEnumerationFacet)
330 //else if (Facet is XmlSchemaMaxInclusiveFacet)
332 //else if (Facet is XmlSchemaMaxExclusiveFacet)
334 //else if (Facet is XmlSchemaMinInclusiveFacet)
336 //else if (Facet is XmlSchemaMinExclusiveFacet)
338 //else if (Facet is XmlSchemaFractionDigitsFacet)
340 //else if (Facet is XmlSchemaTotalDigitsFacet)
342 //else if (Facet is XmlSchemaWhiteSpaceFacet)
348 private void ReadXmlSchemaComplexType (XmlSchemaComplexType Type, DataColumn Column)
350 // TODO: is it possible that column-element have complextype
353 // Reads XmlSchemaComplexType with DataTable
354 private void ReadXmlSchemaComplexType (XmlSchemaComplexType Type, DataTable Table)
356 XmlSchemaComplexType ComplexType = Type as XmlSchemaComplexType;
358 if (ComplexType.Name != null && ComplexType.Name != string.Empty) {
360 if (ElementCollection.Contains (ComplexType.Name)) {
362 if (ComplexType.Particle is XmlSchemaChoice) {
363 ReadXmlSchemaChoice (ComplexType.Particle as XmlSchemaChoice);
365 else if (ComplexType.Particle is XmlSchemaSequence) {
367 DataTable TempTable = ElementCollection [ComplexType.Name] as DataTable;
368 ElementCollection.Remove (ComplexType.Name);
369 ReadXmlSchemaSequence (ComplexType.Particle as XmlSchemaSequence, TempTable);
372 else if (ComplexType.Name != null && !TypeCollection.Contains (ComplexType.Name)) {
373 TypeCollection.Add (ComplexType.Name, ComplexType);
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);
384 XmlSchemaParticle Particle;
385 if ((Particle = ComplexType.Particle as XmlSchemaChoice) != null) {
386 ReadXmlSchemaChoice (Particle as XmlSchemaChoice);
388 else if ((Particle = ComplexType.Particle as XmlSchemaSequence) != null) {
389 ReadXmlSchemaSequence (Particle as XmlSchemaSequence, Table);
394 #endregion // TypeReaderHelppers