diff options
author | Atsushi Eno <atsushieno@gmail.com> | 2006-11-01 23:12:00 +0300 |
---|---|---|
committer | Atsushi Eno <atsushieno@gmail.com> | 2006-11-01 23:12:00 +0300 |
commit | 658311053b31bc054945664c6b8d6734c1c0c4a1 (patch) | |
tree | 5312ec7262d6f946d55c224396cbb3ef5d415b56 /mcs/class/System.XML/System.Xml.Serialization/XmlSchemaImporter.cs | |
parent | 922203ea7cf193f7e22d399a8bcbed1768e54ac8 (diff) |
eol-style:native
svn path=/branches/atsushi/mcs/; revision=67237
Diffstat (limited to 'mcs/class/System.XML/System.Xml.Serialization/XmlSchemaImporter.cs')
-rw-r--r-- | mcs/class/System.XML/System.Xml.Serialization/XmlSchemaImporter.cs | 3704 |
1 files changed, 1852 insertions, 1852 deletions
diff --git a/mcs/class/System.XML/System.Xml.Serialization/XmlSchemaImporter.cs b/mcs/class/System.XML/System.Xml.Serialization/XmlSchemaImporter.cs index c78dafd59c6..3767c2667c0 100644 --- a/mcs/class/System.XML/System.Xml.Serialization/XmlSchemaImporter.cs +++ b/mcs/class/System.XML/System.Xml.Serialization/XmlSchemaImporter.cs @@ -1,1852 +1,1852 @@ -//
-// System.Xml.Serialization.XmlSchemaImporter
-//
-// Author:
-// Tim Coleman (tim@timcoleman.com)
-// Lluis Sanchez Gual (lluis@ximian.com)
-//
-// Copyright (C) Tim Coleman, 2002
-//
-
-//
-// 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.Xml;
-#if !TARGET_JVM
-using System.CodeDom.Compiler;
-#endif
-using System.Xml.Schema;
-using System.Collections;
-
-namespace System.Xml.Serialization
-{
- public class XmlSchemaImporter
-#if NET_2_0
- : SchemaImporter
-#endif
- {
- #region Fields
-
- XmlSchemas schemas;
- CodeIdentifiers typeIdentifiers;
- CodeIdentifiers elemIdentifiers = new CodeIdentifiers ();
- Hashtable mappedTypes = new Hashtable ();
- Hashtable dataMappedTypes = new Hashtable ();
- Queue pendingMaps = new Queue ();
- Hashtable sharedAnonymousTypes = new Hashtable ();
- bool encodedFormat = false;
- XmlReflectionImporter auxXmlRefImporter;
- SoapReflectionImporter auxSoapRefImporter;
- bool anyTypeImported;
-
-#if NET_2_0
- CodeGenerationOptions options;
-#endif
-
- static readonly XmlQualifiedName anyType = new XmlQualifiedName ("anyType",XmlSchema.Namespace);
- static readonly XmlQualifiedName arrayType = new XmlQualifiedName ("Array",XmlSerializer.EncodingNamespace);
- static readonly XmlQualifiedName arrayTypeRefName = new XmlQualifiedName ("arrayType",XmlSerializer.EncodingNamespace);
-
- const string XmlNamespace = "http://www.w3.org/XML/1998/namespace";
-
- XmlSchemaElement anyElement = null;
-
- class MapFixup
- {
- public XmlTypeMapping Map;
- public XmlSchemaComplexType SchemaType;
- public XmlQualifiedName TypeName;
- }
-
- #endregion
-
- #region Constructors
-
- public XmlSchemaImporter (XmlSchemas schemas)
- {
- this.schemas = schemas;
- typeIdentifiers = new CodeIdentifiers ();
- }
-
- public XmlSchemaImporter (XmlSchemas schemas, CodeIdentifiers typeIdentifiers)
- : this (schemas)
- {
- this.typeIdentifiers = typeIdentifiers;
- }
-
-#if NET_2_0
-#if !TARGET_JVM
- [MonoTODO]
- public XmlSchemaImporter (XmlSchemas schemas, CodeGenerationOptions options, CodeDomProvider codeProvider, ImportContext context)
- {
- this.schemas = schemas;
- this.options = options;
- if (context != null) {
- typeIdentifiers = context.TypeIdentifiers;
- InitSharedData (context);
- }
- else
- typeIdentifiers = new CodeIdentifiers ();
- }
-#endif
-
- public XmlSchemaImporter (XmlSchemas schemas, CodeGenerationOptions options, ImportContext context)
- {
- this.schemas = schemas;
- this.options = options;
- if (context != null) {
- typeIdentifiers = context.TypeIdentifiers;
- InitSharedData (context);
- }
- else
- typeIdentifiers = new CodeIdentifiers ();
- }
-
-
- public XmlSchemaImporter (XmlSchemas schemas, CodeIdentifiers typeIdentifiers, CodeGenerationOptions options)
- {
- this.typeIdentifiers = typeIdentifiers;
- this.schemas = schemas;
- this.options = options;
- }
-
- void InitSharedData (ImportContext context)
- {
- if (context.ShareTypes) {
- mappedTypes = context.MappedTypes;
- dataMappedTypes = context.DataMappedTypes;
- sharedAnonymousTypes = context.SharedAnonymousTypes;
- }
- }
-#endif
-
- internal bool UseEncodedFormat
- {
- get { return encodedFormat; }
- set { encodedFormat = value; }
- }
-
- #endregion // Constructors
-
- #region Methods
-
- public XmlMembersMapping ImportAnyType (XmlQualifiedName typeName, string elementName)
- {
- if (typeName == XmlQualifiedName.Empty)
- {
- XmlTypeMapMemberAnyElement mapMem = new XmlTypeMapMemberAnyElement ();
- mapMem.Name = typeName.Name;
- mapMem.TypeData = TypeTranslator.GetTypeData(typeof(XmlNode));
- mapMem.ElementInfo.Add (CreateElementInfo (typeName.Namespace, mapMem, typeName.Name, mapMem.TypeData, true, XmlSchemaForm.None));
-
- XmlMemberMapping[] mm = new XmlMemberMapping [1];
- mm[0] = new XmlMemberMapping (typeName.Name, typeName.Namespace, mapMem, encodedFormat);
- return new XmlMembersMapping (mm);
- }
- else
- {
- XmlSchemaComplexType stype = (XmlSchemaComplexType) schemas.Find (typeName, typeof (XmlSchemaComplexType));
- if (stype == null)
- throw new InvalidOperationException ("Referenced type '" + typeName + "' not found");
-
- if (!CanBeAnyElement (stype))
- throw new InvalidOperationException ("The type '" + typeName + "' is not valid for a collection of any elements");
-
- ClassMap cmap = new ClassMap ();
- CodeIdentifiers classIds = new CodeIdentifiers ();
- bool isMixed = stype.IsMixed;
- ImportSequenceContent (typeName, cmap, ((XmlSchemaSequence) stype.Particle).Items, classIds, false, ref isMixed);
- XmlTypeMapMemberAnyElement mapMem = (XmlTypeMapMemberAnyElement) cmap.AllMembers[0];
- mapMem.Name = typeName.Name;
-
- XmlMemberMapping[] mm = new XmlMemberMapping [1];
- mm[0] = new XmlMemberMapping (typeName.Name, typeName.Namespace, mapMem, encodedFormat);
- return new XmlMembersMapping (mm);
- }
- }
-
- public XmlTypeMapping ImportDerivedTypeMapping (XmlQualifiedName name, Type baseType)
- {
- return ImportDerivedTypeMapping (name, baseType, true);
- }
-
- public XmlTypeMapping ImportDerivedTypeMapping (XmlQualifiedName name, Type baseType, bool baseTypeCanBeIndirect)
- {
- XmlQualifiedName qname;
- XmlSchemaType stype;
-
- if (encodedFormat)
- {
- qname = name;
- stype = schemas.Find (name, typeof (XmlSchemaComplexType)) as XmlSchemaComplexType;
- if (stype == null) throw new InvalidOperationException ("Schema type '" + name + "' not found or not valid");
- }
- else
- {
- if (!LocateElement (name, out qname, out stype))
- return null;
- }
-
- XmlTypeMapping map = GetRegisteredTypeMapping (qname);
- if (map != null)
- {
- // If the type has already been imported, make sure that the map
- // has the requested base type
-
- SetMapBaseType (map, baseType);
- map.UpdateRoot (name);
- return map;
- }
-
- map = CreateTypeMapping (qname, SchemaTypes.Class, name);
- if (stype != null) {
- map.Documentation = GetDocumentation (stype);
- RegisterMapFixup (map, qname, (XmlSchemaComplexType)stype);
- } else {
- ClassMap cmap = new ClassMap ();
- CodeIdentifiers classIds = new CodeIdentifiers ();
- map.ObjectMap = cmap;
- AddTextMember (qname, cmap, classIds);
- }
-
- BuildPendingMaps ();
- SetMapBaseType (map, baseType);
-
- return map;
- }
-
- void SetMapBaseType (XmlTypeMapping map, Type baseType)
- {
- // This method sets the base type for a given map.
- // If the map already inherits from this type, it does nothing.
-
- // Fiirst of all, check if the map already inherits from baseType
-
- XmlTypeMapping topMap = null;
- while (map != null)
- {
- if (map.TypeData.Type == baseType)
- return;
- topMap = map;
- map = map.BaseMap;
- }
-
- // Does not have the requested base type.
- // Then, get/create a map for that base type.
-
- XmlTypeMapping baseMap = ReflectType (baseType);
-
- // Add this map as a derived map of the base map
-
- topMap.BaseMap = baseMap;
- baseMap.DerivedTypes.Add (topMap);
- baseMap.DerivedTypes.AddRange (topMap.DerivedTypes);
-
- // Now add the base type fields to all derived maps
-
- ClassMap baseClassMap = (ClassMap)baseMap.ObjectMap;
-
- ClassMap cmap = (ClassMap)topMap.ObjectMap;
- foreach (XmlTypeMapMember member in baseClassMap.AllMembers)
- cmap.AddMember (member);
-
- foreach (XmlTypeMapping derivedMap in topMap.DerivedTypes)
- {
- cmap = (ClassMap)derivedMap.ObjectMap;
- foreach (XmlTypeMapMember member in baseClassMap.AllMembers)
- cmap.AddMember (member);
- }
- }
-
- public XmlMembersMapping ImportMembersMapping (XmlQualifiedName name)
- {
- XmlSchemaElement elem = (XmlSchemaElement) schemas.Find (name, typeof (XmlSchemaElement));
- if (elem == null) throw new InvalidOperationException ("Schema element '" + name + "' not found or not valid");
-
- XmlSchemaComplexType stype;
- if (elem.SchemaType != null)
- {
- stype = elem.SchemaType as XmlSchemaComplexType;
- }
- else
- {
- if (elem.SchemaTypeName.IsEmpty) return null;
- object type = schemas.Find (elem.SchemaTypeName, typeof (XmlSchemaComplexType));
- if (type == null) {
- if (IsPrimitiveTypeNamespace (elem.SchemaTypeName.Namespace)) return null;
- throw new InvalidOperationException ("Schema type '" + elem.SchemaTypeName + "' not found");
- }
- stype = type as XmlSchemaComplexType;
- }
-
- if (stype == null)
- throw new InvalidOperationException ("Schema element '" + name + "' not found or not valid");
-
- XmlMemberMapping[] mapping = ImportMembersMappingComposite (stype, name);
- return new XmlMembersMapping (name.Name, name.Namespace, mapping);
- }
-
- public XmlMembersMapping ImportMembersMapping (XmlQualifiedName[] names)
- {
- XmlMemberMapping[] mapping = new XmlMemberMapping [names.Length];
- for (int n=0; n<names.Length; n++)
- {
- XmlSchemaElement elem = (XmlSchemaElement) schemas.Find (names[n], typeof (XmlSchemaElement));
- if (elem == null) throw new InvalidOperationException ("Schema element '" + names[n] + "' not found");
-
- XmlQualifiedName typeQName = new XmlQualifiedName ("Message", names[n].Namespace);
- XmlTypeMapping tmap;
- TypeData td = GetElementTypeData (typeQName, elem, names[n], out tmap);
-
- mapping[n] = ImportMemberMapping (elem.Name, typeQName.Namespace, elem.IsNillable, td, tmap);
- }
- BuildPendingMaps ();
- return new XmlMembersMapping (mapping);
- }
-
-#if NET_2_0
- [MonoTODO]
- public XmlMembersMapping ImportMembersMapping (string name, string ns, SoapSchemaMember[] members)
- {
- throw new NotImplementedException ();
- }
-
- [MonoTODO]
- public XmlTypeMapping ImportSchemaType (XmlQualifiedName typeName)
- {
- throw new NotImplementedException ();
- }
-
- [MonoTODO]
- public XmlTypeMapping ImportSchemaType (XmlQualifiedName typeName, Type baseType)
- {
- throw new NotImplementedException ();
- }
-
- [MonoTODO]
- public XmlTypeMapping ImportSchemaType (XmlQualifiedName typeName, Type baseType, bool baseTypeCanBeIndirect)
- {
- throw new NotImplementedException ();
- }
-#endif
-
- internal XmlMembersMapping ImportEncodedMembersMapping (string name, string ns, SoapSchemaMember[] members, bool hasWrapperElement)
- {
- XmlMemberMapping[] mapping = new XmlMemberMapping [members.Length];
- for (int n=0; n<members.Length; n++)
- {
- TypeData td = GetTypeData (members[n].MemberType, null);
- XmlTypeMapping tmap = GetTypeMapping (td);
- mapping[n] = ImportMemberMapping (members[n].MemberName, members[n].MemberType.Namespace, true, td, tmap);
- }
- BuildPendingMaps ();
- return new XmlMembersMapping (name, ns, hasWrapperElement, false, mapping);
- }
-
- internal XmlMembersMapping ImportEncodedMembersMapping (string name, string ns, SoapSchemaMember member)
- {
- XmlSchemaComplexType stype = schemas.Find (member.MemberType, typeof (XmlSchemaComplexType)) as XmlSchemaComplexType;
- if (stype == null) throw new InvalidOperationException ("Schema type '" + member.MemberType + "' not found or not valid");
-
- XmlMemberMapping[] mapping = ImportMembersMappingComposite (stype, member.MemberType);
- return new XmlMembersMapping (name, ns, mapping);
- }
-
- XmlMemberMapping[] ImportMembersMappingComposite (XmlSchemaComplexType stype, XmlQualifiedName refer)
- {
- if (stype.Particle == null)
- return new XmlMemberMapping [0];
-
- ClassMap cmap = new ClassMap ();
-
- XmlSchemaSequence seq = stype.Particle as XmlSchemaSequence;
- if (seq == null) throw new InvalidOperationException ("Schema element '" + refer + "' cannot be imported as XmlMembersMapping");
-
- CodeIdentifiers classIds = new CodeIdentifiers ();
- ImportParticleComplexContent (refer, cmap, seq, classIds, false);
- ImportAttributes (refer, cmap, stype.Attributes, stype.AnyAttribute, classIds);
-
- BuildPendingMaps ();
-
- int n = 0;
- XmlMemberMapping[] mapping = new XmlMemberMapping [cmap.AllMembers.Count];
- foreach (XmlTypeMapMember mapMem in cmap.AllMembers)
- mapping[n++] = new XmlMemberMapping (mapMem.Name, refer.Namespace, mapMem, encodedFormat);
-
- return mapping;
- }
-
- XmlMemberMapping ImportMemberMapping (string name, string ns, bool isNullable, TypeData type, XmlTypeMapping emap)
- {
- XmlTypeMapMemberElement mapMem;
-
- if (type.IsListType)
- mapMem = new XmlTypeMapMemberList ();
- else
- mapMem = new XmlTypeMapMemberElement ();
-
- mapMem.Name = name;
- mapMem.TypeData = type;
- mapMem.ElementInfo.Add (CreateElementInfo (ns, mapMem, name, type, isNullable, XmlSchemaForm.None, emap));
- return new XmlMemberMapping (name, ns, mapMem, encodedFormat);
- }
-
- [MonoTODO]
- public XmlMembersMapping ImportMembersMapping (XmlQualifiedName[] names, Type baseType, bool baseTypeCanBeIndirect)
- {
- throw new NotImplementedException ();
- }
-
- public XmlTypeMapping ImportTypeMapping (XmlQualifiedName name)
- {
- XmlQualifiedName qname;
- XmlSchemaType stype;
-
- XmlSchemaElement elem = (XmlSchemaElement) schemas.Find (name, typeof (XmlSchemaElement));
- if (!LocateElement (elem, out qname, out stype)) return null;
-
- if (stype == null) {
- // Importing a primitive type
- TypeData td = TypeTranslator.GetPrimitiveTypeData (qname.Name);
- return ReflectType (td, name.Namespace);
- }
-
- XmlTypeMapping map = GetRegisteredTypeMapping (qname);
- if (map != null) return map;
-
- map = CreateTypeMapping (qname, SchemaTypes.Class, name);
- map.Documentation = GetDocumentation (stype);
- map.IsNullable = elem.IsNillable;
- RegisterMapFixup (map, qname, (XmlSchemaComplexType)stype);
-
- BuildPendingMaps ();
- return map;
- }
-
- bool LocateElement (XmlQualifiedName name, out XmlQualifiedName qname, out XmlSchemaType stype)
- {
- XmlSchemaElement elem = (XmlSchemaElement) schemas.Find (name, typeof (XmlSchemaElement));
- return LocateElement (elem, out qname, out stype);
- }
-
- bool LocateElement (XmlSchemaElement elem, out XmlQualifiedName qname, out XmlSchemaType stype)
- {
- qname = null;
- stype = null;
-
- if (elem == null) return false;
-
- // The root element must be an element with complex type
-
- if (elem.SchemaType != null)
- {
- stype = elem.SchemaType;
- qname = elem.QualifiedName;
- }
- else
- {
- if (elem.SchemaTypeName.IsEmpty) return false;
-
- object type = schemas.Find (elem.SchemaTypeName, typeof (XmlSchemaComplexType));
- if (type == null) type = schemas.Find (elem.SchemaTypeName, typeof (XmlSchemaSimpleType));
- if (type == null) {
- if (IsPrimitiveTypeNamespace (elem.SchemaTypeName.Namespace)) {
- qname = elem.SchemaTypeName;
- return true;
- }
- throw new InvalidOperationException ("Schema type '" + elem.SchemaTypeName + "' not found");
- }
- stype = (XmlSchemaType) type;
- qname = stype.QualifiedName;
-
- XmlSchemaType btype = stype.BaseSchemaType as XmlSchemaType;
- if (btype != null && btype.QualifiedName == elem.SchemaTypeName)
- throw new InvalidOperationException ("Cannot import schema for type '" + elem.SchemaTypeName.Name + "' from namespace '" + elem.SchemaTypeName.Namespace + "'. Redefine not supported");
- }
-
- if (stype is XmlSchemaSimpleType) return false;
- return true;
- }
-
- XmlTypeMapping ImportType (XmlQualifiedName name, XmlQualifiedName root, bool throwOnError)
- {
- XmlTypeMapping map = GetRegisteredTypeMapping (name);
- if (map != null) {
- map.UpdateRoot (root);
- return map;
- }
-
- XmlSchemaType type = (XmlSchemaType) schemas.Find (name, typeof (XmlSchemaComplexType));
- if (type == null) type = (XmlSchemaType) schemas.Find (name, typeof (XmlSchemaSimpleType));
-
- if (type == null)
- {
- if (throwOnError) {
- if (name.Namespace == XmlSerializer.EncodingNamespace)
- throw new InvalidOperationException ("Referenced type '" + name + "' valid only for encoded SOAP.");
- else
- throw new InvalidOperationException ("Referenced type '" + name + "' not found.");
- } else
- return null;
- }
-
- return ImportType (name, type, root);
- }
-
- XmlTypeMapping ImportClass (XmlQualifiedName name)
- {
- XmlTypeMapping map = ImportType (name, null, true);
- if (map.TypeData.SchemaType == SchemaTypes.Class) return map;
- XmlSchemaComplexType stype = schemas.Find (name, typeof (XmlSchemaComplexType)) as XmlSchemaComplexType;
- return CreateClassMap (name, stype, new XmlQualifiedName (map.ElementName, map.Namespace));
- }
-
- XmlTypeMapping ImportType (XmlQualifiedName name, XmlSchemaType stype, XmlQualifiedName root)
- {
- XmlTypeMapping map = GetRegisteredTypeMapping (name);
- if (map != null) {
- XmlSchemaComplexType ct = stype as XmlSchemaComplexType;
- if (map.TypeData.SchemaType != SchemaTypes.Class || ct == null || !CanBeArray (name, ct)) {
- map.UpdateRoot (root);
- return map;
- }
-
- // The map was initially imported as a class, but it turns out that it is an
- // array. It has to be imported now as array.
- }
-
- if (stype is XmlSchemaComplexType)
- return ImportClassComplexType (name, (XmlSchemaComplexType) stype, root);
- else if (stype is XmlSchemaSimpleType)
- return ImportClassSimpleType (name, (XmlSchemaSimpleType) stype, root);
-
- throw new NotSupportedException ("Schema type not supported: " + stype.GetType ());
- }
-
- XmlTypeMapping ImportClassComplexType (XmlQualifiedName typeQName, XmlSchemaComplexType stype, XmlQualifiedName root)
- {
- // The need for fixups: If the complex type is an array, then to get the type of the
- // array we need first to get the type of the items of the array.
- // But if one of the item types or its children has a referece to this type array,
- // then we enter in an infinite loop. This does not happen with class types because
- // the class map is registered before parsing the children. We can't do the same
- // with the array type because to register the array map we need the type of the array.
-
- Type anyType = GetAnyElementType (stype);
- if (anyType != null)
- return GetTypeMapping (TypeTranslator.GetTypeData(anyType));
-
- if (CanBeArray (typeQName, stype))
- {
- TypeData typeData;
- ListMap listMap = BuildArrayMap (typeQName, stype, out typeData);
- if (listMap != null)
- {
- XmlTypeMapping map = CreateArrayTypeMapping (typeQName, typeData);
- map.ObjectMap = listMap;
- return map;
- }
-
- // After all, it is not an array. Create a class map then.
- }
- else if (CanBeIXmlSerializable (stype))
- {
- return ImportXmlSerializableMapping (typeQName.Namespace);
- }
-
- // Register the map right now but do not build it,
- // This will avoid loops.
-
- return CreateClassMap (typeQName, stype, root);
- }
-
- XmlTypeMapping CreateClassMap (XmlQualifiedName typeQName, XmlSchemaComplexType stype, XmlQualifiedName root)
- {
- XmlTypeMapping map = CreateTypeMapping (typeQName, SchemaTypes.Class, root);
- map.Documentation = GetDocumentation (stype);
- RegisterMapFixup (map, typeQName, stype);
- return map;
- }
-
- void RegisterMapFixup (XmlTypeMapping map, XmlQualifiedName typeQName, XmlSchemaComplexType stype)
- {
- MapFixup fixup = new MapFixup ();
- fixup.Map = map;
- fixup.SchemaType = stype;
- fixup.TypeName = typeQName;
- pendingMaps.Enqueue (fixup);
- }
-
- void BuildPendingMaps ()
- {
- while (pendingMaps.Count > 0) {
- MapFixup fixup = (MapFixup) pendingMaps.Dequeue ();
- if (fixup.Map.ObjectMap == null) {
- BuildClassMap (fixup.Map, fixup.TypeName, fixup.SchemaType);
- if (fixup.Map.ObjectMap == null) pendingMaps.Enqueue (fixup);
- }
- }
- }
-
- void BuildPendingMap (XmlTypeMapping map)
- {
- if (map.ObjectMap != null) return;
-
- foreach (MapFixup fixup in pendingMaps)
- {
- if (fixup.Map == map) {
- BuildClassMap (fixup.Map, fixup.TypeName, fixup.SchemaType);
- return;
- }
- }
- throw new InvalidOperationException ("Can't complete map of type " + map.XmlType + " : " + map.Namespace);
- }
-
- void BuildClassMap (XmlTypeMapping map, XmlQualifiedName typeQName, XmlSchemaComplexType stype)
- {
- CodeIdentifiers classIds = new CodeIdentifiers();
- classIds.AddReserved (map.TypeData.TypeName);
-
- ClassMap cmap = new ClassMap ();
- map.ObjectMap = cmap;
- bool isMixed = stype.IsMixed;
-
- if (stype.Particle != null)
- ImportParticleComplexContent (typeQName, cmap, stype.Particle, classIds, isMixed);
- else
- {
- if (stype.ContentModel is XmlSchemaSimpleContent) {
- ImportSimpleContent (typeQName, map, (XmlSchemaSimpleContent)stype.ContentModel, classIds, isMixed);
- }
- else if (stype.ContentModel is XmlSchemaComplexContent) {
- ImportComplexContent (typeQName, map, (XmlSchemaComplexContent)stype.ContentModel, classIds, isMixed);
- }
- }
-
- ImportAttributes (typeQName, cmap, stype.Attributes, stype.AnyAttribute, classIds);
- ImportExtensionTypes (typeQName);
-
- if (isMixed) AddTextMember (typeQName, cmap, classIds);
-
- AddObjectDerivedMap (map);
- }
-
- void ImportAttributes (XmlQualifiedName typeQName, ClassMap cmap, XmlSchemaObjectCollection atts, XmlSchemaAnyAttribute anyat, CodeIdentifiers classIds)
- {
- if (anyat != null)
- {
- XmlTypeMapMemberAnyAttribute member = new XmlTypeMapMemberAnyAttribute ();
- member.Name = classIds.AddUnique ("AnyAttribute", member);
- member.TypeData = TypeTranslator.GetTypeData (typeof(XmlAttribute[]));
- cmap.AddMember (member);
- }
-
- foreach (XmlSchemaObject at in atts)
- {
- if (at is XmlSchemaAttribute)
- {
- string ns;
- XmlSchemaAttribute attr = (XmlSchemaAttribute)at;
- XmlSchemaAttribute refAttr = GetRefAttribute (typeQName, attr, out ns);
- XmlTypeMapMemberAttribute member = new XmlTypeMapMemberAttribute ();
- member.Name = classIds.AddUnique (CodeIdentifier.MakeValid (refAttr.Name), member);
- member.Documentation = GetDocumentation (attr);
- member.AttributeName = refAttr.Name;
- member.Namespace = ns;
- member.Form = refAttr.Form;
- member.TypeData = GetAttributeTypeData (typeQName, attr);
-
- if (refAttr.DefaultValue != null)
- member.DefaultValue = ImportDefaultValue (member.TypeData, refAttr.DefaultValue);
- else if (member.TypeData.IsValueType)
- member.IsOptionalValueType = (refAttr.ValidatedUse != XmlSchemaUse.Required);
-
- if (member.TypeData.IsComplexType)
- member.MappedType = GetTypeMapping (member.TypeData);
- cmap.AddMember (member);
- }
- else if (at is XmlSchemaAttributeGroupRef)
- {
- XmlSchemaAttributeGroupRef gref = (XmlSchemaAttributeGroupRef)at;
- XmlSchemaAttributeGroup grp = FindRefAttributeGroup (gref.RefName);
- ImportAttributes (typeQName, cmap, grp.Attributes, grp.AnyAttribute, classIds);
- }
- }
- }
-
- ListMap BuildArrayMap (XmlQualifiedName typeQName, XmlSchemaComplexType stype, out TypeData arrayTypeData)
- {
- if (encodedFormat)
- {
- XmlSchemaComplexContent content = stype.ContentModel as XmlSchemaComplexContent;
- XmlSchemaComplexContentRestriction rest = content.Content as XmlSchemaComplexContentRestriction;
- XmlSchemaAttribute arrayTypeAt = FindArrayAttribute (rest.Attributes);
-
- if (arrayTypeAt != null)
- {
- XmlAttribute[] uatts = arrayTypeAt.UnhandledAttributes;
- if (uatts == null || uatts.Length == 0) throw new InvalidOperationException ("arrayType attribute not specified in array declaration: " + typeQName);
-
- XmlAttribute xat = null;
- foreach (XmlAttribute at in uatts)
- if (at.LocalName == "arrayType" && at.NamespaceURI == XmlSerializer.WsdlNamespace)
- { xat = at; break; }
-
- if (xat == null)
- throw new InvalidOperationException ("arrayType attribute not specified in array declaration: " + typeQName);
-
- string name, ns, dims;
- TypeTranslator.ParseArrayType (xat.Value, out name, out ns, out dims);
- return BuildEncodedArrayMap (name + dims, ns, out arrayTypeData);
- }
- else
- {
- XmlSchemaElement elem = null;
- XmlSchemaSequence seq = rest.Particle as XmlSchemaSequence;
- if (seq != null && seq.Items.Count == 1)
- elem = seq.Items[0] as XmlSchemaElement;
- else {
- XmlSchemaAll all = rest.Particle as XmlSchemaAll;
- if (all != null && all.Items.Count == 1)
- elem = all.Items[0] as XmlSchemaElement;
- }
- if (elem == null)
- throw new InvalidOperationException ("Unknown array format");
-
- return BuildEncodedArrayMap (elem.SchemaTypeName.Name + "[]", elem.SchemaTypeName.Namespace, out arrayTypeData);
- }
- }
- else
- {
- ClassMap cmap = new ClassMap ();
- CodeIdentifiers classIds = new CodeIdentifiers();
- ImportParticleComplexContent (typeQName, cmap, stype.Particle, classIds, stype.IsMixed);
-
- XmlTypeMapMemberFlatList list = (cmap.AllMembers.Count == 1) ? cmap.AllMembers[0] as XmlTypeMapMemberFlatList : null;
- if (list != null && list.ChoiceMember == null)
- {
- arrayTypeData = list.TypeData;
- return list.ListMap;
- }
- else
- {
- arrayTypeData = null;
- return null;
- }
- }
- }
-
- ListMap BuildEncodedArrayMap (string type, string ns, out TypeData arrayTypeData)
- {
- ListMap map = new ListMap ();
-
- int i = type.LastIndexOf ("[");
- if (i == -1) throw new InvalidOperationException ("Invalid arrayType value: " + type);
- if (type.IndexOf (",",i) != -1) throw new InvalidOperationException ("Multidimensional arrays are not supported");
-
- string itemType = type.Substring (0,i);
-
- TypeData itemTypeData;
- if (itemType.IndexOf ("[") != -1)
- {
- ListMap innerListMap = BuildEncodedArrayMap (itemType, ns, out itemTypeData);
-
- int dims = itemType.Split ('[').Length - 1;
- string name = TypeTranslator.GetArrayName (type, dims);
- XmlQualifiedName qname = new XmlQualifiedName (name, ns);
- XmlTypeMapping tmap = CreateArrayTypeMapping (qname, itemTypeData);
- tmap.ObjectMap = innerListMap;
- }
- else
- {
- itemTypeData = GetTypeData (new XmlQualifiedName (itemType, ns), null);
- }
-
- arrayTypeData = itemTypeData.ListTypeData;
-
- map.ItemInfo = new XmlTypeMapElementInfoList();
- map.ItemInfo.Add (CreateElementInfo ("", null, "Item", itemTypeData, true, XmlSchemaForm.None));
- return map;
- }
-
- XmlSchemaAttribute FindArrayAttribute (XmlSchemaObjectCollection atts)
- {
- foreach (object ob in atts)
- {
- XmlSchemaAttribute att = ob as XmlSchemaAttribute;
- if (att != null && att.RefName == arrayTypeRefName) return att;
-
- XmlSchemaAttributeGroupRef gref = ob as XmlSchemaAttributeGroupRef;
- if (gref != null)
- {
- XmlSchemaAttributeGroup grp = FindRefAttributeGroup (gref.RefName);
- att = FindArrayAttribute (grp.Attributes);
- if (att != null) return att;
- }
- }
- return null;
- }
-
- void ImportParticleComplexContent (XmlQualifiedName typeQName, ClassMap cmap, XmlSchemaParticle particle, CodeIdentifiers classIds, bool isMixed)
- {
- ImportParticleContent (typeQName, cmap, particle, classIds, false, ref isMixed);
- if (isMixed) AddTextMember (typeQName, cmap, classIds);
- }
-
- void AddTextMember (XmlQualifiedName typeQName, ClassMap cmap, CodeIdentifiers classIds)
- {
- if (cmap.XmlTextCollector == null)
- {
- XmlTypeMapMemberFlatList member = new XmlTypeMapMemberFlatList ();
- member.Name = classIds.AddUnique ("Text", member);
- member.TypeData = TypeTranslator.GetTypeData (typeof(string[]));
- member.ElementInfo.Add (CreateTextElementInfo (typeQName.Namespace, member, member.TypeData.ListItemTypeData));
- member.IsXmlTextCollector = true;
- member.ListMap = new ListMap ();
- member.ListMap.ItemInfo = member.ElementInfo;
- cmap.AddMember (member);
- }
- }
-
- void ImportParticleContent (XmlQualifiedName typeQName, ClassMap cmap, XmlSchemaParticle particle, CodeIdentifiers classIds, bool multiValue, ref bool isMixed)
- {
- if (particle == null) return;
-
- if (particle is XmlSchemaGroupRef)
- particle = GetRefGroupParticle ((XmlSchemaGroupRef)particle);
-
- if (particle.MaxOccurs > 1) multiValue = true;
-
- if (particle is XmlSchemaSequence) {
- ImportSequenceContent (typeQName, cmap, ((XmlSchemaSequence)particle).Items, classIds, multiValue, ref isMixed);
- }
- else if (particle is XmlSchemaChoice) {
- if (((XmlSchemaChoice)particle).Items.Count == 1)
- ImportSequenceContent (typeQName, cmap, ((XmlSchemaChoice)particle).Items, classIds, multiValue, ref isMixed);
- else
- ImportChoiceContent (typeQName, cmap, (XmlSchemaChoice)particle, classIds, multiValue);
- }
- else if (particle is XmlSchemaAll) {
- ImportSequenceContent (typeQName, cmap, ((XmlSchemaAll)particle).Items, classIds, multiValue, ref isMixed);
- }
- }
-
- void ImportSequenceContent (XmlQualifiedName typeQName, ClassMap cmap, XmlSchemaObjectCollection items, CodeIdentifiers classIds, bool multiValue, ref bool isMixed)
- {
- foreach (XmlSchemaObject item in items)
- {
- if (item is XmlSchemaElement)
- {
- string ns;
- XmlSchemaElement elem = (XmlSchemaElement) item;
- XmlTypeMapping emap;
- TypeData typeData = GetElementTypeData (typeQName, elem, null, out emap);
- XmlSchemaElement refElem = GetRefElement (typeQName, elem, out ns);
-
- if (elem.MaxOccurs == 1 && !multiValue)
- {
- XmlTypeMapMemberElement member = null;
- if (typeData.SchemaType != SchemaTypes.Array)
- {
- member = new XmlTypeMapMemberElement ();
- if (refElem.DefaultValue != null) member.DefaultValue = ImportDefaultValue (typeData, refElem.DefaultValue);
- }
- else if (GetTypeMapping (typeData).IsSimpleType)
- {
- // It is a simple list (space separated list).
- // Since this is not supported, map as a single item value
- member = new XmlTypeMapMemberElement ();
-#if NET_2_0
- // In MS.NET those types are mapped to a string
- typeData = TypeTranslator.GetTypeData(typeof(string));
-#else
- typeData = typeData.ListItemTypeData;
-#endif
- }
- else
- member = new XmlTypeMapMemberList ();
-
- if (elem.MinOccurs == 0 && typeData.IsValueType)
- member.IsOptionalValueType = true;
-
- member.Name = classIds.AddUnique(CodeIdentifier.MakeValid(refElem.Name), member);
- member.Documentation = GetDocumentation (elem);
- member.TypeData = typeData;
- member.ElementInfo.Add (CreateElementInfo (ns, member, refElem.Name, typeData, refElem.IsNillable, refElem.Form, emap));
- cmap.AddMember (member);
- }
- else
- {
- XmlTypeMapMemberFlatList member = new XmlTypeMapMemberFlatList ();
- member.ListMap = new ListMap ();
- member.Name = classIds.AddUnique(CodeIdentifier.MakeValid(refElem.Name), member);
- member.Documentation = GetDocumentation (elem);
- member.TypeData = typeData.ListTypeData;
- member.ElementInfo.Add (CreateElementInfo (ns, member, refElem.Name, typeData, refElem.IsNillable, refElem.Form, emap));
- member.ListMap.ItemInfo = member.ElementInfo;
- cmap.AddMember (member);
- }
- }
- else if (item is XmlSchemaAny)
- {
- XmlSchemaAny elem = (XmlSchemaAny) item;
- XmlTypeMapMemberAnyElement member = new XmlTypeMapMemberAnyElement ();
- member.Name = classIds.AddUnique ("Any", member);
- member.Documentation = GetDocumentation (elem);
-
- Type ctype;
- if (elem.MaxOccurs != 1 || multiValue)
- ctype = isMixed ? typeof(XmlNode[]) : typeof(XmlElement[]);
- else
- ctype = isMixed ? typeof(XmlNode) : typeof(XmlElement);
-
- member.TypeData = TypeTranslator.GetTypeData (ctype);
- XmlTypeMapElementInfo einfo = new XmlTypeMapElementInfo (member, member.TypeData);
- einfo.IsUnnamedAnyElement = true;
- member.ElementInfo.Add (einfo);
-
- if (isMixed)
- {
- einfo = CreateTextElementInfo (typeQName.Namespace, member, member.TypeData);
- member.ElementInfo.Add (einfo);
- member.IsXmlTextCollector = true;
- isMixed = false; //Allow only one XmlTextAttribute
- }
-
- cmap.AddMember (member);
- }
- else if (item is XmlSchemaParticle) {
- ImportParticleContent (typeQName, cmap, (XmlSchemaParticle)item, classIds, multiValue, ref isMixed);
- }
- }
- }
-
- object ImportDefaultValue (TypeData typeData, string value)
- {
- if (typeData.SchemaType == SchemaTypes.Enum) {
- XmlTypeMapping map = GetTypeMapping (typeData);
- EnumMap emap = (EnumMap) map.ObjectMap;
- string res = emap.GetEnumName (map.TypeFullName, value);
- if (res == null) throw new InvalidOperationException ("'" + value + "' is not a valid enumeration value");
- return res;
- } else
- return XmlCustomFormatter.FromXmlString (typeData, value);
- }
-
- void ImportChoiceContent (XmlQualifiedName typeQName, ClassMap cmap, XmlSchemaChoice choice, CodeIdentifiers classIds, bool multiValue)
- {
- XmlTypeMapElementInfoList choices = new XmlTypeMapElementInfoList ();
- multiValue = ImportChoices (typeQName, null, choices, choice.Items) || multiValue;
- if (choices.Count == 0) return;
-
- if (choice.MaxOccurs > 1) multiValue = true;
-
- XmlTypeMapMemberElement member;
- if (multiValue)
- {
- member = new XmlTypeMapMemberFlatList ();
- member.Name = classIds.AddUnique ("Items", member);
- ListMap listMap = new ListMap ();
- listMap.ItemInfo = choices;
- ((XmlTypeMapMemberFlatList)member).ListMap = listMap;
- }
- else
- {
- member = new XmlTypeMapMemberElement ();
- member.Name = classIds.AddUnique ("Item", member);
- }
-
- // If all choices have the same type, use that type for the member.
- // If not use System.Object.
- // If there are at least two choices with the same type, use a choice
- // identifier attribute
-
- TypeData typeData = null;
- bool twoEqual = false;
- bool allEqual = true;
- Hashtable types = new Hashtable ();
-
- for (int n = choices.Count - 1; n >= 0; n--)
- {
- XmlTypeMapElementInfo einfo = (XmlTypeMapElementInfo) choices [n];
-
- // In some complex schemas, we may end up with several options
- // with the same name. It is better to ignore the extra options
- // than to crash. It's the best we can do, and btw it works
- // better than in MS.NET.
-
- if (cmap.GetElement (einfo.ElementName, einfo.Namespace) != null ||
- choices.IndexOfElement (einfo.ElementName, einfo.Namespace) != n)
- {
- choices.RemoveAt (n);
- continue;
- }
-
- if (types.ContainsKey (einfo.TypeData)) twoEqual = true;
- else types.Add (einfo.TypeData, einfo);
-
- TypeData choiceType = einfo.TypeData;
- if (choiceType.SchemaType == SchemaTypes.Class)
- {
- // When comparing class types, use the most generic class in the
- // inheritance hierarchy
-
- XmlTypeMapping choiceMap = GetTypeMapping (choiceType);
- BuildPendingMap (choiceMap);
- while (choiceMap.BaseMap != null) {
- choiceMap = choiceMap.BaseMap;
- BuildPendingMap (choiceMap);
- choiceType = choiceMap.TypeData;
- }
- }
-
- if (typeData == null) typeData = choiceType;
- else if (typeData != choiceType) allEqual = false;
- }
-
- if (!allEqual)
- typeData = TypeTranslator.GetTypeData (typeof(object));
-
- if (twoEqual)
- {
- // Create the choice member
- XmlTypeMapMemberElement choiceMember = new XmlTypeMapMemberElement ();
- choiceMember.Ignore = true;
- choiceMember.Name = classIds.AddUnique (member.Name + "ElementName", choiceMember);
- member.ChoiceMember = choiceMember.Name;
-
- // Create the choice enum
- XmlTypeMapping enumMap = CreateTypeMapping (new XmlQualifiedName (member.Name + "ChoiceType", typeQName.Namespace), SchemaTypes.Enum, null);
- enumMap.IncludeInSchema = false;
-
- CodeIdentifiers codeIdents = new CodeIdentifiers ();
- EnumMap.EnumMapMember[] members = new EnumMap.EnumMapMember [choices.Count];
- for (int n=0; n<choices.Count; n++)
- {
- XmlTypeMapElementInfo it =(XmlTypeMapElementInfo) choices[n];
- bool extraNs = (it.Namespace != null && it.Namespace != "" && it.Namespace != typeQName.Namespace);
- string xmlName = extraNs ? it.Namespace + ":" + it.ElementName : it.ElementName;
- string enumName = codeIdents.AddUnique (CodeIdentifier.MakeValid (it.ElementName), it);
- members [n] = new EnumMap.EnumMapMember (xmlName, enumName);
- }
- enumMap.ObjectMap = new EnumMap (members, false);
-
- choiceMember.TypeData = multiValue ? enumMap.TypeData.ListTypeData : enumMap.TypeData;
- choiceMember.ElementInfo.Add (CreateElementInfo (typeQName.Namespace, choiceMember, choiceMember.Name, choiceMember.TypeData, false, XmlSchemaForm.None));
- cmap.AddMember (choiceMember);
- }
-
- if (typeData == null)
- return;
-
- if (multiValue)
- typeData = typeData.ListTypeData;
-
- member.ElementInfo = choices;
- member.Documentation = GetDocumentation (choice);
- member.TypeData = typeData;
- cmap.AddMember (member);
- }
-
- bool ImportChoices (XmlQualifiedName typeQName, XmlTypeMapMember member, XmlTypeMapElementInfoList choices, XmlSchemaObjectCollection items)
- {
- bool multiValue = false;
- foreach (XmlSchemaObject titem in items)
- {
- XmlSchemaObject item = titem;
- if (item is XmlSchemaGroupRef)
- item = GetRefGroupParticle ((XmlSchemaGroupRef)item);
-
- if (item is XmlSchemaElement)
- {
- string ns;
- XmlSchemaElement elem = (XmlSchemaElement) item;
- XmlTypeMapping emap;
- TypeData typeData = GetElementTypeData (typeQName, elem, null, out emap);
- XmlSchemaElement refElem = GetRefElement (typeQName, elem, out ns);
- choices.Add (CreateElementInfo (ns, member, refElem.Name, typeData, refElem.IsNillable, refElem.Form, emap));
- if (elem.MaxOccurs > 1) multiValue = true;
- }
- else if (item is XmlSchemaAny)
- {
- XmlTypeMapElementInfo einfo = new XmlTypeMapElementInfo (member, TypeTranslator.GetTypeData(typeof(XmlElement)));
- einfo.IsUnnamedAnyElement = true;
- choices.Add (einfo);
- }
- else if (item is XmlSchemaChoice) {
- multiValue = ImportChoices (typeQName, member, choices, ((XmlSchemaChoice)item).Items) || multiValue;
- }
- else if (item is XmlSchemaSequence) {
- multiValue = ImportChoices (typeQName, member, choices, ((XmlSchemaSequence)item).Items) || multiValue;
- }
- }
- return multiValue;
- }
-
- void ImportSimpleContent (XmlQualifiedName typeQName, XmlTypeMapping map, XmlSchemaSimpleContent content, CodeIdentifiers classIds, bool isMixed)
- {
- XmlSchemaSimpleContentExtension ext = content.Content as XmlSchemaSimpleContentExtension;
- ClassMap cmap = (ClassMap)map.ObjectMap;
- XmlQualifiedName qname = GetContentBaseType (content.Content);
- TypeData simpleType = null;
-
- if (!IsPrimitiveTypeNamespace (qname.Namespace))
- {
- // Add base map members to this map
-
- XmlTypeMapping baseMap = ImportType (qname, null, true);
- BuildPendingMap (baseMap);
-
- if (baseMap.IsSimpleType) {
- simpleType = baseMap.TypeData;
- } else {
- ClassMap baseClassMap = (ClassMap)baseMap.ObjectMap;
-
- foreach (XmlTypeMapMember member in baseClassMap.AllMembers)
- cmap.AddMember (member);
-
- map.BaseMap = baseMap;
- baseMap.DerivedTypes.Add (map);
- }
- }
- else
- simpleType = FindBuiltInType (qname);
-
- if (simpleType != null) {
- XmlTypeMapMemberElement member = new XmlTypeMapMemberElement ();
- member.Name = classIds.AddUnique("Value", member);
- member.TypeData = simpleType;
- member.ElementInfo.Add (CreateTextElementInfo (typeQName.Namespace, member, member.TypeData));
- member.IsXmlTextCollector = true;
- cmap.AddMember (member);
- }
-
- if (ext != null)
- ImportAttributes (typeQName, cmap, ext.Attributes, ext.AnyAttribute, classIds);
- }
-
- TypeData FindBuiltInType (XmlQualifiedName qname)
- {
- XmlSchemaComplexType ct = (XmlSchemaComplexType) schemas.Find (qname, typeof(XmlSchemaComplexType));
- if (ct != null)
- {
- XmlSchemaSimpleContent sc = ct.ContentModel as XmlSchemaSimpleContent;
- if (sc == null) throw new InvalidOperationException ("Invalid schema");
- return FindBuiltInType (GetContentBaseType (sc.Content));
- }
-
- XmlSchemaSimpleType st = (XmlSchemaSimpleType) schemas.Find (qname, typeof(XmlSchemaSimpleType));
- if (st != null)
- return FindBuiltInType (qname, st);
-
- if (IsPrimitiveTypeNamespace (qname.Namespace))
- return TypeTranslator.GetPrimitiveTypeData (qname.Name);
-
- throw new InvalidOperationException ("Definition of type '" + qname + "' not found");
- }
-
- TypeData FindBuiltInType (XmlQualifiedName qname, XmlSchemaSimpleType st)
- {
- if (CanBeEnum (st) && qname != null)
- return ImportType (qname, null, true).TypeData;
-
- if (st.Content is XmlSchemaSimpleTypeRestriction) {
- XmlSchemaSimpleTypeRestriction rest = (XmlSchemaSimpleTypeRestriction) st.Content;
- XmlQualifiedName bn = GetContentBaseType (rest);
- if (bn == XmlQualifiedName.Empty && rest.BaseType != null)
- return FindBuiltInType (qname, rest.BaseType);
- else
- return FindBuiltInType (bn);
- }
- else if (st.Content is XmlSchemaSimpleTypeList) {
- return FindBuiltInType (GetContentBaseType (st.Content)).ListTypeData;
- }
- else if (st.Content is XmlSchemaSimpleTypeUnion) {
- // MS.NET always import simple unions as string
- return FindBuiltInType (new XmlQualifiedName ("string", XmlSchema.Namespace));
- }
- else
- return null;
- }
-
- XmlQualifiedName GetContentBaseType (XmlSchemaObject ob)
- {
- if (ob is XmlSchemaSimpleContentExtension)
- return ((XmlSchemaSimpleContentExtension)ob).BaseTypeName;
- else if (ob is XmlSchemaSimpleContentRestriction)
- return ((XmlSchemaSimpleContentRestriction)ob).BaseTypeName;
- else if (ob is XmlSchemaSimpleTypeRestriction)
- return ((XmlSchemaSimpleTypeRestriction)ob).BaseTypeName;
- else if (ob is XmlSchemaSimpleTypeList)
- return ((XmlSchemaSimpleTypeList)ob).ItemTypeName;
- else
- return null;
- }
-
- void ImportComplexContent (XmlQualifiedName typeQName, XmlTypeMapping map, XmlSchemaComplexContent content, CodeIdentifiers classIds, bool isMixed)
- {
- ClassMap cmap = (ClassMap)map.ObjectMap;
- XmlQualifiedName qname;
-
- XmlSchemaComplexContentExtension ext = content.Content as XmlSchemaComplexContentExtension;
- if (ext != null) qname = ext.BaseTypeName;
- else qname = ((XmlSchemaComplexContentRestriction)content.Content).BaseTypeName;
-
- if (qname == typeQName)
- throw new InvalidOperationException ("Cannot import schema for type '" + typeQName.Name + "' from namespace '" + typeQName.Namespace + "'. Redefine not supported");
-
- // Add base map members to this map
-
- XmlTypeMapping baseMap = ImportClass (qname);
- BuildPendingMap (baseMap);
- ClassMap baseClassMap = (ClassMap)baseMap.ObjectMap;
-
- foreach (XmlTypeMapMember member in baseClassMap.AllMembers)
- cmap.AddMember (member);
-
- if (baseClassMap.XmlTextCollector != null) isMixed = false;
- else if (content.IsMixed) isMixed = true;
-
- map.BaseMap = baseMap;
- baseMap.DerivedTypes.Add (map);
-
- if (ext != null) {
- // Add the members of this map
- ImportParticleComplexContent (typeQName, cmap, ext.Particle, classIds, isMixed);
- ImportAttributes (typeQName, cmap, ext.Attributes, ext.AnyAttribute, classIds);
- }
- else {
- if (isMixed) ImportParticleComplexContent (typeQName, cmap, null, classIds, true);
- }
- }
-
- void ImportExtensionTypes (XmlQualifiedName qname)
- {
- foreach (XmlSchema schema in schemas) {
- foreach (XmlSchemaObject sob in schema.Items)
- {
- XmlSchemaComplexType sct = sob as XmlSchemaComplexType;
- if (sct != null && sct.ContentModel is XmlSchemaComplexContent) {
- XmlQualifiedName exqname;
- XmlSchemaComplexContentExtension ext = sct.ContentModel.Content as XmlSchemaComplexContentExtension;
- if (ext != null) exqname = ext.BaseTypeName;
- else exqname = ((XmlSchemaComplexContentRestriction)sct.ContentModel.Content).BaseTypeName;
- if (exqname == qname)
- ImportType (new XmlQualifiedName (sct.Name, schema.TargetNamespace), sct, null);
- }
- }
- }
- }
-
- XmlTypeMapping ImportClassSimpleType (XmlQualifiedName typeQName, XmlSchemaSimpleType stype, XmlQualifiedName root)
- {
- if (CanBeEnum (stype))
- {
- // Create an enum map
-
- CodeIdentifiers codeIdents = new CodeIdentifiers ();
- XmlTypeMapping enumMap = CreateTypeMapping (typeQName, SchemaTypes.Enum, null);
- enumMap.Documentation = GetDocumentation (stype);
-
- bool isFlags = false;
- if (stype.Content is XmlSchemaSimpleTypeList) {
- stype = ((XmlSchemaSimpleTypeList)stype.Content).ItemType;
- isFlags = true;
- }
- XmlSchemaSimpleTypeRestriction rest = (XmlSchemaSimpleTypeRestriction)stype.Content;
-
- codeIdents.AddReserved (enumMap.TypeData.TypeName);
-
- EnumMap.EnumMapMember[] members = new EnumMap.EnumMapMember [rest.Facets.Count];
- for (int n=0; n<rest.Facets.Count; n++)
- {
- XmlSchemaEnumerationFacet enu = (XmlSchemaEnumerationFacet) rest.Facets[n];
- string enumName = codeIdents.AddUnique(CodeIdentifier.MakeValid (enu.Value), enu);
- members [n] = new EnumMap.EnumMapMember (enu.Value, enumName);
- members [n].Documentation = GetDocumentation (enu);
- }
- enumMap.ObjectMap = new EnumMap (members, isFlags);
- enumMap.IsSimpleType = true;
- return enumMap;
- }
-
- if (stype.Content is XmlSchemaSimpleTypeList)
- {
- XmlSchemaSimpleTypeList slist = (XmlSchemaSimpleTypeList)stype.Content;
- TypeData arrayTypeData = FindBuiltInType (slist.ItemTypeName, stype);
-
- ListMap listMap = new ListMap ();
-
- listMap.ItemInfo = new XmlTypeMapElementInfoList ();
- listMap.ItemInfo.Add (CreateElementInfo (typeQName.Namespace, null, "Item", arrayTypeData.ListItemTypeData, false, XmlSchemaForm.None));
-
- XmlTypeMapping map = CreateArrayTypeMapping (typeQName, arrayTypeData);
- map.ObjectMap = listMap;
- map.IsSimpleType = true;
- return map;
- }
-
- // It is an extension of a primitive or known type
-
- TypeData typeData = FindBuiltInType (typeQName, stype);
- XmlTypeMapping rmap = GetTypeMapping (typeData);
-
- // The resulting map must be a simple type. It needs to be explicitely set for arrays
- rmap.IsSimpleType = true;
- return rmap;
- }
-
- bool CanBeEnum (XmlSchemaSimpleType stype)
- {
- if (stype.Content is XmlSchemaSimpleTypeRestriction)
- {
- XmlSchemaSimpleTypeRestriction rest = (XmlSchemaSimpleTypeRestriction)stype.Content;
- if (rest.Facets.Count == 0) return false;
- foreach (object ob in rest.Facets)
- if (!(ob is XmlSchemaEnumerationFacet)) return false;
- return true;
- }
- else if (stype.Content is XmlSchemaSimpleTypeList)
- {
- XmlSchemaSimpleTypeList list = (XmlSchemaSimpleTypeList) stype.Content;
- return (list.ItemType != null && CanBeEnum (list.ItemType));
- }
- return false;
- }
-
- bool CanBeArray (XmlQualifiedName typeQName, XmlSchemaComplexType stype)
- {
- if (encodedFormat)
- {
- XmlSchemaComplexContent content = stype.ContentModel as XmlSchemaComplexContent;
- if (content == null) return false;
- XmlSchemaComplexContentRestriction rest = content.Content as XmlSchemaComplexContentRestriction;
- if (rest == null) return false;
- return rest.BaseTypeName == arrayType;
- }
- else
- {
- if (stype.Attributes.Count > 0 || stype.AnyAttribute != null) return false;
- else return !stype.IsMixed && CanBeArray (typeQName, stype.Particle, false);
- }
- }
-
- bool CanBeArray (XmlQualifiedName typeQName, XmlSchemaParticle particle, bool multiValue)
- {
- // To be an array, there can't be a direct child of type typeQName
-
- if (particle == null) return false;
-
- multiValue = multiValue || particle.MaxOccurs > 1;
-
- if (particle is XmlSchemaGroupRef)
- return CanBeArray (typeQName, GetRefGroupParticle ((XmlSchemaGroupRef)particle), multiValue);
-
- if (particle is XmlSchemaElement)
- {
- XmlSchemaElement elem = (XmlSchemaElement)particle;
- if (!elem.RefName.IsEmpty)
- return CanBeArray (typeQName, FindRefElement (elem), multiValue);
- else
- return multiValue && !typeQName.Equals (((XmlSchemaElement)particle).SchemaTypeName);
- }
-
- if (particle is XmlSchemaAny)
- return multiValue;
-
- if (particle is XmlSchemaSequence)
- {
- XmlSchemaSequence seq = particle as XmlSchemaSequence;
- if (seq.Items.Count != 1) return false;
- return CanBeArray (typeQName, (XmlSchemaParticle)seq.Items[0], multiValue);
- }
-
- if (particle is XmlSchemaChoice)
- {
- // Can be array if all choices have different types
- ArrayList types = new ArrayList ();
- if(!CheckChoiceType (typeQName, particle, types, ref multiValue)) return false;
- return multiValue;
- }
-
- return false;
- }
-
- bool CheckChoiceType (XmlQualifiedName typeQName, XmlSchemaParticle particle, ArrayList types, ref bool multiValue)
- {
- XmlQualifiedName type = null;
-
- multiValue = multiValue || particle.MaxOccurs > 1;
-
- if (particle is XmlSchemaGroupRef)
- return CheckChoiceType (typeQName, GetRefGroupParticle ((XmlSchemaGroupRef)particle), types, ref multiValue);
-
- if (particle is XmlSchemaElement) {
- string ns;
- XmlSchemaElement elem = (XmlSchemaElement)particle;
- XmlSchemaElement refElem = GetRefElement (typeQName, elem, out ns);
- if (refElem.SchemaType != null) return true;
- type = refElem.SchemaTypeName;
- }
- else if (particle is XmlSchemaAny) {
- type = anyType;
- }
- else if (particle is XmlSchemaSequence)
- {
- XmlSchemaSequence seq = particle as XmlSchemaSequence;
- foreach (XmlSchemaParticle par in seq.Items)
- if (!CheckChoiceType (typeQName, par, types, ref multiValue)) return false;
- return true;
- }
- else if (particle is XmlSchemaChoice)
- {
- foreach (XmlSchemaParticle choice in ((XmlSchemaChoice)particle).Items)
- if (!CheckChoiceType (typeQName, choice, types, ref multiValue)) return false;
- return true;
- }
-
- if (typeQName.Equals (type)) return false;
-
- // For primitive types, compare using CLR types, since several
- // xml types can be mapped to a single CLR type
-
- string t;
- if (IsPrimitiveTypeNamespace (type.Namespace))
- t = TypeTranslator.GetPrimitiveTypeData (type.Name).FullTypeName + ":" + type.Namespace;
-
- else
- t = type.Name + ":" + type.Namespace;
-
- if (types.Contains (t)) return false;
- types.Add (t);
- return true;
- }
-
- bool CanBeAnyElement (XmlSchemaComplexType stype)
- {
- XmlSchemaSequence seq = stype.Particle as XmlSchemaSequence;
- return (seq != null) && (seq.Items.Count == 1) && (seq.Items[0] is XmlSchemaAny);
- }
-
- Type GetAnyElementType (XmlSchemaComplexType stype)
- {
- XmlSchemaSequence seq = stype.Particle as XmlSchemaSequence;
-
- if ((seq == null) || (seq.Items.Count != 1) || !(seq.Items[0] is XmlSchemaAny))
- return null;
-
- if (encodedFormat)
- return typeof(object);
-
- XmlSchemaAny any = seq.Items[0] as XmlSchemaAny;
- if (any.MaxOccurs == 1)
- {
- if (stype.IsMixed)
- return typeof(XmlNode);
- else
- return typeof(XmlElement);
- }
- else
- {
- if (stype.IsMixed)
- return typeof(XmlNode[]);
- else
- return typeof(XmlElement[]);
- }
- }
-
- bool CanBeIXmlSerializable (XmlSchemaComplexType stype)
- {
- XmlSchemaSequence seq = stype.Particle as XmlSchemaSequence;
- if (seq == null) return false;
- if (seq.Items.Count != 2) return false;
- XmlSchemaElement elem = seq.Items[0] as XmlSchemaElement;
- if (elem == null) return false;
- if (elem.RefName != new XmlQualifiedName ("schema",XmlSchema.Namespace)) return false;
- return (seq.Items[1] is XmlSchemaAny);
- }
-
- XmlTypeMapping ImportXmlSerializableMapping (string ns)
- {
- XmlQualifiedName qname = new XmlQualifiedName ("System.Data.DataSet",ns);
- XmlTypeMapping map = mappedTypes [qname] as XmlTypeMapping;
- if (map != null) return map;
-
- TypeData typeData = new TypeData ("System.Data.DataSet", "System.Data.DataSet", "System.Data.DataSet", SchemaTypes.XmlSerializable, null);
- map = new XmlTypeMapping ("System.Data.DataSet", "", typeData, "System.Data.DataSet", ns);
- map.IncludeInSchema = true;
- mappedTypes [qname] = map;
- dataMappedTypes [typeData] = map;
- return map;
- }
-
- XmlTypeMapElementInfo CreateElementInfo (string ns, XmlTypeMapMember member, string name, TypeData typeData, bool isNillable, XmlSchemaForm form)
- {
- if (typeData.IsComplexType)
- return CreateElementInfo (ns, member, name, typeData, isNillable, form, GetTypeMapping (typeData));
- else
- return CreateElementInfo (ns, member, name, typeData, isNillable, form, null);
- }
-
- XmlTypeMapElementInfo CreateElementInfo (string ns, XmlTypeMapMember member, string name, TypeData typeData, bool isNillable, XmlSchemaForm form, XmlTypeMapping emap)
- {
- XmlTypeMapElementInfo einfo = new XmlTypeMapElementInfo (member, typeData);
- einfo.ElementName = name;
- einfo.Namespace = ns;
- einfo.IsNullable = isNillable;
- einfo.Form = form;
- if (typeData.IsComplexType)
- einfo.MappedType = emap;
- return einfo;
- }
-
- XmlTypeMapElementInfo CreateTextElementInfo (string ns, XmlTypeMapMember member, TypeData typeData)
- {
- XmlTypeMapElementInfo einfo = new XmlTypeMapElementInfo (member, typeData);
- einfo.IsTextElement = true;
- einfo.WrappedElement = false;
- if (typeData.IsComplexType)
- einfo.MappedType = GetTypeMapping (typeData);
- return einfo;
- }
-
- XmlTypeMapping CreateTypeMapping (XmlQualifiedName typeQName, SchemaTypes schemaType, XmlQualifiedName root)
- {
- string typeName = CodeIdentifier.MakeValid (typeQName.Name);
- typeName = typeIdentifiers.AddUnique (typeName, null);
-
- TypeData typeData = new TypeData (typeName, typeName, typeName, schemaType, null);
-
- string rootElem;
- string rootNs;
- if (root != null) {
- rootElem = root.Name;
- rootNs = root.Namespace;
- }
- else {
- rootElem = typeQName.Name;
- rootNs = "";
- }
-
- XmlTypeMapping map = new XmlTypeMapping (rootElem, rootNs, typeData, typeQName.Name, typeQName.Namespace);
- map.IncludeInSchema = true;
- mappedTypes [typeQName] = map;
- dataMappedTypes [typeData] = map;
-
- return map;
- }
-
- XmlTypeMapping CreateArrayTypeMapping (XmlQualifiedName typeQName, TypeData arrayTypeData)
- {
- XmlTypeMapping map;
- if (encodedFormat) map = new XmlTypeMapping ("Array", XmlSerializer.EncodingNamespace, arrayTypeData, "Array", XmlSerializer.EncodingNamespace);
- else map = new XmlTypeMapping (arrayTypeData.XmlType, typeQName.Namespace, arrayTypeData, arrayTypeData.XmlType, typeQName.Namespace);
-
- map.IncludeInSchema = true;
- mappedTypes [typeQName] = map;
- dataMappedTypes [arrayTypeData] = map;
-
- return map;
- }
-
- XmlSchemaElement GetRefElement (XmlQualifiedName typeQName, XmlSchemaElement elem, out string ns)
- {
-
- if (!elem.RefName.IsEmpty)
- {
- ns = elem.RefName.Namespace;
- return FindRefElement (elem);
- }
- else
- {
- ns = typeQName.Namespace;
- return elem;
- }
- }
-
- XmlSchemaAttribute GetRefAttribute (XmlQualifiedName typeQName, XmlSchemaAttribute attr, out string ns)
- {
- if (!attr.RefName.IsEmpty)
- {
- ns = attr.RefName.Namespace;
- XmlSchemaAttribute at = FindRefAttribute (attr.RefName);
- if (at == null) throw new InvalidOperationException ("The attribute " + attr.RefName + " is missing");
- return at;
- }
- else
- {
- ns = typeQName.Namespace;
- return attr;
- }
- }
-
- TypeData GetElementTypeData (XmlQualifiedName typeQName, XmlSchemaElement elem, XmlQualifiedName root, out XmlTypeMapping map)
- {
- bool sharedAnnType = false;
- map = null;
-
- if (!elem.RefName.IsEmpty) {
- XmlSchemaElement refElem = FindRefElement (elem);
- if (refElem == null) throw new InvalidOperationException ("Global element not found: " + elem.RefName);
- root = elem.RefName;
- elem = refElem;
- sharedAnnType = true;
- }
-
- TypeData td;
- if (!elem.SchemaTypeName.IsEmpty) {
- td = GetTypeData (elem.SchemaTypeName, root);
- map = GetRegisteredTypeMapping (elem.SchemaTypeName);
- }
- else if (elem.SchemaType == null)
- td = TypeTranslator.GetTypeData (typeof(object));
- else
- td = GetTypeData (elem.SchemaType, typeQName, elem.Name, sharedAnnType, root);
-
- if (map == null && td.IsComplexType)
- map = GetTypeMapping (td);
-
- return td;
- }
-
- TypeData GetAttributeTypeData (XmlQualifiedName typeQName, XmlSchemaAttribute attr)
- {
- bool sharedAnnType = false;
-
- if (!attr.RefName.IsEmpty) {
- XmlSchemaAttribute refAtt = FindRefAttribute (attr.RefName);
- if (refAtt == null) throw new InvalidOperationException ("Global attribute not found: " + attr.RefName);
- attr = refAtt;
- sharedAnnType = true;
- }
-
- if (!attr.SchemaTypeName.IsEmpty) return GetTypeData (attr.SchemaTypeName, null);
- if (attr.SchemaType == null) return TypeTranslator.GetTypeData (typeof(string));
- else return GetTypeData (attr.SchemaType, typeQName, attr.Name, sharedAnnType, null);
- }
-
- TypeData GetTypeData (XmlQualifiedName typeQName, XmlQualifiedName root)
- {
- if (IsPrimitiveTypeNamespace (typeQName.Namespace)) {
- XmlTypeMapping map = ImportType (typeQName, root, false);
- if (map != null) return map.TypeData;
- else return TypeTranslator.GetPrimitiveTypeData (typeQName.Name);
- }
-
- if (encodedFormat && typeQName.Namespace == "")
- return TypeTranslator.GetPrimitiveTypeData (typeQName.Name);
-
- return ImportType (typeQName, root, true).TypeData;
- }
-
- TypeData GetTypeData (XmlSchemaType stype, XmlQualifiedName typeQNname, string propertyName, bool sharedAnnType, XmlQualifiedName root)
- {
- string baseName;
-
- if (sharedAnnType)
- {
- // Anonymous types defined in root elements or attributes can be shared among all elements that
- // reference this root element or attribute
- TypeData std = sharedAnonymousTypes [stype] as TypeData;
- if (std != null) return std;
- baseName = propertyName;
- }
- else
- baseName = typeQNname.Name + typeIdentifiers.MakeRightCase (propertyName);
-
- baseName = elemIdentifiers.AddUnique (baseName, stype);
-
- XmlQualifiedName newName;
- newName = new XmlQualifiedName (baseName, typeQNname.Namespace);
-
- XmlTypeMapping map = ImportType (newName, stype, root);
- if (sharedAnnType) sharedAnonymousTypes [stype] = map.TypeData;
-
- return map.TypeData;
- }
-
- XmlTypeMapping GetTypeMapping (TypeData typeData)
- {
- if (typeData.Type == typeof(object) && !anyTypeImported)
- ImportAllObjectTypes ();
-
- XmlTypeMapping map = (XmlTypeMapping) dataMappedTypes [typeData];
- if (map != null) return map;
-
- if (typeData.IsListType)
- {
- // Create an array map for the type
-
- XmlTypeMapping itemMap = GetTypeMapping (typeData.ListItemTypeData);
-
- map = new XmlTypeMapping (typeData.XmlType, itemMap.Namespace, typeData, typeData.XmlType, itemMap.Namespace);
- map.IncludeInSchema = true;
-
- ListMap listMap = new ListMap ();
- listMap.ItemInfo = new XmlTypeMapElementInfoList();
- listMap.ItemInfo.Add (CreateElementInfo (itemMap.Namespace, null, typeData.ListItemTypeData.XmlType, typeData.ListItemTypeData, false, XmlSchemaForm.None));
- map.ObjectMap = listMap;
-
- mappedTypes [new XmlQualifiedName(map.ElementName, map.Namespace)] = map;
- dataMappedTypes [typeData] = map;
- return map;
- }
- else if (typeData.SchemaType == SchemaTypes.Primitive || typeData.Type == typeof(object) || typeof(XmlNode).IsAssignableFrom(typeData.Type))
- {
- return CreateSystemMap (typeData);
- }
-
- throw new InvalidOperationException ("Map for type " + typeData.TypeName + " not found");
- }
-
- void AddObjectDerivedMap (XmlTypeMapping map)
- {
- TypeData typeData = TypeTranslator.GetTypeData (typeof(object));
- XmlTypeMapping omap = (XmlTypeMapping) dataMappedTypes [typeData];
- if (omap == null)
- omap = CreateSystemMap (typeData);
- omap.DerivedTypes.Add (map);
- }
-
- XmlTypeMapping CreateSystemMap (TypeData typeData)
- {
- XmlTypeMapping map = new XmlTypeMapping (typeData.XmlType, XmlSchema.Namespace, typeData, typeData.XmlType, XmlSchema.Namespace);
- map.IncludeInSchema = false;
- map.ObjectMap = new ClassMap ();
- dataMappedTypes [typeData] = map;
- return map;
- }
-
- void ImportAllObjectTypes ()
- {
- // All complex types are subtypes of anyType, so all of them
- // must also be imported
-
- anyTypeImported = true;
- foreach (XmlSchema schema in schemas) {
- foreach (XmlSchemaObject sob in schema.Items)
- {
- XmlSchemaComplexType sct = sob as XmlSchemaComplexType;
- if (sct != null)
- ImportType (new XmlQualifiedName (sct.Name, schema.TargetNamespace), sct, null);
- }
- }
- }
-
-
- XmlTypeMapping GetRegisteredTypeMapping (XmlQualifiedName typeQName)
- {
- return (XmlTypeMapping) mappedTypes [typeQName];
- }
-
- XmlSchemaParticle GetRefGroupParticle (XmlSchemaGroupRef refGroup)
- {
- XmlSchemaGroup grp = (XmlSchemaGroup) schemas.Find (refGroup.RefName, typeof (XmlSchemaGroup));
- return grp.Particle;
- }
-
- XmlSchemaElement FindRefElement (XmlSchemaElement elem)
- {
- XmlSchemaElement refelem = (XmlSchemaElement) schemas.Find (elem.RefName, typeof(XmlSchemaElement));
- if (refelem != null) return refelem;
-
- if (IsPrimitiveTypeNamespace (elem.RefName.Namespace))
- {
- if (anyElement != null) return anyElement;
- anyElement = new XmlSchemaElement ();
- anyElement.Name = "any";
- anyElement.SchemaTypeName = anyType;
- return anyElement;
- } else
- return null;
- }
-
- XmlSchemaAttribute FindRefAttribute (XmlQualifiedName refName)
- {
- if (refName.Namespace == XmlNamespace)
- {
- XmlSchemaAttribute at = new XmlSchemaAttribute ();
- at.Name = refName.Name;
- at.SchemaTypeName = new XmlQualifiedName ("string",XmlSchema.Namespace);
- return at;
- }
- return (XmlSchemaAttribute) schemas.Find (refName, typeof(XmlSchemaAttribute));
- }
-
- XmlSchemaAttributeGroup FindRefAttributeGroup (XmlQualifiedName refName)
- {
- XmlSchemaAttributeGroup grp = (XmlSchemaAttributeGroup) schemas.Find (refName, typeof(XmlSchemaAttributeGroup));
- foreach (XmlSchemaObject at in grp.Attributes)
- {
- if (at is XmlSchemaAttributeGroupRef && ((XmlSchemaAttributeGroupRef)at).RefName == refName)
- throw new InvalidOperationException ("Cannot import attribute group '" + refName.Name + "' from namespace '" + refName.Namespace + "'. Redefine not supported");
-
- }
- return grp;
- }
-
- XmlTypeMapping ReflectType (Type type)
- {
- TypeData typeData = TypeTranslator.GetTypeData (type);
- return ReflectType (typeData, (string) null);
- }
-
- XmlTypeMapping ReflectType (TypeData typeData, string ns)
- {
- if (!encodedFormat)
- {
- if (auxXmlRefImporter == null) auxXmlRefImporter = new XmlReflectionImporter ();
- return auxXmlRefImporter.ImportTypeMapping (typeData, ns);
- }
- else
- {
- if (auxSoapRefImporter == null) auxSoapRefImporter = new SoapReflectionImporter ();
- return auxSoapRefImporter.ImportTypeMapping (typeData, ns);
- }
- }
-
-
- string GetDocumentation (XmlSchemaAnnotated elem)
- {
- string res = "";
- XmlSchemaAnnotation anot = elem.Annotation;
- if (anot == null || anot.Items == null) return null;
-
- foreach (object ob in anot.Items)
- {
- XmlSchemaDocumentation doc = ob as XmlSchemaDocumentation;
- if (doc != null && doc.Markup != null && doc.Markup.Length > 0) {
- if (res != string.Empty) res += "\n";
- foreach (XmlNode node in doc.Markup)
- res += node.Value;
- }
- }
- return res;
- }
-
- bool IsPrimitiveTypeNamespace (string ns)
- {
- return (ns == XmlSchema.Namespace) || (encodedFormat && ns == XmlSerializer.EncodingNamespace);
- }
-
- #endregion // Methods
- }
-}
+// +// System.Xml.Serialization.XmlSchemaImporter +// +// Author: +// Tim Coleman (tim@timcoleman.com) +// Lluis Sanchez Gual (lluis@ximian.com) +// +// Copyright (C) Tim Coleman, 2002 +// + +// +// 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.Xml; +#if !TARGET_JVM +using System.CodeDom.Compiler; +#endif +using System.Xml.Schema; +using System.Collections; + +namespace System.Xml.Serialization +{ + public class XmlSchemaImporter +#if NET_2_0 + : SchemaImporter +#endif + { + #region Fields + + XmlSchemas schemas; + CodeIdentifiers typeIdentifiers; + CodeIdentifiers elemIdentifiers = new CodeIdentifiers (); + Hashtable mappedTypes = new Hashtable (); + Hashtable dataMappedTypes = new Hashtable (); + Queue pendingMaps = new Queue (); + Hashtable sharedAnonymousTypes = new Hashtable (); + bool encodedFormat = false; + XmlReflectionImporter auxXmlRefImporter; + SoapReflectionImporter auxSoapRefImporter; + bool anyTypeImported; + +#if NET_2_0 + CodeGenerationOptions options; +#endif + + static readonly XmlQualifiedName anyType = new XmlQualifiedName ("anyType",XmlSchema.Namespace); + static readonly XmlQualifiedName arrayType = new XmlQualifiedName ("Array",XmlSerializer.EncodingNamespace); + static readonly XmlQualifiedName arrayTypeRefName = new XmlQualifiedName ("arrayType",XmlSerializer.EncodingNamespace); + + const string XmlNamespace = "http://www.w3.org/XML/1998/namespace"; + + XmlSchemaElement anyElement = null; + + class MapFixup + { + public XmlTypeMapping Map; + public XmlSchemaComplexType SchemaType; + public XmlQualifiedName TypeName; + } + + #endregion + + #region Constructors + + public XmlSchemaImporter (XmlSchemas schemas) + { + this.schemas = schemas; + typeIdentifiers = new CodeIdentifiers (); + } + + public XmlSchemaImporter (XmlSchemas schemas, CodeIdentifiers typeIdentifiers) + : this (schemas) + { + this.typeIdentifiers = typeIdentifiers; + } + +#if NET_2_0 +#if !TARGET_JVM + [MonoTODO] + public XmlSchemaImporter (XmlSchemas schemas, CodeGenerationOptions options, CodeDomProvider codeProvider, ImportContext context) + { + this.schemas = schemas; + this.options = options; + if (context != null) { + typeIdentifiers = context.TypeIdentifiers; + InitSharedData (context); + } + else + typeIdentifiers = new CodeIdentifiers (); + } +#endif + + public XmlSchemaImporter (XmlSchemas schemas, CodeGenerationOptions options, ImportContext context) + { + this.schemas = schemas; + this.options = options; + if (context != null) { + typeIdentifiers = context.TypeIdentifiers; + InitSharedData (context); + } + else + typeIdentifiers = new CodeIdentifiers (); + } + + + public XmlSchemaImporter (XmlSchemas schemas, CodeIdentifiers typeIdentifiers, CodeGenerationOptions options) + { + this.typeIdentifiers = typeIdentifiers; + this.schemas = schemas; + this.options = options; + } + + void InitSharedData (ImportContext context) + { + if (context.ShareTypes) { + mappedTypes = context.MappedTypes; + dataMappedTypes = context.DataMappedTypes; + sharedAnonymousTypes = context.SharedAnonymousTypes; + } + } +#endif + + internal bool UseEncodedFormat + { + get { return encodedFormat; } + set { encodedFormat = value; } + } + + #endregion // Constructors + + #region Methods + + public XmlMembersMapping ImportAnyType (XmlQualifiedName typeName, string elementName) + { + if (typeName == XmlQualifiedName.Empty) + { + XmlTypeMapMemberAnyElement mapMem = new XmlTypeMapMemberAnyElement (); + mapMem.Name = typeName.Name; + mapMem.TypeData = TypeTranslator.GetTypeData(typeof(XmlNode)); + mapMem.ElementInfo.Add (CreateElementInfo (typeName.Namespace, mapMem, typeName.Name, mapMem.TypeData, true, XmlSchemaForm.None)); + + XmlMemberMapping[] mm = new XmlMemberMapping [1]; + mm[0] = new XmlMemberMapping (typeName.Name, typeName.Namespace, mapMem, encodedFormat); + return new XmlMembersMapping (mm); + } + else + { + XmlSchemaComplexType stype = (XmlSchemaComplexType) schemas.Find (typeName, typeof (XmlSchemaComplexType)); + if (stype == null) + throw new InvalidOperationException ("Referenced type '" + typeName + "' not found"); + + if (!CanBeAnyElement (stype)) + throw new InvalidOperationException ("The type '" + typeName + "' is not valid for a collection of any elements"); + + ClassMap cmap = new ClassMap (); + CodeIdentifiers classIds = new CodeIdentifiers (); + bool isMixed = stype.IsMixed; + ImportSequenceContent (typeName, cmap, ((XmlSchemaSequence) stype.Particle).Items, classIds, false, ref isMixed); + XmlTypeMapMemberAnyElement mapMem = (XmlTypeMapMemberAnyElement) cmap.AllMembers[0]; + mapMem.Name = typeName.Name; + + XmlMemberMapping[] mm = new XmlMemberMapping [1]; + mm[0] = new XmlMemberMapping (typeName.Name, typeName.Namespace, mapMem, encodedFormat); + return new XmlMembersMapping (mm); + } + } + + public XmlTypeMapping ImportDerivedTypeMapping (XmlQualifiedName name, Type baseType) + { + return ImportDerivedTypeMapping (name, baseType, true); + } + + public XmlTypeMapping ImportDerivedTypeMapping (XmlQualifiedName name, Type baseType, bool baseTypeCanBeIndirect) + { + XmlQualifiedName qname; + XmlSchemaType stype; + + if (encodedFormat) + { + qname = name; + stype = schemas.Find (name, typeof (XmlSchemaComplexType)) as XmlSchemaComplexType; + if (stype == null) throw new InvalidOperationException ("Schema type '" + name + "' not found or not valid"); + } + else + { + if (!LocateElement (name, out qname, out stype)) + return null; + } + + XmlTypeMapping map = GetRegisteredTypeMapping (qname); + if (map != null) + { + // If the type has already been imported, make sure that the map + // has the requested base type + + SetMapBaseType (map, baseType); + map.UpdateRoot (name); + return map; + } + + map = CreateTypeMapping (qname, SchemaTypes.Class, name); + if (stype != null) { + map.Documentation = GetDocumentation (stype); + RegisterMapFixup (map, qname, (XmlSchemaComplexType)stype); + } else { + ClassMap cmap = new ClassMap (); + CodeIdentifiers classIds = new CodeIdentifiers (); + map.ObjectMap = cmap; + AddTextMember (qname, cmap, classIds); + } + + BuildPendingMaps (); + SetMapBaseType (map, baseType); + + return map; + } + + void SetMapBaseType (XmlTypeMapping map, Type baseType) + { + // This method sets the base type for a given map. + // If the map already inherits from this type, it does nothing. + + // Fiirst of all, check if the map already inherits from baseType + + XmlTypeMapping topMap = null; + while (map != null) + { + if (map.TypeData.Type == baseType) + return; + topMap = map; + map = map.BaseMap; + } + + // Does not have the requested base type. + // Then, get/create a map for that base type. + + XmlTypeMapping baseMap = ReflectType (baseType); + + // Add this map as a derived map of the base map + + topMap.BaseMap = baseMap; + baseMap.DerivedTypes.Add (topMap); + baseMap.DerivedTypes.AddRange (topMap.DerivedTypes); + + // Now add the base type fields to all derived maps + + ClassMap baseClassMap = (ClassMap)baseMap.ObjectMap; + + ClassMap cmap = (ClassMap)topMap.ObjectMap; + foreach (XmlTypeMapMember member in baseClassMap.AllMembers) + cmap.AddMember (member); + + foreach (XmlTypeMapping derivedMap in topMap.DerivedTypes) + { + cmap = (ClassMap)derivedMap.ObjectMap; + foreach (XmlTypeMapMember member in baseClassMap.AllMembers) + cmap.AddMember (member); + } + } + + public XmlMembersMapping ImportMembersMapping (XmlQualifiedName name) + { + XmlSchemaElement elem = (XmlSchemaElement) schemas.Find (name, typeof (XmlSchemaElement)); + if (elem == null) throw new InvalidOperationException ("Schema element '" + name + "' not found or not valid"); + + XmlSchemaComplexType stype; + if (elem.SchemaType != null) + { + stype = elem.SchemaType as XmlSchemaComplexType; + } + else + { + if (elem.SchemaTypeName.IsEmpty) return null; + object type = schemas.Find (elem.SchemaTypeName, typeof (XmlSchemaComplexType)); + if (type == null) { + if (IsPrimitiveTypeNamespace (elem.SchemaTypeName.Namespace)) return null; + throw new InvalidOperationException ("Schema type '" + elem.SchemaTypeName + "' not found"); + } + stype = type as XmlSchemaComplexType; + } + + if (stype == null) + throw new InvalidOperationException ("Schema element '" + name + "' not found or not valid"); + + XmlMemberMapping[] mapping = ImportMembersMappingComposite (stype, name); + return new XmlMembersMapping (name.Name, name.Namespace, mapping); + } + + public XmlMembersMapping ImportMembersMapping (XmlQualifiedName[] names) + { + XmlMemberMapping[] mapping = new XmlMemberMapping [names.Length]; + for (int n=0; n<names.Length; n++) + { + XmlSchemaElement elem = (XmlSchemaElement) schemas.Find (names[n], typeof (XmlSchemaElement)); + if (elem == null) throw new InvalidOperationException ("Schema element '" + names[n] + "' not found"); + + XmlQualifiedName typeQName = new XmlQualifiedName ("Message", names[n].Namespace); + XmlTypeMapping tmap; + TypeData td = GetElementTypeData (typeQName, elem, names[n], out tmap); + + mapping[n] = ImportMemberMapping (elem.Name, typeQName.Namespace, elem.IsNillable, td, tmap); + } + BuildPendingMaps (); + return new XmlMembersMapping (mapping); + } + +#if NET_2_0 + [MonoTODO] + public XmlMembersMapping ImportMembersMapping (string name, string ns, SoapSchemaMember[] members) + { + throw new NotImplementedException (); + } + + [MonoTODO] + public XmlTypeMapping ImportSchemaType (XmlQualifiedName typeName) + { + throw new NotImplementedException (); + } + + [MonoTODO] + public XmlTypeMapping ImportSchemaType (XmlQualifiedName typeName, Type baseType) + { + throw new NotImplementedException (); + } + + [MonoTODO] + public XmlTypeMapping ImportSchemaType (XmlQualifiedName typeName, Type baseType, bool baseTypeCanBeIndirect) + { + throw new NotImplementedException (); + } +#endif + + internal XmlMembersMapping ImportEncodedMembersMapping (string name, string ns, SoapSchemaMember[] members, bool hasWrapperElement) + { + XmlMemberMapping[] mapping = new XmlMemberMapping [members.Length]; + for (int n=0; n<members.Length; n++) + { + TypeData td = GetTypeData (members[n].MemberType, null); + XmlTypeMapping tmap = GetTypeMapping (td); + mapping[n] = ImportMemberMapping (members[n].MemberName, members[n].MemberType.Namespace, true, td, tmap); + } + BuildPendingMaps (); + return new XmlMembersMapping (name, ns, hasWrapperElement, false, mapping); + } + + internal XmlMembersMapping ImportEncodedMembersMapping (string name, string ns, SoapSchemaMember member) + { + XmlSchemaComplexType stype = schemas.Find (member.MemberType, typeof (XmlSchemaComplexType)) as XmlSchemaComplexType; + if (stype == null) throw new InvalidOperationException ("Schema type '" + member.MemberType + "' not found or not valid"); + + XmlMemberMapping[] mapping = ImportMembersMappingComposite (stype, member.MemberType); + return new XmlMembersMapping (name, ns, mapping); + } + + XmlMemberMapping[] ImportMembersMappingComposite (XmlSchemaComplexType stype, XmlQualifiedName refer) + { + if (stype.Particle == null) + return new XmlMemberMapping [0]; + + ClassMap cmap = new ClassMap (); + + XmlSchemaSequence seq = stype.Particle as XmlSchemaSequence; + if (seq == null) throw new InvalidOperationException ("Schema element '" + refer + "' cannot be imported as XmlMembersMapping"); + + CodeIdentifiers classIds = new CodeIdentifiers (); + ImportParticleComplexContent (refer, cmap, seq, classIds, false); + ImportAttributes (refer, cmap, stype.Attributes, stype.AnyAttribute, classIds); + + BuildPendingMaps (); + + int n = 0; + XmlMemberMapping[] mapping = new XmlMemberMapping [cmap.AllMembers.Count]; + foreach (XmlTypeMapMember mapMem in cmap.AllMembers) + mapping[n++] = new XmlMemberMapping (mapMem.Name, refer.Namespace, mapMem, encodedFormat); + + return mapping; + } + + XmlMemberMapping ImportMemberMapping (string name, string ns, bool isNullable, TypeData type, XmlTypeMapping emap) + { + XmlTypeMapMemberElement mapMem; + + if (type.IsListType) + mapMem = new XmlTypeMapMemberList (); + else + mapMem = new XmlTypeMapMemberElement (); + + mapMem.Name = name; + mapMem.TypeData = type; + mapMem.ElementInfo.Add (CreateElementInfo (ns, mapMem, name, type, isNullable, XmlSchemaForm.None, emap)); + return new XmlMemberMapping (name, ns, mapMem, encodedFormat); + } + + [MonoTODO] + public XmlMembersMapping ImportMembersMapping (XmlQualifiedName[] names, Type baseType, bool baseTypeCanBeIndirect) + { + throw new NotImplementedException (); + } + + public XmlTypeMapping ImportTypeMapping (XmlQualifiedName name) + { + XmlQualifiedName qname; + XmlSchemaType stype; + + XmlSchemaElement elem = (XmlSchemaElement) schemas.Find (name, typeof (XmlSchemaElement)); + if (!LocateElement (elem, out qname, out stype)) return null; + + if (stype == null) { + // Importing a primitive type + TypeData td = TypeTranslator.GetPrimitiveTypeData (qname.Name); + return ReflectType (td, name.Namespace); + } + + XmlTypeMapping map = GetRegisteredTypeMapping (qname); + if (map != null) return map; + + map = CreateTypeMapping (qname, SchemaTypes.Class, name); + map.Documentation = GetDocumentation (stype); + map.IsNullable = elem.IsNillable; + RegisterMapFixup (map, qname, (XmlSchemaComplexType)stype); + + BuildPendingMaps (); + return map; + } + + bool LocateElement (XmlQualifiedName name, out XmlQualifiedName qname, out XmlSchemaType stype) + { + XmlSchemaElement elem = (XmlSchemaElement) schemas.Find (name, typeof (XmlSchemaElement)); + return LocateElement (elem, out qname, out stype); + } + + bool LocateElement (XmlSchemaElement elem, out XmlQualifiedName qname, out XmlSchemaType stype) + { + qname = null; + stype = null; + + if (elem == null) return false; + + // The root element must be an element with complex type + + if (elem.SchemaType != null) + { + stype = elem.SchemaType; + qname = elem.QualifiedName; + } + else + { + if (elem.SchemaTypeName.IsEmpty) return false; + + object type = schemas.Find (elem.SchemaTypeName, typeof (XmlSchemaComplexType)); + if (type == null) type = schemas.Find (elem.SchemaTypeName, typeof (XmlSchemaSimpleType)); + if (type == null) { + if (IsPrimitiveTypeNamespace (elem.SchemaTypeName.Namespace)) { + qname = elem.SchemaTypeName; + return true; + } + throw new InvalidOperationException ("Schema type '" + elem.SchemaTypeName + "' not found"); + } + stype = (XmlSchemaType) type; + qname = stype.QualifiedName; + + XmlSchemaType btype = stype.BaseSchemaType as XmlSchemaType; + if (btype != null && btype.QualifiedName == elem.SchemaTypeName) + throw new InvalidOperationException ("Cannot import schema for type '" + elem.SchemaTypeName.Name + "' from namespace '" + elem.SchemaTypeName.Namespace + "'. Redefine not supported"); + } + + if (stype is XmlSchemaSimpleType) return false; + return true; + } + + XmlTypeMapping ImportType (XmlQualifiedName name, XmlQualifiedName root, bool throwOnError) + { + XmlTypeMapping map = GetRegisteredTypeMapping (name); + if (map != null) { + map.UpdateRoot (root); + return map; + } + + XmlSchemaType type = (XmlSchemaType) schemas.Find (name, typeof (XmlSchemaComplexType)); + if (type == null) type = (XmlSchemaType) schemas.Find (name, typeof (XmlSchemaSimpleType)); + + if (type == null) + { + if (throwOnError) { + if (name.Namespace == XmlSerializer.EncodingNamespace) + throw new InvalidOperationException ("Referenced type '" + name + "' valid only for encoded SOAP."); + else + throw new InvalidOperationException ("Referenced type '" + name + "' not found."); + } else + return null; + } + + return ImportType (name, type, root); + } + + XmlTypeMapping ImportClass (XmlQualifiedName name) + { + XmlTypeMapping map = ImportType (name, null, true); + if (map.TypeData.SchemaType == SchemaTypes.Class) return map; + XmlSchemaComplexType stype = schemas.Find (name, typeof (XmlSchemaComplexType)) as XmlSchemaComplexType; + return CreateClassMap (name, stype, new XmlQualifiedName (map.ElementName, map.Namespace)); + } + + XmlTypeMapping ImportType (XmlQualifiedName name, XmlSchemaType stype, XmlQualifiedName root) + { + XmlTypeMapping map = GetRegisteredTypeMapping (name); + if (map != null) { + XmlSchemaComplexType ct = stype as XmlSchemaComplexType; + if (map.TypeData.SchemaType != SchemaTypes.Class || ct == null || !CanBeArray (name, ct)) { + map.UpdateRoot (root); + return map; + } + + // The map was initially imported as a class, but it turns out that it is an + // array. It has to be imported now as array. + } + + if (stype is XmlSchemaComplexType) + return ImportClassComplexType (name, (XmlSchemaComplexType) stype, root); + else if (stype is XmlSchemaSimpleType) + return ImportClassSimpleType (name, (XmlSchemaSimpleType) stype, root); + + throw new NotSupportedException ("Schema type not supported: " + stype.GetType ()); + } + + XmlTypeMapping ImportClassComplexType (XmlQualifiedName typeQName, XmlSchemaComplexType stype, XmlQualifiedName root) + { + // The need for fixups: If the complex type is an array, then to get the type of the + // array we need first to get the type of the items of the array. + // But if one of the item types or its children has a referece to this type array, + // then we enter in an infinite loop. This does not happen with class types because + // the class map is registered before parsing the children. We can't do the same + // with the array type because to register the array map we need the type of the array. + + Type anyType = GetAnyElementType (stype); + if (anyType != null) + return GetTypeMapping (TypeTranslator.GetTypeData(anyType)); + + if (CanBeArray (typeQName, stype)) + { + TypeData typeData; + ListMap listMap = BuildArrayMap (typeQName, stype, out typeData); + if (listMap != null) + { + XmlTypeMapping map = CreateArrayTypeMapping (typeQName, typeData); + map.ObjectMap = listMap; + return map; + } + + // After all, it is not an array. Create a class map then. + } + else if (CanBeIXmlSerializable (stype)) + { + return ImportXmlSerializableMapping (typeQName.Namespace); + } + + // Register the map right now but do not build it, + // This will avoid loops. + + return CreateClassMap (typeQName, stype, root); + } + + XmlTypeMapping CreateClassMap (XmlQualifiedName typeQName, XmlSchemaComplexType stype, XmlQualifiedName root) + { + XmlTypeMapping map = CreateTypeMapping (typeQName, SchemaTypes.Class, root); + map.Documentation = GetDocumentation (stype); + RegisterMapFixup (map, typeQName, stype); + return map; + } + + void RegisterMapFixup (XmlTypeMapping map, XmlQualifiedName typeQName, XmlSchemaComplexType stype) + { + MapFixup fixup = new MapFixup (); + fixup.Map = map; + fixup.SchemaType = stype; + fixup.TypeName = typeQName; + pendingMaps.Enqueue (fixup); + } + + void BuildPendingMaps () + { + while (pendingMaps.Count > 0) { + MapFixup fixup = (MapFixup) pendingMaps.Dequeue (); + if (fixup.Map.ObjectMap == null) { + BuildClassMap (fixup.Map, fixup.TypeName, fixup.SchemaType); + if (fixup.Map.ObjectMap == null) pendingMaps.Enqueue (fixup); + } + } + } + + void BuildPendingMap (XmlTypeMapping map) + { + if (map.ObjectMap != null) return; + + foreach (MapFixup fixup in pendingMaps) + { + if (fixup.Map == map) { + BuildClassMap (fixup.Map, fixup.TypeName, fixup.SchemaType); + return; + } + } + throw new InvalidOperationException ("Can't complete map of type " + map.XmlType + " : " + map.Namespace); + } + + void BuildClassMap (XmlTypeMapping map, XmlQualifiedName typeQName, XmlSchemaComplexType stype) + { + CodeIdentifiers classIds = new CodeIdentifiers(); + classIds.AddReserved (map.TypeData.TypeName); + + ClassMap cmap = new ClassMap (); + map.ObjectMap = cmap; + bool isMixed = stype.IsMixed; + + if (stype.Particle != null) + ImportParticleComplexContent (typeQName, cmap, stype.Particle, classIds, isMixed); + else + { + if (stype.ContentModel is XmlSchemaSimpleContent) { + ImportSimpleContent (typeQName, map, (XmlSchemaSimpleContent)stype.ContentModel, classIds, isMixed); + } + else if (stype.ContentModel is XmlSchemaComplexContent) { + ImportComplexContent (typeQName, map, (XmlSchemaComplexContent)stype.ContentModel, classIds, isMixed); + } + } + + ImportAttributes (typeQName, cmap, stype.Attributes, stype.AnyAttribute, classIds); + ImportExtensionTypes (typeQName); + + if (isMixed) AddTextMember (typeQName, cmap, classIds); + + AddObjectDerivedMap (map); + } + + void ImportAttributes (XmlQualifiedName typeQName, ClassMap cmap, XmlSchemaObjectCollection atts, XmlSchemaAnyAttribute anyat, CodeIdentifiers classIds) + { + if (anyat != null) + { + XmlTypeMapMemberAnyAttribute member = new XmlTypeMapMemberAnyAttribute (); + member.Name = classIds.AddUnique ("AnyAttribute", member); + member.TypeData = TypeTranslator.GetTypeData (typeof(XmlAttribute[])); + cmap.AddMember (member); + } + + foreach (XmlSchemaObject at in atts) + { + if (at is XmlSchemaAttribute) + { + string ns; + XmlSchemaAttribute attr = (XmlSchemaAttribute)at; + XmlSchemaAttribute refAttr = GetRefAttribute (typeQName, attr, out ns); + XmlTypeMapMemberAttribute member = new XmlTypeMapMemberAttribute (); + member.Name = classIds.AddUnique (CodeIdentifier.MakeValid (refAttr.Name), member); + member.Documentation = GetDocumentation (attr); + member.AttributeName = refAttr.Name; + member.Namespace = ns; + member.Form = refAttr.Form; + member.TypeData = GetAttributeTypeData (typeQName, attr); + + if (refAttr.DefaultValue != null) + member.DefaultValue = ImportDefaultValue (member.TypeData, refAttr.DefaultValue); + else if (member.TypeData.IsValueType) + member.IsOptionalValueType = (refAttr.ValidatedUse != XmlSchemaUse.Required); + + if (member.TypeData.IsComplexType) + member.MappedType = GetTypeMapping (member.TypeData); + cmap.AddMember (member); + } + else if (at is XmlSchemaAttributeGroupRef) + { + XmlSchemaAttributeGroupRef gref = (XmlSchemaAttributeGroupRef)at; + XmlSchemaAttributeGroup grp = FindRefAttributeGroup (gref.RefName); + ImportAttributes (typeQName, cmap, grp.Attributes, grp.AnyAttribute, classIds); + } + } + } + + ListMap BuildArrayMap (XmlQualifiedName typeQName, XmlSchemaComplexType stype, out TypeData arrayTypeData) + { + if (encodedFormat) + { + XmlSchemaComplexContent content = stype.ContentModel as XmlSchemaComplexContent; + XmlSchemaComplexContentRestriction rest = content.Content as XmlSchemaComplexContentRestriction; + XmlSchemaAttribute arrayTypeAt = FindArrayAttribute (rest.Attributes); + + if (arrayTypeAt != null) + { + XmlAttribute[] uatts = arrayTypeAt.UnhandledAttributes; + if (uatts == null || uatts.Length == 0) throw new InvalidOperationException ("arrayType attribute not specified in array declaration: " + typeQName); + + XmlAttribute xat = null; + foreach (XmlAttribute at in uatts) + if (at.LocalName == "arrayType" && at.NamespaceURI == XmlSerializer.WsdlNamespace) + { xat = at; break; } + + if (xat == null) + throw new InvalidOperationException ("arrayType attribute not specified in array declaration: " + typeQName); + + string name, ns, dims; + TypeTranslator.ParseArrayType (xat.Value, out name, out ns, out dims); + return BuildEncodedArrayMap (name + dims, ns, out arrayTypeData); + } + else + { + XmlSchemaElement elem = null; + XmlSchemaSequence seq = rest.Particle as XmlSchemaSequence; + if (seq != null && seq.Items.Count == 1) + elem = seq.Items[0] as XmlSchemaElement; + else { + XmlSchemaAll all = rest.Particle as XmlSchemaAll; + if (all != null && all.Items.Count == 1) + elem = all.Items[0] as XmlSchemaElement; + } + if (elem == null) + throw new InvalidOperationException ("Unknown array format"); + + return BuildEncodedArrayMap (elem.SchemaTypeName.Name + "[]", elem.SchemaTypeName.Namespace, out arrayTypeData); + } + } + else + { + ClassMap cmap = new ClassMap (); + CodeIdentifiers classIds = new CodeIdentifiers(); + ImportParticleComplexContent (typeQName, cmap, stype.Particle, classIds, stype.IsMixed); + + XmlTypeMapMemberFlatList list = (cmap.AllMembers.Count == 1) ? cmap.AllMembers[0] as XmlTypeMapMemberFlatList : null; + if (list != null && list.ChoiceMember == null) + { + arrayTypeData = list.TypeData; + return list.ListMap; + } + else + { + arrayTypeData = null; + return null; + } + } + } + + ListMap BuildEncodedArrayMap (string type, string ns, out TypeData arrayTypeData) + { + ListMap map = new ListMap (); + + int i = type.LastIndexOf ("["); + if (i == -1) throw new InvalidOperationException ("Invalid arrayType value: " + type); + if (type.IndexOf (",",i) != -1) throw new InvalidOperationException ("Multidimensional arrays are not supported"); + + string itemType = type.Substring (0,i); + + TypeData itemTypeData; + if (itemType.IndexOf ("[") != -1) + { + ListMap innerListMap = BuildEncodedArrayMap (itemType, ns, out itemTypeData); + + int dims = itemType.Split ('[').Length - 1; + string name = TypeTranslator.GetArrayName (type, dims); + XmlQualifiedName qname = new XmlQualifiedName (name, ns); + XmlTypeMapping tmap = CreateArrayTypeMapping (qname, itemTypeData); + tmap.ObjectMap = innerListMap; + } + else + { + itemTypeData = GetTypeData (new XmlQualifiedName (itemType, ns), null); + } + + arrayTypeData = itemTypeData.ListTypeData; + + map.ItemInfo = new XmlTypeMapElementInfoList(); + map.ItemInfo.Add (CreateElementInfo ("", null, "Item", itemTypeData, true, XmlSchemaForm.None)); + return map; + } + + XmlSchemaAttribute FindArrayAttribute (XmlSchemaObjectCollection atts) + { + foreach (object ob in atts) + { + XmlSchemaAttribute att = ob as XmlSchemaAttribute; + if (att != null && att.RefName == arrayTypeRefName) return att; + + XmlSchemaAttributeGroupRef gref = ob as XmlSchemaAttributeGroupRef; + if (gref != null) + { + XmlSchemaAttributeGroup grp = FindRefAttributeGroup (gref.RefName); + att = FindArrayAttribute (grp.Attributes); + if (att != null) return att; + } + } + return null; + } + + void ImportParticleComplexContent (XmlQualifiedName typeQName, ClassMap cmap, XmlSchemaParticle particle, CodeIdentifiers classIds, bool isMixed) + { + ImportParticleContent (typeQName, cmap, particle, classIds, false, ref isMixed); + if (isMixed) AddTextMember (typeQName, cmap, classIds); + } + + void AddTextMember (XmlQualifiedName typeQName, ClassMap cmap, CodeIdentifiers classIds) + { + if (cmap.XmlTextCollector == null) + { + XmlTypeMapMemberFlatList member = new XmlTypeMapMemberFlatList (); + member.Name = classIds.AddUnique ("Text", member); + member.TypeData = TypeTranslator.GetTypeData (typeof(string[])); + member.ElementInfo.Add (CreateTextElementInfo (typeQName.Namespace, member, member.TypeData.ListItemTypeData)); + member.IsXmlTextCollector = true; + member.ListMap = new ListMap (); + member.ListMap.ItemInfo = member.ElementInfo; + cmap.AddMember (member); + } + } + + void ImportParticleContent (XmlQualifiedName typeQName, ClassMap cmap, XmlSchemaParticle particle, CodeIdentifiers classIds, bool multiValue, ref bool isMixed) + { + if (particle == null) return; + + if (particle is XmlSchemaGroupRef) + particle = GetRefGroupParticle ((XmlSchemaGroupRef)particle); + + if (particle.MaxOccurs > 1) multiValue = true; + + if (particle is XmlSchemaSequence) { + ImportSequenceContent (typeQName, cmap, ((XmlSchemaSequence)particle).Items, classIds, multiValue, ref isMixed); + } + else if (particle is XmlSchemaChoice) { + if (((XmlSchemaChoice)particle).Items.Count == 1) + ImportSequenceContent (typeQName, cmap, ((XmlSchemaChoice)particle).Items, classIds, multiValue, ref isMixed); + else + ImportChoiceContent (typeQName, cmap, (XmlSchemaChoice)particle, classIds, multiValue); + } + else if (particle is XmlSchemaAll) { + ImportSequenceContent (typeQName, cmap, ((XmlSchemaAll)particle).Items, classIds, multiValue, ref isMixed); + } + } + + void ImportSequenceContent (XmlQualifiedName typeQName, ClassMap cmap, XmlSchemaObjectCollection items, CodeIdentifiers classIds, bool multiValue, ref bool isMixed) + { + foreach (XmlSchemaObject item in items) + { + if (item is XmlSchemaElement) + { + string ns; + XmlSchemaElement elem = (XmlSchemaElement) item; + XmlTypeMapping emap; + TypeData typeData = GetElementTypeData (typeQName, elem, null, out emap); + XmlSchemaElement refElem = GetRefElement (typeQName, elem, out ns); + + if (elem.MaxOccurs == 1 && !multiValue) + { + XmlTypeMapMemberElement member = null; + if (typeData.SchemaType != SchemaTypes.Array) + { + member = new XmlTypeMapMemberElement (); + if (refElem.DefaultValue != null) member.DefaultValue = ImportDefaultValue (typeData, refElem.DefaultValue); + } + else if (GetTypeMapping (typeData).IsSimpleType) + { + // It is a simple list (space separated list). + // Since this is not supported, map as a single item value + member = new XmlTypeMapMemberElement (); +#if NET_2_0 + // In MS.NET those types are mapped to a string + typeData = TypeTranslator.GetTypeData(typeof(string)); +#else + typeData = typeData.ListItemTypeData; +#endif + } + else + member = new XmlTypeMapMemberList (); + + if (elem.MinOccurs == 0 && typeData.IsValueType) + member.IsOptionalValueType = true; + + member.Name = classIds.AddUnique(CodeIdentifier.MakeValid(refElem.Name), member); + member.Documentation = GetDocumentation (elem); + member.TypeData = typeData; + member.ElementInfo.Add (CreateElementInfo (ns, member, refElem.Name, typeData, refElem.IsNillable, refElem.Form, emap)); + cmap.AddMember (member); + } + else + { + XmlTypeMapMemberFlatList member = new XmlTypeMapMemberFlatList (); + member.ListMap = new ListMap (); + member.Name = classIds.AddUnique(CodeIdentifier.MakeValid(refElem.Name), member); + member.Documentation = GetDocumentation (elem); + member.TypeData = typeData.ListTypeData; + member.ElementInfo.Add (CreateElementInfo (ns, member, refElem.Name, typeData, refElem.IsNillable, refElem.Form, emap)); + member.ListMap.ItemInfo = member.ElementInfo; + cmap.AddMember (member); + } + } + else if (item is XmlSchemaAny) + { + XmlSchemaAny elem = (XmlSchemaAny) item; + XmlTypeMapMemberAnyElement member = new XmlTypeMapMemberAnyElement (); + member.Name = classIds.AddUnique ("Any", member); + member.Documentation = GetDocumentation (elem); + + Type ctype; + if (elem.MaxOccurs != 1 || multiValue) + ctype = isMixed ? typeof(XmlNode[]) : typeof(XmlElement[]); + else + ctype = isMixed ? typeof(XmlNode) : typeof(XmlElement); + + member.TypeData = TypeTranslator.GetTypeData (ctype); + XmlTypeMapElementInfo einfo = new XmlTypeMapElementInfo (member, member.TypeData); + einfo.IsUnnamedAnyElement = true; + member.ElementInfo.Add (einfo); + + if (isMixed) + { + einfo = CreateTextElementInfo (typeQName.Namespace, member, member.TypeData); + member.ElementInfo.Add (einfo); + member.IsXmlTextCollector = true; + isMixed = false; //Allow only one XmlTextAttribute + } + + cmap.AddMember (member); + } + else if (item is XmlSchemaParticle) { + ImportParticleContent (typeQName, cmap, (XmlSchemaParticle)item, classIds, multiValue, ref isMixed); + } + } + } + + object ImportDefaultValue (TypeData typeData, string value) + { + if (typeData.SchemaType == SchemaTypes.Enum) { + XmlTypeMapping map = GetTypeMapping (typeData); + EnumMap emap = (EnumMap) map.ObjectMap; + string res = emap.GetEnumName (map.TypeFullName, value); + if (res == null) throw new InvalidOperationException ("'" + value + "' is not a valid enumeration value"); + return res; + } else + return XmlCustomFormatter.FromXmlString (typeData, value); + } + + void ImportChoiceContent (XmlQualifiedName typeQName, ClassMap cmap, XmlSchemaChoice choice, CodeIdentifiers classIds, bool multiValue) + { + XmlTypeMapElementInfoList choices = new XmlTypeMapElementInfoList (); + multiValue = ImportChoices (typeQName, null, choices, choice.Items) || multiValue; + if (choices.Count == 0) return; + + if (choice.MaxOccurs > 1) multiValue = true; + + XmlTypeMapMemberElement member; + if (multiValue) + { + member = new XmlTypeMapMemberFlatList (); + member.Name = classIds.AddUnique ("Items", member); + ListMap listMap = new ListMap (); + listMap.ItemInfo = choices; + ((XmlTypeMapMemberFlatList)member).ListMap = listMap; + } + else + { + member = new XmlTypeMapMemberElement (); + member.Name = classIds.AddUnique ("Item", member); + } + + // If all choices have the same type, use that type for the member. + // If not use System.Object. + // If there are at least two choices with the same type, use a choice + // identifier attribute + + TypeData typeData = null; + bool twoEqual = false; + bool allEqual = true; + Hashtable types = new Hashtable (); + + for (int n = choices.Count - 1; n >= 0; n--) + { + XmlTypeMapElementInfo einfo = (XmlTypeMapElementInfo) choices [n]; + + // In some complex schemas, we may end up with several options + // with the same name. It is better to ignore the extra options + // than to crash. It's the best we can do, and btw it works + // better than in MS.NET. + + if (cmap.GetElement (einfo.ElementName, einfo.Namespace) != null || + choices.IndexOfElement (einfo.ElementName, einfo.Namespace) != n) + { + choices.RemoveAt (n); + continue; + } + + if (types.ContainsKey (einfo.TypeData)) twoEqual = true; + else types.Add (einfo.TypeData, einfo); + + TypeData choiceType = einfo.TypeData; + if (choiceType.SchemaType == SchemaTypes.Class) + { + // When comparing class types, use the most generic class in the + // inheritance hierarchy + + XmlTypeMapping choiceMap = GetTypeMapping (choiceType); + BuildPendingMap (choiceMap); + while (choiceMap.BaseMap != null) { + choiceMap = choiceMap.BaseMap; + BuildPendingMap (choiceMap); + choiceType = choiceMap.TypeData; + } + } + + if (typeData == null) typeData = choiceType; + else if (typeData != choiceType) allEqual = false; + } + + if (!allEqual) + typeData = TypeTranslator.GetTypeData (typeof(object)); + + if (twoEqual) + { + // Create the choice member + XmlTypeMapMemberElement choiceMember = new XmlTypeMapMemberElement (); + choiceMember.Ignore = true; + choiceMember.Name = classIds.AddUnique (member.Name + "ElementName", choiceMember); + member.ChoiceMember = choiceMember.Name; + + // Create the choice enum + XmlTypeMapping enumMap = CreateTypeMapping (new XmlQualifiedName (member.Name + "ChoiceType", typeQName.Namespace), SchemaTypes.Enum, null); + enumMap.IncludeInSchema = false; + + CodeIdentifiers codeIdents = new CodeIdentifiers (); + EnumMap.EnumMapMember[] members = new EnumMap.EnumMapMember [choices.Count]; + for (int n=0; n<choices.Count; n++) + { + XmlTypeMapElementInfo it =(XmlTypeMapElementInfo) choices[n]; + bool extraNs = (it.Namespace != null && it.Namespace != "" && it.Namespace != typeQName.Namespace); + string xmlName = extraNs ? it.Namespace + ":" + it.ElementName : it.ElementName; + string enumName = codeIdents.AddUnique (CodeIdentifier.MakeValid (it.ElementName), it); + members [n] = new EnumMap.EnumMapMember (xmlName, enumName); + } + enumMap.ObjectMap = new EnumMap (members, false); + + choiceMember.TypeData = multiValue ? enumMap.TypeData.ListTypeData : enumMap.TypeData; + choiceMember.ElementInfo.Add (CreateElementInfo (typeQName.Namespace, choiceMember, choiceMember.Name, choiceMember.TypeData, false, XmlSchemaForm.None)); + cmap.AddMember (choiceMember); + } + + if (typeData == null) + return; + + if (multiValue) + typeData = typeData.ListTypeData; + + member.ElementInfo = choices; + member.Documentation = GetDocumentation (choice); + member.TypeData = typeData; + cmap.AddMember (member); + } + + bool ImportChoices (XmlQualifiedName typeQName, XmlTypeMapMember member, XmlTypeMapElementInfoList choices, XmlSchemaObjectCollection items) + { + bool multiValue = false; + foreach (XmlSchemaObject titem in items) + { + XmlSchemaObject item = titem; + if (item is XmlSchemaGroupRef) + item = GetRefGroupParticle ((XmlSchemaGroupRef)item); + + if (item is XmlSchemaElement) + { + string ns; + XmlSchemaElement elem = (XmlSchemaElement) item; + XmlTypeMapping emap; + TypeData typeData = GetElementTypeData (typeQName, elem, null, out emap); + XmlSchemaElement refElem = GetRefElement (typeQName, elem, out ns); + choices.Add (CreateElementInfo (ns, member, refElem.Name, typeData, refElem.IsNillable, refElem.Form, emap)); + if (elem.MaxOccurs > 1) multiValue = true; + } + else if (item is XmlSchemaAny) + { + XmlTypeMapElementInfo einfo = new XmlTypeMapElementInfo (member, TypeTranslator.GetTypeData(typeof(XmlElement))); + einfo.IsUnnamedAnyElement = true; + choices.Add (einfo); + } + else if (item is XmlSchemaChoice) { + multiValue = ImportChoices (typeQName, member, choices, ((XmlSchemaChoice)item).Items) || multiValue; + } + else if (item is XmlSchemaSequence) { + multiValue = ImportChoices (typeQName, member, choices, ((XmlSchemaSequence)item).Items) || multiValue; + } + } + return multiValue; + } + + void ImportSimpleContent (XmlQualifiedName typeQName, XmlTypeMapping map, XmlSchemaSimpleContent content, CodeIdentifiers classIds, bool isMixed) + { + XmlSchemaSimpleContentExtension ext = content.Content as XmlSchemaSimpleContentExtension; + ClassMap cmap = (ClassMap)map.ObjectMap; + XmlQualifiedName qname = GetContentBaseType (content.Content); + TypeData simpleType = null; + + if (!IsPrimitiveTypeNamespace (qname.Namespace)) + { + // Add base map members to this map + + XmlTypeMapping baseMap = ImportType (qname, null, true); + BuildPendingMap (baseMap); + + if (baseMap.IsSimpleType) { + simpleType = baseMap.TypeData; + } else { + ClassMap baseClassMap = (ClassMap)baseMap.ObjectMap; + + foreach (XmlTypeMapMember member in baseClassMap.AllMembers) + cmap.AddMember (member); + + map.BaseMap = baseMap; + baseMap.DerivedTypes.Add (map); + } + } + else + simpleType = FindBuiltInType (qname); + + if (simpleType != null) { + XmlTypeMapMemberElement member = new XmlTypeMapMemberElement (); + member.Name = classIds.AddUnique("Value", member); + member.TypeData = simpleType; + member.ElementInfo.Add (CreateTextElementInfo (typeQName.Namespace, member, member.TypeData)); + member.IsXmlTextCollector = true; + cmap.AddMember (member); + } + + if (ext != null) + ImportAttributes (typeQName, cmap, ext.Attributes, ext.AnyAttribute, classIds); + } + + TypeData FindBuiltInType (XmlQualifiedName qname) + { + XmlSchemaComplexType ct = (XmlSchemaComplexType) schemas.Find (qname, typeof(XmlSchemaComplexType)); + if (ct != null) + { + XmlSchemaSimpleContent sc = ct.ContentModel as XmlSchemaSimpleContent; + if (sc == null) throw new InvalidOperationException ("Invalid schema"); + return FindBuiltInType (GetContentBaseType (sc.Content)); + } + + XmlSchemaSimpleType st = (XmlSchemaSimpleType) schemas.Find (qname, typeof(XmlSchemaSimpleType)); + if (st != null) + return FindBuiltInType (qname, st); + + if (IsPrimitiveTypeNamespace (qname.Namespace)) + return TypeTranslator.GetPrimitiveTypeData (qname.Name); + + throw new InvalidOperationException ("Definition of type '" + qname + "' not found"); + } + + TypeData FindBuiltInType (XmlQualifiedName qname, XmlSchemaSimpleType st) + { + if (CanBeEnum (st) && qname != null) + return ImportType (qname, null, true).TypeData; + + if (st.Content is XmlSchemaSimpleTypeRestriction) { + XmlSchemaSimpleTypeRestriction rest = (XmlSchemaSimpleTypeRestriction) st.Content; + XmlQualifiedName bn = GetContentBaseType (rest); + if (bn == XmlQualifiedName.Empty && rest.BaseType != null) + return FindBuiltInType (qname, rest.BaseType); + else + return FindBuiltInType (bn); + } + else if (st.Content is XmlSchemaSimpleTypeList) { + return FindBuiltInType (GetContentBaseType (st.Content)).ListTypeData; + } + else if (st.Content is XmlSchemaSimpleTypeUnion) { + // MS.NET always import simple unions as string + return FindBuiltInType (new XmlQualifiedName ("string", XmlSchema.Namespace)); + } + else + return null; + } + + XmlQualifiedName GetContentBaseType (XmlSchemaObject ob) + { + if (ob is XmlSchemaSimpleContentExtension) + return ((XmlSchemaSimpleContentExtension)ob).BaseTypeName; + else if (ob is XmlSchemaSimpleContentRestriction) + return ((XmlSchemaSimpleContentRestriction)ob).BaseTypeName; + else if (ob is XmlSchemaSimpleTypeRestriction) + return ((XmlSchemaSimpleTypeRestriction)ob).BaseTypeName; + else if (ob is XmlSchemaSimpleTypeList) + return ((XmlSchemaSimpleTypeList)ob).ItemTypeName; + else + return null; + } + + void ImportComplexContent (XmlQualifiedName typeQName, XmlTypeMapping map, XmlSchemaComplexContent content, CodeIdentifiers classIds, bool isMixed) + { + ClassMap cmap = (ClassMap)map.ObjectMap; + XmlQualifiedName qname; + + XmlSchemaComplexContentExtension ext = content.Content as XmlSchemaComplexContentExtension; + if (ext != null) qname = ext.BaseTypeName; + else qname = ((XmlSchemaComplexContentRestriction)content.Content).BaseTypeName; + + if (qname == typeQName) + throw new InvalidOperationException ("Cannot import schema for type '" + typeQName.Name + "' from namespace '" + typeQName.Namespace + "'. Redefine not supported"); + + // Add base map members to this map + + XmlTypeMapping baseMap = ImportClass (qname); + BuildPendingMap (baseMap); + ClassMap baseClassMap = (ClassMap)baseMap.ObjectMap; + + foreach (XmlTypeMapMember member in baseClassMap.AllMembers) + cmap.AddMember (member); + + if (baseClassMap.XmlTextCollector != null) isMixed = false; + else if (content.IsMixed) isMixed = true; + + map.BaseMap = baseMap; + baseMap.DerivedTypes.Add (map); + + if (ext != null) { + // Add the members of this map + ImportParticleComplexContent (typeQName, cmap, ext.Particle, classIds, isMixed); + ImportAttributes (typeQName, cmap, ext.Attributes, ext.AnyAttribute, classIds); + } + else { + if (isMixed) ImportParticleComplexContent (typeQName, cmap, null, classIds, true); + } + } + + void ImportExtensionTypes (XmlQualifiedName qname) + { + foreach (XmlSchema schema in schemas) { + foreach (XmlSchemaObject sob in schema.Items) + { + XmlSchemaComplexType sct = sob as XmlSchemaComplexType; + if (sct != null && sct.ContentModel is XmlSchemaComplexContent) { + XmlQualifiedName exqname; + XmlSchemaComplexContentExtension ext = sct.ContentModel.Content as XmlSchemaComplexContentExtension; + if (ext != null) exqname = ext.BaseTypeName; + else exqname = ((XmlSchemaComplexContentRestriction)sct.ContentModel.Content).BaseTypeName; + if (exqname == qname) + ImportType (new XmlQualifiedName (sct.Name, schema.TargetNamespace), sct, null); + } + } + } + } + + XmlTypeMapping ImportClassSimpleType (XmlQualifiedName typeQName, XmlSchemaSimpleType stype, XmlQualifiedName root) + { + if (CanBeEnum (stype)) + { + // Create an enum map + + CodeIdentifiers codeIdents = new CodeIdentifiers (); + XmlTypeMapping enumMap = CreateTypeMapping (typeQName, SchemaTypes.Enum, null); + enumMap.Documentation = GetDocumentation (stype); + + bool isFlags = false; + if (stype.Content is XmlSchemaSimpleTypeList) { + stype = ((XmlSchemaSimpleTypeList)stype.Content).ItemType; + isFlags = true; + } + XmlSchemaSimpleTypeRestriction rest = (XmlSchemaSimpleTypeRestriction)stype.Content; + + codeIdents.AddReserved (enumMap.TypeData.TypeName); + + EnumMap.EnumMapMember[] members = new EnumMap.EnumMapMember [rest.Facets.Count]; + for (int n=0; n<rest.Facets.Count; n++) + { + XmlSchemaEnumerationFacet enu = (XmlSchemaEnumerationFacet) rest.Facets[n]; + string enumName = codeIdents.AddUnique(CodeIdentifier.MakeValid (enu.Value), enu); + members [n] = new EnumMap.EnumMapMember (enu.Value, enumName); + members [n].Documentation = GetDocumentation (enu); + } + enumMap.ObjectMap = new EnumMap (members, isFlags); + enumMap.IsSimpleType = true; + return enumMap; + } + + if (stype.Content is XmlSchemaSimpleTypeList) + { + XmlSchemaSimpleTypeList slist = (XmlSchemaSimpleTypeList)stype.Content; + TypeData arrayTypeData = FindBuiltInType (slist.ItemTypeName, stype); + + ListMap listMap = new ListMap (); + + listMap.ItemInfo = new XmlTypeMapElementInfoList (); + listMap.ItemInfo.Add (CreateElementInfo (typeQName.Namespace, null, "Item", arrayTypeData.ListItemTypeData, false, XmlSchemaForm.None)); + + XmlTypeMapping map = CreateArrayTypeMapping (typeQName, arrayTypeData); + map.ObjectMap = listMap; + map.IsSimpleType = true; + return map; + } + + // It is an extension of a primitive or known type + + TypeData typeData = FindBuiltInType (typeQName, stype); + XmlTypeMapping rmap = GetTypeMapping (typeData); + + // The resulting map must be a simple type. It needs to be explicitely set for arrays + rmap.IsSimpleType = true; + return rmap; + } + + bool CanBeEnum (XmlSchemaSimpleType stype) + { + if (stype.Content is XmlSchemaSimpleTypeRestriction) + { + XmlSchemaSimpleTypeRestriction rest = (XmlSchemaSimpleTypeRestriction)stype.Content; + if (rest.Facets.Count == 0) return false; + foreach (object ob in rest.Facets) + if (!(ob is XmlSchemaEnumerationFacet)) return false; + return true; + } + else if (stype.Content is XmlSchemaSimpleTypeList) + { + XmlSchemaSimpleTypeList list = (XmlSchemaSimpleTypeList) stype.Content; + return (list.ItemType != null && CanBeEnum (list.ItemType)); + } + return false; + } + + bool CanBeArray (XmlQualifiedName typeQName, XmlSchemaComplexType stype) + { + if (encodedFormat) + { + XmlSchemaComplexContent content = stype.ContentModel as XmlSchemaComplexContent; + if (content == null) return false; + XmlSchemaComplexContentRestriction rest = content.Content as XmlSchemaComplexContentRestriction; + if (rest == null) return false; + return rest.BaseTypeName == arrayType; + } + else + { + if (stype.Attributes.Count > 0 || stype.AnyAttribute != null) return false; + else return !stype.IsMixed && CanBeArray (typeQName, stype.Particle, false); + } + } + + bool CanBeArray (XmlQualifiedName typeQName, XmlSchemaParticle particle, bool multiValue) + { + // To be an array, there can't be a direct child of type typeQName + + if (particle == null) return false; + + multiValue = multiValue || particle.MaxOccurs > 1; + + if (particle is XmlSchemaGroupRef) + return CanBeArray (typeQName, GetRefGroupParticle ((XmlSchemaGroupRef)particle), multiValue); + + if (particle is XmlSchemaElement) + { + XmlSchemaElement elem = (XmlSchemaElement)particle; + if (!elem.RefName.IsEmpty) + return CanBeArray (typeQName, FindRefElement (elem), multiValue); + else + return multiValue && !typeQName.Equals (((XmlSchemaElement)particle).SchemaTypeName); + } + + if (particle is XmlSchemaAny) + return multiValue; + + if (particle is XmlSchemaSequence) + { + XmlSchemaSequence seq = particle as XmlSchemaSequence; + if (seq.Items.Count != 1) return false; + return CanBeArray (typeQName, (XmlSchemaParticle)seq.Items[0], multiValue); + } + + if (particle is XmlSchemaChoice) + { + // Can be array if all choices have different types + ArrayList types = new ArrayList (); + if(!CheckChoiceType (typeQName, particle, types, ref multiValue)) return false; + return multiValue; + } + + return false; + } + + bool CheckChoiceType (XmlQualifiedName typeQName, XmlSchemaParticle particle, ArrayList types, ref bool multiValue) + { + XmlQualifiedName type = null; + + multiValue = multiValue || particle.MaxOccurs > 1; + + if (particle is XmlSchemaGroupRef) + return CheckChoiceType (typeQName, GetRefGroupParticle ((XmlSchemaGroupRef)particle), types, ref multiValue); + + if (particle is XmlSchemaElement) { + string ns; + XmlSchemaElement elem = (XmlSchemaElement)particle; + XmlSchemaElement refElem = GetRefElement (typeQName, elem, out ns); + if (refElem.SchemaType != null) return true; + type = refElem.SchemaTypeName; + } + else if (particle is XmlSchemaAny) { + type = anyType; + } + else if (particle is XmlSchemaSequence) + { + XmlSchemaSequence seq = particle as XmlSchemaSequence; + foreach (XmlSchemaParticle par in seq.Items) + if (!CheckChoiceType (typeQName, par, types, ref multiValue)) return false; + return true; + } + else if (particle is XmlSchemaChoice) + { + foreach (XmlSchemaParticle choice in ((XmlSchemaChoice)particle).Items) + if (!CheckChoiceType (typeQName, choice, types, ref multiValue)) return false; + return true; + } + + if (typeQName.Equals (type)) return false; + + // For primitive types, compare using CLR types, since several + // xml types can be mapped to a single CLR type + + string t; + if (IsPrimitiveTypeNamespace (type.Namespace)) + t = TypeTranslator.GetPrimitiveTypeData (type.Name).FullTypeName + ":" + type.Namespace; + + else + t = type.Name + ":" + type.Namespace; + + if (types.Contains (t)) return false; + types.Add (t); + return true; + } + + bool CanBeAnyElement (XmlSchemaComplexType stype) + { + XmlSchemaSequence seq = stype.Particle as XmlSchemaSequence; + return (seq != null) && (seq.Items.Count == 1) && (seq.Items[0] is XmlSchemaAny); + } + + Type GetAnyElementType (XmlSchemaComplexType stype) + { + XmlSchemaSequence seq = stype.Particle as XmlSchemaSequence; + + if ((seq == null) || (seq.Items.Count != 1) || !(seq.Items[0] is XmlSchemaAny)) + return null; + + if (encodedFormat) + return typeof(object); + + XmlSchemaAny any = seq.Items[0] as XmlSchemaAny; + if (any.MaxOccurs == 1) + { + if (stype.IsMixed) + return typeof(XmlNode); + else + return typeof(XmlElement); + } + else + { + if (stype.IsMixed) + return typeof(XmlNode[]); + else + return typeof(XmlElement[]); + } + } + + bool CanBeIXmlSerializable (XmlSchemaComplexType stype) + { + XmlSchemaSequence seq = stype.Particle as XmlSchemaSequence; + if (seq == null) return false; + if (seq.Items.Count != 2) return false; + XmlSchemaElement elem = seq.Items[0] as XmlSchemaElement; + if (elem == null) return false; + if (elem.RefName != new XmlQualifiedName ("schema",XmlSchema.Namespace)) return false; + return (seq.Items[1] is XmlSchemaAny); + } + + XmlTypeMapping ImportXmlSerializableMapping (string ns) + { + XmlQualifiedName qname = new XmlQualifiedName ("System.Data.DataSet",ns); + XmlTypeMapping map = mappedTypes [qname] as XmlTypeMapping; + if (map != null) return map; + + TypeData typeData = new TypeData ("System.Data.DataSet", "System.Data.DataSet", "System.Data.DataSet", SchemaTypes.XmlSerializable, null); + map = new XmlTypeMapping ("System.Data.DataSet", "", typeData, "System.Data.DataSet", ns); + map.IncludeInSchema = true; + mappedTypes [qname] = map; + dataMappedTypes [typeData] = map; + return map; + } + + XmlTypeMapElementInfo CreateElementInfo (string ns, XmlTypeMapMember member, string name, TypeData typeData, bool isNillable, XmlSchemaForm form) + { + if (typeData.IsComplexType) + return CreateElementInfo (ns, member, name, typeData, isNillable, form, GetTypeMapping (typeData)); + else + return CreateElementInfo (ns, member, name, typeData, isNillable, form, null); + } + + XmlTypeMapElementInfo CreateElementInfo (string ns, XmlTypeMapMember member, string name, TypeData typeData, bool isNillable, XmlSchemaForm form, XmlTypeMapping emap) + { + XmlTypeMapElementInfo einfo = new XmlTypeMapElementInfo (member, typeData); + einfo.ElementName = name; + einfo.Namespace = ns; + einfo.IsNullable = isNillable; + einfo.Form = form; + if (typeData.IsComplexType) + einfo.MappedType = emap; + return einfo; + } + + XmlTypeMapElementInfo CreateTextElementInfo (string ns, XmlTypeMapMember member, TypeData typeData) + { + XmlTypeMapElementInfo einfo = new XmlTypeMapElementInfo (member, typeData); + einfo.IsTextElement = true; + einfo.WrappedElement = false; + if (typeData.IsComplexType) + einfo.MappedType = GetTypeMapping (typeData); + return einfo; + } + + XmlTypeMapping CreateTypeMapping (XmlQualifiedName typeQName, SchemaTypes schemaType, XmlQualifiedName root) + { + string typeName = CodeIdentifier.MakeValid (typeQName.Name); + typeName = typeIdentifiers.AddUnique (typeName, null); + + TypeData typeData = new TypeData (typeName, typeName, typeName, schemaType, null); + + string rootElem; + string rootNs; + if (root != null) { + rootElem = root.Name; + rootNs = root.Namespace; + } + else { + rootElem = typeQName.Name; + rootNs = ""; + } + + XmlTypeMapping map = new XmlTypeMapping (rootElem, rootNs, typeData, typeQName.Name, typeQName.Namespace); + map.IncludeInSchema = true; + mappedTypes [typeQName] = map; + dataMappedTypes [typeData] = map; + + return map; + } + + XmlTypeMapping CreateArrayTypeMapping (XmlQualifiedName typeQName, TypeData arrayTypeData) + { + XmlTypeMapping map; + if (encodedFormat) map = new XmlTypeMapping ("Array", XmlSerializer.EncodingNamespace, arrayTypeData, "Array", XmlSerializer.EncodingNamespace); + else map = new XmlTypeMapping (arrayTypeData.XmlType, typeQName.Namespace, arrayTypeData, arrayTypeData.XmlType, typeQName.Namespace); + + map.IncludeInSchema = true; + mappedTypes [typeQName] = map; + dataMappedTypes [arrayTypeData] = map; + + return map; + } + + XmlSchemaElement GetRefElement (XmlQualifiedName typeQName, XmlSchemaElement elem, out string ns) + { + + if (!elem.RefName.IsEmpty) + { + ns = elem.RefName.Namespace; + return FindRefElement (elem); + } + else + { + ns = typeQName.Namespace; + return elem; + } + } + + XmlSchemaAttribute GetRefAttribute (XmlQualifiedName typeQName, XmlSchemaAttribute attr, out string ns) + { + if (!attr.RefName.IsEmpty) + { + ns = attr.RefName.Namespace; + XmlSchemaAttribute at = FindRefAttribute (attr.RefName); + if (at == null) throw new InvalidOperationException ("The attribute " + attr.RefName + " is missing"); + return at; + } + else + { + ns = typeQName.Namespace; + return attr; + } + } + + TypeData GetElementTypeData (XmlQualifiedName typeQName, XmlSchemaElement elem, XmlQualifiedName root, out XmlTypeMapping map) + { + bool sharedAnnType = false; + map = null; + + if (!elem.RefName.IsEmpty) { + XmlSchemaElement refElem = FindRefElement (elem); + if (refElem == null) throw new InvalidOperationException ("Global element not found: " + elem.RefName); + root = elem.RefName; + elem = refElem; + sharedAnnType = true; + } + + TypeData td; + if (!elem.SchemaTypeName.IsEmpty) { + td = GetTypeData (elem.SchemaTypeName, root); + map = GetRegisteredTypeMapping (elem.SchemaTypeName); + } + else if (elem.SchemaType == null) + td = TypeTranslator.GetTypeData (typeof(object)); + else + td = GetTypeData (elem.SchemaType, typeQName, elem.Name, sharedAnnType, root); + + if (map == null && td.IsComplexType) + map = GetTypeMapping (td); + + return td; + } + + TypeData GetAttributeTypeData (XmlQualifiedName typeQName, XmlSchemaAttribute attr) + { + bool sharedAnnType = false; + + if (!attr.RefName.IsEmpty) { + XmlSchemaAttribute refAtt = FindRefAttribute (attr.RefName); + if (refAtt == null) throw new InvalidOperationException ("Global attribute not found: " + attr.RefName); + attr = refAtt; + sharedAnnType = true; + } + + if (!attr.SchemaTypeName.IsEmpty) return GetTypeData (attr.SchemaTypeName, null); + if (attr.SchemaType == null) return TypeTranslator.GetTypeData (typeof(string)); + else return GetTypeData (attr.SchemaType, typeQName, attr.Name, sharedAnnType, null); + } + + TypeData GetTypeData (XmlQualifiedName typeQName, XmlQualifiedName root) + { + if (IsPrimitiveTypeNamespace (typeQName.Namespace)) { + XmlTypeMapping map = ImportType (typeQName, root, false); + if (map != null) return map.TypeData; + else return TypeTranslator.GetPrimitiveTypeData (typeQName.Name); + } + + if (encodedFormat && typeQName.Namespace == "") + return TypeTranslator.GetPrimitiveTypeData (typeQName.Name); + + return ImportType (typeQName, root, true).TypeData; + } + + TypeData GetTypeData (XmlSchemaType stype, XmlQualifiedName typeQNname, string propertyName, bool sharedAnnType, XmlQualifiedName root) + { + string baseName; + + if (sharedAnnType) + { + // Anonymous types defined in root elements or attributes can be shared among all elements that + // reference this root element or attribute + TypeData std = sharedAnonymousTypes [stype] as TypeData; + if (std != null) return std; + baseName = propertyName; + } + else + baseName = typeQNname.Name + typeIdentifiers.MakeRightCase (propertyName); + + baseName = elemIdentifiers.AddUnique (baseName, stype); + + XmlQualifiedName newName; + newName = new XmlQualifiedName (baseName, typeQNname.Namespace); + + XmlTypeMapping map = ImportType (newName, stype, root); + if (sharedAnnType) sharedAnonymousTypes [stype] = map.TypeData; + + return map.TypeData; + } + + XmlTypeMapping GetTypeMapping (TypeData typeData) + { + if (typeData.Type == typeof(object) && !anyTypeImported) + ImportAllObjectTypes (); + + XmlTypeMapping map = (XmlTypeMapping) dataMappedTypes [typeData]; + if (map != null) return map; + + if (typeData.IsListType) + { + // Create an array map for the type + + XmlTypeMapping itemMap = GetTypeMapping (typeData.ListItemTypeData); + + map = new XmlTypeMapping (typeData.XmlType, itemMap.Namespace, typeData, typeData.XmlType, itemMap.Namespace); + map.IncludeInSchema = true; + + ListMap listMap = new ListMap (); + listMap.ItemInfo = new XmlTypeMapElementInfoList(); + listMap.ItemInfo.Add (CreateElementInfo (itemMap.Namespace, null, typeData.ListItemTypeData.XmlType, typeData.ListItemTypeData, false, XmlSchemaForm.None)); + map.ObjectMap = listMap; + + mappedTypes [new XmlQualifiedName(map.ElementName, map.Namespace)] = map; + dataMappedTypes [typeData] = map; + return map; + } + else if (typeData.SchemaType == SchemaTypes.Primitive || typeData.Type == typeof(object) || typeof(XmlNode).IsAssignableFrom(typeData.Type)) + { + return CreateSystemMap (typeData); + } + + throw new InvalidOperationException ("Map for type " + typeData.TypeName + " not found"); + } + + void AddObjectDerivedMap (XmlTypeMapping map) + { + TypeData typeData = TypeTranslator.GetTypeData (typeof(object)); + XmlTypeMapping omap = (XmlTypeMapping) dataMappedTypes [typeData]; + if (omap == null) + omap = CreateSystemMap (typeData); + omap.DerivedTypes.Add (map); + } + + XmlTypeMapping CreateSystemMap (TypeData typeData) + { + XmlTypeMapping map = new XmlTypeMapping (typeData.XmlType, XmlSchema.Namespace, typeData, typeData.XmlType, XmlSchema.Namespace); + map.IncludeInSchema = false; + map.ObjectMap = new ClassMap (); + dataMappedTypes [typeData] = map; + return map; + } + + void ImportAllObjectTypes () + { + // All complex types are subtypes of anyType, so all of them + // must also be imported + + anyTypeImported = true; + foreach (XmlSchema schema in schemas) { + foreach (XmlSchemaObject sob in schema.Items) + { + XmlSchemaComplexType sct = sob as XmlSchemaComplexType; + if (sct != null) + ImportType (new XmlQualifiedName (sct.Name, schema.TargetNamespace), sct, null); + } + } + } + + + XmlTypeMapping GetRegisteredTypeMapping (XmlQualifiedName typeQName) + { + return (XmlTypeMapping) mappedTypes [typeQName]; + } + + XmlSchemaParticle GetRefGroupParticle (XmlSchemaGroupRef refGroup) + { + XmlSchemaGroup grp = (XmlSchemaGroup) schemas.Find (refGroup.RefName, typeof (XmlSchemaGroup)); + return grp.Particle; + } + + XmlSchemaElement FindRefElement (XmlSchemaElement elem) + { + XmlSchemaElement refelem = (XmlSchemaElement) schemas.Find (elem.RefName, typeof(XmlSchemaElement)); + if (refelem != null) return refelem; + + if (IsPrimitiveTypeNamespace (elem.RefName.Namespace)) + { + if (anyElement != null) return anyElement; + anyElement = new XmlSchemaElement (); + anyElement.Name = "any"; + anyElement.SchemaTypeName = anyType; + return anyElement; + } else + return null; + } + + XmlSchemaAttribute FindRefAttribute (XmlQualifiedName refName) + { + if (refName.Namespace == XmlNamespace) + { + XmlSchemaAttribute at = new XmlSchemaAttribute (); + at.Name = refName.Name; + at.SchemaTypeName = new XmlQualifiedName ("string",XmlSchema.Namespace); + return at; + } + return (XmlSchemaAttribute) schemas.Find (refName, typeof(XmlSchemaAttribute)); + } + + XmlSchemaAttributeGroup FindRefAttributeGroup (XmlQualifiedName refName) + { + XmlSchemaAttributeGroup grp = (XmlSchemaAttributeGroup) schemas.Find (refName, typeof(XmlSchemaAttributeGroup)); + foreach (XmlSchemaObject at in grp.Attributes) + { + if (at is XmlSchemaAttributeGroupRef && ((XmlSchemaAttributeGroupRef)at).RefName == refName) + throw new InvalidOperationException ("Cannot import attribute group '" + refName.Name + "' from namespace '" + refName.Namespace + "'. Redefine not supported"); + + } + return grp; + } + + XmlTypeMapping ReflectType (Type type) + { + TypeData typeData = TypeTranslator.GetTypeData (type); + return ReflectType (typeData, (string) null); + } + + XmlTypeMapping ReflectType (TypeData typeData, string ns) + { + if (!encodedFormat) + { + if (auxXmlRefImporter == null) auxXmlRefImporter = new XmlReflectionImporter (); + return auxXmlRefImporter.ImportTypeMapping (typeData, ns); + } + else + { + if (auxSoapRefImporter == null) auxSoapRefImporter = new SoapReflectionImporter (); + return auxSoapRefImporter.ImportTypeMapping (typeData, ns); + } + } + + + string GetDocumentation (XmlSchemaAnnotated elem) + { + string res = ""; + XmlSchemaAnnotation anot = elem.Annotation; + if (anot == null || anot.Items == null) return null; + + foreach (object ob in anot.Items) + { + XmlSchemaDocumentation doc = ob as XmlSchemaDocumentation; + if (doc != null && doc.Markup != null && doc.Markup.Length > 0) { + if (res != string.Empty) res += "\n"; + foreach (XmlNode node in doc.Markup) + res += node.Value; + } + } + return res; + } + + bool IsPrimitiveTypeNamespace (string ns) + { + return (ns == XmlSchema.Namespace) || (encodedFormat && ns == XmlSerializer.EncodingNamespace); + } + + #endregion // Methods + } +} |