add ISafeSerializationData
[mcs.git] / tools / mono-xsd / XSD2Class.cs
blob36a646a063f61fdbc625920a444bfe4e92c9290a
1 //
2 // XSD2Class - xml schema based class generator
3 //
4 // Author
5 // Atsushi Enomoto (ginga@kit.hi-ho.ne.jp)
6 //
7 // (C)2003 Atsushi Enomoto
8 //
9 // TODO:
10 // * Currently it is developed with MS.NET and Microsoft.CSharp namespace.
11 // * Handling members of choice fields are on changing. No enum types are
12 // generated and/or collected and registered as fields of the enum.
13 // * maxOccurs should be considered (and should emit member as array, if
14 // required).
16 // * It is desirable to have an alternative generator that generates
17 // property members instead of simple fields, which checks their values
18 // in relation to their facets. (It may contradict XmlTypeMapping way,
19 // which seems not to have xml schema type itself, so we (they?) cannot
20 // get any facets from typemapping).
23 using System;
24 using System.CodeDom;
25 using System.Collections;
26 using System.Text;
27 using System.Xml;
28 using System.Xml.Schema;
29 using System.Xml.Serialization;
30 using Microsoft.CSharp;
32 namespace Commons.Xml.XSD2ClassLib
35 public class Driver
37 public static void Main (string [] args)
39 if (args.Length < 1) {
40 Console.WriteLine ("usage: xsd2class [filename]");
41 return;
43 XmlTextReader xtr = new XmlTextReader (args [0]);
44 // xtr.XmlResolver = null;
45 ValidationEventHandler errorHandler = new ValidationEventHandler (OnValidationError);
46 XmlSchema xs = XmlSchema.Read (xtr, errorHandler);
47 xs.Compile (errorHandler);
48 XmlSchemas schemas = new XmlSchemas ();
49 schemas.Add (xs);
50 new XSD2Class ().Generate (schemas);
53 static void OnValidationError (object o, ValidationEventArgs e)
55 // Hey... is it sane doing !?
56 Console.WriteLine (e.Exception.ToString ());
62 public class XSD2Class
64 XmlSchemas schemas;
65 CodeCompileUnit codeCompileUnit;
66 CodeNamespace codeNamespace;
67 CodeTypeDeclaration currentType;
68 Hashtable codeTypes = new Hashtable ();
70 // Constructor
72 public XSD2Class ()
76 // Main process
78 public void Generate (XmlSchemas schemas)
80 Generate (schemas, new CodeNamespace ());
83 public void Generate (XmlSchemas schemas, CodeNamespace codeNamespace)
85 Generate (schemas, codeNamespace, new CodeCompileUnit ());
88 public void Generate (XmlSchemas schemas,
89 CodeNamespace codeNamespace,
90 CodeCompileUnit codeCompileUnit)
92 this.schemas = schemas;
93 this.codeCompileUnit = codeCompileUnit;
94 this.codeNamespace = codeNamespace;
95 codeCompileUnit.Namespaces.Add (codeNamespace);
97 foreach (XmlSchema schema in schemas)
98 GenerateSchemaTypes (schema);
100 new CSharpCodeProvider ().CreateGenerator ().GenerateCodeFromCompileUnit (codeCompileUnit, Console.Out, null);
103 public void GenerateSchemaTypes (XmlSchema schema)
105 foreach (XmlSchemaObject sob in schema.Items) {
106 XmlSchemaElement element = sob as XmlSchemaElement;
107 if (element == null)
108 continue;
109 XmlSchemaComplexType xsType = element.ElementType as XmlSchemaComplexType;
110 if (xsType == null)
111 continue;
113 GenerateComplexType (element.QualifiedName.Name, xsType);
117 // Type generation
119 private void GenerateComplexType (XmlSchemaComplexType xsType)
121 GenerateComplexType ("", xsType);
124 private void GenerateComplexType (string elementName, XmlSchemaComplexType xsType)
126 string typeName = xsType.QualifiedName.Name;
127 if (typeName == "")
128 typeName = elementName;
129 if (codeTypes.Contains (typeName))
130 return;
132 currentType = CreateType (typeName);
133 codeTypes.Add (xsType.QualifiedName.Name, currentType);
134 codeNamespace.Types.Add (currentType);
135 // base type
136 XmlSchemaComplexType baseComplexType = xsType.BaseSchemaType as XmlSchemaComplexType;
137 if (baseComplexType != null) {
138 GenerateComplexType (baseComplexType);
139 // currentType.BaseTypes = new CodeTypeReferenceCollection ();
140 currentType.BaseTypes.Add (new CodeTypeReference (((CodeTypeDeclaration) codeTypes [baseComplexType.QualifiedName.Name]).Name));
141 } else if (xsType.BaseSchemaType != null) {
142 // TODO: insufficient. e.g. XmlQualifiedName
143 currentType.BaseTypes.Add (new CodeTypeReference (((XmlSchemaSimpleType) xsType.BaseSchemaType).Name));
146 // anyAttribute
147 if (xsType.AnyAttribute != null)
148 currentType.Members.Add (CreateMemberField (
149 typeof (XmlAttribute).FullName, "AnyAttr", XmlStructureType.AnyAttribute));
151 // attributes
152 foreach (XmlSchemaAttribute schemaAtt in xsType.Attributes)
153 GenerateAttributeField (schemaAtt);
155 // elements
156 if (xsType.Particle != null) {
157 // particle
158 GenerateParticleField (xsType.Particle);
159 } else if (xsType.ContentModel != null) {
160 XmlSchemaComplexContentExtension ce = xsType.ContentModel.Content as XmlSchemaComplexContentExtension;
161 XmlSchemaComplexContentRestriction cr = xsType.ContentModel.Content as XmlSchemaComplexContentRestriction;
162 if (ce != null)
163 GenerateParticleField (ce.Particle);
164 else if (cr != null)
165 GenerateParticleField (cr.Particle);
166 // TODO: handle simpleContent (how to?)
170 // Field generation
172 private void GenerateAttributeField (XmlSchemaAttribute schemaAtt)
174 XmlSchemaDatatype primitive = schemaAtt.AttributeType
175 as XmlSchemaDatatype;
176 XmlSchemaSimpleType simple = schemaAtt.AttributeType
177 as XmlSchemaSimpleType;
178 XmlSchemaDerivationMethod deriv =
179 XmlSchemaDerivationMethod.None;
181 while (primitive == null) {
182 if (simple == null) // maybe union
183 break;
184 primitive = simple.BaseSchemaType
185 as XmlSchemaDatatype;
186 if (primitive == null) {
187 simple = simple.BaseSchemaType
188 as XmlSchemaSimpleType;
189 if (simple != null && simple.DerivedBy != XmlSchemaDerivationMethod.None)
190 deriv = simple.DerivedBy;
194 Type type = primitive != null ?
195 primitive.ValueType : typeof (object);
196 bool isList = (simple != null && simple.DerivedBy == XmlSchemaDerivationMethod.List);
197 CodeTypeReference cType = new CodeTypeReference (type);
198 cType.ArrayRank = isList ? 1 : 0;
200 CodeMemberField cmf = CreateMemberField (cType, schemaAtt.QualifiedName.Name, XmlStructureType.Attribute);
201 currentType.Members.Add (cmf);
204 private void GenerateElementField (XmlSchemaElement schemaElem)
206 CodeMemberField cmf;
208 XmlSchemaDatatype dt =
209 schemaElem.ElementType as XmlSchemaDatatype;
210 XmlSchemaSimpleType st =
211 schemaElem.ElementType as XmlSchemaSimpleType;
212 // TODO: see GenerateAttributeField to know how to get correct type.
213 if (st != null)
214 dt = st.Datatype;
215 bool isList = (st != null && st.DerivedBy == XmlSchemaDerivationMethod.List);
217 if (schemaElem.ElementType == null) {
218 CodeTypeReference cType = new CodeTypeReference (typeof (object));
219 cType.ArrayRank = isList ? 1 : 0;
220 cmf = CreateMemberField (cType,
221 schemaElem.QualifiedName.Name);
222 currentType.Members.Add (cmf);
223 } else if (dt != null) {
224 // simple type member.
225 CodeTypeReference cType = new CodeTypeReference (dt.ValueType);
226 cType.ArrayRank = isList ? 1 : 0;
227 cmf = CreateMemberField (cType,
228 schemaElem.QualifiedName.Name);
229 currentType.Members.Add (cmf);
230 } else {
231 // complex type member.
232 XmlSchemaComplexType ct = schemaElem.ElementType
233 as XmlSchemaComplexType;
235 CodeTypeDeclaration ctd = currentType;
236 GenerateComplexType (ct);
237 currentType = ctd;
238 CodeTypeDeclaration cType = codeTypes [ct.QualifiedName.Name] as CodeTypeDeclaration;
239 cmf = CreateMemberField (cType.Name, schemaElem.QualifiedName.Name);
240 currentType.Members.Add (cmf);
244 private void GenerateParticleField (XmlSchemaParticle particle)
246 if (particle is XmlSchemaAny)
247 GenerateParticleAnyField (particle
248 as XmlSchemaAny);
249 else if (particle is XmlSchemaElement)
250 GenerateElementField (particle
251 as XmlSchemaElement);
252 else if (particle is XmlSchemaAll)
253 GenerateParticleAllField (particle
254 as XmlSchemaAll);
255 else if (particle is XmlSchemaChoice)
256 GenerateParticleChoiceField (particle
257 as XmlSchemaChoice);
258 else if (particle is XmlSchemaSequence)
259 GenerateParticleSequenceField (particle
260 as XmlSchemaSequence);
261 else if (particle is XmlSchemaGroupRef) {
262 XmlSchemaGroupRef gRef = particle
263 as XmlSchemaGroupRef;
264 GenerateGroupField (FindGroup (gRef.RefName));
268 private void GenerateParticleAnyField (XmlSchemaAny xsany)
270 CodeMemberField cmf = CreateMemberField (
271 typeof (XmlElement).FullName, "Any");
272 currentType.Members.Add (cmf);
275 private void GenerateParticleAllField (XmlSchemaAll xsall)
277 foreach (XmlSchemaParticle cp in xsall.Items)
278 GenerateParticleField (cp);
281 private void GenerateParticleSequenceField (XmlSchemaSequence sequence)
283 foreach (XmlSchemaParticle cp in sequence.Items)
284 GenerateParticleField (cp);
287 private void GenerateParticleChoiceField (XmlSchemaChoice choice)
289 #if true
290 foreach (XmlSchemaParticle cp in choice.Items)
291 GenerateParticleField (cp);
292 #else
293 // TODO: first, collect all choice alternatives that
294 // they might be common typed elements. In such case,
295 // no enum fields and types should be created.
296 Type itemType = typeof (Object);
298 // enum type generation
299 // [XmlType (IncludeInSchema=false)]
300 CodeTypeDeclaration enumType = CreateType ("ItemChoiceType", false);
301 enumType.IsEnum = true;
302 // TODO: add enum members.
303 codeNamespace.Types.Add (enumType);
305 // add enum field
306 CodeMemberField cid = CreateMemberField (
307 enumType.Name, "ItemElementType");
308 cid.CustomAttributes.Add (new CodeAttributeDeclaration (
309 typeof (XmlIgnoreAttribute).FullName));
310 currentType.Members.Add (cid);
312 // add item field
313 // TODO: type should be computed whether common or not.
314 CodeMemberField cmf = CreateMemberField (
315 itemType.FullName, "Item");
316 CodeAttributeDeclaration choiceIdent =
317 new CodeAttributeDeclaration (
318 typeof (XmlChoiceIdentifierAttribute).FullName);
319 choiceIdent.Arguments.Add (new CodeAttributeArgument (
320 "MemberName",
321 new CodePrimitiveExpression (cid.Name)));
322 cmf.CustomAttributes.Add (choiceIdent);
323 currentType.Members.Add (cmf);
324 #endif
327 private void GenerateGroupField (XmlSchemaGroup group)
329 GenerateParticleField (group.Particle);
332 // CreateMemberField
334 private CodeMemberField CreateMemberField (string typeName, string name)
336 return CreateMemberField (typeName, name, XmlStructureType.Element);
339 private CodeMemberField CreateMemberField (string typeName, string name, XmlStructureType sType)
341 return CreateMemberField (new CodeTypeReference (typeName), name, sType);
344 private CodeMemberField CreateMemberField (CodeTypeReference reference, string name)
346 return CreateMemberField (reference, name, XmlStructureType.Element);
349 private CodeMemberField CreateMemberField (CodeTypeReference reference, string xmlName, XmlStructureType sType)
351 int i = 1;
352 string clrName = xmlName;
353 if (CodeMemberContains (clrName)) {
354 while (CodeMemberContains (clrName + i))
355 i++;
356 clrName = clrName + i;
359 CodeMemberField cmf = new CodeMemberField (reference, clrName);
360 cmf.Attributes = MemberAttributes.Public;
362 switch (sType) {
363 case XmlStructureType.Element:
364 if (clrName != xmlName)
365 cmf.CustomAttributes.Add (CreateXmlAttribute (typeof (XmlElementAttribute), xmlName));
366 break;
367 case XmlStructureType.Attribute:
368 cmf.CustomAttributes.Add (CreateXmlAttribute (typeof (XmlAttributeAttribute), clrName != xmlName ? xmlName : null));
369 break;
370 case XmlStructureType.AnyAttribute:
371 cmf.CustomAttributes.Add (CreateXmlAttribute (typeof (XmlAnyAttributeAttribute), null));
372 reference.ArrayRank = 1;
373 break;
376 return cmf;
379 // CreateType
381 private CodeTypeDeclaration CreateType (string xmlName)
383 return CreateType (xmlName, true);
386 private CodeTypeDeclaration CreateType (string xmlName, bool includeInSchema)
388 int i = 1;
389 string clrName = CodeIdentifier.MakeValid (xmlName);
390 if (CodeTypeContains (clrName)) {
391 while (CodeTypeContains (clrName + i))
392 i++;
393 clrName = clrName + i;
396 CodeTypeDeclaration decl = new CodeTypeDeclaration (clrName);
397 if (includeInSchema) {
398 if (xmlName != clrName)
399 decl.CustomAttributes.Add (CreateXmlAttribute (typeof (XmlTypeAttribute), xmlName));
400 } else {
401 CodeAttributeDeclaration xt = new CodeAttributeDeclaration (typeof (XmlTypeAttribute).FullName);
402 xt.Arguments.Add (new CodeAttributeArgument (
403 "IncludeInSchema",
404 new CodePrimitiveExpression (false)));
405 decl.CustomAttributes.Add (xt);
407 return decl;
410 // Utilities
412 private XmlSchemaGroup FindGroup (XmlQualifiedName qname)
414 foreach (XmlSchema schema in schemas) {
415 foreach (XmlQualifiedName name in schema.Groups.Names) {
416 XmlSchemaGroup group = schema.Groups [name] as XmlSchemaGroup;
417 if (group.Name == qname.Name)
418 return group;
421 return null;
424 private bool CodeTypeContains (string name)
426 for (int i=0; i<codeNamespace.Types.Count; i++)
427 if (codeNamespace.Types [i].Name == name)
428 return true;
429 return false;
432 private bool CodeMemberContains (string name)
434 for (int i=0; i<currentType.Members.Count; i++)
435 if (currentType.Members [i].Name == name)
436 return true;
437 return false;
440 private CodeAttributeDeclaration CreateXmlAttribute (Type attrType, string name)
442 CodeAttributeDeclaration xmlAtt = new CodeAttributeDeclaration (attrType.FullName);
443 if (name != null)
444 xmlAtt.Arguments.Add (new CodeAttributeArgument ("Name", new CodePrimitiveExpression (name)));
446 return xmlAtt;
449 #if false
450 // XmlSchemaImporter emulation
452 public XmlTypeMapping ImportTypeMapping (XmlQualifiedName qname)
454 XmlSchemaComplexType xsType = FindComplexType (qname);
455 if (xsType == null)
456 throw new InvalidOperationException ("Type " + qname + " not found.");
458 GenerateComplexType (xsType);
459 return null;
462 private XmlSchemaComplexType FindComplexType (XmlQualifiedName qname)
464 foreach (XmlSchema schema in schemas) {
465 foreach (XmlQualifiedName name in schema.SchemaTypes.Names) {
466 XmlSchemaType xsType = schema.SchemaTypes [name] as XmlSchemaType;
467 if (xsType is XmlSchemaSimpleType)
468 continue;
469 if (xsType.QualifiedName == qname)
470 return xsType as XmlSchemaComplexType;
473 return null;
475 #endif
478 internal enum XmlStructureType
480 Element,
481 Attribute,
482 AnyAttribute