New test.
[mono.git] / mcs / class / System.XML / System.Xml.Serialization / XmlSchemaExporter.cs
index 571525992568e43fef15affb9526f7dea4f6708f..1f42becb5280fdd6a222221b6f417a8520e2f83a 100644 (file)
@@ -150,17 +150,20 @@ namespace System.Xml.Serialization {
                                                XmlSchemaElement exe = FindElement (schema.Items, einfo.ElementName);
                                                XmlSchemaElement elem;
                                                
+                                               XmlSchemaObjectContainer container = null;
+                                               // In encoded format, the schema elements are not needed
+                                               if (!encodedFormat)
+                                                       container = new XmlSchemaObjectContainer (schema);
+
                                                Type memType = member.GetType();
                                                if (member is XmlTypeMapMemberFlatList)
                                                        throw new InvalidOperationException ("Unwrapped arrays not supported as parameters");
                                                else if (memType == typeof(XmlTypeMapMemberElement))
-                                                       elem = (XmlSchemaElement) GetSchemaElement (schema, einfo, member.DefaultValue, false);
+                                                       elem = (XmlSchemaElement) GetSchemaElement (schema,
+                                                               einfo, member.DefaultValue, false, container);
                                                else
-                                                       elem = (XmlSchemaElement) GetSchemaElement (schema, einfo, false);
-                                               
-                                               // In encoded format, the schema elements are not needed
-                                               if (!encodedFormat)
-                                                       schema.Items.Add (elem);
+                                                       elem = (XmlSchemaElement) GetSchemaElement (schema,
+                                                               einfo, false, container);
                                                
                                                if (exe != null)
                                                {
@@ -207,13 +210,33 @@ namespace System.Xml.Serialization {
                                if (xmlTypeMapping.TypeData.IsComplexType)
                                        einfo.MappedType = xmlTypeMapping;
                                einfo.IsNullable = false;
-                               schema.Items.Add (GetSchemaElement (schema, einfo, false));
+                               GetSchemaElement (schema, einfo, false, new XmlSchemaObjectContainer (schema));
                                SetElementExported (xmlTypeMapping);
                        }
                        
                        CompileSchemas ();
                }
 
+               void ExportXmlSerializableSchema (XmlSchema currentSchema, XmlSerializableMapping map)
+               {
+               if (IsMapExported (map)) return;
+               SetMapExported (map);
+               
+               if (map.Schema == null) return;
+
+                       string targetNs = map.Schema.TargetNamespace;
+               XmlSchema existingSchema = schemas [targetNs];
+               if (existingSchema == null)
+               {
+                               schemas.Add (map.Schema);
+                               ImportNamespace (currentSchema, targetNs);
+               }
+               else if (existingSchema != map.Schema)
+               {
+                               throw new InvalidOperationException("The namespace '" + targetNs +"' defined by the class '" + map.TypeFullName + "' is a duplicate.");
+               }
+               }
+
                void ExportClassSchema (XmlTypeMapping map)
                {
                        if (IsMapExported (map)) return;
@@ -245,8 +268,11 @@ namespace System.Xml.Serialization {
                                ext.AnyAttribute = anyAttribute;
                                if (map.BaseMap == null)
                                        ext.BaseTypeName = cmap.SimpleContentBaseType;
-                               else
+                               else {
                                        ext.BaseTypeName = new XmlQualifiedName (map.BaseMap.XmlType, map.BaseMap.XmlTypeNamespace);
+                                       ImportNamespace (schema, map.BaseMap.XmlTypeNamespace);
+                                       ExportClassSchema (map.BaseMap);
+                               }
                        }
                        else if (map.BaseMap != null && map.BaseMap.IncludeInSchema)
                        {
@@ -261,7 +287,8 @@ namespace System.Xml.Serialization {
                                ExportMembersMapSchema (schema, cmap, map.BaseMap, ext.Attributes, out particle, out anyAttribute);
                                ext.Particle = particle;
                                ext.AnyAttribute = anyAttribute;
-                               stype.IsMixed = cmap.XmlTextCollector != null;
+                               stype.IsMixed = HasMixedContent (map);
+                               cstype.IsMixed = BaseHasMixedContent (map);
 
                                ImportNamespace (schema, map.BaseMap.XmlTypeNamespace);
                                ExportClassSchema (map.BaseMap);
@@ -279,6 +306,18 @@ namespace System.Xml.Serialization {
                        foreach (XmlTypeMapping dmap in map.DerivedTypes)
                                if (dmap.TypeData.SchemaType == SchemaTypes.Class) ExportClassSchema (dmap);
                }
+               
+               bool BaseHasMixedContent (XmlTypeMapping map)
+               {
+                       ClassMap cmap = (ClassMap)map.ObjectMap;
+                       return (cmap.XmlTextCollector != null && (map.BaseMap != null && DefinedInBaseMap (map.BaseMap, cmap.XmlTextCollector)));
+               }
+
+               bool HasMixedContent (XmlTypeMapping map)
+               {
+                       ClassMap cmap = (ClassMap)map.ObjectMap;
+                       return (cmap.XmlTextCollector != null && (map.BaseMap == null || !DefinedInBaseMap (map.BaseMap, cmap.XmlTextCollector)));
+               }
 
                void ExportMembersMapSchema (XmlSchema schema, ClassMap map, XmlTypeMapping baseMap, XmlSchemaObjectCollection outAttributes, out XmlSchemaSequence particle, out XmlSchemaAnyAttribute anyAttribute)
                {
@@ -304,11 +343,13 @@ namespace System.Xml.Serialization {
                                        }
                                        else if (memType == typeof(XmlTypeMapMemberElement))
                                        {
-                                               seq.Items.Add (GetSchemaElement (schema, (XmlTypeMapElementInfo) member.ElementInfo [0], member.DefaultValue, true));
+                                               GetSchemaElement (schema, (XmlTypeMapElementInfo) member.ElementInfo [0], 
+                                                       member.DefaultValue, true, new XmlSchemaObjectContainer (seq));
                                        }
                                        else
                                        {
-                                               seq.Items.Add (GetSchemaElement (schema, (XmlTypeMapElementInfo) member.ElementInfo [0], true));
+                                               GetSchemaElement (schema, (XmlTypeMapElementInfo) member.ElementInfo[0], 
+                                                       true, new XmlSchemaObjectContainer (seq));
                                        }
                                }
                        }
@@ -398,10 +439,16 @@ namespace System.Xml.Serialization {
 
                XmlSchemaParticle GetSchemaElement (XmlSchema currentSchema, XmlTypeMapElementInfo einfo, bool isTypeMember)
                {
-                       return GetSchemaElement (currentSchema, einfo, System.DBNull.Value, isTypeMember);
+                       return GetSchemaElement (currentSchema, einfo, System.DBNull.Value, 
+                               isTypeMember, (XmlSchemaObjectContainer) null);
                }
                
-               XmlSchemaParticle GetSchemaElement (XmlSchema currentSchema, XmlTypeMapElementInfo einfo, object defaultValue, bool isTypeMember)
+               XmlSchemaParticle GetSchemaElement (XmlSchema currentSchema, XmlTypeMapElementInfo einfo, bool isTypeMember, XmlSchemaObjectContainer container)
+               {
+                       return GetSchemaElement (currentSchema, einfo, System.DBNull.Value, isTypeMember, container);
+               }
+
+               XmlSchemaParticle GetSchemaElement (XmlSchema currentSchema, XmlTypeMapElementInfo einfo, object defaultValue, bool isTypeMember, XmlSchemaObjectContainer container)
                {
                        if (einfo.IsTextElement) return null;
 
@@ -410,10 +457,14 @@ namespace System.Xml.Serialization {
                                XmlSchemaAny any = new XmlSchemaAny ();
                                any.MinOccurs = 0;
                                any.MaxOccurs = 1;
+                               if (container != null)
+                                       container.Items.Add (any);
                                return any;
                        }
                        
                        XmlSchemaElement selem = new XmlSchemaElement ();
+                       if (container != null)
+                               container.Items.Add (selem);
 
                        if (isTypeMember)
                        {
@@ -436,7 +487,6 @@ namespace System.Xml.Serialization {
                        {
                                if (isTypeMember) selem.IsNillable = einfo.IsNullable;
                                selem.Name = einfo.ElementName;
-                               XmlQualifiedName typeName = new XmlQualifiedName (einfo.TypeData.XmlType, einfo.DataTypeNamespace);
 
                                if (defaultValue != System.DBNull.Value)
                                        selem.DefaultValue = XmlCustomFormatter.ToXmlString (einfo.TypeData, defaultValue);
@@ -451,7 +501,8 @@ namespace System.Xml.Serialization {
                                                break;
 
                                        case SchemaTypes.XmlSerializable:
-                                               selem.SchemaType = GetSchemaXmlSerializableType ();
+                                               selem.SchemaType = GetSchemaXmlSerializableType (einfo.MappedType as XmlSerializableMapping);
+                                               ExportXmlSerializableSchema (currentSchema, einfo.MappedType as XmlSerializableMapping);
                                                break;
 
                                        case SchemaTypes.Enum:
@@ -478,7 +529,11 @@ namespace System.Xml.Serialization {
                                                break;
 
                                        case SchemaTypes.Primitive:
-                                               selem.SchemaTypeName = new XmlQualifiedName (einfo.TypeData.XmlType, einfo.DataTypeNamespace);;
+                                               selem.SchemaTypeName = new XmlQualifiedName (einfo.TypeData.XmlType, einfo.DataTypeNamespace);
+                                               if (!einfo.TypeData.IsXsdType) {
+                                                       ImportNamespace (currentSchema, einfo.MappedType.XmlTypeNamespace);
+                                                       ExportDerivedSchema (einfo.MappedType);
+                                               }
                                                break;
                                }
                        }
@@ -488,15 +543,17 @@ namespace System.Xml.Serialization {
                                foreach (XmlSchemaObject ob in memberSchema.Items)
                                        if (ob is XmlSchemaElement && ((XmlSchemaElement)ob).Name == einfo.ElementName)
                                                return selem;
-                                               
-                               memberSchema.Items.Add (GetSchemaElement (memberSchema, einfo, defaultValue, false));
+
+                               GetSchemaElement (memberSchema, einfo, defaultValue, false,
+                                       new XmlSchemaObjectContainer (memberSchema));
                        }
                        return selem;
                }
 
                void ImportNamespace (XmlSchema schema, string ns)
                {
-                       if (ns == "" || ns == schema.TargetNamespace || ns == XmlSchema.Namespace) return;
+                       if (ns == null || ns.Length == 0 ||
+                               ns == schema.TargetNamespace || ns == XmlSchema.Namespace) return;
 
                        foreach (XmlSchemaObject sob in schema.Includes)
                                if ((sob is XmlSchemaImport) && ((XmlSchemaImport)sob).Namespace == ns) return;
@@ -526,14 +583,20 @@ namespace System.Xml.Serialization {
                        return stype;
                }
 
-               XmlSchemaType GetSchemaXmlSerializableType ()
+               XmlSchemaType GetSchemaXmlSerializableType (XmlSerializableMapping map)
                {
                        XmlSchemaComplexType stype = new XmlSchemaComplexType ();
                        XmlSchemaSequence seq = new XmlSchemaSequence ();
-                       XmlSchemaElement selem = new XmlSchemaElement ();
-                       selem.RefName = new XmlQualifiedName ("schema",XmlSchema.Namespace);
-                       seq.Items.Add (selem);
-                       seq.Items.Add (new XmlSchemaAny ());
+                       if (map.Schema == null) {
+                               XmlSchemaElement selem = new XmlSchemaElement ();
+                               selem.RefName = new XmlQualifiedName ("schema",XmlSchema.Namespace);
+                               seq.Items.Add (selem);
+                               seq.Items.Add (new XmlSchemaAny ());
+                       } else {
+                               XmlSchemaAny any = new XmlSchemaAny ();
+                               any.Namespace = map.Schema.TargetNamespace;
+                               seq.Items.Add (any);
+                       }
                        stype.Particle = seq;
                        return stype;
                }
@@ -575,6 +638,23 @@ namespace System.Xml.Serialization {
                        }
                }
 
+               void ExportDerivedSchema(XmlTypeMapping map) {
+                       if (IsMapExported (map)) return;
+                       SetMapExported (map);
+
+                       XmlSchema schema = GetSchema (map.XmlTypeNamespace);
+                       XmlSchemaSimpleType stype = new XmlSchemaSimpleType ();
+                       stype.Name = map.ElementName;
+                       schema.Items.Add (stype);
+
+                       XmlSchemaSimpleTypeRestriction rest = new XmlSchemaSimpleTypeRestriction ();
+                       rest.BaseTypeName = new XmlQualifiedName (map.TypeData.MappedType.XmlType, XmlSchema.Namespace);
+                       XmlSchemaPatternFacet facet = map.TypeData.XmlSchemaPatternFacet;
+                       if (facet != null)
+                               rest.Facets.Add(facet);
+                       stype.Content = rest;
+               }
+
                void ExportEnumSchema (XmlTypeMapping map)
                {
                        if (IsMapExported (map)) return;
@@ -738,7 +818,8 @@ namespace System.Xml.Serialization {
                        if (schema == null)
                        {
                                schema = new XmlSchema ();
-                               schema.TargetNamespace = ns;
+                               if (ns != null && ns.Length > 0)
+                                       schema.TargetNamespace = ns;
                                if (!encodedFormat)
                                        schema.ElementFormDefault = XmlSchemaForm.Qualified;
                                schemas.Add (schema);
@@ -747,5 +828,30 @@ namespace System.Xml.Serialization {
                }
 
                #endregion // Methods
+
+               private class XmlSchemaObjectContainer
+               {
+                       private readonly XmlSchemaObject _xmlSchemaObject;
+
+                       public XmlSchemaObjectContainer (XmlSchema schema)
+                       {
+                               _xmlSchemaObject = schema;
+                       }
+
+                       public XmlSchemaObjectContainer (XmlSchemaGroupBase group)
+                       {
+                               _xmlSchemaObject = group;
+                       }
+
+                       public XmlSchemaObjectCollection Items {
+                               get {
+                                       if (_xmlSchemaObject is XmlSchema) {
+                                               return ((XmlSchema) _xmlSchemaObject).Items;
+                                       } else {
+                                               return ((XmlSchemaGroupBase) _xmlSchemaObject).Items;
+                                       }
+                               }
+                       }
+               }
        }
 }