2 // XSD2Class - xml schema based class generator
5 // Atsushi Enomoto (ginga@kit.hi-ho.ne.jp)
7 // (C)2003 Atsushi Enomoto
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
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).
25 using System
.Collections
;
28 using System
.Xml
.Schema
;
29 using System
.Xml
.Serialization
;
30 using Microsoft
.CSharp
;
32 namespace Commons
.Xml
.XSD2ClassLib
37 public static void Main (string [] args)
39 if (args.Length < 1) {
40 Console.WriteLine ("usage: xsd2class [filename]");
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 ();
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
65 CodeCompileUnit codeCompileUnit
;
66 CodeNamespace codeNamespace
;
67 CodeTypeDeclaration currentType
;
68 Hashtable codeTypes
= new Hashtable ();
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
;
109 XmlSchemaComplexType xsType
= element
.ElementType
as XmlSchemaComplexType
;
113 GenerateComplexType (element
.QualifiedName
.Name
, xsType
);
119 private void GenerateComplexType (XmlSchemaComplexType xsType
)
121 GenerateComplexType ("", xsType
);
124 private void GenerateComplexType (string elementName
, XmlSchemaComplexType xsType
)
126 string typeName
= xsType
.QualifiedName
.Name
;
128 typeName
= elementName
;
129 if (codeTypes
.Contains (typeName
))
132 currentType
= CreateType (typeName
);
133 codeTypes
.Add (xsType
.QualifiedName
.Name
, currentType
);
134 codeNamespace
.Types
.Add (currentType
);
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
));
147 if (xsType
.AnyAttribute
!= null)
148 currentType
.Members
.Add (CreateMemberField (
149 typeof (XmlAttribute
).FullName
, "AnyAttr", XmlStructureType
.AnyAttribute
));
152 foreach (XmlSchemaAttribute schemaAtt
in xsType
.Attributes
)
153 GenerateAttributeField (schemaAtt
);
156 if (xsType
.Particle
!= null) {
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
;
163 GenerateParticleField (ce
.Particle
);
165 GenerateParticleField (cr
.Particle
);
166 // TODO: handle simpleContent (how to?)
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
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
)
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.
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
);
231 // complex type member.
232 XmlSchemaComplexType ct
= schemaElem
.ElementType
233 as XmlSchemaComplexType
;
235 CodeTypeDeclaration ctd
= currentType
;
236 GenerateComplexType (ct
);
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
249 else if (particle
is XmlSchemaElement
)
250 GenerateElementField (particle
251 as XmlSchemaElement
);
252 else if (particle
is XmlSchemaAll
)
253 GenerateParticleAllField (particle
255 else if (particle
is XmlSchemaChoice
)
256 GenerateParticleChoiceField (particle
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
)
290 foreach (XmlSchemaParticle cp
in choice
.Items
)
291 GenerateParticleField (cp
);
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
);
306 CodeMemberField cid
= CreateMemberField (
307 enumType
.Name
, "ItemElementType");
308 cid
.CustomAttributes
.Add (new CodeAttributeDeclaration (
309 typeof (XmlIgnoreAttribute
).FullName
));
310 currentType
.Members
.Add (cid
);
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 (
321 new CodePrimitiveExpression (cid
.Name
)));
322 cmf
.CustomAttributes
.Add (choiceIdent
);
323 currentType
.Members
.Add (cmf
);
327 private void GenerateGroupField (XmlSchemaGroup
group)
329 GenerateParticleField (group.Particle
);
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
)
352 string clrName
= xmlName
;
353 if (CodeMemberContains (clrName
)) {
354 while (CodeMemberContains (clrName
+ i
))
356 clrName
= clrName
+ i
;
359 CodeMemberField cmf
= new CodeMemberField (reference
, clrName
);
360 cmf
.Attributes
= MemberAttributes
.Public
;
363 case XmlStructureType
.Element
:
364 if (clrName
!= xmlName
)
365 cmf
.CustomAttributes
.Add (CreateXmlAttribute (typeof (XmlElementAttribute
), xmlName
));
367 case XmlStructureType
.Attribute
:
368 cmf
.CustomAttributes
.Add (CreateXmlAttribute (typeof (XmlAttributeAttribute
), clrName
!= xmlName
? xmlName
: null));
370 case XmlStructureType
.AnyAttribute
:
371 cmf
.CustomAttributes
.Add (CreateXmlAttribute (typeof (XmlAnyAttributeAttribute
), null));
372 reference
.ArrayRank
= 1;
381 private CodeTypeDeclaration
CreateType (string xmlName
)
383 return CreateType (xmlName
, true);
386 private CodeTypeDeclaration
CreateType (string xmlName
, bool includeInSchema
)
389 string clrName
= CodeIdentifier
.MakeValid (xmlName
);
390 if (CodeTypeContains (clrName
)) {
391 while (CodeTypeContains (clrName
+ 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
));
401 CodeAttributeDeclaration xt
= new CodeAttributeDeclaration (typeof (XmlTypeAttribute
).FullName
);
402 xt
.Arguments
.Add (new CodeAttributeArgument (
404 new CodePrimitiveExpression (false)));
405 decl
.CustomAttributes
.Add (xt
);
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
)
424 private bool CodeTypeContains (string name
)
426 for (int i
=0; i
<codeNamespace
.Types
.Count
; i
++)
427 if (codeNamespace
.Types
[i
].Name
== name
)
432 private bool CodeMemberContains (string name
)
434 for (int i
=0; i
<currentType
.Members
.Count
; i
++)
435 if (currentType
.Members
[i
].Name
== name
)
440 private CodeAttributeDeclaration
CreateXmlAttribute (Type attrType
, string name
)
442 CodeAttributeDeclaration xmlAtt
= new CodeAttributeDeclaration (attrType
.FullName
);
444 xmlAtt
.Arguments
.Add (new CodeAttributeArgument ("Name", new CodePrimitiveExpression (name
)));
450 // XmlSchemaImporter emulation
452 public XmlTypeMapping
ImportTypeMapping (XmlQualifiedName qname
)
454 XmlSchemaComplexType xsType
= FindComplexType (qname
);
456 throw new InvalidOperationException ("Type " + qname
+ " not found.");
458 GenerateComplexType (xsType
);
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
)
469 if (xsType
.QualifiedName
== qname
)
470 return xsType
as XmlSchemaComplexType
;
478 internal enum XmlStructureType