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 ImportOptions import_options
;
65 public ImportOptions Options
{
66 get { return import_options; }
68 import_options
= value;
69 code_provider
= value.CodeProvider
?? code_provider
;
75 public bool CanImport (XmlSchemaSet schemas
)
78 throw new ArgumentNullException ("schemas");
80 if (!schemas
.IsCompiled
)
83 foreach (XmlSchemaElement xe
in schemas
.GlobalElements
.Values
)
84 if (!CanImport (schemas
, xe
))
89 public bool CanImport (XmlSchemaSet schemas
, ICollection
<XmlQualifiedName
> typeNames
)
92 throw new ArgumentNullException ("schemas");
93 if (typeNames
== null)
94 throw new ArgumentNullException ("typeNames");
96 if (!schemas
.IsCompiled
)
99 foreach (var name
in typeNames
)
100 if (!CanImport (schemas
, name
))
105 public bool CanImport (XmlSchemaSet schemas
, XmlQualifiedName typeName
)
108 throw new ArgumentNullException ("schemas");
109 if (typeName
== null)
110 throw new ArgumentNullException ("typeName");
112 if (!schemas
.IsCompiled
)
115 if (!schemas
.GlobalTypes
.Contains (typeName
))
116 throw new InvalidDataContractException (String
.Format ("Type {0} is not found in the schemas", typeName
));
118 return CanImport (schemas
, schemas
.GlobalTypes
[typeName
] as XmlSchemaComplexType
);
121 public bool CanImport (XmlSchemaSet schemas
, XmlSchemaElement element
)
124 throw new ArgumentNullException ("schemas");
126 if (!schemas
.IsCompiled
)
129 return CanImport (schemas
, element
.ElementSchemaType
as XmlSchemaComplexType
);
132 bool CanImport (XmlSchemaSet schemas
, XmlSchemaComplexType type
)
134 if (type
== null || type
.QualifiedName
.Namespace
== XmlSchema
.Namespace
) // xs:anyType -> not supported.
137 if (type
.ContentModel
is XmlSchemaSimpleContent
) // simple content derivation is not supported.
139 if (type
.ContentModel
!= null && type
.ContentModel
.Content
!= null) {
140 var xscce
= type
.ContentModel
.Content
as XmlSchemaComplexContentExtension
;
141 if (xscce
== null) // complex DBR is not supported.
144 if (xscce
.BaseTypeName
!= qname_anytype
&& !CanImport (schemas
, xscce
.BaseTypeName
))
153 public void Import (XmlSchemaSet schemas
)
156 throw new ArgumentNullException ("schemas");
158 if (!schemas
.IsCompiled
)
161 foreach (XmlSchemaElement xe
in schemas
.GlobalElements
.Values
)
162 Import (schemas
, xe
);
165 public void Import (XmlSchemaSet schemas
, ICollection
<XmlQualifiedName
> typeNames
)
168 throw new ArgumentNullException ("schemas");
169 if (typeNames
== null)
170 throw new ArgumentNullException ("typeNames");
171 foreach (var name
in typeNames
)
172 Import (schemas
, name
);
175 // This checks type existence and raises an error if it is missing.
176 public void Import (XmlSchemaSet schemas
, XmlQualifiedName typeName
)
179 throw new ArgumentNullException ("schemas");
180 if (typeName
== null)
181 throw new ArgumentNullException ("typeName");
183 if (IsPredefinedType (typeName
))
186 if (!schemas
.GlobalTypes
.Contains (typeName
))
187 throw new InvalidDataContractException (String
.Format ("Type {0} is not found in the schemas", typeName
));
189 Import (schemas
, schemas
.GlobalTypes
[typeName
] as XmlSchemaType
, typeName
);
192 public XmlQualifiedName
Import (XmlSchemaSet schemas
, XmlSchemaElement element
)
195 throw new ArgumentNullException ("schemas");
197 throw new ArgumentNullException ("element");
199 var elname
= element
.QualifiedName
;
201 switch (elname
.Namespace
) {
202 case KnownTypeCollection
.MSSimpleNamespace
:
203 switch (elname
.Name
) {
212 // FIXME: use element to fill nillable and arrays.
213 var qname
= element
.SchemaType
!= null ? element
.QualifiedName
: element
.ElementSchemaType
.QualifiedName
;
214 Import (schemas
, element
.ElementSchemaType
, qname
);
218 void Import (XmlSchemaSet schemas
, XmlSchemaType type
)
220 Import (schemas
, type
, type
.QualifiedName
);
223 void Import (XmlSchemaSet schemas
, XmlSchemaType type
, XmlQualifiedName qname
)
225 var existing
= imported_types
.FirstOrDefault (it
=> it
.XsdType
== type
);
226 if (existing
!= null)
227 return;// existing.XsdTypeName;
229 if (IsPredefinedType (type
.QualifiedName
))
232 DoImport (schemas
, type
, qname
);
235 void DoImport (XmlSchemaSet schemas
, XmlSchemaType type
, XmlQualifiedName qname
)
237 CodeNamespace cns
= null;
238 CodeTypeReference clrRef
;
239 cns
= GetCodeNamespace (qname
);
240 clrRef
= new CodeTypeReference (cns
.Name
.Length
> 0 ? cns
.Name
+ "." + qname
.Name
: qname
.Name
);
242 var td
= new CodeTypeDeclaration () {
243 Name
= CodeIdentifier
.MakeValid (qname
.Name
),
244 TypeAttributes
= GenerateInternal
? TypeAttributes
.NotPublic
: TypeAttributes
.Public
};
247 var info
= new TypeImportInfo () { ClrType = clrRef, XsdType = type, XsdTypeName = qname }
;
248 imported_types
.Add (info
);
250 var st
= type
as XmlSchemaSimpleType
;
252 ImportSimpleType (td
, schemas
, st
, qname
);
254 var ct
= (XmlSchemaComplexType
) type
;
255 var sc
= ct
.ContentModel
as XmlSchemaSimpleContent
;
257 if (sc
.Content
is XmlSchemaSimpleContentExtension
)
258 throw new InvalidDataContractException (String
.Format ("complex type '{0}' with simple content extension is not supported", type
.QualifiedName
));
260 if (!ImportComplexType (td
, schemas
, ct
, qname
)) {
261 cns
.Types
.Remove (td
);
262 if (cns
.Types
.Count
== 0)
263 CodeCompileUnit
.Namespaces
.Remove (cns
);
267 foreach (var impinfo
in imported_types
)
268 for (; impinfo
.KnownTypeOutputIndex
< impinfo
.KnownClrTypes
.Count
; impinfo
.KnownTypeOutputIndex
++)
269 td
.CustomAttributes
.Add (new CodeAttributeDeclaration (
270 new CodeTypeReference (typeof (KnownTypeAttribute
)),
271 new CodeAttributeArgument (new CodeTypeOfExpression (impinfo
.KnownClrTypes
[impinfo
.KnownTypeOutputIndex
]))));
274 static readonly string ass_name
= typeof (DataContractAttribute
).Assembly
.GetName ().Name
;
275 static readonly string ass_version
= typeof (DataContractAttribute
).Assembly
.GetName ().Version
.ToString ();
276 static readonly CodeTypeReference typeref_data_contract
= new CodeTypeReference (typeof (DataContractAttribute
));
277 static readonly CodeTypeReference typeref_coll_contract
= new CodeTypeReference (typeof (CollectionDataContractAttribute
));
279 void AddTypeAttributes (CodeTypeDeclaration td
, XmlSchemaType type
, params XmlSchemaElement
[] collectionArgs
)
281 var name
= type
.QualifiedName
;
282 // [GeneratedCode (assembly_name, assembly_version)]
283 td
.CustomAttributes
.Add (new CodeAttributeDeclaration (
284 new CodeTypeReference (typeof (GeneratedCodeAttribute
)),
285 new CodeAttributeArgument (new CodePrimitiveExpression (ass_name
)),
286 new CodeAttributeArgument (new CodePrimitiveExpression (ass_version
))));
288 var ct
= type
as XmlSchemaComplexType
;
290 // [DataContract(Name="foobar",Namespace="urn:foobar")] (optionally IsReference=true),
291 // or [CollectionDataContract(ditto, ItemType/KeyType/ValueType)]
292 var dca
= new CodeAttributeDeclaration (
293 collectionArgs
!= null && collectionArgs
.Length
> 0 ? typeref_coll_contract
: typeref_data_contract
,
294 new CodeAttributeArgument ("Name", new CodePrimitiveExpression (name
.Name
)),
295 new CodeAttributeArgument ("Namespace", new CodePrimitiveExpression (name
.Namespace
)));
296 if (collectionArgs
!= null) {
297 if (collectionArgs
.Length
> 0)
298 dca
.Arguments
.Add (new CodeAttributeArgument ("ItemName", new CodePrimitiveExpression (CodeIdentifier
.MakeValid (collectionArgs
[0].QualifiedName
.Name
))));
299 if (collectionArgs
.Length
> 2) {
300 dca
.Arguments
.Add (new CodeAttributeArgument ("KeyName", new CodePrimitiveExpression (CodeIdentifier
.MakeValid (collectionArgs
[1].QualifiedName
.Name
))));
301 dca
.Arguments
.Add (new CodeAttributeArgument ("ValueName", new CodePrimitiveExpression (CodeIdentifier
.MakeValid (collectionArgs
[2].QualifiedName
.Name
))));
304 if (ct
!= null && ct
.AttributeUses
[new XmlQualifiedName ("Ref", KnownTypeCollection
.MSSimpleNamespace
)] != null)
305 dca
.Arguments
.Add (new CodeAttributeArgument ("IsReference", new CodePrimitiveExpression (true)));
306 td
.CustomAttributes
.Add (dca
);
308 // optional [Serializable]
309 if (Options
!= null && Options
.GenerateSerializable
)
310 td
.CustomAttributes
.Add (new CodeAttributeDeclaration ("System.SerializableAttribute"));
313 static readonly CodeTypeReference typeref_ext_iface
= new CodeTypeReference ("System.Runtime.Serialization.IExtensibleDataObject");
314 static readonly CodeTypeReference typeref_ext_class
= new CodeTypeReference ("System.Runtime.Serialization.ExtensionDataObject");
316 void AddExtensionData (CodeTypeDeclaration td
)
318 td
.BaseTypes
.Add (typeref_ext_iface
);
320 var field
= new CodeMemberField (typeref_ext_class
, "extensionDataField");
321 td
.Members
.Add (field
);
323 var prop
= new CodeMemberProperty () { Type = field.Type, Name = "ExtensionData", Attributes = (GenerateInternal ? MemberAttributes.Assembly : MemberAttributes.Public) | MemberAttributes.Final }
;
324 prop
.GetStatements
.Add (new CodeMethodReturnStatement (
325 new CodeFieldReferenceExpression (
326 new CodeThisReferenceExpression (),
327 "extensionDataField")));
328 prop
.SetStatements
.Add (new CodeAssignStatement (
329 new CodeFieldReferenceExpression (
330 new CodeThisReferenceExpression (),
331 "extensionDataField"),
332 new CodePropertySetValueReferenceExpression ()));
334 td
.Members
.Add (prop
);
337 void ImportSimpleType (CodeTypeDeclaration td
, XmlSchemaSet schemas
, XmlSchemaSimpleType type
, XmlQualifiedName qname
)
339 var scl
= type
.Content
as XmlSchemaSimpleTypeList
;
341 if (scl
.ItemType
== null)
342 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
));
343 var itemType
= scl
.ItemType
as XmlSchemaSimpleType
;
344 var ir
= itemType
.Content
as XmlSchemaSimpleTypeRestriction
;
346 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
));
347 ImportEnum (td
, schemas
, ir
, type
, qname
, true);
350 var scr
= type
.Content
as XmlSchemaSimpleTypeRestriction
;
352 ImportEnum (td
, schemas
, scr
, type
, qname
, false);
356 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
));
359 static readonly CodeTypeReference enum_member_att_ref
= new CodeTypeReference (typeof (EnumMemberAttribute
));
361 void ImportEnum (CodeTypeDeclaration td
, XmlSchemaSet schemas
, XmlSchemaSimpleTypeRestriction r
, XmlSchemaType type
, XmlQualifiedName qname
, bool isFlag
)
363 if (isFlag
&& !r
.BaseTypeName
.Equals (new XmlQualifiedName ("string", XmlSchema
.Namespace
)))
364 throw new InvalidDataContractException (String
.Format ("For flags enumeration '{0}', the base type for the simple type restriction must be XML schema string", qname
));
367 AddTypeAttributes (td
, type
);
369 td
.CustomAttributes
.Add (new CodeAttributeDeclaration (new CodeTypeReference (typeof (FlagsAttribute
))));
371 foreach (var facet
in r
.Facets
) {
372 var e
= facet
as XmlSchemaEnumerationFacet
;
374 throw new InvalidDataContractException (String
.Format ("Invalid simple type restriction (type {0}). Only enumeration is allowed.", qname
));
375 var em
= new CodeMemberField () { Name = CodeIdentifier.MakeValid (e.Value) }
;
376 var ea
= new CodeAttributeDeclaration (enum_member_att_ref
);
377 if (e
.Value
!= em
.Name
)
378 ea
.Arguments
.Add (new CodeAttributeArgument ("Value", new CodePrimitiveExpression (e
.Value
)));
379 em
.CustomAttributes
.Add (ea
);
384 // Returns false if it should remove the imported type.
385 // FIXME: also support ImportXmlType
386 bool ImportComplexType (CodeTypeDeclaration td
, XmlSchemaSet schemas
, XmlSchemaComplexType type
, XmlQualifiedName qname
)
388 foreach (XmlSchemaAttribute att
in type
.AttributeUses
.Values
)
389 if (att
.Use
!= XmlSchemaUse
.Optional
|| att
.QualifiedName
.Namespace
!= KnownTypeCollection
.MSSimpleNamespace
)
390 throw new InvalidDataContractException (String
.Format ("attribute in DataContract complex type '{0}' is limited to those in {1} namespace, and optional.", qname
, KnownTypeCollection
.MSSimpleNamespace
));
392 CodeTypeReference baseClrType
= null;
393 var particle
= type
.Particle
;
394 if (type
.ContentModel
!= null) {
395 var xsscr
= type
.ContentModel
.Content
as XmlSchemaSimpleContentRestriction
;
397 if (xsscr
.BaseType
!= null)
398 Import (schemas
, xsscr
.BaseType
);
400 Import (schemas
, xsscr
.BaseTypeName
);
401 // The above will result in an error, but make sure to show we don't support it.
402 throw new InvalidDataContractException (String
.Format ("complex type simple content restriction is not supported in DataContract (type '{0}')", qname
));
404 var xscce
= type
.ContentModel
.Content
as XmlSchemaComplexContentExtension
;
406 Import (schemas
, xscce
.BaseTypeName
);
407 baseClrType
= GetCodeTypeReferenceInternal (xscce
.BaseTypeName
, false);
408 if (baseClrType
!= null)
409 td
.BaseTypes
.Add (baseClrType
);
411 var baseInfo
= GetTypeInfo (xscce
.BaseTypeName
, false);
412 if (baseInfo
!= null)
413 baseInfo
.KnownClrTypes
.Add (imported_types
.First (it
=> it
.XsdType
== type
).ClrType
);
414 particle
= xscce
.Particle
;
416 var xsccr
= type
.ContentModel
.Content
as XmlSchemaComplexContentRestriction
;
418 throw new InvalidDataContractException (String
.Format ("complex content type (for type '{0}') has a restriction content model, which is not supported in DataContract.", qname
));
421 var seq
= particle
as XmlSchemaSequence
;
422 if (seq
== null && particle
!= null)
423 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
));
427 foreach (var child
in seq
.Items
)
428 if (!(child
is XmlSchemaElement
))
429 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
));
431 bool isDictionary
= false;
432 if (type
.Annotation
!= null) {
433 foreach (var ann
in type
.Annotation
.Items
) {
434 var ai
= ann
as XmlSchemaAppInfo
;
435 if (ai
!= null && ai
.Markup
!= null &&
436 ai
.Markup
.Length
> 0 &&
437 ai
.Markup
[0].NodeType
== XmlNodeType
.Element
&&
438 ai
.Markup
[0].LocalName
== "IsDictionary" &&
439 ai
.Markup
[0].NamespaceURI
== KnownTypeCollection
.MSSimpleNamespace
)
444 if (seq
.Items
.Count
== 1) {
445 var xe
= (XmlSchemaElement
) seq
.Items
[0];
446 if (xe
.MaxOccursString
== "unbounded") {
447 // import as a collection contract.
449 var kvt
= xe
.ElementSchemaType
as XmlSchemaComplexType
;
450 var seq2
= kvt
!= null ? kvt
.Particle
as XmlSchemaSequence
: null;
451 var k
= seq2
!= null && seq2
.Items
.Count
== 2 ? seq2
.Items
[0] as XmlSchemaElement
: null;
452 var v
= seq2
!= null && seq2
.Items
.Count
== 2 ? seq2
.Items
[1] as XmlSchemaElement
: null;
453 if (k
== null || v
== null)
454 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
));
455 Import (schemas
, k
.ElementSchemaType
);
456 Import (schemas
, v
.ElementSchemaType
);
457 td
.BaseTypes
.Add (new CodeTypeReference ("System.Collections.Generic.Dictionary", GetCodeTypeReference (k
.ElementSchemaType
.QualifiedName
), GetCodeTypeReference (v
.ElementSchemaType
.QualifiedName
)));
458 AddTypeAttributes (td
, type
, xe
, k
, v
);
460 } else if (type
.QualifiedName
.Namespace
== KnownTypeCollection
.MSArraysNamespace
&&
461 IsPredefinedType (xe
.ElementSchemaType
.QualifiedName
)) {
462 // then this CodeTypeDeclaration is to be removed, and CodeTypeReference to this type should be an array instead.
463 var cti
= imported_types
.First (i
=> i
.XsdType
== type
);
464 cti
.ClrType
= new CodeTypeReference (GetCodeTypeReference (xe
.ElementSchemaType
.QualifiedName
), 1);
469 Import (schemas
, xe
.ElementSchemaType
);
470 td
.BaseTypes
.Add (new CodeTypeReference ("System.Collections.Generic.List", GetCodeTypeReference (xe
.ElementSchemaType
.QualifiedName
)));
471 AddTypeAttributes (td
, type
, xe
);
476 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
));
478 // import as a (normal) contract.
479 var elems
= new List
<XmlSchemaElement
> ();
480 foreach (XmlSchemaElement xe
in seq
.Items
) {
481 if (xe
.MaxOccurs
!= 1)
482 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
));
484 if (elems
.Any (e
=> e
.QualifiedName
.Name
== xe
.QualifiedName
.Name
))
485 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
));
489 foreach (var xe
in elems
) {
490 // import property type in prior.
491 Import (schemas
, xe
.ElementSchemaType
.QualifiedName
);
492 AddProperty (td
, xe
);
497 AddTypeAttributes (td
, type
);
498 AddExtensionData (td
);
503 static readonly CodeExpression this_expr
= new CodeThisReferenceExpression ();
504 static readonly CodeExpression arg_value_expr
= new CodePropertySetValueReferenceExpression ();
506 bool GenerateInternal
{
507 get { return Options != null && Options.GenerateInternal; }
510 void AddProperty (CodeTypeDeclaration td
, XmlSchemaElement xe
)
512 var att
= GenerateInternal
? MemberAttributes
.Assembly
: MemberAttributes
.Public
;
513 var fi
= new CodeMemberField () { Name = CodeIdentifier.MakeValid (xe.QualifiedName.Name + "Field"), Type = GetCodeTypeReference (xe.ElementSchemaType.QualifiedName, xe) }
;
515 var pi
= new CodeMemberProperty () { Name = xe.QualifiedName.Name, Attributes = att, HasGet = true, HasSet = true, Type = fi.Type }
;
516 // [DataMember(Name=foobar, IsRequired=!nillable)]
517 var dma
= new CodeAttributeDeclaration (
518 new CodeTypeReference (typeof (DataMemberAttribute
)));
519 if (fi
.Name
!= xe
.QualifiedName
.Name
)
520 new CodeAttributeArgument ("Name", new CodePrimitiveExpression (xe
.QualifiedName
.Name
));
522 new CodeAttributeArgument ("IsRequired", new CodePrimitiveExpression (true));
523 pi
.CustomAttributes
.Add (dma
);
525 pi
.GetStatements
.Add (new CodeMethodReturnStatement () { Expression = new CodeFieldReferenceExpression (this_expr, fi.Name) }
);
526 pi
.SetStatements
.Add (new CodeAssignStatement (new CodeFieldReferenceExpression (this_expr
, fi
.Name
), arg_value_expr
));
532 bool IsPredefinedType (XmlQualifiedName qname
)
534 // FIXME: support char, guid and duration (MSSimpleNamespace); fix GetPrimitiveTypeFromName() first and then this at a time.
535 switch (qname
.Namespace
) {
536 case KnownTypeCollection
.MSSimpleNamespace
:
537 switch (qname
.Name
) {
544 case XmlSchema
.Namespace
:
545 return KnownTypeCollection
.GetPrimitiveTypeFromName (qname
.Name
) != null;
550 CodeNamespace
GetCodeNamespace (XmlQualifiedName name
)
553 if (Options
== null || !Options
.Namespaces
.TryGetValue (name
.Namespace
, out ns
))
554 ns
= GetCodeNamespaceFromXmlns (name
.Namespace
);
556 foreach (CodeNamespace cns
in CodeCompileUnit
.Namespaces
)
559 var newCns
= new CodeNamespace () { Name = ns }
;
560 CodeCompileUnit
.Namespaces
.Add (newCns
);
564 const string default_ns_prefix
= "http://schemas.datacontract.org/2004/07/";
566 string GetCodeNamespaceFromXmlns (string xns
)
568 if (xns
.StartsWith (default_ns_prefix
, StringComparison
.Ordinal
))
569 xns
= xns
.Substring (default_ns_prefix
.Length
);
573 if (Uri
.TryCreate (xns
, UriKind
.Absolute
, out u
) && (tmp
= MakeStringNamespaceComponentsValid (u
.GetComponents (UriComponents
.Host
| UriComponents
.Path
, UriFormat
.Unescaped
))).Length
> 0)
576 return MakeStringNamespaceComponentsValid (xns
);
579 static readonly char [] split_tokens
= new char [] {'/', '.'}
;
581 string MakeStringNamespaceComponentsValid (string ns
)
583 var arr
= ns
.Split (split_tokens
, StringSplitOptions
.RemoveEmptyEntries
);
584 for (int i
= 0; i
< arr
.Length
; i
++)
585 arr
[i
] = CodeIdentifier
.MakeValid (arr
[i
]);
586 return String
.Join (".", arr
);
589 // Post-compilation information retrieval
591 TypeImportInfo
GetTypeInfo (XmlQualifiedName typeName
, bool throwError
)
593 var info
= imported_types
.FirstOrDefault (i
=> i
.XsdTypeName
.Equals (typeName
));
596 throw new InvalidOperationException (String
.Format ("schema type '{0}' has not been imported yet. Import it first.", typeName
));
602 public CodeTypeReference
GetCodeTypeReference (XmlQualifiedName typeName
)
604 return GetCodeTypeReferenceInternal (typeName
, true);
607 CodeTypeReference
GetCodeTypeReferenceInternal (XmlQualifiedName typeName
, bool throwError
)
609 if (typeName
== null)
610 throw new ArgumentNullException ("typeName");
612 switch (typeName
.Namespace
) {
613 case XmlSchema
.Namespace
:
614 return new CodeTypeReference (KnownTypeCollection
.GetPrimitiveTypeFromName (typeName
.Name
));
615 case KnownTypeCollection
.MSSimpleNamespace
:
616 switch (typeName
.Name
) {
618 return new CodeTypeReference (typeof (Guid
));
620 return new CodeTypeReference (typeof (TimeSpan
));
625 var info
= GetTypeInfo (typeName
, throwError
);
626 return info
!= null ? info
.ClrType
: null;
629 [MonoTODO ("use element argument and fill Nullable etc.")]
630 public CodeTypeReference
GetCodeTypeReference (XmlQualifiedName typeName
, XmlSchemaElement element
)
632 if (typeName
== null)
633 throw new ArgumentNullException ("typeName");
635 throw new ArgumentNullException ("element");
637 return GetCodeTypeReference (typeName
);
640 public ICollection
<CodeTypeReference
> GetKnownTypeReferences (XmlQualifiedName typeName
)
642 if (typeName
== null)
643 throw new ArgumentNullException ("typeName");
645 return GetTypeInfo (typeName
, true).KnownClrTypes
;
648 List
<TypeImportInfo
> imported_types
= new List
<TypeImportInfo
> ();
652 public TypeImportInfo ()
654 KnownClrTypes
= new List
<CodeTypeReference
> ();
657 public CodeTypeReference ClrType { get; set; }
658 public XmlQualifiedName XsdTypeName { get; set; }
659 public XmlSchemaType XsdType { get; set; }
660 public List
<CodeTypeReference
> KnownClrTypes { get; private set; }
661 public int KnownTypeOutputIndex { get; set; }
// updated while importing.