2010-02-18 Atsushi Enomoto <atsushi@ximian.com>
authorAtsushi Eno <atsushieno@gmail.com>
Thu, 18 Feb 2010 11:57:44 +0000 (11:57 -0000)
committerAtsushi Eno <atsushieno@gmail.com>
Thu, 18 Feb 2010 11:57:44 +0000 (11:57 -0000)
* XsdDataContractImporter-new.cs, XsdDataContractImporter.cs :
  replaced implementation.
* ImportOptions.cs : add correct MonoTODOs.

* XsdDataContractImporterTest.cs : enabled new tests.

svn path=/trunk/mcs/; revision=151975

mcs/class/System.Runtime.Serialization/System.Runtime.Serialization/ChangeLog
mcs/class/System.Runtime.Serialization/System.Runtime.Serialization/ImportOptions.cs
mcs/class/System.Runtime.Serialization/System.Runtime.Serialization/XsdDataContractImporter-new.cs [deleted file]
mcs/class/System.Runtime.Serialization/System.Runtime.Serialization/XsdDataContractImporter.cs
mcs/class/System.Runtime.Serialization/Test/System.Runtime.Serialization/ChangeLog
mcs/class/System.Runtime.Serialization/Test/System.Runtime.Serialization/XsdDataContractImporterTest.cs

index 3729635d2ef11d995e4787946a8efe6d17b00479..63ee91abbf086a3088c833063b9d78ff3e9e53e2 100755 (executable)
@@ -1,3 +1,9 @@
+2010-02-18  Atsushi Enomoto  <atsushi@ximian.com>
+
+       * XsdDataContractImporter-new.cs, XsdDataContractImporter.cs :
+         replaced implementation.
+       * ImportOptions.cs : add correct MonoTODOs.
+
 2010-02-18  Atsushi Enomoto  <atsushi@ximian.com>
 
        * XsdDataContractImporter-new.cs : output [KnownType] to expose
index 3a060a4e64d44910bb92637e13a1c903595e91b1..8b5b5e389e99c4724e0725ba6837daa585da4064 100644 (file)
@@ -55,11 +55,13 @@ namespace System.Runtime.Serialization
                        set { code_provider = value; }
                }
 
+               [MonoTODO]
                public IDataContractSurrogate DataContractSurrogate {
                        get { return surrogate; }
                        set { surrogate = value; }
                }
 
+               [MonoTODO]
                public bool EnableDataBinding {
                        get { return enable_data_binding; }
                        set { enable_data_binding = value; }
@@ -75,6 +77,7 @@ namespace System.Runtime.Serialization
                        set { generate_serializable = value; }
                }
 
+               [MonoTODO]
                public bool ImportXmlType {
                        get { return import_xml_type; }
                        set { import_xml_type = value; }
@@ -84,10 +87,12 @@ namespace System.Runtime.Serialization
                        get { return namespaces; }
                }
 
+               [MonoTODO]
                public ICollection<Type> ReferencedCollectionTypes {
                        get { return referenced_collection_types; }
                }
 
+               [MonoTODO]
                public ICollection<Type> ReferencedTypes {
                        get { return referenced_types; }
                }
diff --git a/mcs/class/System.Runtime.Serialization/System.Runtime.Serialization/XsdDataContractImporter-new.cs b/mcs/class/System.Runtime.Serialization/System.Runtime.Serialization/XsdDataContractImporter-new.cs
deleted file mode 100644 (file)
index 7d46901..0000000
+++ /dev/null
@@ -1,631 +0,0 @@
-//
-// XsdDataContractImporter.cs
-//
-// Author:
-//     Atsushi Enomoto <atsushi@ximian.com>
-//
-// Copyright (C) 2010 Novell, Inc.  http://www.novell.com
-//
-// Permission is hereby granted, free of charge, to any person obtaining
-// a copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to
-// permit persons to whom the Software is furnished to do so, subject to
-// the following conditions:
-// 
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
-// 
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-//
-
-using System;
-using System.CodeDom;
-using System.CodeDom.Compiler;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Reflection;
-using System.Xml;
-using System.Xml.Schema;
-using System.Xml.Serialization;
-
-namespace System.Runtime.Serialization
-{
-       [MonoTODO ("Support ImportXmlType option; support arrays; CanImport is not up to date with Import")]
-       public class XsdDataContractImporter
-       {
-               static readonly XmlQualifiedName qname_anytype = new XmlQualifiedName ("anyType", XmlSchema.Namespace);
-
-               public XsdDataContractImporter ()
-                       : this (null)
-               {
-               }
-
-               public XsdDataContractImporter (CodeCompileUnit codeCompileUnit)
-               {
-                       // null argument is ok.
-                       CodeCompileUnit = codeCompileUnit ?? new CodeCompileUnit ();
-
-                       // Options is null by default
-               }
-
-               public CodeCompileUnit CodeCompileUnit { get; private set; }
-
-               CodeDomProvider code_provider = CodeDomProvider.CreateProvider ("csharp");
-               ImportOptions import_options;
-
-               public ImportOptions Options {
-                       get { return import_options; }
-                       set {
-                               import_options = value;
-                               code_provider = value.CodeProvider ?? code_provider;
-                       }
-               }
-
-               // CanImport
-
-               public bool CanImport (XmlSchemaSet schemas)
-               {
-                       if (schemas == null)
-                               throw new ArgumentNullException ("schemas");
-
-                       if (!schemas.IsCompiled)
-                               schemas.Compile ();
-
-                       foreach (XmlSchemaElement xe in schemas.GlobalElements.Values)
-                               if (!CanImport (schemas, xe))
-                                       return false;
-                       return true;
-               }
-
-               public bool CanImport (XmlSchemaSet schemas, ICollection<XmlQualifiedName> typeNames)
-               {
-                       if (schemas == null)
-                               throw new ArgumentNullException ("schemas");
-                       if (typeNames == null)
-                               throw new ArgumentNullException ("typeNames");
-
-                       if (!schemas.IsCompiled)
-                               schemas.Compile ();
-
-                       foreach (var name in typeNames)
-                               if (!CanImport (schemas, name))
-                                       return false;
-                       return true;
-               }
-
-               public bool CanImport (XmlSchemaSet schemas, XmlQualifiedName typeName)
-               {
-                       if (schemas == null)
-                               throw new ArgumentNullException ("schemas");
-                       if (typeName == null)
-                               throw new ArgumentNullException ("typeName");
-
-                       if (!schemas.IsCompiled)
-                               schemas.Compile ();
-
-                       if (!schemas.GlobalTypes.Contains (typeName))
-                               throw new InvalidDataContractException (String.Format ("Type {0} is not found in the schemas", typeName));
-
-                       return CanImport (schemas, schemas.GlobalTypes [typeName] as XmlSchemaComplexType);
-               }
-
-               public bool CanImport (XmlSchemaSet schemas, XmlSchemaElement element)
-               {
-                       if (schemas == null)
-                               throw new ArgumentNullException ("schemas");
-
-                       if (!schemas.IsCompiled)
-                               schemas.Compile ();
-
-                       return CanImport (schemas, element.ElementSchemaType as XmlSchemaComplexType);
-               }
-
-               bool CanImport (XmlSchemaSet schemas, XmlSchemaComplexType type)
-               {
-                       if (type == null || type.QualifiedName.Namespace == XmlSchema.Namespace) // xs:anyType -> not supported.
-                               return false;
-
-                       if (type.ContentModel is XmlSchemaSimpleContent) // simple content derivation is not supported.
-                               return false;
-                       if (type.ContentModel != null && type.ContentModel.Content != null) {
-                               var xscce = type.ContentModel.Content as XmlSchemaComplexContentExtension;
-                               if (xscce == null) // complex DBR is not supported.
-                                       return false;
-                               // check base type
-                               if (xscce.BaseTypeName != qname_anytype && !CanImport (schemas, xscce.BaseTypeName))
-                                       return false;
-                       }
-
-                       return true;
-               }
-
-               // Import
-
-               public void Import (XmlSchemaSet schemas)
-               {
-                       if (schemas == null)
-                               throw new ArgumentNullException ("schemas");
-
-                       if (!schemas.IsCompiled)
-                               schemas.Compile ();
-
-                       foreach (XmlSchemaElement xe in schemas.GlobalElements.Values)
-                               Import (schemas, xe);
-               }
-
-               public void Import (XmlSchemaSet schemas, ICollection<XmlQualifiedName> typeNames)
-               {
-                       if (schemas == null)
-                               throw new ArgumentNullException ("schemas");
-                       if (typeNames == null)
-                               throw new ArgumentNullException ("typeNames");
-                       foreach (var name in typeNames)
-                               Import (schemas, name);
-               }
-
-               // This checks type existence and raises an error if it is missing.
-               public void Import (XmlSchemaSet schemas, XmlQualifiedName typeName)
-               {
-                       if (schemas == null)
-                               throw new ArgumentNullException ("schemas");
-                       if (typeName == null)
-                               throw new ArgumentNullException ("typeName");
-
-                       if (IsPredefinedType (typeName))
-                               return;
-
-                       if (!schemas.GlobalTypes.Contains (typeName))
-                               throw new InvalidDataContractException (String.Format ("Type {0} is not found in the schemas", typeName));
-
-                       Import (schemas, schemas.GlobalTypes [typeName] as XmlSchemaType, typeName);
-               }
-
-               public XmlQualifiedName Import (XmlSchemaSet schemas, XmlSchemaElement element)
-               {
-                       if (schemas == null)
-                               throw new ArgumentNullException ("schemas");
-                       if (element == null)
-                               throw new ArgumentNullException ("element");
-
-                       var elname = element.QualifiedName;
-
-                       switch (elname.Namespace) {
-                       case KnownTypeCollection.MSSimpleNamespace:
-                               switch (elname.Name) {
-                               case "char":
-                               case "duration":
-                               case "guid":
-                                       return elname;
-                               }
-                               break;
-                       }
-
-                       // FIXME: use element to fill nillable and arrays.
-                       var qname = element.SchemaType != null ? element.QualifiedName : element.ElementSchemaType.QualifiedName;
-                       Import (schemas, element.ElementSchemaType, qname);
-                       return qname;
-               }
-
-               void Import (XmlSchemaSet schemas, XmlSchemaType type)
-               {
-                       Import (schemas, type, type.QualifiedName);
-               }
-
-               void Import (XmlSchemaSet schemas, XmlSchemaType type, XmlQualifiedName qname)
-               {
-                       var existing = imported_types.FirstOrDefault (it => it.XsdType == type);
-                       if (existing != null)
-                               return;// existing.XsdTypeName;
-
-                       if (IsPredefinedType (type.QualifiedName))
-                               return;
-
-                       DoImport (schemas, type, qname);
-               }
-
-               void DoImport (XmlSchemaSet schemas, XmlSchemaType type, XmlQualifiedName qname)
-               {
-                       CodeNamespace cns = null;
-                       CodeTypeReference clrRef;
-                       cns = GetCodeNamespace (qname);
-                       clrRef = new CodeTypeReference (cns.Name.Length > 0 ? cns.Name + "." + qname.Name : qname.Name);
-
-                       var td = new CodeTypeDeclaration () {
-                               Name = CodeIdentifier.MakeValid (qname.Name),
-                               TypeAttributes = GenerateInternal ? TypeAttributes.NotPublic : TypeAttributes.Public };
-                       cns.Types.Add (td);
-
-                       var info = new TypeImportInfo () { ClrType = clrRef, XsdType = type,  XsdTypeName = qname };
-                       imported_types.Add (info);
-
-                       var st = type as XmlSchemaSimpleType;
-                       if (st != null) {
-                               ImportSimpleType (td, schemas, st, qname);
-                       } else {
-                               var ct = (XmlSchemaComplexType) type;
-                               var sc = ct.ContentModel as XmlSchemaSimpleContent;
-                               if (sc != null) {
-                                       if (sc.Content is XmlSchemaSimpleContentExtension)
-                                               throw new InvalidDataContractException (String.Format ("complex type '{0}' with simple content extension is not supported", type.QualifiedName));
-                               }
-                               if (!ImportComplexType (td, schemas, ct, qname)) {
-                                       cns.Types.Remove (td);
-                                       if (cns.Types.Count == 0)
-                                               CodeCompileUnit.Namespaces.Remove (cns);
-                               }
-                       }
-
-                       foreach (var impinfo in imported_types)
-                               for (; impinfo.KnownTypeOutputIndex < impinfo.KnownClrTypes.Count; impinfo.KnownTypeOutputIndex++)
-                                       td.CustomAttributes.Add (new CodeAttributeDeclaration (
-                                               new CodeTypeReference (typeof (KnownTypeAttribute)),
-                                               new CodeAttributeArgument (new CodeTypeOfExpression (impinfo.KnownClrTypes [impinfo.KnownTypeOutputIndex]))));
-               }
-
-               static readonly string ass_name = typeof (DataContractAttribute).Assembly.GetName ().Name;
-               static readonly string ass_version = typeof (DataContractAttribute).Assembly.GetName ().Version.ToString ();
-               static readonly CodeTypeReference typeref_data_contract = new CodeTypeReference (typeof (DataContractAttribute));
-               static readonly CodeTypeReference typeref_coll_contract = new CodeTypeReference (typeof (CollectionDataContractAttribute));
-
-               void AddTypeAttributes (CodeTypeDeclaration td, XmlSchemaType type, string collectionItemName)
-               {
-                       var name = type.QualifiedName;
-                       // [GeneratedCode (assembly_name, assembly_version)]
-                       td.CustomAttributes.Add (new CodeAttributeDeclaration (
-                               new CodeTypeReference (typeof (GeneratedCodeAttribute)),
-                               new CodeAttributeArgument (new CodePrimitiveExpression (ass_name)),
-                               new CodeAttributeArgument (new CodePrimitiveExpression (ass_version))));
-
-                       var ct = type as XmlSchemaComplexType;
-
-                       // [DataContract(Name="foobar",Namespace="urn:foobar")] (optionally IsReference=true),
-                       // or [CollectionDataContract(ditto)]
-                       var dca = new CodeAttributeDeclaration (
-                               collectionItemName != null ? typeref_coll_contract : typeref_data_contract,
-                               new CodeAttributeArgument ("Name", new CodePrimitiveExpression (name.Name)),
-                               new CodeAttributeArgument ("Namespace", new CodePrimitiveExpression (name.Namespace)));
-                       if (collectionItemName != null)
-                               dca.Arguments.Add (new CodeAttributeArgument ("ItemName", new CodePrimitiveExpression (collectionItemName)));
-                       if (ct != null && ct.AttributeUses [new XmlQualifiedName ("Ref", KnownTypeCollection.MSSimpleNamespace)] != null)
-                               dca.Arguments.Add (new CodeAttributeArgument ("IsReference", new CodePrimitiveExpression (true)));
-                       td.CustomAttributes.Add (dca);
-
-                       // optional [Serializable]
-                       if (Options != null && Options.GenerateSerializable)
-                               td.CustomAttributes.Add (new CodeAttributeDeclaration ("System.SerializableAttribute"));
-               }
-
-               static readonly CodeTypeReference typeref_ext_iface = new CodeTypeReference ("System.Runtime.Serialization.IExtensibleDataObject");
-               static readonly CodeTypeReference typeref_ext_class = new CodeTypeReference ("System.Runtime.Serialization.ExtensibleDataObject");
-
-               void AddExtensionData (CodeTypeDeclaration td)
-               {
-                       td.BaseTypes.Add (typeref_ext_iface);
-
-                       var field = new CodeMemberField (typeref_ext_class, "extensionDataField");
-                       td.Members.Add (field);
-
-                       var prop = new CodeMemberProperty () { Type = field.Type, Name = "ExtensionData", Attributes = (GenerateInternal ? MemberAttributes.Assembly : MemberAttributes.Public) | MemberAttributes.Final };
-                       prop.GetStatements.Add (new CodeMethodReturnStatement (
-                               new CodeFieldReferenceExpression (
-                               new CodeThisReferenceExpression (),
-                               "extensionDataField")));
-                       prop.SetStatements.Add (new CodeAssignStatement (
-                               new CodeFieldReferenceExpression (
-                               new CodeThisReferenceExpression (),
-                               "extensionDataField"),
-                               new CodePropertySetValueReferenceExpression ()));
-
-                       td.Members.Add (prop);
-               }
-
-               void ImportSimpleType (CodeTypeDeclaration td, XmlSchemaSet schemas, XmlSchemaSimpleType type, XmlQualifiedName qname)
-               {
-                       var scl = type.Content as XmlSchemaSimpleTypeList;
-                       if (scl != null) {
-                               if (scl.ItemType == null)
-                                       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));
-                               var itemType = scl.ItemType as XmlSchemaSimpleType;
-                               var ir = itemType.Content as XmlSchemaSimpleTypeRestriction;
-                               if (ir == null)
-                                       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));
-                               ImportEnum (td, schemas, ir, type, qname, true);
-                               return;
-                       }
-                       var scr = type.Content as XmlSchemaSimpleTypeRestriction;
-                       if (scr != null) {
-                               ImportEnum (td, schemas, scr, type, qname, false);
-                               return;
-                       }
-
-                       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));
-               }
-
-               static readonly CodeTypeReference enum_member_att_ref = new CodeTypeReference (typeof (EnumMemberAttribute));
-
-               void ImportEnum (CodeTypeDeclaration td, XmlSchemaSet schemas, XmlSchemaSimpleTypeRestriction r, XmlSchemaType type, XmlQualifiedName qname, bool isFlag)
-               {
-                       if (isFlag && !r.BaseTypeName.Equals (new XmlQualifiedName ("string", XmlSchema.Namespace)))
-                               throw new InvalidDataContractException (String.Format ("For flags enumeration '{0}', the base type for the simple type restriction must be XML schema string", qname));
-
-                       td.IsEnum = true;
-                       AddTypeAttributes (td, type, null);
-                       if (isFlag)
-                               td.CustomAttributes.Add (new CodeAttributeDeclaration (new CodeTypeReference (typeof (FlagsAttribute))));
-
-                       foreach (var facet in r.Facets) {
-                               var e = facet as XmlSchemaEnumerationFacet;
-                               if (e == null)
-                                       throw new InvalidDataContractException (String.Format ("Invalid simple type restriction (type {0}). Only enumeration is allowed.", qname));
-                               var em = new CodeMemberField () { Name = CodeIdentifier.MakeValid (e.Value) };
-                               var ea = new CodeAttributeDeclaration (enum_member_att_ref);
-                               if (e.Value != em.Name)
-                                       ea.Arguments.Add (new CodeAttributeArgument ("Value", new CodePrimitiveExpression (e.Value)));
-                               em.CustomAttributes.Add (ea);
-                               td.Members.Add (em);
-                       }
-               }
-
-               // Returns false if it should remove the imported type.
-               // FIXME: also support ImportXmlType
-               bool ImportComplexType (CodeTypeDeclaration td, XmlSchemaSet schemas, XmlSchemaComplexType type, XmlQualifiedName qname)
-               {
-                       foreach (XmlSchemaAttribute att in type.AttributeUses.Values)
-                               if (att.Use != XmlSchemaUse.Optional || att.QualifiedName.Namespace != KnownTypeCollection.MSSimpleNamespace)
-                                       throw new InvalidDataContractException (String.Format ("attribute in DataContract complex type '{0}' is limited to those in {1} namespace, and optional.", qname, KnownTypeCollection.MSSimpleNamespace));
-
-                       CodeTypeReference baseClrType = null;
-                       var particle = type.Particle;
-                       if (type.ContentModel != null) {
-                               var xsscr = type.ContentModel.Content as XmlSchemaSimpleContentRestriction;
-                               if (xsscr != null) {
-                                       if (xsscr.BaseType != null)
-                                               Import (schemas, xsscr.BaseType);
-                                       else
-                                               Import (schemas, xsscr.BaseTypeName);
-                                       // The above will result in an error, but make sure to show we don't support it.
-                                       throw new InvalidDataContractException (String.Format ("complex type simple content restriction is not supported in DataContract (type '{0}')", qname));
-                               }
-                               var xscce = type.ContentModel.Content as XmlSchemaComplexContentExtension;
-                               if (xscce != null) {
-                                       Import (schemas, xscce.BaseTypeName);
-                                       baseClrType = GetCodeTypeReferenceInternal (xscce.BaseTypeName, false);
-                                       if (baseClrType != null)
-                                               td.BaseTypes.Add (baseClrType);
-
-                                       var baseInfo = GetTypeInfo (xscce.BaseTypeName, false);
-                                       if (baseInfo != null)
-                                               baseInfo.KnownClrTypes.Add (imported_types.First (it => it.XsdType == type).ClrType);
-                                       particle = xscce.Particle;
-                               }
-                               var xsccr = type.ContentModel.Content as XmlSchemaComplexContentRestriction;
-                               if (xsccr != null)
-                                       throw new InvalidDataContractException (String.Format ("complex content type (for type '{0}') has a restriction content model, which is not supported in DataContract.", qname));
-                       }
-
-                       var seq = particle as XmlSchemaSequence;
-                       if (seq == null && particle != null)
-                               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));
-
-                       if (seq != null) {
-
-                       foreach (var child in seq.Items)
-                               if (!(child is XmlSchemaElement))
-                                       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));
-
-                       if (seq.Items.Count == 1) {
-                               var xe = (XmlSchemaElement) seq.Items [0];
-                               if (xe.MaxOccursString == "unbounded") {
-                                       // import as a collection contract.
-                                       if (type.QualifiedName.Namespace == KnownTypeCollection.MSArraysNamespace &&
-                                           IsPredefinedType (xe.ElementSchemaType.QualifiedName)) {
-                                               // then this CodeTypeDeclaration is to be removed, and CodeTypeReference to this type should be an array instead.
-                                               var cti = imported_types.First (i => i.XsdType == type);
-                                               cti.ClrType = new CodeTypeReference (GetCodeTypeReference (xe.ElementSchemaType.QualifiedName), 1);
-                                               
-                                               return false;
-                                       }
-                                       else
-                                               Import (schemas, xe.ElementSchemaType);
-                                       td.BaseTypes.Add (new CodeTypeReference ("System.Collections.Generic.List", GetCodeTypeReference (xe.ElementSchemaType.QualifiedName)));
-                                       AddTypeAttributes (td, type, CodeIdentifier.MakeValid (xe.QualifiedName.Name));
-                                       return true;
-                               }
-                       }
-
-                       // import as a (normal) contract.
-                       var elems = new List<XmlSchemaElement> ();
-                       foreach (XmlSchemaElement xe in seq.Items) {
-                               if (xe.MaxOccurs != 1)
-                                       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));
-
-                               if (elems.Any (e => e.QualifiedName.Name == xe.QualifiedName.Name))
-                                       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));
-
-                               elems.Add (xe);
-                       }
-                       foreach (var xe in elems) {
-                               // import property type in prior.
-                               Import (schemas, xe.ElementSchemaType.QualifiedName);
-                               AddProperty (td, xe);
-                       }
-
-                       } // if (seq != 0)
-
-                       AddTypeAttributes (td, type, null);
-                       AddExtensionData (td);
-
-                       return true;
-               }
-
-               static readonly CodeExpression this_expr = new CodeThisReferenceExpression ();
-               static readonly CodeExpression arg_value_expr = new CodePropertySetValueReferenceExpression ();
-
-               bool GenerateInternal {
-                       get { return Options != null && Options.GenerateInternal; }
-               }
-
-               void AddProperty (CodeTypeDeclaration td, XmlSchemaElement xe)
-               {
-                       var att = GenerateInternal ? MemberAttributes.Assembly : MemberAttributes.Public;
-                       var fi = new CodeMemberField () { Name = CodeIdentifier.MakeValid (xe.QualifiedName.Name + "Field"), Type = GetCodeTypeReference (xe.ElementSchemaType.QualifiedName, xe) };
-                       td.Members.Add (fi);
-                       var pi = new CodeMemberProperty () { Name = xe.QualifiedName.Name, Attributes = att, HasGet = true, HasSet = true, Type = fi.Type };
-                       // [DataMember(Name=foobar, IsRequired=!nillable)]
-                       var dma = new CodeAttributeDeclaration (
-                               new CodeTypeReference (typeof (DataMemberAttribute)));
-                       if (fi.Name != xe.QualifiedName.Name)
-                               new CodeAttributeArgument ("Name", new CodePrimitiveExpression (xe.QualifiedName.Name));
-                       if (!xe.IsNillable)
-                               new CodeAttributeArgument ("IsRequired", new CodePrimitiveExpression (true));
-                       pi.CustomAttributes.Add (dma);
-
-                       pi.GetStatements.Add (new CodeMethodReturnStatement () { Expression = new CodeFieldReferenceExpression (this_expr, fi.Name) });
-                       pi.SetStatements.Add (new CodeAssignStatement (new CodeFieldReferenceExpression (this_expr, fi.Name), arg_value_expr));
-
-
-                       td.Members.Add (pi);
-               }
-
-               bool IsPredefinedType (XmlQualifiedName qname)
-               {
-                       // FIXME: support char, guid and duration (MSSimpleNamespace); fix GetPrimitiveTypeFromName() first and then this at a time.
-                       switch (qname.Namespace) {
-                       case KnownTypeCollection.MSSimpleNamespace:
-                               switch (qname.Name) {
-                               case "char":
-                               case "guid":
-                               case "duration":
-                                       return true;
-                               }
-                               return false;
-                       case XmlSchema.Namespace:
-                               return KnownTypeCollection.GetPrimitiveTypeFromName (qname.Name) != null;
-                       }
-                       return false;
-               }
-
-               CodeNamespace GetCodeNamespace (XmlQualifiedName name)
-               {
-                       string ns = null;
-                       if (Options == null || !Options.Namespaces.TryGetValue (name.Namespace, out ns))
-                               ns = GetCodeNamespaceFromXmlns (name.Namespace);
-
-                       foreach (CodeNamespace cns in CodeCompileUnit.Namespaces)
-                               if (cns.Name == ns)
-                                       return cns;
-                       var newCns = new CodeNamespace () { Name = ns };
-                       CodeCompileUnit.Namespaces.Add (newCns);
-                       return newCns;
-               }
-
-               const string default_ns_prefix = "http://schemas.datacontract.org/2004/07/";
-
-               string GetCodeNamespaceFromXmlns (string xns)
-               {
-                       if (xns.StartsWith (default_ns_prefix, StringComparison.Ordinal))
-                               xns = xns.Substring (default_ns_prefix.Length);
-                       else {
-                               Uri u;
-                               string tmp;
-                               if (Uri.TryCreate (xns, UriKind.Absolute, out u) && (tmp = MakeStringNamespaceComponentsValid (u.GetComponents (UriComponents.Host | UriComponents.Path, UriFormat.Unescaped))).Length > 0)
-                                       xns = tmp;
-                       }
-                       return MakeStringNamespaceComponentsValid (xns);
-               }
-
-               static readonly char [] split_tokens = new char [] {'/', '.'};
-
-               string MakeStringNamespaceComponentsValid (string ns)
-               {
-                       var arr = ns.Split (split_tokens, StringSplitOptions.RemoveEmptyEntries);
-                       for (int i = 0; i < arr.Length; i++)
-                               arr [i] = CodeIdentifier.MakeValid (arr [i]);
-                       return String.Join (".", arr);
-               }
-
-               // Post-compilation information retrieval
-
-               TypeImportInfo GetTypeInfo (XmlQualifiedName typeName, bool throwError)
-               {
-                       var info = imported_types.FirstOrDefault (i => i.XsdTypeName.Equals (typeName));
-                       if (info == null) {
-                               if (throwError)
-                                       throw new InvalidOperationException (String.Format ("schema type '{0}' has not been imported yet. Import it first.", typeName));
-                               return null;
-                       }
-                       return info;
-               }
-
-               public CodeTypeReference GetCodeTypeReference (XmlQualifiedName typeName)
-               {
-                       return GetCodeTypeReferenceInternal (typeName, true);
-               }
-
-               CodeTypeReference GetCodeTypeReferenceInternal (XmlQualifiedName typeName, bool throwError)
-               {
-                       if (typeName == null)
-                               throw new ArgumentNullException ("typeName");
-
-                       switch (typeName.Namespace) {
-                       case XmlSchema.Namespace:
-                               return new CodeTypeReference (KnownTypeCollection.GetPrimitiveTypeFromName (typeName.Name));
-                       case KnownTypeCollection.MSSimpleNamespace:
-                               switch (typeName.Name) {
-                               case "guid":
-                                       return new CodeTypeReference (typeof (Guid));
-                               case "duration":
-                                       return new CodeTypeReference (typeof (TimeSpan));
-                               }
-                               break;
-                       }
-
-                       var info = GetTypeInfo (typeName, throwError);
-                       return info != null ? info.ClrType : null;
-               }
-
-               [MonoTODO ("use element argument and fill Nullable etc.")]
-               public CodeTypeReference GetCodeTypeReference (XmlQualifiedName typeName, XmlSchemaElement element)
-               {
-                       if (typeName == null)
-                               throw new ArgumentNullException ("typeName");
-                       if (element == null)
-                               throw new ArgumentNullException ("element");
-
-                       return GetCodeTypeReference (typeName);
-               }
-
-               public ICollection<CodeTypeReference> GetKnownTypeReferences (XmlQualifiedName typeName)
-               {
-                       if (typeName == null)
-                               throw new ArgumentNullException ("typeName");
-
-                       return GetTypeInfo (typeName, true).KnownClrTypes;
-               }
-
-               List<TypeImportInfo> imported_types = new List<TypeImportInfo> ();
-
-               class TypeImportInfo
-               {
-                       public TypeImportInfo ()
-                       {
-                               KnownClrTypes = new List<CodeTypeReference> ();
-                       }
-
-                       public CodeTypeReference ClrType { get; set; }
-                       public XmlQualifiedName XsdTypeName { get; set; }
-                       public XmlSchemaType XsdType { get; set; }
-                       public List<CodeTypeReference> KnownClrTypes { get; private set; }
-                       public int KnownTypeOutputIndex { get; set; } // updated while importing.
-               }
-       }
-}
index 74f89bafc6f53a3befd5ef6cb8ee06d776b53002..7d46901d6ab53f7dd9bd722346f098123832563f 100644 (file)
@@ -4,7 +4,7 @@
 // Author:
 //     Atsushi Enomoto <atsushi@ximian.com>
 //
-// Copyright (C) 2005 Novell, Inc.  http://www.novell.com
+// Copyright (C) 2010 Novell, Inc.  http://www.novell.com
 //
 // Permission is hereby granted, free of charge, to any person obtaining
 // a copy of this software and associated documentation files (the
 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
-#if NET_2_0
+
 using System;
 using System.CodeDom;
+using System.CodeDom.Compiler;
 using System.Collections.Generic;
 using System.IO;
+using System.Linq;
+using System.Reflection;
 using System.Xml;
 using System.Xml.Schema;
 using System.Xml.Serialization;
 
-using QName = System.Xml.XmlQualifiedName;
-
 namespace System.Runtime.Serialization
 {
+       [MonoTODO ("Support ImportXmlType option; support arrays; CanImport is not up to date with Import")]
        public class XsdDataContractImporter
        {
-               ImportOptions options;
-               CodeCompileUnit ccu;
-               Dictionary<QName, QName> imported_names = new Dictionary<QName, QName> ();
+               static readonly XmlQualifiedName qname_anytype = new XmlQualifiedName ("anyType", XmlSchema.Namespace);
 
                public XsdDataContractImporter ()
                        : this (null)
                {
                }
 
-               public XsdDataContractImporter (CodeCompileUnit ccu)
+               public XsdDataContractImporter (CodeCompileUnit codeCompileUnit)
                {
-                       this.ccu = ccu;
-                       this.imported_names = new Dictionary<QName, QName> ();
-               }
+                       // null argument is ok.
+                       CodeCompileUnit = codeCompileUnit ?? new CodeCompileUnit ();
 
-               public CodeCompileUnit CodeCompileUnit {
-                       get { 
-                               if (ccu == null)
-                                       ccu = new CodeCompileUnit ();
-                       
-                               return ccu; 
-                       }
+                       // Options is null by default
                }
 
-               public ImportOptions Options {
-                       get { return options; }
-                       set { options = value; }
-               }
+               public CodeCompileUnit CodeCompileUnit { get; private set; }
 
-               [MonoTODO]
-               public ICollection<CodeTypeReference> GetKnownTypeReferences (QName typeName)
-               {
-                       throw new NotImplementedException ();
-               }
+               CodeDomProvider code_provider = CodeDomProvider.CreateProvider ("csharp");
+               ImportOptions import_options;
 
-               [MonoTODO]
-               public CodeTypeReference GetCodeTypeReference (QName typeName)
-               {
-                       throw new NotImplementedException ();
+               public ImportOptions Options {
+                       get { return import_options; }
+                       set {
+                               import_options = value;
+                               code_provider = value.CodeProvider ?? code_provider;
+                       }
                }
 
-               [MonoTODO]
-               public CodeTypeReference GetCodeTypeReference (QName typeName,
-                       XmlSchemaElement element)
-               {
-                       throw new NotImplementedException ();
-               }
+               // CanImport
 
                public bool CanImport (XmlSchemaSet schemas)
                {
-                       foreach (XmlSchemaElement e in schemas.GlobalElements)
-                               if (!CanImport (schemas, e))
+                       if (schemas == null)
+                               throw new ArgumentNullException ("schemas");
+
+                       if (!schemas.IsCompiled)
+                               schemas.Compile ();
+
+                       foreach (XmlSchemaElement xe in schemas.GlobalElements.Values)
+                               if (!CanImport (schemas, xe))
                                        return false;
                        return true;
                }
 
-               public bool CanImport (XmlSchemaSet schemas,
-                       ICollection<QName> typeNames)
+               public bool CanImport (XmlSchemaSet schemas, ICollection<XmlQualifiedName> typeNames)
                {
-                       foreach (QName name in typeNames)
+                       if (schemas == null)
+                               throw new ArgumentNullException ("schemas");
+                       if (typeNames == null)
+                               throw new ArgumentNullException ("typeNames");
+
+                       if (!schemas.IsCompiled)
+                               schemas.Compile ();
+
+                       foreach (var name in typeNames)
                                if (!CanImport (schemas, name))
                                        return false;
                        return true;
                }
 
-               public bool CanImport (XmlSchemaSet schemas, QName name)
+               public bool CanImport (XmlSchemaSet schemas, XmlQualifiedName typeName)
                {
-                       return CanImport (schemas,
-                               (XmlSchemaElement) schemas.GlobalElements [name]);
+                       if (schemas == null)
+                               throw new ArgumentNullException ("schemas");
+                       if (typeName == null)
+                               throw new ArgumentNullException ("typeName");
+
+                       if (!schemas.IsCompiled)
+                               schemas.Compile ();
+
+                       if (!schemas.GlobalTypes.Contains (typeName))
+                               throw new InvalidDataContractException (String.Format ("Type {0} is not found in the schemas", typeName));
+
+                       return CanImport (schemas, schemas.GlobalTypes [typeName] as XmlSchemaComplexType);
                }
 
-               [MonoTODO]
                public bool CanImport (XmlSchemaSet schemas, XmlSchemaElement element)
                {
-                       throw new NotImplementedException ();
+                       if (schemas == null)
+                               throw new ArgumentNullException ("schemas");
+
+                       if (!schemas.IsCompiled)
+                               schemas.Compile ();
+
+                       return CanImport (schemas, element.ElementSchemaType as XmlSchemaComplexType);
                }
 
-               [MonoTODO]
+               bool CanImport (XmlSchemaSet schemas, XmlSchemaComplexType type)
+               {
+                       if (type == null || type.QualifiedName.Namespace == XmlSchema.Namespace) // xs:anyType -> not supported.
+                               return false;
+
+                       if (type.ContentModel is XmlSchemaSimpleContent) // simple content derivation is not supported.
+                               return false;
+                       if (type.ContentModel != null && type.ContentModel.Content != null) {
+                               var xscce = type.ContentModel.Content as XmlSchemaComplexContentExtension;
+                               if (xscce == null) // complex DBR is not supported.
+                                       return false;
+                               // check base type
+                               if (xscce.BaseTypeName != qname_anytype && !CanImport (schemas, xscce.BaseTypeName))
+                                       return false;
+                       }
+
+                       return true;
+               }
+
+               // Import
+
                public void Import (XmlSchemaSet schemas)
                {
                        if (schemas == null)
                                throw new ArgumentNullException ("schemas");
 
-                       schemas.Compile ();
-                       foreach (XmlSchemaElement e in schemas.GlobalElements.Values)
-                               ImportInternal (schemas, e.QualifiedName);
+                       if (!schemas.IsCompiled)
+                               schemas.Compile ();
+
+                       foreach (XmlSchemaElement xe in schemas.GlobalElements.Values)
+                               Import (schemas, xe);
                }
 
-               public void Import (XmlSchemaSet schemas,
-                       ICollection<QName> typeNames)
+               public void Import (XmlSchemaSet schemas, ICollection<XmlQualifiedName> typeNames)
                {
                        if (schemas == null)
                                throw new ArgumentNullException ("schemas");
                        if (typeNames == null)
                                throw new ArgumentNullException ("typeNames");
-
-                       schemas.Compile ();
-                       foreach (QName name in typeNames)
-                               ImportInternal (schemas, name);
+                       foreach (var name in typeNames)
+                               Import (schemas, name);
                }
 
-               public void Import (XmlSchemaSet schemas, QName name)
+               // This checks type existence and raises an error if it is missing.
+               public void Import (XmlSchemaSet schemas, XmlQualifiedName typeName)
                {
                        if (schemas == null)
                                throw new ArgumentNullException ("schemas");
-                       if (name == null)
-                               throw new ArgumentNullException ("name");
+                       if (typeName == null)
+                               throw new ArgumentNullException ("typeName");
 
-                       schemas.Compile ();
-                       
-                       if (schemas.GlobalTypes [name] == null)
-                               throw new InvalidDataContractException (String.Format (
-                                               "Type with name '{0}' not found in schema with namespace '{1}'", 
-                                               name.Name, name.Namespace));
+                       if (IsPredefinedType (typeName))
+                               return;
+
+                       if (!schemas.GlobalTypes.Contains (typeName))
+                               throw new InvalidDataContractException (String.Format ("Type {0} is not found in the schemas", typeName));
 
-                       ImportInternal (schemas, name);
+                       Import (schemas, schemas.GlobalTypes [typeName] as XmlSchemaType, typeName);
                }
 
-               [MonoTODO]
-               public QName Import (XmlSchemaSet schemas, XmlSchemaElement element)
+               public XmlQualifiedName Import (XmlSchemaSet schemas, XmlSchemaElement element)
                {
                        if (schemas == null)
                                throw new ArgumentNullException ("schemas");
                        if (element == null)
                                throw new ArgumentNullException ("element");
 
-                       schemas.Compile ();
-                       QName ret = ImportInternal (schemas, element.QualifiedName);
+                       var elname = element.QualifiedName;
 
-                       foreach (QName qname in schemas.GlobalTypes.Names)
-                               ImportInternal (schemas, qname);
+                       switch (elname.Namespace) {
+                       case KnownTypeCollection.MSSimpleNamespace:
+                               switch (elname.Name) {
+                               case "char":
+                               case "duration":
+                               case "guid":
+                                       return elname;
+                               }
+                               break;
+                       }
 
-                       return ret;
+                       // FIXME: use element to fill nillable and arrays.
+                       var qname = element.SchemaType != null ? element.QualifiedName : element.ElementSchemaType.QualifiedName;
+                       Import (schemas, element.ElementSchemaType, qname);
+                       return qname;
                }
 
-               private QName ImportInternal (XmlSchemaSet schemas, QName qname)
+               void Import (XmlSchemaSet schemas, XmlSchemaType type)
                {
-                       if (qname.Namespace == KnownTypeCollection.MSSimpleNamespace)
-                               //Primitive type
-                               return qname;
+                       Import (schemas, type, type.QualifiedName);
+               }
 
-                       if (imported_names.ContainsKey (qname))
-                               return imported_names [qname];
+               void Import (XmlSchemaSet schemas, XmlSchemaType type, XmlQualifiedName qname)
+               {
+                       var existing = imported_types.FirstOrDefault (it => it.XsdType == type);
+                       if (existing != null)
+                               return;// existing.XsdTypeName;
 
-                       XmlSchemas xss = new XmlSchemas ();
-                       foreach (XmlSchema schema in schemas.Schemas ())
-                               xss.Add (schema);
-                       
-                       XmlSchemaImporter xsi = new XmlSchemaImporter (xss);
-                       XmlTypeMapping xtm = xsi.ImportTypeMapping (qname);
+                       if (IsPredefinedType (type.QualifiedName))
+                               return;
 
-                       ImportFromTypeMapping (xtm);
-                       return qname;
+                       DoImport (schemas, type, qname);
                }
 
-               //Duplicate code from ServiceContractGenerator.ExportDataContract
-               private void ImportFromTypeMapping (XmlTypeMapping mapping)
+               void DoImport (XmlSchemaSet schemas, XmlSchemaType type, XmlQualifiedName qname)
                {
-                       if (mapping == null)
-                               return;
+                       CodeNamespace cns = null;
+                       CodeTypeReference clrRef;
+                       cns = GetCodeNamespace (qname);
+                       clrRef = new CodeTypeReference (cns.Name.Length > 0 ? cns.Name + "." + qname.Name : qname.Name);
+
+                       var td = new CodeTypeDeclaration () {
+                               Name = CodeIdentifier.MakeValid (qname.Name),
+                               TypeAttributes = GenerateInternal ? TypeAttributes.NotPublic : TypeAttributes.Public };
+                       cns.Types.Add (td);
+
+                       var info = new TypeImportInfo () { ClrType = clrRef, XsdType = type,  XsdTypeName = qname };
+                       imported_types.Add (info);
+
+                       var st = type as XmlSchemaSimpleType;
+                       if (st != null) {
+                               ImportSimpleType (td, schemas, st, qname);
+                       } else {
+                               var ct = (XmlSchemaComplexType) type;
+                               var sc = ct.ContentModel as XmlSchemaSimpleContent;
+                               if (sc != null) {
+                                       if (sc.Content is XmlSchemaSimpleContentExtension)
+                                               throw new InvalidDataContractException (String.Format ("complex type '{0}' with simple content extension is not supported", type.QualifiedName));
+                               }
+                               if (!ImportComplexType (td, schemas, ct, qname)) {
+                                       cns.Types.Remove (td);
+                                       if (cns.Types.Count == 0)
+                                               CodeCompileUnit.Namespaces.Remove (cns);
+                               }
+                       }
+
+                       foreach (var impinfo in imported_types)
+                               for (; impinfo.KnownTypeOutputIndex < impinfo.KnownClrTypes.Count; impinfo.KnownTypeOutputIndex++)
+                                       td.CustomAttributes.Add (new CodeAttributeDeclaration (
+                                               new CodeTypeReference (typeof (KnownTypeAttribute)),
+                                               new CodeAttributeArgument (new CodeTypeOfExpression (impinfo.KnownClrTypes [impinfo.KnownTypeOutputIndex]))));
+               }
 
-                       QName qname = new QName (mapping.TypeName, mapping.Namespace);
-                       if (imported_names.ContainsKey (qname))
+               static readonly string ass_name = typeof (DataContractAttribute).Assembly.GetName ().Name;
+               static readonly string ass_version = typeof (DataContractAttribute).Assembly.GetName ().Version.ToString ();
+               static readonly CodeTypeReference typeref_data_contract = new CodeTypeReference (typeof (DataContractAttribute));
+               static readonly CodeTypeReference typeref_coll_contract = new CodeTypeReference (typeof (CollectionDataContractAttribute));
+
+               void AddTypeAttributes (CodeTypeDeclaration td, XmlSchemaType type, string collectionItemName)
+               {
+                       var name = type.QualifiedName;
+                       // [GeneratedCode (assembly_name, assembly_version)]
+                       td.CustomAttributes.Add (new CodeAttributeDeclaration (
+                               new CodeTypeReference (typeof (GeneratedCodeAttribute)),
+                               new CodeAttributeArgument (new CodePrimitiveExpression (ass_name)),
+                               new CodeAttributeArgument (new CodePrimitiveExpression (ass_version))));
+
+                       var ct = type as XmlSchemaComplexType;
+
+                       // [DataContract(Name="foobar",Namespace="urn:foobar")] (optionally IsReference=true),
+                       // or [CollectionDataContract(ditto)]
+                       var dca = new CodeAttributeDeclaration (
+                               collectionItemName != null ? typeref_coll_contract : typeref_data_contract,
+                               new CodeAttributeArgument ("Name", new CodePrimitiveExpression (name.Name)),
+                               new CodeAttributeArgument ("Namespace", new CodePrimitiveExpression (name.Namespace)));
+                       if (collectionItemName != null)
+                               dca.Arguments.Add (new CodeAttributeArgument ("ItemName", new CodePrimitiveExpression (collectionItemName)));
+                       if (ct != null && ct.AttributeUses [new XmlQualifiedName ("Ref", KnownTypeCollection.MSSimpleNamespace)] != null)
+                               dca.Arguments.Add (new CodeAttributeArgument ("IsReference", new CodePrimitiveExpression (true)));
+                       td.CustomAttributes.Add (dca);
+
+                       // optional [Serializable]
+                       if (Options != null && Options.GenerateSerializable)
+                               td.CustomAttributes.Add (new CodeAttributeDeclaration ("System.SerializableAttribute"));
+               }
+
+               static readonly CodeTypeReference typeref_ext_iface = new CodeTypeReference ("System.Runtime.Serialization.IExtensibleDataObject");
+               static readonly CodeTypeReference typeref_ext_class = new CodeTypeReference ("System.Runtime.Serialization.ExtensibleDataObject");
+
+               void AddExtensionData (CodeTypeDeclaration td)
+               {
+                       td.BaseTypes.Add (typeref_ext_iface);
+
+                       var field = new CodeMemberField (typeref_ext_class, "extensionDataField");
+                       td.Members.Add (field);
+
+                       var prop = new CodeMemberProperty () { Type = field.Type, Name = "ExtensionData", Attributes = (GenerateInternal ? MemberAttributes.Assembly : MemberAttributes.Public) | MemberAttributes.Final };
+                       prop.GetStatements.Add (new CodeMethodReturnStatement (
+                               new CodeFieldReferenceExpression (
+                               new CodeThisReferenceExpression (),
+                               "extensionDataField")));
+                       prop.SetStatements.Add (new CodeAssignStatement (
+                               new CodeFieldReferenceExpression (
+                               new CodeThisReferenceExpression (),
+                               "extensionDataField"),
+                               new CodePropertySetValueReferenceExpression ()));
+
+                       td.Members.Add (prop);
+               }
+
+               void ImportSimpleType (CodeTypeDeclaration td, XmlSchemaSet schemas, XmlSchemaSimpleType type, XmlQualifiedName qname)
+               {
+                       var scl = type.Content as XmlSchemaSimpleTypeList;
+                       if (scl != null) {
+                               if (scl.ItemType == null)
+                                       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));
+                               var itemType = scl.ItemType as XmlSchemaSimpleType;
+                               var ir = itemType.Content as XmlSchemaSimpleTypeRestriction;
+                               if (ir == null)
+                                       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));
+                               ImportEnum (td, schemas, ir, type, qname, true);
+                               return;
+                       }
+                       var scr = type.Content as XmlSchemaSimpleTypeRestriction;
+                       if (scr != null) {
+                               ImportEnum (td, schemas, scr, type, qname, false);
                                return;
+                       }
+
+                       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));
+               }
+
+               static readonly CodeTypeReference enum_member_att_ref = new CodeTypeReference (typeof (EnumMemberAttribute));
+
+               void ImportEnum (CodeTypeDeclaration td, XmlSchemaSet schemas, XmlSchemaSimpleTypeRestriction r, XmlSchemaType type, XmlQualifiedName qname, bool isFlag)
+               {
+                       if (isFlag && !r.BaseTypeName.Equals (new XmlQualifiedName ("string", XmlSchema.Namespace)))
+                               throw new InvalidDataContractException (String.Format ("For flags enumeration '{0}', the base type for the simple type restriction must be XML schema string", qname));
+
+                       td.IsEnum = true;
+                       AddTypeAttributes (td, type, null);
+                       if (isFlag)
+                               td.CustomAttributes.Add (new CodeAttributeDeclaration (new CodeTypeReference (typeof (FlagsAttribute))));
+
+                       foreach (var facet in r.Facets) {
+                               var e = facet as XmlSchemaEnumerationFacet;
+                               if (e == null)
+                                       throw new InvalidDataContractException (String.Format ("Invalid simple type restriction (type {0}). Only enumeration is allowed.", qname));
+                               var em = new CodeMemberField () { Name = CodeIdentifier.MakeValid (e.Value) };
+                               var ea = new CodeAttributeDeclaration (enum_member_att_ref);
+                               if (e.Value != em.Name)
+                                       ea.Arguments.Add (new CodeAttributeArgument ("Value", new CodePrimitiveExpression (e.Value)));
+                               em.CustomAttributes.Add (ea);
+                               td.Members.Add (em);
+                       }
+               }
 
-                       CodeNamespace cns = new CodeNamespace ();
-                       cns.Name = FromXmlnsToClrName (mapping.Namespace);
-
-                       XmlCodeExporter xce = new XmlCodeExporter (cns);
-                       xce.ExportTypeMapping (mapping);
-
-                       List <CodeTypeDeclaration> to_remove = new List <CodeTypeDeclaration> ();
-                       
-                       //Process the types just generated
-                       //FIXME: Iterate and assign the types to correct namespaces
-                       //At the end, add all those namespaces to the ccu
-                       foreach (CodeTypeDeclaration type in cns.Types) {
-                               string ns = GetNamespace (type);
-                               if (ns == null)
-                                       //FIXME: do what here?
-                                       continue;
-
-                               QName type_name = new QName (type.Name, ns);
-                               if (imported_names.ContainsKey (type_name)) {
-                                       //Type got reemitted, so remove it!
-                                       to_remove.Add (type);
-                                       continue;
+               // Returns false if it should remove the imported type.
+               // FIXME: also support ImportXmlType
+               bool ImportComplexType (CodeTypeDeclaration td, XmlSchemaSet schemas, XmlSchemaComplexType type, XmlQualifiedName qname)
+               {
+                       foreach (XmlSchemaAttribute att in type.AttributeUses.Values)
+                               if (att.Use != XmlSchemaUse.Optional || att.QualifiedName.Namespace != KnownTypeCollection.MSSimpleNamespace)
+                                       throw new InvalidDataContractException (String.Format ("attribute in DataContract complex type '{0}' is limited to those in {1} namespace, and optional.", qname, KnownTypeCollection.MSSimpleNamespace));
+
+                       CodeTypeReference baseClrType = null;
+                       var particle = type.Particle;
+                       if (type.ContentModel != null) {
+                               var xsscr = type.ContentModel.Content as XmlSchemaSimpleContentRestriction;
+                               if (xsscr != null) {
+                                       if (xsscr.BaseType != null)
+                                               Import (schemas, xsscr.BaseType);
+                                       else
+                                               Import (schemas, xsscr.BaseTypeName);
+                                       // The above will result in an error, but make sure to show we don't support it.
+                                       throw new InvalidDataContractException (String.Format ("complex type simple content restriction is not supported in DataContract (type '{0}')", qname));
                                }
-                               if (type_name.Namespace == KnownTypeCollection.MSArraysNamespace) {
-                                       to_remove.Add (type);
-                                       continue;
+                               var xscce = type.ContentModel.Content as XmlSchemaComplexContentExtension;
+                               if (xscce != null) {
+                                       Import (schemas, xscce.BaseTypeName);
+                                       baseClrType = GetCodeTypeReferenceInternal (xscce.BaseTypeName, false);
+                                       if (baseClrType != null)
+                                               td.BaseTypes.Add (baseClrType);
+
+                                       var baseInfo = GetTypeInfo (xscce.BaseTypeName, false);
+                                       if (baseInfo != null)
+                                               baseInfo.KnownClrTypes.Add (imported_types.First (it => it.XsdType == type).ClrType);
+                                       particle = xscce.Particle;
                                }
+                               var xsccr = type.ContentModel.Content as XmlSchemaComplexContentRestriction;
+                               if (xsccr != null)
+                                       throw new InvalidDataContractException (String.Format ("complex content type (for type '{0}') has a restriction content model, which is not supported in DataContract.", qname));
+                       }
 
-                               imported_names [type_name] = type_name;
-
-                               type.Comments.Clear ();
-                               //Custom Attributes
-                               type.CustomAttributes.Clear ();
-
-                               type.CustomAttributes.Add (
-                                       new CodeAttributeDeclaration (
-                                               new CodeTypeReference ("System.CodeDom.Compiler.GeneratedCodeAttribute"),
-                                               new CodeAttributeArgument (new CodePrimitiveExpression ("System.Runtime.Serialization")),
-                                               new CodeAttributeArgument (new CodePrimitiveExpression ("3.0.0.0"))));
-                       
-                               type.CustomAttributes.Add (
-                                       new CodeAttributeDeclaration (
-                                               new CodeTypeReference ("System.Runtime.Serialization.DataContractAttribute")));
-
-                               if (type.IsEnum)
-                                       //FIXME: Add test case for this
-                                       continue;
-       
-                               //BaseType and interface
-                               type.BaseTypes.Add (new CodeTypeReference (typeof (object)));
-                               type.BaseTypes.Add (new CodeTypeReference ("System.Runtime.Serialization.IExtensibleDataObject"));
-
-                               foreach (CodeTypeMember mbr in type.Members) {
-                                       CodeMemberProperty p = mbr as CodeMemberProperty;
-                                       if (p == null)
-                                               continue;
-
-                                       if ((p.Attributes & MemberAttributes.Public) == MemberAttributes.Public) {
-                                               //FIXME: Clear all attributes or only XmlElementAttribute?
-                                               p.CustomAttributes.Clear ();
-                                               p.CustomAttributes.Add (new CodeAttributeDeclaration (
-                                                       new CodeTypeReference ("System.Runtime.Serialization.DataMemberAttribute")));
-
-                                               p.Comments.Clear ();
+                       var seq = particle as XmlSchemaSequence;
+                       if (seq == null && particle != null)
+                               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));
+
+                       if (seq != null) {
+
+                       foreach (var child in seq.Items)
+                               if (!(child is XmlSchemaElement))
+                                       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));
+
+                       if (seq.Items.Count == 1) {
+                               var xe = (XmlSchemaElement) seq.Items [0];
+                               if (xe.MaxOccursString == "unbounded") {
+                                       // import as a collection contract.
+                                       if (type.QualifiedName.Namespace == KnownTypeCollection.MSArraysNamespace &&
+                                           IsPredefinedType (xe.ElementSchemaType.QualifiedName)) {
+                                               // then this CodeTypeDeclaration is to be removed, and CodeTypeReference to this type should be an array instead.
+                                               var cti = imported_types.First (i => i.XsdType == type);
+                                               cti.ClrType = new CodeTypeReference (GetCodeTypeReference (xe.ElementSchemaType.QualifiedName), 1);
+                                               
+                                               return false;
                                        }
+                                       else
+                                               Import (schemas, xe.ElementSchemaType);
+                                       td.BaseTypes.Add (new CodeTypeReference ("System.Collections.Generic.List", GetCodeTypeReference (xe.ElementSchemaType.QualifiedName)));
+                                       AddTypeAttributes (td, type, CodeIdentifier.MakeValid (xe.QualifiedName.Name));
+                                       return true;
                                }
+                       }
 
-                               //Fields
-                               CodeMemberField field = new CodeMemberField (
-                                       new CodeTypeReference ("System.Runtime.Serialization.ExtensionDataObject"),
-                                       "extensionDataField");
-                               field.Attributes = MemberAttributes.Private | MemberAttributes.Final;
-                               type.Members.Add (field);
-
-                               //Property 
-                               CodeMemberProperty prop = new CodeMemberProperty ();
-                               prop.Type = new CodeTypeReference ("System.Runtime.Serialization.ExtensionDataObject");
-                               prop.Name = "ExtensionData";
-                               prop.Attributes = MemberAttributes.Public | MemberAttributes.Final;
-
-                               //Get
-                               prop.GetStatements.Add (new CodeMethodReturnStatement (
-                                       new CodeFieldReferenceExpression (
-                                       new CodeThisReferenceExpression (),
-                                       "extensionDataField")));
-
-                               //Set
-                               prop.SetStatements.Add (new CodeAssignStatement (
-                                       new CodeFieldReferenceExpression (
-                                       new CodeThisReferenceExpression (),
-                                       "extensionDataField"),
-                                       new CodePropertySetValueReferenceExpression ()));
-
-                               type.Members.Add (prop);
+                       // import as a (normal) contract.
+                       var elems = new List<XmlSchemaElement> ();
+                       foreach (XmlSchemaElement xe in seq.Items) {
+                               if (xe.MaxOccurs != 1)
+                                       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));
+
+                               if (elems.Any (e => e.QualifiedName.Name == xe.QualifiedName.Name))
+                                       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));
+
+                               elems.Add (xe);
                        }
+                       foreach (var xe in elems) {
+                               // import property type in prior.
+                               Import (schemas, xe.ElementSchemaType.QualifiedName);
+                               AddProperty (td, xe);
+                       }
+
+                       } // if (seq != 0)
+
+                       AddTypeAttributes (td, type, null);
+                       AddExtensionData (td);
+
+                       return true;
+               }
+
+               static readonly CodeExpression this_expr = new CodeThisReferenceExpression ();
+               static readonly CodeExpression arg_value_expr = new CodePropertySetValueReferenceExpression ();
+
+               bool GenerateInternal {
+                       get { return Options != null && Options.GenerateInternal; }
+               }
 
-                       foreach (CodeTypeDeclaration type in to_remove)
-                               cns.Types.Remove (type);
+               void AddProperty (CodeTypeDeclaration td, XmlSchemaElement xe)
+               {
+                       var att = GenerateInternal ? MemberAttributes.Assembly : MemberAttributes.Public;
+                       var fi = new CodeMemberField () { Name = CodeIdentifier.MakeValid (xe.QualifiedName.Name + "Field"), Type = GetCodeTypeReference (xe.ElementSchemaType.QualifiedName, xe) };
+                       td.Members.Add (fi);
+                       var pi = new CodeMemberProperty () { Name = xe.QualifiedName.Name, Attributes = att, HasGet = true, HasSet = true, Type = fi.Type };
+                       // [DataMember(Name=foobar, IsRequired=!nillable)]
+                       var dma = new CodeAttributeDeclaration (
+                               new CodeTypeReference (typeof (DataMemberAttribute)));
+                       if (fi.Name != xe.QualifiedName.Name)
+                               new CodeAttributeArgument ("Name", new CodePrimitiveExpression (xe.QualifiedName.Name));
+                       if (!xe.IsNillable)
+                               new CodeAttributeArgument ("IsRequired", new CodePrimitiveExpression (true));
+                       pi.CustomAttributes.Add (dma);
+
+                       pi.GetStatements.Add (new CodeMethodReturnStatement () { Expression = new CodeFieldReferenceExpression (this_expr, fi.Name) });
+                       pi.SetStatements.Add (new CodeAssignStatement (new CodeFieldReferenceExpression (this_expr, fi.Name), arg_value_expr));
+
+
+                       td.Members.Add (pi);
+               }
+
+               bool IsPredefinedType (XmlQualifiedName qname)
+               {
+                       // FIXME: support char, guid and duration (MSSimpleNamespace); fix GetPrimitiveTypeFromName() first and then this at a time.
+                       switch (qname.Namespace) {
+                       case KnownTypeCollection.MSSimpleNamespace:
+                               switch (qname.Name) {
+                               case "char":
+                               case "guid":
+                               case "duration":
+                                       return true;
+                               }
+                               return false;
+                       case XmlSchema.Namespace:
+                               return KnownTypeCollection.GetPrimitiveTypeFromName (qname.Name) != null;
+                       }
+                       return false;
+               }
 
-                       if (cns.Types.Count > 0)
-                               CodeCompileUnit.Namespaces.Add (cns);
+               CodeNamespace GetCodeNamespace (XmlQualifiedName name)
+               {
+                       string ns = null;
+                       if (Options == null || !Options.Namespaces.TryGetValue (name.Namespace, out ns))
+                               ns = GetCodeNamespaceFromXmlns (name.Namespace);
+
+                       foreach (CodeNamespace cns in CodeCompileUnit.Namespaces)
+                               if (cns.Name == ns)
+                                       return cns;
+                       var newCns = new CodeNamespace () { Name = ns };
+                       CodeCompileUnit.Namespaces.Add (newCns);
+                       return newCns;
                }
 
                const string default_ns_prefix = "http://schemas.datacontract.org/2004/07/";
 
-               string FromXmlnsToClrName (string xns)
+               string GetCodeNamespaceFromXmlns (string xns)
                {
                        if (xns.StartsWith (default_ns_prefix, StringComparison.Ordinal))
                                xns = xns.Substring (default_ns_prefix.Length);
@@ -333,24 +553,79 @@ namespace System.Runtime.Serialization
                        return String.Join (".", arr);
                }
 
-               private string GetNamespace (CodeTypeDeclaration type)
+               // Post-compilation information retrieval
+
+               TypeImportInfo GetTypeInfo (XmlQualifiedName typeName, bool throwError)
                {
-                       foreach (CodeAttributeDeclaration attr in type.CustomAttributes) {
-                               if (attr.Name == "System.Xml.Serialization.XmlTypeAttribute" ||
-                                       attr.Name == "System.Xml.Serialization.XmlRootAttribute") {
+                       var info = imported_types.FirstOrDefault (i => i.XsdTypeName.Equals (typeName));
+                       if (info == null) {
+                               if (throwError)
+                                       throw new InvalidOperationException (String.Format ("schema type '{0}' has not been imported yet. Import it first.", typeName));
+                               return null;
+                       }
+                       return info;
+               }
 
-                                       foreach (CodeAttributeArgument arg in attr.Arguments)
-                                               if (arg.Name == "Namespace")
-                                                       return ((CodePrimitiveExpression)arg.Value).Value as string;
+               public CodeTypeReference GetCodeTypeReference (XmlQualifiedName typeName)
+               {
+                       return GetCodeTypeReferenceInternal (typeName, true);
+               }
 
-                                       //Could not find Namespace arg!
-                                       return null;    
+               CodeTypeReference GetCodeTypeReferenceInternal (XmlQualifiedName typeName, bool throwError)
+               {
+                       if (typeName == null)
+                               throw new ArgumentNullException ("typeName");
+
+                       switch (typeName.Namespace) {
+                       case XmlSchema.Namespace:
+                               return new CodeTypeReference (KnownTypeCollection.GetPrimitiveTypeFromName (typeName.Name));
+                       case KnownTypeCollection.MSSimpleNamespace:
+                               switch (typeName.Name) {
+                               case "guid":
+                                       return new CodeTypeReference (typeof (Guid));
+                               case "duration":
+                                       return new CodeTypeReference (typeof (TimeSpan));
                                }
+                               break;
                        }
-                       
-                       return null;
+
+                       var info = GetTypeInfo (typeName, throwError);
+                       return info != null ? info.ClrType : null;
                }
 
+               [MonoTODO ("use element argument and fill Nullable etc.")]
+               public CodeTypeReference GetCodeTypeReference (XmlQualifiedName typeName, XmlSchemaElement element)
+               {
+                       if (typeName == null)
+                               throw new ArgumentNullException ("typeName");
+                       if (element == null)
+                               throw new ArgumentNullException ("element");
+
+                       return GetCodeTypeReference (typeName);
+               }
+
+               public ICollection<CodeTypeReference> GetKnownTypeReferences (XmlQualifiedName typeName)
+               {
+                       if (typeName == null)
+                               throw new ArgumentNullException ("typeName");
+
+                       return GetTypeInfo (typeName, true).KnownClrTypes;
+               }
+
+               List<TypeImportInfo> imported_types = new List<TypeImportInfo> ();
+
+               class TypeImportInfo
+               {
+                       public TypeImportInfo ()
+                       {
+                               KnownClrTypes = new List<CodeTypeReference> ();
+                       }
+
+                       public CodeTypeReference ClrType { get; set; }
+                       public XmlQualifiedName XsdTypeName { get; set; }
+                       public XmlSchemaType XsdType { get; set; }
+                       public List<CodeTypeReference> KnownClrTypes { get; private set; }
+                       public int KnownTypeOutputIndex { get; set; } // updated while importing.
+               }
        }
 }
-#endif
index f11b69847b8b56149c267419c6627aa9cac75c10..f32a3a56e673595ea19b8341b13af9713e054457 100644 (file)
@@ -1,3 +1,7 @@
+2010-02-18  Atsushi Enomoto  <atsushi@ximian.com>
+
+       * XsdDataContractImporterTest.cs : enabled new tests.
+
 2010-02-17  Atsushi Enomoto  <atsushi@ximian.com>
 
        * XsdDataContractImporterTest.cs : added a bunch of tests for new
index 713e9822c62bf5668dd6ac6c2f2a5534a84186b2..a64cbf57e788aac02fae91b5313c7d7a113ec288 100644 (file)
@@ -409,8 +409,6 @@ namespace MonoTests.System.Runtime.Serialization
                        Assert.IsTrue (t, "te");
                }
 
-#if false // FIXME: enable when we switch to the new implementation.
-
                CodeCompileUnit DoImport (params string [] schemaFiles)
                {
                        var ccu = new CodeCompileUnit ();
@@ -609,8 +607,6 @@ namespace MonoTests.System.Runtime.Serialization
                        DoImport ("Test/Resources/Schemas/ns27.xsd");
                }
 
-#endif
-
                /* Helper methods */
                private void CheckDC (CodeTypeDeclaration type, string name, Dictionary<string, string> members, string msg)
                {