Просмотр исходного кода

2010-03-01 Atsushi Enomoto <[email protected]>

	* SerializationMap.XsdExporter.cs, XsdDataContractExporter-new.cs:
	  refresh implementation to reflect the latest WCF impl.
	* SerializationMap.cs : make types partial.

	* XsdDataContractExporterTest.cs : remove [NotWorking].

	* System.Runtime.Serialization.dll.sources: use new implementation
	  (will be renamed later).


svn path=/trunk/mcs/; revision=152657
Atsushi Eno 16 лет назад
Родитель
Сommit
25414103fa

+ 5 - 0
mcs/class/System.Runtime.Serialization/ChangeLog

@@ -1,3 +1,8 @@
+2010-03-01  Atsushi Enomoto  <[email protected]>
+
+	* System.Runtime.Serialization.dll.sources: use new implementation
+	  (will be renamed later).
+
 2010-02-10  Atsushi Enomoto  <[email protected]>
 
 	* Makefile: add Test/Resources/Schemas/* to extra dist.

+ 2 - 1
mcs/class/System.Runtime.Serialization/System.Runtime.Serialization.dll.sources

@@ -27,11 +27,12 @@ System.Runtime.Serialization/KnownTypeAttribute.cs
 System.Runtime.Serialization/KnownTypeCollection.cs
 System.Runtime.Serialization/NetDataContractSerializer.cs
 System.Runtime.Serialization/SerializationMap.cs
+System.Runtime.Serialization/SerializationMap.XsdExporter.cs
 System.Runtime.Serialization/XmlFormatterDeserializer.cs
 System.Runtime.Serialization/XmlFormatterSerializer.cs
 System.Runtime.Serialization/XmlObjectSerializer.cs
 System.Runtime.Serialization/XmlSerializableServices.cs
-System.Runtime.Serialization/XsdDataContractExporter.cs
+System.Runtime.Serialization/XsdDataContractExporter-new.cs
 System.Runtime.Serialization/XsdDataContractImporter.cs
 System.Xml/IFragmentCapableXmlDictionaryWriter.cs
 System.Xml/IStreamProvider.cs

+ 6 - 0
mcs/class/System.Runtime.Serialization/System.Runtime.Serialization/ChangeLog

@@ -1,3 +1,9 @@
+2010-03-01  Atsushi Enomoto  <[email protected]>
+
+	* SerializationMap.XsdExporter.cs, XsdDataContractExporter-new.cs:
+	  refresh implementation to reflect the latest WCF impl.
+	* SerializationMap.cs : make types partial.
+
 2010-02-19  Atsushi Enomoto  <[email protected]>
 
 	* XsdDataContractImporter.cs : fix extension type name (and comment).

+ 116 - 0
mcs/class/System.Runtime.Serialization/System.Runtime.Serialization/SerializationMap.XsdExporter.cs

@@ -0,0 +1,116 @@
+//
+// SerializationMap.XsdExporter.cs
+//
+// Author:
+//	Atsushi Enomoto <[email protected]>
+//
+// 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;
+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
+{
+	internal abstract partial class SerializationMap
+	{
+		public abstract void ExportSchemaType (XsdDataContractExporter exporter);
+	}
+	
+	internal partial class XmlSerializableMap
+	{
+		public override void ExportSchemaType (XsdDataContractExporter exporter)
+		{
+			// .NET also expects a default constructor.
+			var ixs = (IXmlSerializable) Activator.CreateInstance (RuntimeType, true);
+			var xs = ixs.GetSchema ();
+			if (xs != null)
+				exporter.Schemas.Add (xs);
+		}
+	}
+	
+	internal partial class SharedContractMap
+	{
+		public override void ExportSchemaType (XsdDataContractExporter exporter)
+		{
+			exporter.ExportStandardComplexType (RuntimeType.GetCustomAttribute<DataContractAttribute> (false), RuntimeType);
+		}
+	}
+	
+	internal partial class DefaultTypeMap
+	{
+		public override void ExportSchemaType (XsdDataContractExporter exporter)
+		{
+			exporter.ExportStandardComplexType (null, RuntimeType);
+		}
+	}
+	
+	internal partial class CollectionContractTypeMap
+	{
+		public override void ExportSchemaType (XsdDataContractExporter exporter)
+		{
+			exporter.ExportListContractType (a, RuntimeType);
+		}
+	}
+	
+	internal partial class CollectionTypeMap
+	{
+		public override void ExportSchemaType (XsdDataContractExporter exporter)
+		{
+			exporter.ExportListContractType (null, RuntimeType);
+		}
+	}
+	
+	internal partial class DictionaryTypeMap
+	{
+		public override void ExportSchemaType (XsdDataContractExporter exporter)
+		{
+			exporter.ExportDictionaryContractType (a, RuntimeType, GetGenericDictionaryInterface (RuntimeType));
+		}
+	}
+	
+	internal partial class SharedTypeMap
+	{
+		public override void ExportSchemaType (XsdDataContractExporter exporter)
+		{
+			throw new NotImplementedException ();
+		}
+	}
+	
+	internal partial class EnumMap
+	{
+		public override void ExportSchemaType (XsdDataContractExporter exporter)
+		{
+			exporter.ExportEnumContractType (RuntimeType.GetCustomAttribute<DataContractAttribute> (false), RuntimeType);
+		}
+	}
+}

+ 12 - 9
mcs/class/System.Runtime.Serialization/System.Runtime.Serialization/SerializationMap.cs

@@ -78,7 +78,7 @@ namespace System.Runtime.Serialization
 	  exists (and raises InvalidOperationException if required).
 
 */
-	internal abstract class SerializationMap
+	internal abstract partial class SerializationMap
 	{
 		public const BindingFlags AllInstanceFlags =
 			BindingFlags.Public | BindingFlags.NonPublic |
@@ -461,7 +461,7 @@ namespace System.Runtime.Serialization
 		}
 	}
 
-	internal class XmlSerializableMap : SerializationMap
+	internal partial class XmlSerializableMap : SerializationMap
 	{
 		public XmlSerializableMap (Type type, QName qname, KnownTypeCollection knownTypes)
 			: base (type, qname, knownTypes)
@@ -494,7 +494,7 @@ namespace System.Runtime.Serialization
 #endif
 	}
 
-	internal class SharedContractMap : SerializationMap
+	internal partial class SharedContractMap : SerializationMap
 	{
 		public SharedContractMap (
 			Type type, QName qname, KnownTypeCollection knownTypes)
@@ -559,7 +559,7 @@ namespace System.Runtime.Serialization
 		}
 	}
 
-	internal class DefaultTypeMap : SerializationMap
+	internal partial class DefaultTypeMap : SerializationMap
 	{
 		public DefaultTypeMap (Type type, KnownTypeCollection knownTypes)
 			: base (type, KnownTypeCollection.GetContractQName (type, null, null), knownTypes)
@@ -590,13 +590,16 @@ namespace System.Runtime.Serialization
 
 	// FIXME: it still needs to consider ItemName/KeyName/ValueName
 	// (especially Dictionary collection is not likely considered yet.)
-	internal class CollectionContractTypeMap : CollectionTypeMap
+	internal partial class CollectionContractTypeMap : CollectionTypeMap
 	{
+		CollectionDataContractAttribute a;
+
 		public CollectionContractTypeMap (
 			Type type, CollectionDataContractAttribute a, Type elementType,
 			QName qname, KnownTypeCollection knownTypes)
 			: base (type, elementType, qname, knownTypes)
 		{
+			this.a = a;
 			IsReference = a.IsReference;
 		}
 
@@ -609,7 +612,7 @@ namespace System.Runtime.Serialization
 	{
 	}
 
-	internal class CollectionTypeMap : SerializationMap, ICollectionTypeMap
+	internal partial class CollectionTypeMap : SerializationMap, ICollectionTypeMap
 	{
 		Type element_type;
 		internal QName element_qname;
@@ -765,7 +768,7 @@ namespace System.Runtime.Serialization
 #endif
 	}
 
-	internal class DictionaryTypeMap : SerializationMap, ICollectionTypeMap
+	internal partial class DictionaryTypeMap : SerializationMap, ICollectionTypeMap
 	{
 		Type key_type, value_type;
 		QName dict_qname, item_qname, key_qname, value_qname;
@@ -955,7 +958,7 @@ namespace System.Runtime.Serialization
 #endif
 	}
 
-	internal class SharedTypeMap : SerializationMap
+	internal partial class SharedTypeMap : SerializationMap
 	{
 		public SharedTypeMap (
 			Type type, QName qname, KnownTypeCollection knownTypes)
@@ -996,7 +999,7 @@ namespace System.Runtime.Serialization
 		}
 	}
 
-	internal class EnumMap : SerializationMap
+	internal partial class EnumMap : SerializationMap
 	{
 		List<EnumMemberInfo> enum_members;
 		bool flag_attr;

+ 548 - 0
mcs/class/System.Runtime.Serialization/System.Runtime.Serialization/XsdDataContractExporter-new.cs

@@ -0,0 +1,548 @@
+//
+// XsdDataContractExporter.cs
+//
+// Author:
+//	Atsushi Enomoto <[email protected]>
+//
+// 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;
+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;
+
+//
+// .NET exports almost empty schema for "http://www.w3.org/2001/XMLSchema" that
+// contains only "schema" element which consists of a complexType with empty
+// definition (i.e. <complexType/> ).
+//
+
+namespace System.Runtime.Serialization
+{
+	static class TypeExtension
+	{
+		public static T GetCustomAttribute<T> (this MemberInfo mi, bool inherit)
+		{
+			foreach (T att in mi.GetCustomAttributes (typeof (T), inherit))
+				return att;
+			return default (T);
+		}
+	}
+
+	public class XsdDataContractExporter
+	{
+		class TypeImportInfo
+		{
+			public Type ClrType { get; set; }
+			public QName RootElementName { get; set; }
+			public XmlSchemaType SchemaType { get; set; }
+			public QName  SchemaTypeName { get; set; }
+		}
+
+		static readonly List<TypeImportInfo> predefined_types;
+
+		static XsdDataContractExporter ()
+		{
+			var l = new List<TypeImportInfo> ();
+			predefined_types = l;
+			if (!MSTypesSchema.IsCompiled)
+				MSTypesSchema.Compile (null);
+			foreach (XmlSchemaElement el in MSTypesSchema.Elements.Values) {
+				var typeName = el.ElementSchemaType.QualifiedName;
+				var info = new TypeImportInfo () {
+					RootElementName = el.QualifiedName,
+					SchemaType = typeName.Namespace == XmlSchema.Namespace ? null : el.ElementSchemaType,
+					SchemaTypeName = typeName,
+					ClrType = GetPredefinedTypeFromQName (typeName) };
+				l.Add (info);
+			}
+		}
+
+		static Type GetPredefinedTypeFromQName (QName qname)
+		{
+			switch (qname.Namespace) {
+			case XmlSchema.Namespace:
+				return KnownTypeCollection.GetPrimitiveTypeFromName (qname.Name);
+			case KnownTypeCollection.MSSimpleNamespace:
+				switch (qname.Name) {
+				case "char":
+					return typeof (char);
+				case "duration":
+					return typeof (TimeSpan);
+				case "guid":
+					return typeof (Guid);
+				}
+				break;
+			}
+			throw new Exception ("Should not happen");
+		}
+
+		static XmlSchema mstypes_schema;
+		static XmlSchema MSTypesSchema {
+			get {
+				if (mstypes_schema == null) {
+					Assembly a = Assembly.GetCallingAssembly ();
+					Stream s = a.GetManifestResourceStream ("mstypes.schema");
+					mstypes_schema= XmlSchema.Read (s, null);
+				}
+				return mstypes_schema;
+			}
+		}
+
+		KnownTypeCollection known_types = new KnownTypeCollection ();
+		List<TypeImportInfo> imported_types = new List<TypeImportInfo> ();
+
+		public XsdDataContractExporter ()
+			: this (new XmlSchemaSet ())
+		{
+		}
+		
+		public XsdDataContractExporter (XmlSchemaSet schemas)
+		{
+			if (schemas == null)
+				throw new ArgumentNullException ("schemas");
+#if false // by default this is the only added schema. But it is pointless...
+			var xs = new XmlSchema () { TargetNamespace = XmlSchema.Namespace };
+			xs.Items.Add (new XmlSchemaElement () { Name = "schema", SchemaType = new XmlSchemaComplexType () });
+			schemas.Add (xs);
+#else // FIXME: it is added only when the included items are in use.
+			schemas.Add (MSTypesSchema);
+#endif
+			Schemas = schemas;
+		}
+		
+		public ExportOptions Options { get; set; }
+		public XmlSchemaSet Schemas { get; private set; }
+
+		// CanExport implementation
+
+		public bool CanExport (ICollection<Assembly> assemblies)
+		{
+			if (assemblies == null)
+				throw new ArgumentNullException ("assemblies");
+			foreach (var ass in assemblies)
+				if (!CanExport (ass.GetTypes ()))
+					return false;
+			return true;
+		}
+		
+		public bool CanExport (ICollection<Type> types)
+		{
+			if (types == null)
+				throw new ArgumentNullException ("types");
+			foreach (var type in types)
+				if (!CanExport (type))
+					return false;
+			return true;
+		}
+		
+		public bool CanExport (Type type)
+		{
+			if (type == null)
+				throw new ArgumentNullException ("type");
+
+			if (predefined_types.FirstOrDefault (i => i.ClrType == type) != null)
+				return true;
+
+			known_types.TryRegister (type);
+			return known_types.FindUserMap (type) != null;
+		}
+
+		// Export implementation
+
+		public void Export (ICollection<Assembly> assemblies)
+		{
+			if (assemblies == null)
+				throw new ArgumentNullException ("assemblies");
+			foreach (var ass in assemblies)
+				Export (ass.GetTypes ());
+		}
+		
+		public void Export (ICollection<Type> types)
+		{
+			if (types == null)
+				throw new ArgumentNullException ("types");
+			foreach (var type in types)
+				Export (type);
+		}
+		
+		public void Export (Type type)
+		{
+			if (ExportCore (type, true)) {
+				// This reprocess is required to clean up compilation state.
+				foreach (XmlSchema xs in Schemas.Schemas ())
+					Schemas.Reprocess (xs);
+				Schemas.Compile ();
+			}
+		}
+
+		// returns true if it requires recompilcation
+		bool ExportCore (Type type, bool rejectNonContract)
+		{
+			if (type == null)
+				throw new ArgumentNullException ("type");
+
+			if (predefined_types.FirstOrDefault (i => i.ClrType == type) != null) {
+				if (Schemas.Contains (MSTypesSchema.TargetNamespace))
+					return false; // exists
+				Schemas.Add (MSTypesSchema);
+				return false;
+			}
+			if (imported_types.FirstOrDefault (i => i.ClrType == type) != null)
+				return false;
+
+#if true
+			known_types.TryRegister (type);
+			var map = known_types.FindUserMap (type);
+			if (map == null)
+				return false;
+			map.ExportSchemaType (this);
+			return true;
+#else
+			var cdca = type.GetCustomAttribute<CollectionDataContractAttribute> (true);
+			var dicType = GetIDictionaryInterfaceType (type);
+			if (dicType != null) {
+				ExportDictionaryContractType (cdca, type, dicType);
+				return true;
+			}
+			// not sure if contract is required
+			if (type.IsArray && type != typeof (byte [])) {
+				ExportListContractType (cdca, type);
+				return true;
+			}
+			if (cdca != null) {
+				ExportListContractType (cdca, type);
+				return true;
+			}
+
+			var dca = type.GetCustomAttribute<DataContractAttribute> (true);
+			if (type.IsEnum) { // regardless of DCA existence.
+				ExportEnumContractType (dca, type);
+				return true;
+			}
+			if (dca != null) {
+				ExportStandardComplexType (dca, type);
+				return true;
+			}
+
+			// FIXME: support [Serializable]
+
+			if (rejectNonContract)
+				throw new InvalidDataContractException ("DataContractAttribute is missing");
+
+			return false;
+#endif
+		}
+
+		// copied from KnownTypeCollection, removing IDictionary
+		static Type GetIDictionaryInterfaceType (Type type)
+		{
+			foreach (var iface in type.GetInterfaces ())
+				if (iface == typeof (IDictionary) || (iface.IsGenericType && iface.GetGenericTypeDefinition () == typeof (IDictionary<,>)))
+					return iface;
+
+			return null;
+		}
+		
+		// copied from KnownTypeCollection, removing IDictionary
+		static Type GetCollectionInterfaceType (Type type)
+		{
+			foreach (var iface in type.GetInterfaces ())
+				if (iface == typeof (IList) || (iface.IsGenericType && iface.GetGenericTypeDefinition () == typeof (ICollection<>)))
+					return iface;
+
+			return null;
+		}
+		
+		internal void ExportDictionaryContractType (CollectionDataContractAttribute attr, Type type, Type dicType)
+		{
+			var qname = GetSchemaTypeName (type);
+
+			var typeArgs = dicType.IsGenericType ? dicType.GetGenericArguments () : null;
+			var keyType = typeArgs != null ? typeArgs [0] : typeof (object);
+			var valueType = typeArgs != null ? typeArgs [1] : typeof (object);
+			ExportCore (keyType, false);
+			ExportCore (valueType, false);
+
+			var keyName = attr.KeyName ?? "Key";
+			var valueName = attr.ValueName ?? "Value";
+
+			var ct = CreateComplexType (qname, type);
+			var appInfo = new XmlSchemaAppInfo ();
+			var node = new XmlDocument ().CreateElement ("IsDictionary", KnownTypeCollection.MSSimpleNamespace);
+			node.InnerText = "true";
+			appInfo.Markup = new XmlNode [] { node };
+			ct.Annotation = new XmlSchemaAnnotation ();
+			ct.Annotation.Items.Add (appInfo);
+
+			var seq = new XmlSchemaSequence ();
+			ct.Particle = seq;
+			var el = new XmlSchemaElement () { Name = attr.ItemName ?? "KeyValueOf" + keyName + valueName, MinOccurs = 0, MaxOccursString = "unbounded" };
+			seq.Items.Add (el);
+
+			var dictType = new XmlSchemaComplexType ();
+			el.SchemaType = dictType;
+			var dictSeq = new XmlSchemaSequence ();
+			dictType.Particle = dictSeq;
+			dictSeq.Items.Add (new XmlSchemaElement () { Name = keyName, SchemaTypeName = GetSchemaTypeName (keyType), IsNillable = true });
+			dictSeq.Items.Add (new XmlSchemaElement () { Name = valueName, SchemaTypeName = GetSchemaTypeName (valueType), IsNillable = true });
+		}
+		
+		internal void ExportListContractType (CollectionDataContractAttribute attr, Type type)
+		{
+			var qname = attr != null && attr.Name != null ? new QName (attr.Name, attr.Namespace ?? GetXmlNamespace (type)) : GetSchemaTypeName (type);
+
+			var typeArgs = type.IsGenericType ? type.GetGenericArguments () : null;
+			if (typeArgs != null && typeArgs.Length != 1)
+				throw new InvalidDataContractException ("CollectionDataContractAttribute is applied to non-collection type.");
+
+			var itemType = typeArgs != null ? typeArgs [0] : type.IsArray ? type.GetElementType () : typeof (object);
+			bool nullable = !itemType.IsValueType;
+			if (itemType.IsGenericType && itemType.GetGenericTypeDefinition () == typeof (Nullable<>)) {
+				itemType = itemType.GetGenericArguments () [0];
+				nullable = true;
+			}
+			ExportCore (itemType, false);
+
+			var itemQName = GetSchemaTypeName (itemType);
+			var itemName = attr != null && attr.ItemName != null ? attr.ItemName : itemQName.Name;
+
+			var ct = CreateComplexType (qname, type);
+			var seq = new XmlSchemaSequence ();
+			ct.Particle = seq;
+			var el = new XmlSchemaElement () { Name = itemName, MinOccurs = 0, MaxOccursString = "unbounded", SchemaTypeName = itemQName, IsNillable = nullable };
+			seq.Items.Add (el);
+
+			/*
+			var arrayType = new XmlSchemaComplexType ();
+			el.SchemaType = arrayType;
+			var arraySeq = new XmlSchemaSequence ();
+			arrayType.Particle = arraySeq;
+			arraySeq.Items.Add (new XmlSchemaElement () { Name = itemName, SchemaTypeName = itemQName, IsNillable = true });
+			*/
+		}
+
+		internal void ExportEnumContractType (DataContractAttribute attr, Type type)
+		{
+			var qname = attr != null && attr.Name != null ? new QName (attr.Name, attr.Namespace ?? GetXmlNamespace (type)) : GetSchemaTypeName (type);
+			var st = CreateSimpleType (qname, type);
+			if (type.GetCustomAttribute<FlagsAttribute> (false) != null) {
+				var list = new XmlSchemaSimpleTypeList ();
+				var sct = new XmlSchemaSimpleType ();
+				sct.Content = CreateEnumMembers (type, attr != null);
+				list.ItemType = sct;
+				st.Content = list;
+			}
+			else
+				st.Content = CreateEnumMembers (type, attr != null);
+		}
+
+		XmlSchemaSimpleTypeRestriction CreateEnumMembers (Type type, bool expectAttribute)
+		{
+			var r = new XmlSchemaSimpleTypeRestriction () { BaseTypeName = GetSchemaTypeName (typeof (string)) };
+			foreach (var mi in type.GetFields (BindingFlags.Public | BindingFlags.Static)) {
+				var ema = expectAttribute ? mi.GetCustomAttribute<EnumMemberAttribute> (false) : null;
+				if (expectAttribute && ema == null)
+					continue;
+				var xe = new XmlSchemaEnumerationFacet () { Value = ema != null && ema.Value != null ? ema.Value : mi.Name };
+				r.Facets.Add (xe);
+			}
+			return r;
+		}
+
+		internal void ExportStandardComplexType (DataContractAttribute attr, Type type)
+		{
+			var qname = attr != null && attr.Name != null ? new QName (attr.Name, attr.Namespace ?? GetXmlNamespace (type)) : GetSchemaTypeName (type);
+			var ct = CreateComplexType (qname, type);
+
+			if (type.BaseType != null && type.BaseType != typeof (object)) {
+				ExportCore (type.BaseType, false);
+				var xcc = new XmlSchemaComplexContent ();
+				ct.ContentModel = xcc;
+				var xcce = new XmlSchemaComplexContentExtension ();
+				xcc.Content = xcce;
+				xcce.BaseTypeName = GetSchemaTypeName (type.BaseType);
+				xcce.Particle = CreateMembersSequence (type, attr != null);
+			}
+			else
+				ct.Particle = CreateMembersSequence (type, attr != null);
+		}
+
+		XmlSchemaSimpleType CreateSimpleType (QName qname, Type type)
+		{
+			var xs = GetSchema (qname.Namespace);
+
+			var el = new XmlSchemaElement () { Name = qname.Name, IsNillable = true };
+			el.SchemaTypeName = qname;
+			xs.Items.Add (el);
+			var st = new XmlSchemaSimpleType () { Name = qname.Name };
+			xs.Items.Add (st);
+			imported_types.Add (new TypeImportInfo () { RootElementName = qname, SchemaType = st, SchemaTypeName = qname,  ClrType = type });
+
+			return st;
+		}
+
+		XmlSchemaComplexType CreateComplexType (QName qname, Type type)
+		{
+			var xs = GetSchema (qname.Namespace);
+
+			var el = new XmlSchemaElement () { Name = qname.Name, IsNillable = true };
+			el.SchemaTypeName = qname;
+			xs.Items.Add (el);
+			var ct = new XmlSchemaComplexType () { Name = qname.Name };
+			xs.Items.Add (ct);
+			imported_types.Add (new TypeImportInfo () { RootElementName = qname, SchemaType = ct, SchemaTypeName = qname,  ClrType = type });
+
+			return ct;
+		}
+
+		static int CompareMembers (MemberInfo m1, MemberInfo m2)
+		{
+			var a1 = m1.GetCustomAttribute<DataMemberAttribute> (false);
+			var a2 = m2.GetCustomAttribute<DataMemberAttribute> (false);
+			return a1.Order == a2.Order ? String.CompareOrdinal (a1.Name ?? m1.Name, a2.Name ?? m2.Name) : a1.Order - a2.Order;
+		}
+
+		XmlSchemaSequence CreateMembersSequence (Type type, bool expectContract)
+		{
+			var seq = new XmlSchemaSequence ();
+			var members = new List<MemberInfo> ();
+			var flags = BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly;
+			if (expectContract)
+				flags |= BindingFlags.NonPublic;
+
+			foreach (var mi in type.GetFields (flags))
+				if (!expectContract || mi.GetCustomAttribute<DataMemberAttribute> (false) != null)
+					members.Add (mi);
+			foreach (var mi in type.GetProperties (flags))
+				if ((!expectContract || mi.GetCustomAttribute<DataMemberAttribute> (false) != null) && mi.GetIndexParameters ().Length == 0)
+					members.Add (mi);
+
+			members.Sort (CompareMembers);
+
+			foreach (var mi in members) {
+				var dma = mi.GetCustomAttribute<DataMemberAttribute> (false);
+				var fi = mi as FieldInfo;
+				var pi = mi as PropertyInfo;
+				var mt = fi != null ? fi.FieldType : pi.PropertyType;
+				bool nullable = !mt.IsValueType;
+				if (mt.IsGenericType && mt.GetGenericTypeDefinition () == typeof (Nullable<>)) {
+					mt = mt.GetGenericArguments () [0];
+					nullable = true;
+				}
+				ExportCore (mt, false);
+
+				var name = dma != null && dma.Name != null ? dma.Name : mi.Name;
+				var xe = new XmlSchemaElement () { Name = name, IsNillable = nullable };
+				xe.SchemaTypeName = GetSchemaTypeName (mt);
+				seq.Items.Add (xe);
+			}
+			return seq;
+		}
+
+		XmlSchema GetSchema (string ns)
+		{
+			foreach (XmlSchema xs in Schemas.Schemas (ns))
+				return xs;
+			var nxs = new XmlSchema () { ElementFormDefault = XmlSchemaForm.Qualified };
+			if (!String.IsNullOrEmpty (ns))
+				nxs.TargetNamespace = ns;
+			Schemas.Add (nxs);
+			return nxs;
+		}
+
+		string GetXmlTypeName (Type type)
+		{
+			var qname = KnownTypeCollection.GetPrimitiveTypeName (type);
+			return qname.Equals (QName.Empty) ? type.Name : qname.Name;
+		}
+
+		string GetXmlNamespace (Type type)
+		{
+			foreach (ContractNamespaceAttribute a in type.Assembly.GetCustomAttributes (typeof (ContractNamespaceAttribute), false))
+				if (a.ClrNamespace == type.Namespace)
+					return a.ContractNamespace;
+			return KnownTypeCollection.DefaultClrNamespaceBase + type.Namespace;
+		}
+
+		// get mapping info (either exported or predefined).
+
+		public QName GetRootElementName (Type type)
+		{
+			var info = predefined_types.FirstOrDefault (i => i.ClrType == type);
+			if (info != null)
+				return info.RootElementName;
+			info = imported_types.FirstOrDefault (i => i.ClrType == type);
+			if (info != null && info.RootElementName != null)
+				return info.RootElementName;
+
+			return GetSchemaTypeName (type);
+		}
+		
+		public XmlSchemaType GetSchemaType (Type type)
+		{
+			var info = predefined_types.FirstOrDefault (i => i.ClrType == type);
+			if (info != null)
+				return info.SchemaType;
+			info = imported_types.FirstOrDefault (i => i.ClrType == type);
+			if (info != null)
+				return info.SchemaType;
+
+			return null;
+		}
+		
+		public QName GetSchemaTypeName (Type type)
+		{
+			var info = predefined_types.FirstOrDefault (i => i.ClrType == type);
+			if (info != null)
+				return info.SchemaTypeName;
+			info = imported_types.FirstOrDefault (i => i.ClrType == type);
+			if (info != null && info.SchemaTypeName != null)
+				return info.SchemaTypeName;
+
+			var cdca = type.GetCustomAttribute<CollectionDataContractAttribute> (false);
+			if (cdca != null)
+				return new QName (cdca.Name ?? GetXmlTypeName (type), cdca.Namespace ?? GetXmlNamespace (type));
+			var dca = type.GetCustomAttribute<DataContractAttribute> (false);
+			if (dca != null)
+				return new QName (dca.Name ?? GetXmlTypeName (type), dca.Namespace ?? GetXmlNamespace (type));
+
+			if (type.IsArray) {
+				var item = GetSchemaTypeName (type.GetElementType ());
+				if (item.Namespace == XmlSchema.Namespace)
+					return new QName ("ArrayOf" + item.Name, KnownTypeCollection.MSArraysNamespace);
+				return new QName ("ArrayOf" + item.Name, item.Namespace);
+			}
+
+			return new QName (type.Name, KnownTypeCollection.DefaultClrNamespaceBase + type.Namespace);
+		}
+	}
+}

+ 4 - 0
mcs/class/System.Runtime.Serialization/Test/System.Runtime.Serialization/ChangeLog

@@ -1,3 +1,7 @@
+2010-03-01  Atsushi Enomoto  <[email protected]>
+
+	* XsdDataContractExporterTest.cs : remove [NotWorking].
+
 2010-02-19  Atsushi Enomoto  <[email protected]>
 
 	* XsdDataContractImporterTest.cs : added Dictionary export tests.

+ 0 - 3
mcs/class/System.Runtime.Serialization/Test/System.Runtime.Serialization/XsdDataContractExporterTest.cs

@@ -67,7 +67,6 @@ namespace MonoTests.System.Runtime.Serialization
 		}
 
 		[Test]
-		[Category ("NotWorking")]
 		public void CanExportTest ()
 		{
 			XsdDataContractExporter xdce = new XsdDataContractExporter ();
@@ -136,7 +135,6 @@ namespace MonoTests.System.Runtime.Serialization
 		}
 
 		[Test]
-		[Category ("NotWorking")]
 		public void Dc3Test ()
 		{
 			//Check for duplicate dc2 ?
@@ -146,7 +144,6 @@ namespace MonoTests.System.Runtime.Serialization
 		}
 
 		[Test]
-		[Category ("NotWorking")]
 		public void Dc3Test2 ()
 		{
 			//Check for duplicate dc2 ?