2 // XsdDataContractImporter.cs
5 // Atsushi Enomoto <atsushi@ximian.com>
7 // Copyright (C) 2010 Novell, Inc. http://www.novell.com
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 using System.CodeDom.Compiler;
32 using System.Collections.Generic;
35 using System.Reflection;
37 using System.Xml.Schema;
38 using System.Xml.Serialization;
40 namespace System.Runtime.Serialization
42 [MonoTODO ("Support ImportXmlType option; support arrays; CanImport is not up to date with Import")]
43 public class XsdDataContractImporter
45 static readonly XmlQualifiedName qname_anytype = new XmlQualifiedName ("anyType", XmlSchema.Namespace);
47 public XsdDataContractImporter ()
52 public XsdDataContractImporter (CodeCompileUnit codeCompileUnit)
54 // null argument is ok.
55 CodeCompileUnit = codeCompileUnit ?? new CodeCompileUnit ();
57 // Options is null by default
60 public CodeCompileUnit CodeCompileUnit { get; private set; }
62 CodeDomProvider code_provider = CodeDomProvider.CreateProvider ("csharp");
63 Dictionary<CodeNamespace,CodeIdentifiers> identifiers_table = new Dictionary<CodeNamespace,CodeIdentifiers> ();
64 ImportOptions import_options;
66 public ImportOptions Options {
67 get { return import_options; }
69 import_options = value;
70 code_provider = value.CodeProvider ?? code_provider;
76 public bool CanImport (XmlSchemaSet schemas)
79 throw new ArgumentNullException ("schemas");
81 if (!schemas.IsCompiled)
84 foreach (XmlSchemaElement xe in schemas.GlobalElements.Values)
85 if (!CanImport (schemas, xe))
90 public bool CanImport (XmlSchemaSet schemas, ICollection<XmlQualifiedName> typeNames)
93 throw new ArgumentNullException ("schemas");
94 if (typeNames == null)
95 throw new ArgumentNullException ("typeNames");
97 if (!schemas.IsCompiled)
100 foreach (var name in typeNames)
101 if (!CanImport (schemas, name))
106 public bool CanImport (XmlSchemaSet schemas, XmlQualifiedName typeName)
109 throw new ArgumentNullException ("schemas");
110 if (typeName == null)
111 throw new ArgumentNullException ("typeName");
113 if (!schemas.IsCompiled)
116 if (!schemas.GlobalTypes.Contains (typeName))
117 throw new InvalidDataContractException (String.Format ("Type {0} is not found in the schemas", typeName));
119 return CanImport (schemas, schemas.GlobalTypes [typeName] as XmlSchemaComplexType);
122 public bool CanImport (XmlSchemaSet schemas, XmlSchemaElement element)
125 throw new ArgumentNullException ("schemas");
127 if (!schemas.IsCompiled)
130 return CanImport (schemas, element.ElementSchemaType as XmlSchemaComplexType);
133 bool CanImport (XmlSchemaSet schemas, XmlSchemaComplexType type)
135 if (type == null || type.QualifiedName.Namespace == XmlSchema.Namespace) // xs:anyType -> not supported.
138 if (type.ContentModel is XmlSchemaSimpleContent) // simple content derivation is not supported.
140 if (type.ContentModel != null && type.ContentModel.Content != null) {
141 var xscce = type.ContentModel.Content as XmlSchemaComplexContentExtension;
142 if (xscce == null) // complex DBR is not supported.
145 if (xscce.BaseTypeName != qname_anytype && !CanImport (schemas, xscce.BaseTypeName))
154 public void Import (XmlSchemaSet schemas)
157 throw new ArgumentNullException ("schemas");
159 if (!schemas.IsCompiled)
162 foreach (XmlSchemaElement xe in schemas.GlobalElements.Values)
163 Import (schemas, xe);
166 public void Import (XmlSchemaSet schemas, ICollection<XmlQualifiedName> typeNames)
169 throw new ArgumentNullException ("schemas");
170 if (typeNames == null)
171 throw new ArgumentNullException ("typeNames");
172 foreach (var name in typeNames)
173 Import (schemas, name);
176 // This checks type existence and raises an error if it is missing.
177 public void Import (XmlSchemaSet schemas, XmlQualifiedName typeName)
180 throw new ArgumentNullException ("schemas");
181 if (typeName == null)
182 throw new ArgumentNullException ("typeName");
184 if (IsPredefinedType (typeName))
187 if (!schemas.GlobalTypes.Contains (typeName))
188 throw new InvalidDataContractException (String.Format ("Type {0} is not found in the schemas", typeName));
190 Import (schemas, schemas.GlobalTypes [typeName] as XmlSchemaType, typeName);
193 public XmlQualifiedName Import (XmlSchemaSet schemas, XmlSchemaElement element)
196 throw new ArgumentNullException ("schemas");
198 throw new ArgumentNullException ("element");
200 var elname = element.QualifiedName;
202 switch (elname.Namespace) {
203 case KnownTypeCollection.MSSimpleNamespace:
204 switch (elname.Name) {
213 // FIXME: use element to fill nillable and arrays.
214 var qname = element.SchemaType != null ? element.QualifiedName : element.ElementSchemaType.QualifiedName;
215 Import (schemas, element.ElementSchemaType, qname);
219 void Import (XmlSchemaSet schemas, XmlSchemaType type)
221 Import (schemas, type, type.QualifiedName);
224 void Import (XmlSchemaSet schemas, XmlSchemaType type, XmlQualifiedName qname)
226 var existing = imported_types.FirstOrDefault (it => it.XsdType == type);
227 if (existing != null)
228 return;// existing.XsdTypeName;
230 if (IsPredefinedType (type.QualifiedName))
233 DoImport (schemas, type, qname);
236 string GetUniqueName (string name, CodeNamespace cns)
239 if (!identifiers_table.TryGetValue (cns, out i)) {
240 i = new CodeIdentifiers ();
241 identifiers_table.Add (cns, i);
243 return i.AddUnique (name, null);
246 void DoImport (XmlSchemaSet schemas, XmlSchemaType type, XmlQualifiedName qname)
248 CodeNamespace cns = null;
249 CodeTypeReference clrRef;
250 cns = GetCodeNamespace (qname);
251 clrRef = new CodeTypeReference (cns.Name.Length > 0 ? cns.Name + "." + qname.Name : qname.Name);
253 var td = new CodeTypeDeclaration () {
254 Name = GetUniqueName (CodeIdentifier.MakeValid (qname.Name), cns),
255 TypeAttributes = GenerateInternal ? TypeAttributes.NotPublic : TypeAttributes.Public };
258 var info = new TypeImportInfo () { ClrType = clrRef, XsdType = type, XsdTypeName = qname };
259 imported_types.Add (info);
261 var st = type as XmlSchemaSimpleType;
263 ImportSimpleType (td, schemas, st, qname);
265 var ct = (XmlSchemaComplexType) type;
266 var sc = ct.ContentModel as XmlSchemaSimpleContent;
268 if (sc.Content is XmlSchemaSimpleContentExtension)
269 throw new InvalidDataContractException (String.Format ("complex type '{0}' with simple content extension is not supported", type.QualifiedName));
271 if (!ImportComplexType (td, schemas, ct, qname)) {
272 cns.Types.Remove (td);
273 if (cns.Types.Count == 0)
274 CodeCompileUnit.Namespaces.Remove (cns);
278 foreach (var impinfo in imported_types)
279 for (; impinfo.KnownTypeOutputIndex < impinfo.KnownClrTypes.Count; impinfo.KnownTypeOutputIndex++)
280 td.CustomAttributes.Add (new CodeAttributeDeclaration (
281 new CodeTypeReference (typeof (KnownTypeAttribute)),
282 new CodeAttributeArgument (new CodeTypeOfExpression (impinfo.KnownClrTypes [impinfo.KnownTypeOutputIndex]))));
285 static readonly string ass_name = typeof (DataContractAttribute).Assembly.GetName ().Name;
286 static readonly string ass_version = typeof (DataContractAttribute).Assembly.GetName ().Version.ToString ();
287 static readonly CodeTypeReference typeref_data_contract = new CodeTypeReference (typeof (DataContractAttribute));
288 static readonly CodeTypeReference typeref_coll_contract = new CodeTypeReference (typeof (CollectionDataContractAttribute));
290 void AddTypeAttributes (CodeTypeDeclaration td, XmlSchemaType type, params XmlSchemaElement [] collectionArgs)
292 var name = type.QualifiedName;
293 // [GeneratedCode (assembly_name, assembly_version)]
294 td.CustomAttributes.Add (new CodeAttributeDeclaration (
295 new CodeTypeReference (typeof (GeneratedCodeAttribute)),
296 new CodeAttributeArgument (new CodePrimitiveExpression (ass_name)),
297 new CodeAttributeArgument (new CodePrimitiveExpression (ass_version))));
299 var ct = type as XmlSchemaComplexType;
301 // [DataContract(Name="foobar",Namespace="urn:foobar")] (optionally IsReference=true),
302 // or [CollectionDataContract(ditto, ItemType/KeyType/ValueType)]
303 var dca = new CodeAttributeDeclaration (
304 collectionArgs != null && collectionArgs.Length > 0 ? typeref_coll_contract : typeref_data_contract,
305 new CodeAttributeArgument ("Name", new CodePrimitiveExpression (name.Name)),
306 new CodeAttributeArgument ("Namespace", new CodePrimitiveExpression (name.Namespace)));
307 if (collectionArgs != null) {
308 if (collectionArgs.Length > 0)
309 dca.Arguments.Add (new CodeAttributeArgument ("ItemName", new CodePrimitiveExpression (CodeIdentifier.MakeValid (collectionArgs [0].QualifiedName.Name))));
310 if (collectionArgs.Length > 2) {
311 dca.Arguments.Add (new CodeAttributeArgument ("KeyName", new CodePrimitiveExpression (CodeIdentifier.MakeValid (collectionArgs [1].QualifiedName.Name))));
312 dca.Arguments.Add (new CodeAttributeArgument ("ValueName", new CodePrimitiveExpression (CodeIdentifier.MakeValid (collectionArgs [2].QualifiedName.Name))));
315 if (ct != null && ct.AttributeUses [new XmlQualifiedName ("Ref", KnownTypeCollection.MSSimpleNamespace)] != null)
316 dca.Arguments.Add (new CodeAttributeArgument ("IsReference", new CodePrimitiveExpression (true)));
317 td.CustomAttributes.Add (dca);
319 // optional [Serializable]
320 if (Options != null && Options.GenerateSerializable)
321 td.CustomAttributes.Add (new CodeAttributeDeclaration ("System.SerializableAttribute"));
324 static readonly CodeTypeReference typeref_ext_iface = new CodeTypeReference ("System.Runtime.Serialization.IExtensibleDataObject");
325 static readonly CodeTypeReference typeref_ext_class = new CodeTypeReference ("System.Runtime.Serialization.ExtensionDataObject");
327 void AddExtensionData (CodeTypeDeclaration td)
329 td.BaseTypes.Add (typeref_ext_iface);
331 var field = new CodeMemberField (typeref_ext_class, "extensionDataField");
332 td.Members.Add (field);
334 var prop = new CodeMemberProperty () { Type = field.Type, Name = "ExtensionData", Attributes = (GenerateInternal ? MemberAttributes.Assembly : MemberAttributes.Public) | MemberAttributes.Final };
335 prop.GetStatements.Add (new CodeMethodReturnStatement (
336 new CodeFieldReferenceExpression (
337 new CodeThisReferenceExpression (),
338 "extensionDataField")));
339 prop.SetStatements.Add (new CodeAssignStatement (
340 new CodeFieldReferenceExpression (
341 new CodeThisReferenceExpression (),
342 "extensionDataField"),
343 new CodePropertySetValueReferenceExpression ()));
345 td.Members.Add (prop);
348 void ImportSimpleType (CodeTypeDeclaration td, XmlSchemaSet schemas, XmlSchemaSimpleType type, XmlQualifiedName qname)
350 var scl = type.Content as XmlSchemaSimpleTypeList;
352 if (scl.ItemType == null)
353 throw new InvalidDataContractException (String.Format ("simple type list is allowed only with an anonymous simple type with enumeration restriction content as its item type definition (type is {0})", type.QualifiedName));
354 var itemType = scl.ItemType as XmlSchemaSimpleType;
355 var ir = itemType.Content as XmlSchemaSimpleTypeRestriction;
357 throw new InvalidDataContractException (String.Format ("simple type list is allowed only with an anonymous simple type with enumeration restriction content as its item type definition (type is {0})", type.QualifiedName));
358 ImportEnum (td, schemas, ir, type, qname, true);
361 var scr = type.Content as XmlSchemaSimpleTypeRestriction;
363 ImportEnum (td, schemas, scr, type, qname, false);
367 throw new InvalidDataContractException (String.Format ("simple type is supported only if it has enumeration or list of an anonymous simple type with enumeration restriction content as its item type definition (type is {0})", qname));
370 static readonly CodeTypeReference enum_member_att_ref = new CodeTypeReference (typeof (EnumMemberAttribute));
372 void ImportEnum (CodeTypeDeclaration td, XmlSchemaSet schemas, XmlSchemaSimpleTypeRestriction r, XmlSchemaType type, XmlQualifiedName qname, bool isFlag)
374 if (isFlag && !r.BaseTypeName.Equals (new XmlQualifiedName ("string", XmlSchema.Namespace)))
375 throw new InvalidDataContractException (String.Format ("For flags enumeration '{0}', the base type for the simple type restriction must be XML schema string", qname));
378 AddTypeAttributes (td, type);
380 td.CustomAttributes.Add (new CodeAttributeDeclaration (new CodeTypeReference (typeof (FlagsAttribute))));
382 foreach (var facet in r.Facets) {
383 var e = facet as XmlSchemaEnumerationFacet;
385 throw new InvalidDataContractException (String.Format ("Invalid simple type restriction (type {0}). Only enumeration is allowed.", qname));
386 var em = new CodeMemberField () { Name = CodeIdentifier.MakeValid (e.Value) };
387 var ea = new CodeAttributeDeclaration (enum_member_att_ref);
388 if (e.Value != em.Name)
389 ea.Arguments.Add (new CodeAttributeArgument ("Value", new CodePrimitiveExpression (e.Value)));
390 em.CustomAttributes.Add (ea);
395 // Returns false if it should remove the imported type.
396 // FIXME: also support ImportXmlType
397 bool ImportComplexType (CodeTypeDeclaration td, XmlSchemaSet schemas, XmlSchemaComplexType type, XmlQualifiedName qname)
399 foreach (XmlSchemaAttribute att in type.AttributeUses.Values)
400 if (att.Use != XmlSchemaUse.Optional || att.QualifiedName.Namespace != KnownTypeCollection.MSSimpleNamespace)
401 throw new InvalidDataContractException (String.Format ("attribute in DataContract complex type '{0}' is limited to those in {1} namespace, and optional.", qname, KnownTypeCollection.MSSimpleNamespace));
403 CodeTypeReference baseClrType = null;
404 var particle = type.Particle;
405 if (type.ContentModel != null) {
406 var xsscr = type.ContentModel.Content as XmlSchemaSimpleContentRestriction;
408 if (xsscr.BaseType != null)
409 Import (schemas, xsscr.BaseType);
411 Import (schemas, xsscr.BaseTypeName);
412 // The above will result in an error, but make sure to show we don't support it.
413 throw new InvalidDataContractException (String.Format ("complex type simple content restriction is not supported in DataContract (type '{0}')", qname));
415 var xscce = type.ContentModel.Content as XmlSchemaComplexContentExtension;
417 Import (schemas, xscce.BaseTypeName);
418 baseClrType = GetCodeTypeReferenceInternal (xscce.BaseTypeName, false);
419 if (baseClrType != null)
420 td.BaseTypes.Add (baseClrType);
422 var baseInfo = GetTypeInfo (xscce.BaseTypeName, false);
423 if (baseInfo != null)
424 baseInfo.KnownClrTypes.Add (imported_types.First (it => it.XsdType == type).ClrType);
425 particle = xscce.Particle;
427 var xsccr = type.ContentModel.Content as XmlSchemaComplexContentRestriction;
429 throw new InvalidDataContractException (String.Format ("complex content type (for type '{0}') has a restriction content model, which is not supported in DataContract.", qname));
432 var seq = particle as XmlSchemaSequence;
433 if (seq == null && particle != null)
434 throw new InvalidDataContractException (String.Format ("Not supported particle {1}. In DataContract, only sequence particle is allowed as the top-level content of a complex type (type '{0}')", qname, particle));
438 foreach (var child in seq.Items)
439 if (!(child is XmlSchemaElement))
440 throw new InvalidDataContractException (String.Format ("Only local element is allowed as the content of the sequence of the top-level content of a complex type '{0}'. Other particles (sequence, choice, all, any, group ref) are not supported.", qname));
442 bool isDictionary = false;
443 if (type.Annotation != null) {
444 foreach (var ann in type.Annotation.Items) {
445 var ai = ann as XmlSchemaAppInfo;
446 if (ai != null && ai.Markup != null &&
447 ai.Markup.Length > 0 &&
448 ai.Markup [0].NodeType == XmlNodeType.Element &&
449 ai.Markup [0].LocalName == "IsDictionary" &&
450 ai.Markup [0].NamespaceURI == KnownTypeCollection.MSSimpleNamespace)
455 if (seq.Items.Count == 1) {
456 var xe = (XmlSchemaElement) seq.Items [0];
457 if (xe.MaxOccursString == "unbounded") {
458 // import as a collection contract.
460 var kvt = xe.ElementSchemaType as XmlSchemaComplexType;
461 var seq2 = kvt != null ? kvt.Particle as XmlSchemaSequence : null;
462 var k = seq2 != null && seq2.Items.Count == 2 ? seq2.Items [0] as XmlSchemaElement : null;
463 var v = seq2 != null && seq2.Items.Count == 2 ? seq2.Items [1] as XmlSchemaElement : null;
464 if (k == null || v == null)
465 throw new InvalidDataContractException (String.Format ("Invalid Dictionary contract type '{0}'. A Dictionary schema type must have a sequence particle which contains exactly two schema elements for key and value.", type.QualifiedName));
466 Import (schemas, k.ElementSchemaType);
467 Import (schemas, v.ElementSchemaType);
468 td.BaseTypes.Add (new CodeTypeReference ("System.Collections.Generic.Dictionary", GetCodeTypeReference (k.ElementSchemaType.QualifiedName), GetCodeTypeReference (v.ElementSchemaType.QualifiedName)));
469 AddTypeAttributes (td, type, xe, k, v);
471 } else if (type.QualifiedName.Namespace == KnownTypeCollection.MSArraysNamespace &&
472 IsPredefinedType (xe.ElementSchemaType.QualifiedName)) {
473 // then this CodeTypeDeclaration is to be removed, and CodeTypeReference to this type should be an array instead.
474 var cti = imported_types.First (i => i.XsdType == type);
475 cti.ClrType = new CodeTypeReference (GetCodeTypeReference (xe.ElementSchemaType.QualifiedName), 1);
480 Import (schemas, xe.ElementSchemaType);
481 td.BaseTypes.Add (new CodeTypeReference ("System.Collections.Generic.List", GetCodeTypeReference (xe.ElementSchemaType.QualifiedName)));
482 AddTypeAttributes (td, type, xe);
487 throw new InvalidDataContractException (String.Format ("complex type '{0}' is an invalid Dictionary type definition. A Dictionary must have a sequence particle with exactly two child elements", qname));
489 // import as a (normal) contract.
490 var elems = new List<XmlSchemaElement> ();
491 foreach (XmlSchemaElement xe in seq.Items) {
492 if (xe.MaxOccurs != 1)
493 throw new InvalidDataContractException (String.Format ("schema complex type '{0}' has a content sequence containing an element '{1}' with 'maxOccurs' value as more than 1, which is not supported in DataContract.", qname, xe.QualifiedName));
495 if (elems.Any (e => e.QualifiedName.Name == xe.QualifiedName.Name))
496 throw new InvalidDataContractException (String.Format ("In schema type '{0}', there already is an element whose name is {1}, where duplicate of element names are not supported.", qname, xe.QualifiedName.Name));
500 foreach (var xe in elems) {
501 // import property type in prior.
502 Import (schemas, xe.ElementSchemaType.QualifiedName);
503 AddProperty (td, xe);
508 AddTypeAttributes (td, type);
509 AddExtensionData (td);
514 static readonly CodeExpression this_expr = new CodeThisReferenceExpression ();
515 static readonly CodeExpression arg_value_expr = new CodePropertySetValueReferenceExpression ();
517 bool GenerateInternal {
518 get { return Options != null && Options.GenerateInternal; }
521 void AddProperty (CodeTypeDeclaration td, XmlSchemaElement xe)
523 var att = GenerateInternal ? MemberAttributes.Assembly : MemberAttributes.Public;
524 var fi = new CodeMemberField () { Name = CodeIdentifier.MakeValid (xe.QualifiedName.Name + "Field"), Type = GetCodeTypeReference (xe.ElementSchemaType.QualifiedName, xe) };
526 var pi = new CodeMemberProperty () { Name = xe.QualifiedName.Name, Attributes = att, HasGet = true, HasSet = true, Type = fi.Type };
527 // [DataMember(Name=foobar, IsRequired=!nillable)]
528 var dma = new CodeAttributeDeclaration (
529 new CodeTypeReference (typeof (DataMemberAttribute)));
530 if (fi.Name != xe.QualifiedName.Name)
531 new CodeAttributeArgument ("Name", new CodePrimitiveExpression (xe.QualifiedName.Name));
533 new CodeAttributeArgument ("IsRequired", new CodePrimitiveExpression (true));
534 pi.CustomAttributes.Add (dma);
536 pi.GetStatements.Add (new CodeMethodReturnStatement () { Expression = new CodeFieldReferenceExpression (this_expr, fi.Name) });
537 pi.SetStatements.Add (new CodeAssignStatement (new CodeFieldReferenceExpression (this_expr, fi.Name), arg_value_expr));
543 bool IsPredefinedType (XmlQualifiedName qname)
545 // FIXME: support char, guid and duration (MSSimpleNamespace); fix GetPrimitiveTypeFromName() first and then this at a time.
546 switch (qname.Namespace) {
547 case KnownTypeCollection.MSSimpleNamespace:
548 switch (qname.Name) {
555 case XmlSchema.Namespace:
556 return KnownTypeCollection.GetPrimitiveTypeFromName (qname.Name) != null;
561 CodeNamespace GetCodeNamespace (XmlQualifiedName name)
564 if (Options == null || !Options.Namespaces.TryGetValue (name.Namespace, out ns))
565 ns = GetCodeNamespaceFromXmlns (name.Namespace);
567 foreach (CodeNamespace cns in CodeCompileUnit.Namespaces)
570 var newCns = new CodeNamespace () { Name = ns };
571 CodeCompileUnit.Namespaces.Add (newCns);
575 const string default_ns_prefix = "http://schemas.datacontract.org/2004/07/";
577 string GetCodeNamespaceFromXmlns (string xns)
579 if (xns.StartsWith (default_ns_prefix, StringComparison.Ordinal))
580 xns = xns.Substring (default_ns_prefix.Length);
584 if (Uri.TryCreate (xns, UriKind.Absolute, out u) && (tmp = MakeStringNamespaceComponentsValid (u.GetComponents (UriComponents.Host | UriComponents.Path, UriFormat.Unescaped))).Length > 0)
587 return MakeStringNamespaceComponentsValid (xns);
590 static readonly char [] split_tokens = new char [] {'/', '.'};
592 string MakeStringNamespaceComponentsValid (string ns)
594 var arr = ns.Split (split_tokens, StringSplitOptions.RemoveEmptyEntries);
595 for (int i = 0; i < arr.Length; i++)
596 arr [i] = CodeIdentifier.MakeValid (arr [i]);
597 return String.Join (".", arr);
600 // Post-compilation information retrieval
602 TypeImportInfo GetTypeInfo (XmlQualifiedName typeName, bool throwError)
604 var info = imported_types.FirstOrDefault (i => i.XsdTypeName.Equals (typeName));
607 throw new InvalidOperationException (String.Format ("schema type '{0}' has not been imported yet. Import it first.", typeName));
613 public CodeTypeReference GetCodeTypeReference (XmlQualifiedName typeName)
615 return GetCodeTypeReferenceInternal (typeName, true);
618 CodeTypeReference GetCodeTypeReferenceInternal (XmlQualifiedName typeName, bool throwError)
620 if (typeName == null)
621 throw new ArgumentNullException ("typeName");
623 switch (typeName.Namespace) {
624 case XmlSchema.Namespace:
625 return new CodeTypeReference (KnownTypeCollection.GetPrimitiveTypeFromName (typeName.Name));
626 case KnownTypeCollection.MSSimpleNamespace:
627 switch (typeName.Name) {
629 return new CodeTypeReference (typeof (Guid));
631 return new CodeTypeReference (typeof (TimeSpan));
636 var info = GetTypeInfo (typeName, throwError);
637 return info != null ? info.ClrType : null;
640 [MonoTODO ("use element argument and fill Nullable etc.")]
641 public CodeTypeReference GetCodeTypeReference (XmlQualifiedName typeName, XmlSchemaElement element)
643 if (typeName == null)
644 throw new ArgumentNullException ("typeName");
646 throw new ArgumentNullException ("element");
648 return GetCodeTypeReference (typeName);
651 public ICollection<CodeTypeReference> GetKnownTypeReferences (XmlQualifiedName typeName)
653 if (typeName == null)
654 throw new ArgumentNullException ("typeName");
656 return GetTypeInfo (typeName, true).KnownClrTypes;
659 List<TypeImportInfo> imported_types = new List<TypeImportInfo> ();
663 public TypeImportInfo ()
665 KnownClrTypes = new List<CodeTypeReference> ();
668 public CodeTypeReference ClrType { get; set; }
669 public XmlQualifiedName XsdTypeName { get; set; }
670 public XmlSchemaType XsdType { get; set; }
671 public List<CodeTypeReference> KnownClrTypes { get; private set; }
672 public int KnownTypeOutputIndex { get; set; } // updated while importing.