XmlReflectionImporter.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ FX-1434 / FX-1434 / 1.0 / untmp / whidbey / REDBITS / ndp / fx / src / Xml / System / Xml / Serialization / XmlReflectionImporter.cs / 3 / XmlReflectionImporter.cs

                            //------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// [....] 
//-----------------------------------------------------------------------------
 
namespace System.Xml.Serialization { 

    using System.Reflection; 
    using System;
    using System.Xml.Schema;
    using System.Collections;
    using System.ComponentModel; 
    using System.Globalization;
    using System.CodeDom.Compiler; 
    using System.Threading; 

    ///  
    ///
    /// 
    ///    [To be supplied.]
    ///  
    public class XmlReflectionImporter {
        TypeScope typeScope; 
        XmlAttributeOverrides attributeOverrides; 
        XmlAttributes defaultAttributes = new XmlAttributes();
        NameTable types = new NameTable();      // xmltypename + xmlns -> Mapping 
        NameTable nullables = new NameTable();  // xmltypename + xmlns -> NullableMapping
        NameTable elements = new NameTable();   // xmlelementname + xmlns -> ElementAccessor
        NameTable xsdAttributes;   // xmlattributetname + xmlns -> AttributeAccessor
        Hashtable specials;   // type -> SpecialMapping 
        Hashtable anonymous = new Hashtable();   // type -> AnonymousMapping
        NameTable serializables;  // type name --> new SerializableMapping 
        StructMapping root; 
        string defaultNs;
        ModelScope modelScope; 
        int arrayNestingLevel;
        XmlArrayItemAttributes savedArrayItemAttributes;
        string savedArrayNamespace;
        int choiceNum = 1; 

        enum ImportContext { 
            Text, 
            Attribute,
            Element 
        }

        /// 
        ///  
        ///    [To be supplied.]
        ///  
        public XmlReflectionImporter() : this(null, null) { 
        }
 
        /// 
        /// 
        ///    [To be supplied.]
        ///  
        public XmlReflectionImporter(string defaultNamespace) : this(null, defaultNamespace) {
        } 
 
        /// 
        ///  
        ///    [To be supplied.]
        /// 
        public XmlReflectionImporter(XmlAttributeOverrides attributeOverrides) : this(attributeOverrides, null) {
        } 

        ///  
        ///  
        ///    [To be supplied.]
        ///  
        public XmlReflectionImporter(XmlAttributeOverrides attributeOverrides, string defaultNamespace) {
            if (defaultNamespace == null)
                defaultNamespace = String.Empty;
            if (attributeOverrides == null) 
                attributeOverrides = new XmlAttributeOverrides();
            this.attributeOverrides = attributeOverrides; 
            this.defaultNs = defaultNamespace; 
            this.typeScope = new TypeScope();
            this.modelScope = new ModelScope(this.typeScope); 
        }

        /// 
        ///  
        ///    [To be supplied.]
        ///  
        public void IncludeTypes(ICustomAttributeProvider provider) { 
            object[] attrs = provider.GetCustomAttributes(typeof(XmlIncludeAttribute), false);
            for (int i = 0; i < attrs.Length; i++) { 
                Type type = ((XmlIncludeAttribute)attrs[i]).Type;
                IncludeType(type);
            }
        } 

        ///  
        ///  
        ///    [To be supplied.]
        ///  
        public void IncludeType(Type type) {
            int previousNestingLevel = arrayNestingLevel;
            XmlArrayItemAttributes previousArrayItemAttributes = savedArrayItemAttributes;
            string previousArrayNamespace = savedArrayNamespace; 
            arrayNestingLevel = 0;
            savedArrayItemAttributes = null; 
            savedArrayNamespace = null; 

            TypeMapping mapping = ImportTypeMapping(modelScope.GetTypeModel(type), defaultNs, ImportContext.Element, string.Empty, null); 
            if (mapping.IsAnonymousType && !mapping.TypeDesc.IsSpecial) {
                //XmlAnonymousInclude=Cannot include anonymous type '{0}'.
                throw new InvalidOperationException(Res.GetString(Res.XmlAnonymousInclude, type.FullName));
            } 
            arrayNestingLevel = previousNestingLevel;
            savedArrayItemAttributes = previousArrayItemAttributes; 
            savedArrayNamespace = previousArrayNamespace; 
        }
 
        /// 
        /// 
        ///    [To be supplied.]
        ///  
        public XmlTypeMapping ImportTypeMapping(Type type) {
            return ImportTypeMapping(type, null, null); 
        } 

        ///  
        /// 
        ///    [To be supplied.]
        /// 
        public XmlTypeMapping ImportTypeMapping(Type type, string defaultNamespace) { 
            return ImportTypeMapping(type, null, defaultNamespace);
        } 
 
        /// 
        ///  
        ///    [To be supplied.]
        /// 
        public XmlTypeMapping ImportTypeMapping(Type type, XmlRootAttribute root) {
            return ImportTypeMapping(type, root, null); 
        }
 
        ///  
        /// 
        ///    [To be supplied.] 
        /// 
        public XmlTypeMapping ImportTypeMapping(Type type, XmlRootAttribute root, string defaultNamespace) {
            if (type == null)
                throw new ArgumentNullException("type"); 
            XmlTypeMapping xmlMapping = new XmlTypeMapping(typeScope, ImportElement(modelScope.GetTypeModel(type), root, defaultNamespace));
            xmlMapping.SetKeyInternal(XmlMapping.GenerateKey(type, root, defaultNamespace)); 
            xmlMapping.GenerateSerializer = true; 
            return xmlMapping;
        } 

        /// 
        /// 
        ///    [To be supplied.] 
        /// 
        public XmlMembersMapping ImportMembersMapping(string elementName, string ns, XmlReflectionMember[] members, bool hasWrapperElement) { 
            return ImportMembersMapping(elementName, ns, members, hasWrapperElement, false); 
        }
 
        /// 
        /// 
        ///    [To be supplied.]
        ///  
        public XmlMembersMapping ImportMembersMapping(string elementName, string ns, XmlReflectionMember[] members, bool hasWrapperElement, bool rpc) {
            return ImportMembersMapping(elementName, ns, members, hasWrapperElement, rpc, false); 
        } 

        ///  
        /// 
        ///    [To be supplied.]
        /// 
        /// 
        public XmlMembersMapping ImportMembersMapping(string elementName, string ns, XmlReflectionMember[] members, bool hasWrapperElement, bool rpc, bool openModel) {
            return ImportMembersMapping(elementName, ns, members, hasWrapperElement, rpc, openModel, XmlMappingAccess.Read | XmlMappingAccess.Write); 
        } 

        ///  
        /// 
        ///    [To be supplied.]
        /// 
        /// 
        public XmlMembersMapping ImportMembersMapping(string elementName, string ns, XmlReflectionMember[] members, bool hasWrapperElement, bool rpc, bool openModel, XmlMappingAccess access) {
            ElementAccessor element = new ElementAccessor(); 
            element.Name = elementName == null || elementName.Length == 0 ? elementName : XmlConvert.EncodeLocalName(elementName); 
            element.Namespace = ns;
 
            MembersMapping membersMapping = ImportMembersMapping(members, ns, hasWrapperElement, rpc, openModel);
            element.Mapping = membersMapping;
            element.Form = XmlSchemaForm.Qualified;   // elements within soap:body are always qualified
            if (!rpc) { 
                if (hasWrapperElement)
                    element = (ElementAccessor)ReconcileAccessor(element, this.elements); 
                else { 
                    foreach (MemberMapping mapping in membersMapping.Members) {
                        if (mapping.Elements != null && mapping.Elements.Length > 0) { 
                            mapping.Elements[0] = (ElementAccessor)ReconcileAccessor(mapping.Elements[0], this.elements);
                        }
                    }
                } 
            }
            XmlMembersMapping xmlMapping = new XmlMembersMapping(typeScope, element, access); 
            xmlMapping.GenerateSerializer = true; 
            return xmlMapping;
        } 

        XmlAttributes GetAttributes(Type type, bool canBeSimpleType) {
            XmlAttributes attrs = attributeOverrides[type];
            if (attrs != null) return attrs; 
            if (canBeSimpleType && TypeScope.IsKnownType(type)) {
                return defaultAttributes; 
            } 
            return new XmlAttributes(type);
        } 

        XmlAttributes GetAttributes(MemberInfo memberInfo) {
            XmlAttributes attrs = attributeOverrides[memberInfo.DeclaringType, memberInfo.Name];
            if (attrs != null) return attrs; 
            return new XmlAttributes(memberInfo);
        } 
 
        ElementAccessor ImportElement(TypeModel model, XmlRootAttribute root, string defaultNamespace) {
            XmlAttributes a = GetAttributes(model.Type, true); 

            if (root == null)
                root = a.XmlRoot;
            string ns = root == null ? null : root.Namespace; 
            if (ns == null) ns = defaultNamespace;
            if (ns == null) ns = this.defaultNs; 
 
            arrayNestingLevel = -1;
            savedArrayItemAttributes = null; 
            savedArrayNamespace = null;
            ElementAccessor element = CreateElementAccessor(ImportTypeMapping(model, ns, ImportContext.Element, string.Empty, a), ns);

            if (root != null) { 
                if (root.ElementName.Length > 0)
                    element.Name = XmlConvert.EncodeLocalName(root.ElementName); 
                if (root.IsNullableSpecified && !root.IsNullable && model.TypeDesc.IsOptionalValue) 
                    //XmlInvalidNotNullable=IsNullable may not be set to 'false' for a Nullable<{0}> type. Consider using '{0}' type or removing the IsNullable property from the XmlElement attribute.
                    throw new InvalidOperationException(Res.GetString(Res.XmlInvalidNotNullable, model.TypeDesc.BaseTypeDesc.FullName, "XmlRoot")); 
                element.IsNullable = root.IsNullableSpecified ? root.IsNullable : model.TypeDesc.IsNullable || model.TypeDesc.IsOptionalValue;
                CheckNullable(element.IsNullable, model.TypeDesc, element.Mapping);
            }
            else 
                element.IsNullable = model.TypeDesc.IsNullable || model.TypeDesc.IsOptionalValue;
            element.Form = XmlSchemaForm.Qualified; 
            return (ElementAccessor)ReconcileAccessor(element, this.elements); 
        }
 
        static string GetMappingName(Mapping mapping) {
            if (mapping is MembersMapping)
                return "(method)";
            else if (mapping is TypeMapping) 
                return ((TypeMapping)mapping).TypeDesc.FullName;
            else 
                throw new ArgumentException(Res.GetString(Res.XmlInternalError), "mapping"); 
        }
 
        ElementAccessor ReconcileLocalAccessor(ElementAccessor accessor, string ns) {
            if (accessor.Namespace == ns) return accessor;
            return (ElementAccessor)ReconcileAccessor(accessor, this.elements);
        } 

        Accessor ReconcileAccessor(Accessor accessor, NameTable accessors) { 
            if (accessor.Any && accessor.Name.Length == 0) 
                 return accessor;
 
            Accessor existing = (Accessor)accessors[accessor.Name, accessor.Namespace];
            if (existing == null) {
                accessor.IsTopLevelInSchema = true;
                accessors.Add(accessor.Name, accessor.Namespace, accessor); 
                return accessor;
            } 
 
            if (existing.Mapping == accessor.Mapping)
                return existing; 

            if (!(accessor.Mapping is MembersMapping) && !(existing.Mapping is MembersMapping)) {
                if (accessor.Mapping.TypeDesc == existing.Mapping.TypeDesc
                    || (existing.Mapping is NullableMapping && accessor.Mapping.TypeDesc == ((NullableMapping)existing.Mapping).BaseMapping.TypeDesc) 
                    || (accessor.Mapping is NullableMapping && ((NullableMapping)accessor.Mapping).BaseMapping.TypeDesc == existing.Mapping.TypeDesc))
                { 
                    // need to compare default values 
                    string value1 = Convert.ToString(accessor.Default, CultureInfo.InvariantCulture);
                    string value2 = Convert.ToString(existing.Default, CultureInfo.InvariantCulture); 
                    if (value1 == value2) {
                        return existing;
                    }
                    throw new InvalidOperationException(Res.GetString(Res.XmlCannotReconcileAccessorDefault, accessor.Name, accessor.Namespace, value1, value2)); 
                }
            } 
 
            if (accessor.Mapping is MembersMapping || existing.Mapping is MembersMapping)
                throw new InvalidOperationException(Res.GetString(Res.XmlMethodTypeNameConflict, accessor.Name, accessor.Namespace)); 

            if (accessor.Mapping is ArrayMapping) {
                if (!(existing.Mapping is ArrayMapping)) {
                    throw new InvalidOperationException(Res.GetString(Res.XmlCannotReconcileAccessor, accessor.Name, accessor.Namespace, GetMappingName(existing.Mapping), GetMappingName(accessor.Mapping))); 
                }
                ArrayMapping mapping = (ArrayMapping)accessor.Mapping; 
                ArrayMapping existingMapping = mapping.IsAnonymousType ? null : (ArrayMapping)types[existing.Mapping.TypeName, existing.Mapping.Namespace]; 
                ArrayMapping first = existingMapping;
                while (existingMapping != null) { 
                    if (existingMapping == accessor.Mapping)
                        return existing;
                    existingMapping = existingMapping.Next;
                } 
                mapping.Next = first;
                if (!mapping.IsAnonymousType) 
                    types[existing.Mapping.TypeName, existing.Mapping.Namespace] = mapping; 
                return existing;
            } 
            if (accessor is AttributeAccessor)
                throw new InvalidOperationException(Res.GetString(Res.XmlCannotReconcileAttributeAccessor, accessor.Name, accessor.Namespace, GetMappingName(existing.Mapping), GetMappingName(accessor.Mapping)));
            else
                throw new InvalidOperationException(Res.GetString(Res.XmlCannotReconcileAccessor, accessor.Name, accessor.Namespace, GetMappingName(existing.Mapping), GetMappingName(accessor.Mapping))); 
        }
 
        Exception CreateReflectionException(string context, Exception e) { 
            return new InvalidOperationException(Res.GetString(Res.XmlReflectionError, context), e);
        } 

        Exception CreateTypeReflectionException(string context, Exception e) {
            return new InvalidOperationException(Res.GetString(Res.XmlTypeReflectionError, context), e);
        } 

        Exception CreateMemberReflectionException(FieldModel model, Exception e) { 
            return new InvalidOperationException(Res.GetString(model.IsProperty ? Res.XmlPropertyReflectionError : Res.XmlFieldReflectionError, model.Name), e); 
        }
 
        TypeMapping ImportTypeMapping(TypeModel model, string ns, ImportContext context, string dataType, XmlAttributes a) {
            return ImportTypeMapping(model, ns, context, dataType, a, false, false);
        }
 
        TypeMapping ImportTypeMapping(TypeModel model, string ns, ImportContext context, string dataType, XmlAttributes a, bool repeats, bool openModel) {
            try { 
                if (dataType.Length > 0) { 
                    TypeDesc modelTypeDesc = TypeScope.IsOptionalValue(model.Type) ? model.TypeDesc.BaseTypeDesc : model.TypeDesc;
                    if (!modelTypeDesc.IsPrimitive) { 
                        throw new InvalidOperationException(Res.GetString(Res.XmlInvalidDataTypeUsage, dataType, "XmlElementAttribute.DataType"));
                    }
                    TypeDesc td = typeScope.GetTypeDesc(dataType, XmlSchema.Namespace);
                    if (td == null) { 
                        throw new InvalidOperationException(Res.GetString(Res.XmlInvalidXsdDataType, dataType, "XmlElementAttribute.DataType", new XmlQualifiedName(dataType, XmlSchema.Namespace).ToString()));
                    } 
                    if (modelTypeDesc.FullName != td.FullName) { 
                        throw new InvalidOperationException(Res.GetString(Res.XmlDataTypeMismatch, dataType, "XmlElementAttribute.DataType", modelTypeDesc.FullName));
                    } 
                }

                if (a == null)
                    a = GetAttributes(model.Type, false); 

                if ((a.XmlFlags & ~(XmlAttributeFlags.Type | XmlAttributeFlags.Root)) != 0) 
                    throw new InvalidOperationException(Res.GetString(Res.XmlInvalidTypeAttributes, model.Type.FullName)); 

                switch (model.TypeDesc.Kind) { 
                case TypeKind.Enum:
                    return ImportEnumMapping((EnumModel)model, ns, repeats);
                case TypeKind.Primitive:
                    if (a.XmlFlags != 0) throw InvalidAttributeUseException(model.Type); 
                    return ImportPrimitiveMapping((PrimitiveModel)model, context, dataType, repeats);
                case TypeKind.Array: 
                case TypeKind.Collection: 
                case TypeKind.Enumerable:
                    //if (a.XmlFlags != 0) throw InvalidAttributeUseException(model.Type); 
                    if (context != ImportContext.Element) throw UnsupportedException(model.TypeDesc, context);
                    arrayNestingLevel++;
                    ArrayMapping arrayMapping = ImportArrayLikeMapping((ArrayModel)model, ns);
                    arrayNestingLevel--; 
                    return arrayMapping;
                case TypeKind.Root: 
                case TypeKind.Class: 
                case TypeKind.Struct:
                    if (context != ImportContext.Element) throw UnsupportedException(model.TypeDesc, context); 
                    if (model.TypeDesc.IsOptionalValue) {
                        TypeDesc valueTypeDesc = string.IsNullOrEmpty(dataType) ? model.TypeDesc.BaseTypeDesc : typeScope.GetTypeDesc(dataType, XmlSchema.Namespace);
                        string xsdTypeName = valueTypeDesc.DataType == null ? valueTypeDesc.Name : valueTypeDesc.DataType.Name;
                        TypeMapping baseMapping = GetTypeMapping(xsdTypeName, ns, valueTypeDesc, types, null); 
                        if (baseMapping == null)
                            baseMapping = ImportTypeMapping(modelScope.GetTypeModel(model.TypeDesc.BaseTypeDesc.Type), ns, context, dataType, null, repeats, openModel); 
                        return CreateNullableMapping(baseMapping, model.TypeDesc.Type); 
                    }
                    else { 
                        return ImportStructLikeMapping((StructModel)model, ns, openModel, a);
                    }
                default:
                    if (model.TypeDesc.Kind == TypeKind.Serializable) { 
                        // We allow XmlRoot attribute on IXmlSerializable, but not others
                        if ((a.XmlFlags & ~XmlAttributeFlags.Root) != 0) { 
                            throw new InvalidOperationException(Res.GetString(Res.XmlSerializableAttributes, model.TypeDesc.FullName, typeof(XmlSchemaProviderAttribute).Name)); 
                        }
                    } 
                    else {
                        if (a.XmlFlags != 0) throw InvalidAttributeUseException(model.Type);
                    }
                    if (model.TypeDesc.IsSpecial) 
                        return ImportSpecialMapping(model.Type, model.TypeDesc, ns, context);
                    throw UnsupportedException(model.TypeDesc, context); 
                } 
            }
            catch (Exception e) { 
                if (e is ThreadAbortException || e is StackOverflowException || e is OutOfMemoryException) {
                    throw;
                }
                throw CreateTypeReflectionException(model.TypeDesc.FullName, e); 
            }
            catch { 
                throw CreateTypeReflectionException(model.TypeDesc.FullName, null); 
            }
        } 

        internal static MethodInfo GetMethodFromSchemaProvider(XmlSchemaProviderAttribute provider, Type type) {
            if (provider.IsAny) {
                // do not validate the schema provider method for wildcard types. 
                return null;
            } 
            else if (provider.MethodName == null) { 
                throw new ArgumentNullException("MethodName");
            } 
            if (!CodeGenerator.IsValidLanguageIndependentIdentifier(provider.MethodName))
                throw new ArgumentException(Res.GetString(Res.XmlGetSchemaMethodName, provider.MethodName), "MethodName");

            MethodInfo getMethod = getMethod = type.GetMethod(provider.MethodName, /* BindingFlags.DeclaredOnly | */ BindingFlags.Static | BindingFlags.Public, null, new Type[] {typeof(XmlSchemaSet)}, null); 
            if (getMethod == null)
                throw new InvalidOperationException(Res.GetString(Res.XmlGetSchemaMethodMissing, provider.MethodName, typeof(XmlSchemaSet).Name, type.FullName)); 
 
            if (!(typeof(XmlQualifiedName).IsAssignableFrom(getMethod.ReturnType)) && !(typeof(XmlSchemaType).IsAssignableFrom(getMethod.ReturnType)))
                throw new InvalidOperationException(Res.GetString(Res.XmlGetSchemaMethodReturnType, type.Name, provider.MethodName, typeof(XmlSchemaProviderAttribute).Name, typeof(XmlQualifiedName).FullName, typeof(XmlSchemaType).FullName)); 

            return getMethod;
        }
 
        SpecialMapping ImportSpecialMapping(Type type, TypeDesc typeDesc, string ns, ImportContext context) {
            if (specials == null) 
                specials = new Hashtable(); 
            SpecialMapping mapping = (SpecialMapping)specials[type];
            if (mapping != null) { 
                CheckContext(mapping.TypeDesc, context);
                return mapping;
            }
            if (typeDesc.Kind == TypeKind.Serializable) { 
                //
                SerializableMapping serializableMapping = null; 
 
                // get the schema method info
                object[] attrs = type.GetCustomAttributes(typeof(XmlSchemaProviderAttribute), false); 

                if (attrs.Length > 0) {
                    // new IXmlSerializable
                    XmlSchemaProviderAttribute provider = (XmlSchemaProviderAttribute)attrs[0]; 
                    MethodInfo method = GetMethodFromSchemaProvider(provider, type);
                    serializableMapping = new SerializableMapping(method, provider.IsAny, ns); 
                    XmlQualifiedName qname = serializableMapping.XsiType; 
                    if (qname != null && !qname.IsEmpty) {
                        if (serializables == null) 
                            serializables = new NameTable();
                        SerializableMapping existingMapping = (SerializableMapping)serializables[qname];
                        if (existingMapping != null) {
                            if (existingMapping.Type == null) { 
                                serializableMapping = existingMapping;
                            } 
                            else if (existingMapping.Type != type) { 
                                SerializableMapping next = existingMapping.Next;
                                existingMapping.Next = serializableMapping; 
                                serializableMapping.Next = next;
                            }
                        }
                        else { 
                            XmlSchemaType xsdType = serializableMapping.XsdType;
                            if (xsdType != null) 
                                SetBase(serializableMapping, xsdType.DerivedFrom); 
                            serializables[qname] = serializableMapping;
                        } 
                        serializableMapping.TypeName = qname.Name;
                        serializableMapping.Namespace = qname.Namespace;
                    }
                    serializableMapping.TypeDesc = typeDesc; 
                    serializableMapping.Type = type;
                    IncludeTypes(type); 
                } 
                else {
                    // old IXmlSerializable 
                    serializableMapping = new SerializableMapping();
                    serializableMapping.TypeDesc = typeDesc;
                    serializableMapping.Type = type;
                } 
                mapping = serializableMapping;
            } 
            else { 
                mapping = new SpecialMapping();
                mapping.TypeDesc = typeDesc; 
            }
            CheckContext(typeDesc, context);
            specials.Add(type, mapping);
            typeScope.AddTypeMapping(mapping); 
            return mapping;
        } 
 
        internal static void ValidationCallbackWithErrorCode (object sender, ValidationEventArgs args) {
            // 
            if (args.Severity == XmlSeverityType.Error)
                throw new InvalidOperationException(Res.GetString(Res.XmlSerializableSchemaError, typeof(IXmlSerializable).Name, args.Message));
        }
 
        internal void SetBase(SerializableMapping mapping, XmlQualifiedName baseQname) {
 
            if (baseQname.IsEmpty) return; 
            if (baseQname.Namespace == XmlSchema.Namespace) return;
            XmlSchemaSet schemas = mapping.Schemas; 
            ArrayList srcSchemas = (ArrayList)schemas.Schemas(baseQname.Namespace);

            if (srcSchemas.Count == 0) {
                throw new InvalidOperationException(Res.GetString(Res.XmlMissingSchema, baseQname.Namespace)); 
            }
            if (srcSchemas.Count > 1) { 
                throw new InvalidOperationException(Res.GetString(Res.XmlGetSchemaInclude, baseQname.Namespace, typeof(IXmlSerializable).Name, "GetSchema")); 
            }
            XmlSchema s = (XmlSchema)srcSchemas[0]; 

            XmlSchemaType t = (XmlSchemaType)s.SchemaTypes[baseQname];
            t = t.Redefined != null ? t.Redefined : t;
 
            if (serializables[baseQname] == null) {
                SerializableMapping baseMapping = new SerializableMapping(baseQname, schemas); 
                SetBase(baseMapping, t.DerivedFrom); 
                serializables.Add(baseQname, baseMapping);
            } 
            mapping.SetBaseMapping((SerializableMapping)serializables[baseQname]);
        }

        static string GetContextName(ImportContext context) { 
            switch (context) {
                case ImportContext.Element: return "element"; 
                case ImportContext.Attribute: return "attribute"; 
                case ImportContext.Text: return "text";
                default: 
                    throw new ArgumentException(Res.GetString(Res.XmlInternalError), "context");
            }
        }
 
        static Exception InvalidAttributeUseException(Type type) {
            return new InvalidOperationException(Res.GetString(Res.XmlInvalidAttributeUse, type.FullName)); 
        } 

        static Exception UnsupportedException(TypeDesc typeDesc, ImportContext context) { 
            return new InvalidOperationException(Res.GetString(Res.XmlIllegalTypeContext, typeDesc.FullName, GetContextName(context)));
        }

        StructMapping CreateRootMapping() { 
            TypeDesc typeDesc = typeScope.GetTypeDesc(typeof(object));
            StructMapping mapping = new StructMapping(); 
            mapping.TypeDesc = typeDesc; 
            mapping.TypeName = Soap.UrType;
            mapping.Namespace = XmlSchema.Namespace; 
            mapping.Members = new MemberMapping[0];
            mapping.IncludeInSchema = false;
            return mapping;
        } 

        NullableMapping CreateNullableMapping(TypeMapping baseMapping, Type type) { 
            TypeDesc typeDesc = baseMapping.TypeDesc.GetNullableTypeDesc(type); 
            TypeMapping existingMapping = (TypeMapping)nullables[baseMapping.TypeName, baseMapping.Namespace];
            NullableMapping mapping; 
            if (existingMapping != null) {
                if (existingMapping is NullableMapping) {
                    mapping = (NullableMapping)existingMapping;
                    if (mapping.BaseMapping is PrimitiveMapping && baseMapping is PrimitiveMapping) 
                        return mapping;
                    else if (mapping.BaseMapping == baseMapping) { 
                        return mapping; 
                    }
                    else { 
                        throw new InvalidOperationException(Res.GetString(Res.XmlTypesDuplicate, typeDesc.FullName, existingMapping.TypeDesc.FullName, typeDesc.Name, existingMapping.Namespace));
                    }
                }
                else { 
                    throw new InvalidOperationException(Res.GetString(Res.XmlTypesDuplicate, typeDesc.FullName, existingMapping.TypeDesc.FullName, typeDesc.Name, existingMapping.Namespace));
                } 
            } 
            mapping = new NullableMapping();
            mapping.BaseMapping = baseMapping; 
            mapping.TypeDesc = typeDesc;
            mapping.TypeName = baseMapping.TypeName;
            mapping.Namespace = baseMapping.Namespace;
            mapping.IncludeInSchema = baseMapping.IncludeInSchema; 
            nullables.Add(baseMapping.TypeName, baseMapping.Namespace, mapping);
            typeScope.AddTypeMapping(mapping); 
            return mapping; 
        }
 
        StructMapping GetRootMapping() {
            if (root == null) {
                root = CreateRootMapping();
                typeScope.AddTypeMapping(root); 
            }
            return root; 
        } 

        TypeMapping GetTypeMapping(string typeName, string ns, TypeDesc typeDesc, NameTable typeLib, Type type) { 
            TypeMapping mapping ;
            if (typeName == null || typeName.Length == 0)
                mapping = type == null ? null : (TypeMapping)anonymous[type];
            else 
                mapping = (TypeMapping)typeLib[typeName, ns];
 
            if (mapping == null) return null; 
            if (!mapping.IsAnonymousType && mapping.TypeDesc != typeDesc)
                throw new InvalidOperationException(Res.GetString(Res.XmlTypesDuplicate, typeDesc.FullName, mapping.TypeDesc.FullName, typeName, ns)); 
            return mapping;
        }

        StructMapping ImportStructLikeMapping(StructModel model, string ns, bool openModel, XmlAttributes a) { 
            if (model.TypeDesc.Kind == TypeKind.Root) return GetRootMapping();
            if (a == null) 
                a = GetAttributes(model.Type, false); 

            string typeNs = ns; 
            if (a.XmlType != null && a.XmlType.Namespace != null)
                typeNs = a.XmlType.Namespace;
            else if (a.XmlRoot != null && a.XmlRoot.Namespace != null)
                typeNs = a.XmlRoot.Namespace; 

            string typeName = IsAnonymousType(a, ns) ? null : XsdTypeName(model.Type, a, model.TypeDesc.Name); 
            typeName = XmlConvert.EncodeLocalName(typeName); 

            StructMapping mapping = (StructMapping)GetTypeMapping(typeName, typeNs, model.TypeDesc, types, model.Type); 
            if (mapping == null) {
                mapping = new StructMapping();
                mapping.TypeDesc = model.TypeDesc;
                mapping.Namespace = typeNs; 
                mapping.TypeName = typeName;
                if (!mapping.IsAnonymousType) 
                    types.Add(typeName, typeNs, mapping); 
                else
                    anonymous[model.Type] = mapping; 
                if (a.XmlType != null) {
                    mapping.IncludeInSchema = a.XmlType.IncludeInSchema;
                }
 
                if (model.TypeDesc.BaseTypeDesc != null) {
                    TypeModel baseModel = modelScope.GetTypeModel(model.Type.BaseType, false); 
                    if (!(baseModel is StructModel)) { 
                        //XmlUnsupportedInheritance=Using '{0}' as a base type for a class is not supported by XmlSerializer.
                         throw new NotSupportedException(Res.GetString(Res.XmlUnsupportedInheritance, model.Type.BaseType.FullName)); 
                    }
                    mapping.BaseMapping = ImportStructLikeMapping((StructModel)baseModel, mapping.Namespace, openModel, null);
                    ICollection values = mapping.BaseMapping.LocalAttributes.Values;
                    foreach (AttributeAccessor attribute in values) { 
                        AddUniqueAccessor(mapping.LocalAttributes, attribute);
                    } 
                    if (!mapping.BaseMapping.HasExplicitSequence()) { 
                        values = mapping.BaseMapping.LocalElements.Values;
                        foreach (ElementAccessor e in values) { 
                            AddUniqueAccessor(mapping.LocalElements, e);
                        }
                    }
                } 
                ArrayList members = new ArrayList();
                TextAccessor textAccesor = null; 
                bool hasElements = false; 
                bool isSequence = false;
 
                foreach (MemberInfo memberInfo in model.GetMemberInfos()) {
                    if ((memberInfo.MemberType & (MemberTypes.Field | MemberTypes.Property)) == 0)
                        continue;
                    XmlAttributes memberAttrs = GetAttributes(memberInfo); 
                    if (memberAttrs.XmlIgnore) continue;
                    FieldModel fieldModel = model.GetFieldModel(memberInfo); 
                    if (fieldModel == null) continue; 
                    try {
                        MemberMapping member = ImportFieldMapping(model, fieldModel, memberAttrs, mapping.Namespace); 
                        if (member == null) continue;
                        if (mapping.BaseMapping != null) {
                            if (mapping.BaseMapping.Declares(member, mapping.TypeName)) continue;
                        } 
                        isSequence |= member.IsSequence;
                        // add All memeber accessors to the scope accessors 
                        AddUniqueAccessor(member, mapping.LocalElements, mapping.LocalAttributes, isSequence); 

                        if (member.Text != null) { 
                            if (!member.Text.Mapping.TypeDesc.CanBeTextValue && member.Text.Mapping.IsList)
                                throw new InvalidOperationException(Res.GetString(Res.XmlIllegalTypedTextAttribute, typeName, member.Text.Name, member.Text.Mapping.TypeDesc.FullName));
                            if (textAccesor != null) {
                                throw new InvalidOperationException(Res.GetString(Res.XmlIllegalMultipleText, model.Type.FullName)); 
                            }
                            textAccesor = member.Text; 
                        } 
                        if (member.Xmlns != null) {
                            if (mapping.XmlnsMember != null) 
                                throw new InvalidOperationException(Res.GetString(Res.XmlMultipleXmlns, model.Type.FullName));
                            mapping.XmlnsMember = member;
                        }
                        if (member.Elements != null && member.Elements.Length != 0) { 
                            hasElements = true;
                        } 
                        members.Add(member); 
                    }
                    catch (Exception e) { 
                        if (e is ThreadAbortException || e is StackOverflowException || e is OutOfMemoryException) {
                            throw;
                        }
                        throw CreateMemberReflectionException(fieldModel, e); 
                    }
                    catch { 
                        throw CreateMemberReflectionException(fieldModel, null); 
                    }
                } 
                mapping.SetContentModel(textAccesor, hasElements);
                if (isSequence) {
                    Hashtable ids = new Hashtable();
                    for (int i = 0; i < members.Count; i++) { 
                        MemberMapping member = (MemberMapping)members[i];
                        if (!member.IsParticle) 
                            continue; 
                        if (member.IsSequence) {
                            if (ids[member.SequenceId] != null) { 
                                throw new InvalidOperationException(Res.GetString(Res.XmlSequenceUnique, member.SequenceId.ToString(CultureInfo.InvariantCulture), "Order", member.Name));
                            }
                            ids[member.SequenceId] = member;
                        } 
                        else {
                            throw new InvalidOperationException(Res.GetString(Res.XmlSequenceInconsistent, "Order", member.Name)); 
                        } 
                    }
                    members.Sort(new MemberMappingComparer()); 
                }
                mapping.Members = (MemberMapping[])members.ToArray(typeof(MemberMapping));

                if (mapping.BaseMapping == null) mapping.BaseMapping = GetRootMapping(); 

                if (mapping.XmlnsMember != null && mapping.BaseMapping.HasXmlnsMember) 
                    throw new InvalidOperationException(Res.GetString(Res.XmlMultipleXmlns, model.Type.FullName)); 

                IncludeTypes(model.Type); 
                typeScope.AddTypeMapping(mapping);
            }
            if (openModel)
                mapping.IsOpenModel = true; 
            return mapping;
        } 
 
        static bool IsAnonymousType(XmlAttributes a, string contextNs) {
            if (a.XmlType != null && a.XmlType.AnonymousType) { 
                //
                // check to see if the anonymous type is used in the original context
                // only treat it as Anonymous, if the referencing element's namespace
                // matches the original referencing element, otherwise revert to 
                // non-Anonymous handling for backward compatibility.
                // 
                string originalNs = a.XmlType.Namespace; 
                return string.IsNullOrEmpty(originalNs) || originalNs == contextNs;
            } 
            return false;
        }

        internal string XsdTypeName(Type type) { 
            if (type == typeof(object)) return Soap.UrType;
            TypeDesc typeDesc = typeScope.GetTypeDesc(type); 
            if (typeDesc.IsPrimitive && typeDesc.DataType != null && typeDesc.DataType.Name != null && typeDesc.DataType.Name.Length > 0) 
                return typeDesc.DataType.Name;
            return XsdTypeName(type, GetAttributes(type, false), typeDesc.Name); 
        }

        internal string XsdTypeName(Type type, XmlAttributes a, string name) {
            string typeName = name; 
            if (a.XmlType != null && a.XmlType.TypeName.Length > 0)
                typeName = a.XmlType.TypeName; 
 
            if (type.IsGenericType && typeName.IndexOf('{') >= 0) {
                Type genType = type.GetGenericTypeDefinition(); 
                Type[] names = genType.GetGenericArguments();
                Type[] types = type.GetGenericArguments();

                for (int i = 0; i < names.Length; i++) { 
                    string argument = "{" + names[i] + "}";
                    if (typeName.Contains(argument)) { 
                        typeName = typeName.Replace(argument, XsdTypeName(types[i])); 
                        if (typeName.IndexOf('{') < 0) {
                            break; 
                        }
                    }
                }
            } 
            //
            return typeName; 
        } 

        private static int CountAtLevel(XmlArrayItemAttributes attributes, int level) { 
            int sum = 0;
            for (int i = 0; i < attributes.Count; i++)
                if (attributes[i].NestingLevel == level) sum++;
            return sum; 
        }
 
        void SetArrayMappingType(ArrayMapping mapping, string defaultNs, Type type) { 
            XmlAttributes a = GetAttributes(type, false);
            bool isAnonymous = IsAnonymousType(a, defaultNs); 
            if (isAnonymous) {
                mapping.TypeName = null;
                mapping.Namespace = defaultNs;
                return; 
            }
            string name; 
            string ns; 
            TypeMapping itemTypeMapping;
            ElementAccessor element = null; 

            if (mapping.Elements.Length == 1) {
                element = mapping.Elements[0];
                itemTypeMapping = element.Mapping; 
            }
            else { 
                itemTypeMapping = null; 
            }
 
            bool generateTypeName = true;
            if (a.XmlType != null) {
                ns = a.XmlType.Namespace;
                name = XsdTypeName(type, a, a.XmlType.TypeName); 
                name = XmlConvert.EncodeLocalName(name);
                generateTypeName = name == null; 
            } 
            else if (itemTypeMapping is EnumMapping) {
                ns = itemTypeMapping.Namespace; 
                name = itemTypeMapping.DefaultElementName;
            }
            else if (itemTypeMapping is PrimitiveMapping) {
                ns = defaultNs; 
                name = itemTypeMapping.TypeDesc.DataType.Name;
            } 
            else if (itemTypeMapping is StructMapping && itemTypeMapping.TypeDesc.IsRoot) { 
                ns = defaultNs;
                name = Soap.UrType; 
            }
            else if (itemTypeMapping != null) {
                ns = itemTypeMapping.Namespace == XmlSchema.Namespace ? defaultNs : itemTypeMapping.Namespace;
                name = itemTypeMapping.DefaultElementName; 
            }
            else { 
                ns = defaultNs; 
                name = "Choice" + (choiceNum++);
            } 

            if (name == null)
                name = "Any";
 
            if (element != null)
                ns = element.Namespace; 
 
            if (ns == null)
                ns = defaultNs; 

            string uniqueName = name = generateTypeName ? "ArrayOf" + CodeIdentifier.MakePascal(name) : name;
            int i = 1;
            TypeMapping existingMapping = (TypeMapping)types[uniqueName, ns]; 
            while (existingMapping != null) {
                if (existingMapping is ArrayMapping) { 
                    ArrayMapping arrayMapping = (ArrayMapping)existingMapping; 
                    if (AccessorMapping.ElementsMatch(arrayMapping.Elements, mapping.Elements)) {
                        break; 
                    }
                }
                // need to re-name the mapping
                uniqueName = name + i.ToString(CultureInfo.InvariantCulture); 
                existingMapping = (TypeMapping)types[uniqueName, ns];
                i++; 
            } 
            mapping.TypeName = uniqueName;
            mapping.Namespace = ns; 
        }

        ArrayMapping ImportArrayLikeMapping(ArrayModel model, string ns) {
            ArrayMapping mapping = new ArrayMapping(); 
            mapping.TypeDesc = model.TypeDesc;
 
            if (savedArrayItemAttributes == null) 
                savedArrayItemAttributes = new XmlArrayItemAttributes();
            if (CountAtLevel(savedArrayItemAttributes, arrayNestingLevel) == 0) 
                savedArrayItemAttributes.Add(CreateArrayItemAttribute(typeScope.GetTypeDesc(model.Element.Type), arrayNestingLevel));
            CreateArrayElementsFromAttributes(mapping, savedArrayItemAttributes, model.Element.Type, savedArrayNamespace == null ? ns : savedArrayNamespace);
            SetArrayMappingType(mapping, ns, model.Type);
 
            // reconcile accessors now that we have the ArrayMapping namespace
            for (int i = 0; i < mapping.Elements.Length; i++) { 
                mapping.Elements[i] = ReconcileLocalAccessor(mapping.Elements[i], mapping.Namespace); 
            }
 
            IncludeTypes(model.Type);

            // in the case of an ArrayMapping we can have more that one mapping correspond to a type
            // examples of that are ArrayList and object[] both will map tp ArrayOfur-type 
            // so we create a link list for all mappings of the same XSD type
            ArrayMapping existingMapping = (ArrayMapping)types[mapping.TypeName, mapping.Namespace]; 
            if (existingMapping != null) { 
                ArrayMapping first = existingMapping;
                while (existingMapping != null) { 
                    if (existingMapping.TypeDesc == model.TypeDesc)
                        return existingMapping;
                    existingMapping = existingMapping.Next;
                } 
                mapping.Next = first;
                if (!mapping.IsAnonymousType) 
                    types[mapping.TypeName, mapping.Namespace] = mapping; 
                else
                    anonymous[model.Type] = mapping; 
                return mapping;
            }
            typeScope.AddTypeMapping(mapping);
            if (!mapping.IsAnonymousType) 
                types.Add(mapping.TypeName, mapping.Namespace, mapping);
            else 
                anonymous[model.Type] = mapping; 
            return mapping;
        } 

        void CheckContext(TypeDesc typeDesc, ImportContext context) {
            switch (context) {
                case ImportContext.Element: 
                    if (typeDesc.CanBeElementValue) return;
                    break; 
                case ImportContext.Attribute: 
                    if (typeDesc.CanBeAttributeValue) return;
                    break; 
                case ImportContext.Text:
                    if (typeDesc.CanBeTextValue || typeDesc.IsEnum || typeDesc.IsPrimitive)
                        return;
                    break; 
                default:
                    throw new ArgumentException(Res.GetString(Res.XmlInternalError), "context"); 
            } 
            throw UnsupportedException(typeDesc, context);
        } 

        PrimitiveMapping ImportPrimitiveMapping(PrimitiveModel model, ImportContext context, string dataType, bool repeats) {
            PrimitiveMapping mapping = new PrimitiveMapping();
            if (dataType.Length > 0) { 
                mapping.TypeDesc = typeScope.GetTypeDesc(dataType, XmlSchema.Namespace);
                if (mapping.TypeDesc == null) { 
                    // try it as a non-Xsd type 
                    mapping.TypeDesc = typeScope.GetTypeDesc(dataType, UrtTypes.Namespace);
                    if (mapping.TypeDesc == null) { 
                        throw new InvalidOperationException(Res.GetString(Res.XmlUdeclaredXsdType, dataType));
                    }
                }
            } 
            else {
                mapping.TypeDesc = model.TypeDesc; 
            } 
            mapping.TypeName = mapping.TypeDesc.DataType.Name;
            mapping.Namespace = mapping.TypeDesc.IsXsdType ? XmlSchema.Namespace : UrtTypes.Namespace; 
            mapping.IsList = repeats;
            CheckContext(mapping.TypeDesc, context);
            return mapping;
        } 

        EnumMapping ImportEnumMapping(EnumModel model, string ns, bool repeats) { 
            XmlAttributes a = GetAttributes(model.Type, false); 
            string typeNs = ns;
            if (a.XmlType != null && a.XmlType.Namespace != null) 
                typeNs = a.XmlType.Namespace;

            string typeName = IsAnonymousType(a, ns) ? null : XsdTypeName(model.Type, a, model.TypeDesc.Name);
            typeName = XmlConvert.EncodeLocalName(typeName); 

            EnumMapping mapping = (EnumMapping)GetTypeMapping(typeName, typeNs, model.TypeDesc, types, model.Type); 
            if (mapping == null) { 
                mapping = new EnumMapping();
                mapping.TypeDesc = model.TypeDesc; 
                mapping.TypeName = typeName;
                mapping.Namespace = typeNs;
                mapping.IsFlags =  model.Type.IsDefined(typeof(FlagsAttribute), false);
                if (mapping.IsFlags && repeats) 
                    throw new InvalidOperationException(Res.GetString(Res.XmlIllegalAttributeFlagsArray, model.TypeDesc.FullName));
                mapping.IsList = repeats; 
                mapping.IncludeInSchema = a.XmlType == null ? true : a.XmlType.IncludeInSchema; 
                if (!mapping.IsAnonymousType)
                    types.Add(typeName, typeNs, mapping); 
                else
                    anonymous[model.Type] = mapping;
                ArrayList constants = new ArrayList();
                for (int i = 0; i < model.Constants.Length; i++) { 
                    ConstantMapping constant = ImportConstantMapping(model.Constants[i]);
                    if (constant != null) constants.Add(constant); 
                } 
                if (constants.Count == 0) {
                    throw new InvalidOperationException(Res.GetString(Res.XmlNoSerializableMembers, model.TypeDesc.FullName)); 
                }
                mapping.Constants = (ConstantMapping[])constants.ToArray(typeof(ConstantMapping));
                typeScope.AddTypeMapping(mapping);
            } 
            return mapping;
        } 
 
        ConstantMapping ImportConstantMapping(ConstantModel model) {
            XmlAttributes a = GetAttributes(model.FieldInfo); 
            if (a.XmlIgnore) return null;
            if ((a.XmlFlags & ~XmlAttributeFlags.Enum) != 0)
                throw new InvalidOperationException(Res.GetString(Res.XmlInvalidConstantAttribute));
            if (a.XmlEnum == null) 
                a.XmlEnum = new XmlEnumAttribute();
 
            ConstantMapping constant = new ConstantMapping(); 
            constant.XmlName = a.XmlEnum.Name == null ? model.Name : a.XmlEnum.Name;
            constant.Name = model.Name; 
            constant.Value = model.Value;
            return constant;
        }
 
        MembersMapping ImportMembersMapping(XmlReflectionMember[] xmlReflectionMembers, string ns, bool hasWrapperElement, bool rpc, bool openModel) {
            MembersMapping members = new MembersMapping(); 
            members.TypeDesc = typeScope.GetTypeDesc(typeof(object[])); 
            MemberMapping[] mappings = new MemberMapping[xmlReflectionMembers.Length];
            NameTable elements = new NameTable(); 
            NameTable attributes = new NameTable();
            TextAccessor textAccessor = null;
            bool isSequence = false;
 
            for (int i = 0; i < mappings.Length; i++) {
                try { 
                    MemberMapping mapping = ImportMemberMapping(xmlReflectionMembers[i], ns, xmlReflectionMembers, rpc, openModel); 
                    if (!hasWrapperElement) {
                        if (mapping.Attribute != null) { 
                            if (rpc) {
                                throw new InvalidOperationException(Res.GetString(Res.XmlRpcLitAttributeAttributes));
                            }
                            else { 
                                throw new InvalidOperationException(Res.GetString(Res.XmlInvalidAttributeType, "XmlAttribute"));
                            } 
                        } 
                    }
                    if (rpc && xmlReflectionMembers[i].IsReturnValue) { 
                        if (i > 0) throw new InvalidOperationException(Res.GetString(Res.XmlInvalidReturnPosition));
                        mapping.IsReturnValue = true;
                    }
                    mappings[i] = mapping; 
                    isSequence |= mapping.IsSequence;
                    if (!xmlReflectionMembers[i].XmlAttributes.XmlIgnore) { 
                        // add All memeber accessors to the scope accessors 
                        AddUniqueAccessor(mapping, elements, attributes, isSequence);
                    } 

                    mappings[i] = mapping;
                    if (mapping.Text != null) {
                        if (textAccessor != null) { 
                            throw new InvalidOperationException(Res.GetString(Res.XmlIllegalMultipleTextMembers));
                        } 
                        textAccessor = mapping.Text; 
                    }
 
                    if (mapping.Xmlns != null) {
                        if (members.XmlnsMember != null)
                            throw new InvalidOperationException(Res.GetString(Res.XmlMultipleXmlnsMembers));
                        members.XmlnsMember = mapping; 
                    }
                } 
                catch (Exception e) { 
                    if (e is ThreadAbortException || e is StackOverflowException || e is OutOfMemoryException) {
                        throw; 
                    }
                    throw CreateReflectionException(xmlReflectionMembers[i].MemberName, e);
                }
                catch { 
                    throw CreateReflectionException(xmlReflectionMembers[i].MemberName, null);
                } 
            } 
            if (isSequence) {
                throw new InvalidOperationException(Res.GetString(Res.XmlSequenceMembers, "Order")); 
            }
            members.Members = mappings;
            members.HasWrapperElement = hasWrapperElement;
            return members; 
        }
 
        MemberMapping ImportMemberMapping(XmlReflectionMember xmlReflectionMember, string ns, XmlReflectionMember[] xmlReflectionMembers, bool rpc, bool openModel) { 
            XmlSchemaForm form = rpc ? XmlSchemaForm.Unqualified : XmlSchemaForm.Qualified;
            XmlAttributes a = xmlReflectionMember.XmlAttributes; 
            TypeDesc typeDesc = typeScope.GetTypeDesc(xmlReflectionMember.MemberType);

            if (a.XmlFlags == 0) {
                if (typeDesc.IsArrayLike) { 
                    XmlArrayAttribute xmlArray = CreateArrayAttribute(typeDesc);
                    xmlArray.ElementName = xmlReflectionMember.MemberName; 
                    xmlArray.Namespace = rpc ? null : ns; 
                    xmlArray.Form = form;
                    a.XmlArray = xmlArray; 
                }
                else {
                    XmlElementAttribute xmlElement = CreateElementAttribute(typeDesc);
                    // If there is no metadata specified on a parameter, then see if someone used 
                    // an XmlRoot attribute on the struct or class.
                    if (typeDesc.IsStructLike) { 
                        XmlAttributes structAttrs = new XmlAttributes(xmlReflectionMember.MemberType); 
                        if (structAttrs.XmlRoot != null) {
                            if (structAttrs.XmlRoot.ElementName.Length > 0) 
                                xmlElement.ElementName = structAttrs.XmlRoot.ElementName;
                            if (rpc) {
                                xmlElement.Namespace = null;
                                if (structAttrs.XmlRoot.IsNullableSpecified) 
                                    xmlElement.IsNullable = structAttrs.XmlRoot.IsNullable;
                            } 
                            else { 
                                xmlElement.Namespace = structAttrs.XmlRoot.Namespace;
                                xmlElement.IsNullable = structAttrs.XmlRoot.IsNullable; 
                            }
                        }
                    }
                    if (xmlElement.ElementName.Length == 0) 
                        xmlElement.ElementName = xmlReflectionMember.MemberName;
                    if (xmlElement.Namespace == null && !rpc) 
                        xmlElement.Namespace = ns; 
                    xmlElement.Form = form;
                    a.XmlElements.Add(xmlElement); 
                }
            }
            else if (a.XmlRoot != null) {
                CheckNullable(a.XmlRoot.IsNullable, typeDesc, null); 
            }
            MemberMapping member = new MemberMapping(); 
            member.Name = xmlReflectionMember.MemberName; 
            bool checkSpecified = FindSpecifiedMember(xmlReflectionMember.MemberName, xmlReflectionMembers) != null;
            FieldModel model = new FieldModel(xmlReflectionMember.MemberName, xmlReflectionMember.MemberType, typeScope.GetTypeDesc(xmlReflectionMember.MemberType), checkSpecified, false); 
            member.CheckShouldPersist = model.CheckShouldPersist;
            member.CheckSpecified = model.CheckSpecified;
            member.ReadOnly = model.ReadOnly; // || !model.FieldTypeDesc.HasDefaultConstructor;
 
            Type choiceIdentifierType = null;
            if (a.XmlChoiceIdentifier != null) { 
                choiceIdentifierType = GetChoiceIdentifierType(a.XmlChoiceIdentifier, xmlReflectionMembers, typeDesc.IsArrayLike, model.Name); 
            }
            ImportAccessorMapping(member, model, a, ns, choiceIdentifierType, rpc, openModel); 
            if (xmlReflectionMember.OverrideIsNullable && member.Elements.Length > 0)
                member.Elements[0].IsNullable = false;
            return member;
        } 

        internal static XmlReflectionMember FindSpecifiedMember(string memberName, XmlReflectionMember[] reflectionMembers) { 
            for (int i = 0; i < reflectionMembers.Length; i++) 
                if (string.Compare(reflectionMembers[i].MemberName, memberName + "Specified", StringComparison.Ordinal) == 0)
                    return reflectionMembers[i]; 
            return null;
        }

        MemberMapping ImportFieldMapping(StructModel parent, FieldModel model, XmlAttributes a, string ns) { 
            MemberMapping member = new MemberMapping();
            member.Name = model.Name; 
            member.CheckShouldPersist = model.CheckShouldPersist; 
            member.CheckSpecified = model.CheckSpecified;
            member.ReadOnly = model.ReadOnly; // || !model.FieldTypeDesc.HasDefaultConstructor; 
            Type choiceIdentifierType = null;
            if (a.XmlChoiceIdentifier != null) {
                choiceIdentifierType = GetChoiceIdentifierType(a.XmlChoiceIdentifier, parent, model.FieldTypeDesc.IsArrayLike, model.Name);
            } 
            ImportAccessorMapping(member, model, a, ns, choiceIdentifierType, false, false);
            return member; 
        } 

        Type CheckChoiceIdentifierType(Type type, bool isArrayLike, string identifierName, string memberName) { 
            if (type.IsArray) {
                if (!isArrayLike) {
                    // Inconsistent type of the choice identifier '{0}'.  Please use {1}.
                    throw new InvalidOperationException(Res.GetString(Res.XmlChoiceIdentifierType, identifierName, memberName, type.GetElementType().FullName)); 
                }
                type = type.GetElementType(); 
            } 
            else if (isArrayLike) {
                // Inconsistent type of the choice identifier '{0}'.  Please use {1}. 
                throw new InvalidOperationException(Res.GetString(Res.XmlChoiceIdentifierArrayType, identifierName, memberName, type.FullName));
            }

            if (!type.IsEnum) { 
                // Choice identifier '{0}' must be an enum.
                throw new InvalidOperationException(Res.GetString(Res.XmlChoiceIdentifierTypeEnum, identifierName)); 
            } 
            return type;
        } 

        Type GetChoiceIdentifierType(XmlChoiceIdentifierAttribute choice, XmlReflectionMember[] xmlReflectionMembers, bool isArrayLike, string accessorName) {
            for (int i = 0; i < xmlReflectionMembers.Length; i++) {
                if (choice.MemberName == xmlReflectionMembers[i].MemberName) { 
                    return CheckChoiceIdentifierType(xmlReflectionMembers[i].MemberType, isArrayLike, choice.MemberName, accessorName);
                } 
            } 
            // Missing '{0}' needed for serialization of choice '{1}'.
            throw new InvalidOperationException(Res.GetString(Res.XmlChoiceIdentiferMemberMissing, choice.MemberName, accessorName)); 
        }

        Type GetChoiceIdentifierType(XmlChoiceIdentifierAttribute choice, StructModel structModel, bool isArrayLike, string accessorName) {
            // check that the choice field exists 

            MemberInfo[] infos = structModel.Type.GetMember(choice.MemberName, BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static); 
            if (infos == null || infos.Length == 0) { 
                // if we can not find the choice identifier between fields, check proerties
                PropertyInfo info = structModel.Type.GetProperty(choice.MemberName, BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static); 

                if (info == null) {
                    // Missing '{0}' needed for serialization of choice '{1}'.
                    throw new InvalidOperationException(Res.GetString(Res.XmlChoiceIdentiferMemberMissing, choice.MemberName, accessorName)); 
                }
                infos = new MemberInfo[] { info }; 
            } 
            else if (infos.Length > 1) {
                // Ambiguous choice identifer: there are several members named '{0}'. 
                throw new InvalidOperationException(Res.GetString(Res.XmlChoiceIdentiferAmbiguous, choice.MemberName));
            }

            FieldModel member = structModel.GetFieldModel(infos[0]); 
            if (member == null) {
                // Missing '{0}' needed for serialization of choice '{1}'. 
                throw new InvalidOperationException(Res.GetString(Res.XmlChoiceIdentiferMemberMissing, choice.MemberName, accessorName)); 
            }
            Type enumType = member.FieldType; 
            enumType = CheckChoiceIdentifierType(enumType, isArrayLike, choice.MemberName, accessorName);
            return enumType;
        }
 
        void CreateArrayElementsFromAttributes(ArrayMapping arrayMapping, XmlArrayItemAttributes attributes, Type arrayElementType, string arrayElementNs) {
            NameTable arrayItemElements = new NameTable();   // xmlelementname + xmlns -> ElementAccessor 
 
            for (int i = 0; attributes != null && i < attributes.Count; i++) {
                XmlArrayItemAttribute xmlArrayItem = attributes[i]; 
                if (xmlArrayItem.NestingLevel != arrayNestingLevel)
                    continue;
                Type targetType = xmlArrayItem.Type != null ? xmlArrayItem.Type : arrayElementType;
                TypeDesc targetTypeDesc = typeScope.GetTypeDesc(targetType); 
                ElementAccessor arrayItemElement = new ElementAccessor();
                arrayItemElement.Namespace = xmlArrayItem.Namespace == null ? arrayElementNs : xmlArrayItem.Namespace; 
                arrayItemElement.Mapping = ImportTypeMapping(modelScope.GetTypeModel(targetType), arrayItemElement.Namespace, ImportContext.Element, xmlArrayItem.DataType, null); 
                arrayItemElement.Name = xmlArrayItem.ElementName.Length == 0 ? arrayItemElement.Mapping.DefaultElementName : XmlConvert.EncodeLocalName(xmlArrayItem.ElementName);
                arrayItemElement.IsNullable = xmlArrayItem.IsNullableSpecified ? xmlArrayItem.IsNullable : targetTypeDesc.IsNullable || targetTypeDesc.IsOptionalValue; 
                arrayItemElement.Form = xmlArrayItem.Form == XmlSchemaForm.None ? XmlSchemaForm.Qualified : xmlArrayItem.Form;
                CheckForm(arrayItemElement.Form, arrayElementNs != arrayItemElement.Namespace);
                CheckNullable(arrayItemElement.IsNullable, targetTypeDesc, arrayItemElement.Mapping);
                AddUniqueAccessor(arrayItemElements, arrayItemElement); 
            }
            arrayMapping.Elements = (ElementAccessor[])arrayItemElements.ToArray(typeof(ElementAccessor)); 
        } 

        void ImportAccessorMapping(MemberMapping accessor, FieldModel model, XmlAttributes a, string ns, Type choiceIdentifierType, bool rpc, bool openModel) { 
            XmlSchemaForm elementFormDefault = XmlSchemaForm.Qualified;
            int previousNestingLevel = arrayNestingLevel;
            int sequenceId = -1;
            XmlArrayItemAttributes previousArrayItemAttributes = savedArrayItemAttributes; 
            string previousArrayNamespace = savedArrayNamespace;
            arrayNestingLevel = 0; 
            savedArrayItemAttributes = null; 
            savedArrayNamespace = null;
            Type accessorType = model.FieldType; 
            string accessorName = model.Name;
            ArrayList elementList = new ArrayList();
            NameTable elements = new NameTable();
            accessor.TypeDesc = typeScope.GetTypeDesc(accessorType); 
            XmlAttributeFlags flags = a.XmlFlags;
            accessor.Ignore = a.XmlIgnore; 
            if (rpc) 
                CheckTopLevelAttributes(a, accessorName);
            else 
                CheckAmbiguousChoice(a, accessorType, accessorName);

            XmlAttributeFlags elemFlags = XmlAttributeFlags.Elements | XmlAttributeFlags.Text | XmlAttributeFlags.AnyElements | XmlAttributeFlags.ChoiceIdentifier;
            XmlAttributeFlags attrFlags = XmlAttributeFlags.Attribute | XmlAttributeFlags.AnyAttribute; 
            XmlAttributeFlags arrayFlags = XmlAttributeFlags.Array | XmlAttributeFlags.ArrayItems;
 
            // special case for byte[]. It can be a primitive (base64Binary or hexBinary), or it can 
            // be an array of bytes. Our default is primitive; specify [XmlArray] to get array behavior.
            if ((flags & arrayFlags) != 0 && accessorType == typeof(byte[])) 
                accessor.TypeDesc = typeScope.GetArrayTypeDesc(accessorType);

            if (a.XmlChoiceIdentifier != null) {
                accessor.ChoiceIdentifier = new ChoiceIdentifierAccessor(); 
                accessor.ChoiceIdentifier.MemberName = a.XmlChoiceIdentifier.MemberName;
                accessor.ChoiceIdentifier.Mapping = ImportTypeMapping(modelScope.GetTypeModel(choiceIdentifierType), ns, ImportContext.Element, String.Empty, null); 
                CheckChoiceIdentifierMapping((EnumMapping)accessor.ChoiceIdentifier.Mapping); 
            }
 
            if (accessor.TypeDesc.IsArrayLike) {
                Type arrayElementType = TypeScope.GetArrayElementType(accessorType, model.FieldTypeDesc.FullName + "." + model.Name);

                if ((flags & attrFlags) != 0) { 
                    if ((flags & attrFlags) != flags)
                        throw new InvalidOperationException(Res.GetString(Res.XmlIllegalAttributesArrayAttribute)); 
 
                    if (a.XmlAttribute != null && !accessor.TypeDesc.ArrayElementTypeDesc.IsPrimitive && !accessor.TypeDesc.ArrayElementTypeDesc.IsEnum) {
 
                        if (accessor.TypeDesc.ArrayElementTypeDesc.Kind == TypeKind.Serializable) {
                            throw new InvalidOperationException(Res.GetString(Res.XmlIllegalAttrOrTextInterface, accessorName, accessor.TypeDesc.ArrayElementTypeDesc.FullName, typeof(IXmlSerializable).Name));
                        }
                        else { 
                            throw new InvalidOperationException(Res.GetString(Res.XmlIllegalAttrOrText, accessorName, accessor.TypeDesc.ArrayElementTypeDesc.FullName));
                        } 
                    } 

                    bool isList = a.XmlAttribute != null && (accessor.TypeDesc.ArrayElementTypeDesc.IsPrimitive || accessor.TypeDesc.ArrayElementTypeDesc.IsEnum); 

                    if (a.XmlAnyAttribute != null) {
                        a.XmlAttribute = new XmlAttributeAttribute();
                    } 

                    AttributeAccessor attribute = new AttributeAccessor(); 
                    Type targetType = a.XmlAttribute.Type == null ? arrayElementType : a.XmlAttribute.Type; 
                    TypeDesc targetTypeDesc = typeScope.GetTypeDesc(targetType);
                    attribute.Name = Accessor.EscapeQName(a.XmlAttribute.AttributeName.Length == 0 ? accessorName : a.XmlAttribute.AttributeName); 
                    attribute.Namespace = a.XmlAttribute.Namespace == null ? ns : a.XmlAttribute.Namespace;
                    attribute.Form = a.XmlAttribute.Form;
                    if (attribute.Form == XmlSchemaForm.None && ns != attribute.Namespace) {
                        attribute.Form = XmlSchemaForm.Qualified; 
                    }
                    attribute.CheckSpecial(); 
                    CheckForm(attribute.Form, ns != attribute.Namespace); 
                    attribute.Mapping = ImportTypeMapping(modelScope.GetTypeModel(targetType), ns, ImportContext.Attribute, a.XmlAttribute.DataType, null, isList, false);
                    attribute.IsList = isList; 
                    attribute.Default = GetDefaultValue(model.FieldTypeDesc, model.FieldType, a);
                    attribute.Any = (a.XmlAnyAttribute != null);
                    if (attribute.Form == XmlSchemaForm.Qualified && attribute.Namespace != ns) {
                        if (xsdAttributes == null) 
                            xsdAttributes = new NameTable();
                        attribute = (AttributeAccessor)ReconcileAccessor(attribute, xsdAttributes); 
                    } 
                    accessor.Attribute = attribute;
 
                }
                else if ((flags & elemFlags) != 0) {
                    if ((flags & elemFlags) != flags)
                        throw new InvalidOperationException(Res.GetString(Res.XmlIllegalElementsArrayAttribute)); 

                    if (a.XmlText != null) { 
                        TextAccessor text = new TextAccessor(); 
                        Type targetType = a.XmlText.Type == null ? arrayElementType : a.XmlText.Type;
                        TypeDesc targetTypeDesc = typeScope.GetTypeDesc(targetType); 
                        text.Name = accessorName; // unused except to make more helpful error messages
                        text.Mapping = ImportTypeMapping(modelScope.GetTypeModel(targetType), ns, ImportContext.Text, a.XmlText.DataType, null, true, false);
                        if (!(text.Mapping is SpecialMapping) && targetTypeDesc != typeScope.GetTypeDesc(typeof(string)))
                            throw new InvalidOperationException(Res.GetString(Res.XmlIllegalArrayTextAttribute, accessorName)); 

                        accessor.Text = text; 
                    } 
                    if (a.XmlText == null && a.XmlElements.Count == 0 && a.XmlAnyElements.Count == 0)
                        a.XmlElements.Add(CreateElementAttribute(accessor.TypeDesc)); 

                    for (int i = 0; i < a.XmlElements.Count; i++) {
                        XmlElementAttribute xmlElement = a.XmlElements[i];
                        Type targetType = xmlElement.Type == null ? arrayElementType : xmlElement.Type; 
                        TypeDesc targetTypeDesc = typeScope.GetTypeDesc(targetType);
                        TypeModel typeModel = modelScope.GetTypeModel(targetType); 
                        ElementAccessor element = new ElementAccessor(); 
                        element.Namespace = rpc ? null : xmlElement.Namespace == null ? ns : xmlElement.Namespace;
                        element.Mapping = ImportTypeMapping(typeModel, rpc ? ns : element.Namespace, ImportContext.Element, xmlElement.DataType, null); 
                        if (a.XmlElements.Count == 1) {
                            element.Name = XmlConvert.EncodeLocalName(xmlElement.ElementName.Length == 0 ? accessorName : xmlElement.ElementName);
                            //element.IsUnbounded = element.Mapping is ArrayMapping;
                        } 
                        else {
                            element.Name = xmlElement.ElementName.Length == 0 ? element.Mapping.DefaultElementName : XmlConvert.EncodeLocalName(xmlElement.ElementName); 
                        } 
                        element.Default = GetDefaultValue(model.FieldTypeDesc, model.FieldType, a);
                        if (xmlElement.IsNullableSpecified && !xmlElement.IsNullable && typeModel.TypeDesc.IsOptionalValue) 
                            //XmlInvalidNotNullable=IsNullable may not be set to 'false' for a Nullable<{0}> type. Consider using '{0}' type or removing the IsNullable property from the XmlElement attribute.
                            throw new InvalidOperationException(Res.GetString(Res.XmlInvalidNotNullable, typeModel.TypeDesc.BaseTypeDesc.FullName, "XmlElement"));
                        element.IsNullable = xmlElement.IsNullableSpecified ? xmlElement.IsNullable : typeModel.TypeDesc.IsOptionalValue;
                        element.Form = rpc ? XmlSchemaForm.Unqualified : xmlElement.Form == XmlSchemaForm.None ? elementFormDefault : xmlElement.Form; 

                        CheckNullable(element.IsNullable, targetTypeDesc, element.Mapping); 
                        if (!rpc) { 
                            CheckForm(element.Form, ns != element.Namespace);
                            element = ReconcileLocalAccessor(element, ns); 
                        }
                        if (xmlElement.Order != -1) {
                            if (xmlElement.Order != sequenceId &&  sequenceId != -1)
                                throw new InvalidOperationException(Res.GetString(Res.XmlSequenceMatch, "Order")); 
                            sequenceId = xmlElement.Order;
                        } 
                        AddUniqueAccessor(elements, element); 
                        elementList.Add(element);
                    } 
                    NameTable anys = new NameTable();
                    for (int i = 0; i < a.XmlAnyElements.Count; i++) {
                        XmlAnyElementAttribute xmlAnyElement = a.XmlAnyElements[i];
                        Type targetType = typeof(IXmlSerializable).IsAssignableFrom(arrayElementType) ? arrayElementType : typeof(XmlNode).IsAssignableFrom(arrayElementType) ? arrayElementType : typeof(XmlElement); 
                        if (!arrayElementType.IsAssignableFrom(targetType))
                            throw new InvalidOperationException(Res.GetString(Res.XmlIllegalAnyElement, arrayElementType.FullName)); 
                        string anyName = xmlAnyElement.Name.Length == 0 ? xmlAnyElement.Name : XmlConvert.EncodeLocalName(xmlAnyElement.Name); 
                        string anyNs = xmlAnyElement.NamespaceSpecified ? xmlAnyElement.Namespace : null;
                        if (anys[anyName, anyNs] != null) { 
                            // ignore duplicate anys
                            continue;
                        }
                        anys[anyName, anyNs] = xmlAnyElement; 
                        if (elements[anyName, (anyNs == null ? ns : anyNs)] != null) {
                            throw new InvalidOperationException(Res.GetString(Res.XmlAnyElementDuplicate, accessorName, xmlAnyElement.Name, xmlAnyElement.Namespace == null ? "null" : xmlAnyElement.Namespace)); 
                        } 
                        ElementAccessor element = new ElementAccessor();
                        element.Name = anyName; 
                        element.Namespace = anyNs == null ? ns : anyNs;
                        element.Any = true;
                        element.AnyNamespaces = anyNs;
                        TypeDesc targetTypeDesc = typeScope.GetTypeDesc(targetType); 
                        TypeModel typeModel = modelScope.GetTypeModel(targetType);
                        if (element.Name.Length > 0) 
                            typeModel.TypeDesc.IsMixed = true; 
                        element.Mapping = ImportTypeMapping(typeModel, element.Namespace, ImportContext.Element, String.Empty, null);
                        element.Default = GetDefaultValue(model.FieldTypeDesc, model.FieldType, a); 
                        element.IsNullable = false;
                        element.Form = elementFormDefault;

                        CheckNullable(element.IsNullable, targetTypeDesc, element.Mapping); 
                        if (!rpc) {
                            CheckForm(element.Form, ns != element.Namespace); 
                            element = ReconcileLocalAccessor(element, ns); 
                        }
                        elements.Add(element.Name, element.Namespace, element); 
                        elementList.Add(element);
                        if (xmlAnyElement.Order != -1) {
                            if (xmlAnyElement.Order != sequenceId &&  sequenceId != -1)
                                throw new InvalidOperationException(Res.GetString(Res.XmlSequenceMatch, "Order")); 
                            sequenceId = xmlAnyElement.Order;
                        } 
                    } 
                }
                else { 
                    if ((flags & arrayFlags) != 0) {
                        if ((flags & arrayFlags) != flags)
                            throw new InvalidOperationException(Res.GetString(Res.XmlIllegalArrayArrayAttribute));
                    } 

                    TypeDesc arrayElementTypeDesc = typeScope.GetTypeDesc(arrayElementType); 
                    if (a.XmlArray == null) 
                        a.XmlArray = CreateArrayAttribute(accessor.TypeDesc);
                    if (CountAtLevel(a.XmlArrayItems, arrayNestingLevel) == 0) 
                        a.XmlArrayItems.Add(CreateArrayItemAttribute(arrayElementTypeDesc, arrayNestingLevel));
                    ElementAccessor arrayElement = new ElementAccessor();
                    arrayElement.Name = XmlConvert.EncodeLocalName(a.XmlArray.ElementName.Length == 0 ? accessorName : a.XmlArray.ElementName);
                    arrayElement.Namespace = rpc ? null : a.XmlArray.Namespace == null ? ns : a.XmlArray.Namespace; 
                    savedArrayItemAttributes = a.XmlArrayItems;
                    savedArrayNamespace = arrayElement.Namespace; 
                    ArrayMapping arrayMapping = ImportArrayLikeMapping(modelScope.GetArrayModel(accessorType), ns); 
                    arrayElement.Mapping = arrayMapping;
                    arrayElement.IsNullable = a.XmlArray.IsNullable; 
                    arrayElement.Form = rpc ? XmlSchemaForm.Unqualified : a.XmlArray.Form == XmlSchemaForm.None ? elementFormDefault : a.XmlArray.Form;
                    sequenceId = a.XmlArray.Order;
                    CheckNullable(arrayElement.IsNullable, accessor.TypeDesc, arrayElement.Mapping);
                    if (!rpc) { 
                        CheckForm(arrayElement.Form, ns != arrayElement.Namespace);
                        arrayElement = ReconcileLocalAccessor(arrayElement, ns); 
                    } 
                    savedArrayItemAttributes = null;
                    savedArrayNamespace = null; 

                    AddUniqueAccessor(elements, arrayElement);
                    elementList.Add(arrayElement);
                } 
            }
            else if (!accessor.TypeDesc.IsVoid) { 
                XmlAttributeFlags allFlags = XmlAttributeFlags.Elements | XmlAttributeFlags.Text | XmlAttributeFlags.Attribute | XmlAttributeFlags.AnyElements | XmlAttributeFlags.ChoiceIdentifier | XmlAttributeFlags.XmlnsDeclarations; 
                if ((flags & allFlags) != flags)
                    throw new InvalidOperationException(Res.GetString(Res.XmlIllegalAttribute)); 

                if (accessor.TypeDesc.IsPrimitive || accessor.TypeDesc.IsEnum) {
                    if (a.XmlAnyElements.Count > 0) throw new InvalidOperationException(Res.GetString(Res.XmlIllegalAnyElement, accessor.TypeDesc.FullName));
 
                    if (a.XmlAttribute != null) {
                        if (a.XmlElements.Count > 0) throw new InvalidOperationException(Res.GetString(Res.XmlIllegalAttribute)); 
                        if (a.XmlAttribute.Type != null) throw new InvalidOperationException(Res.GetString(Res.XmlIllegalType, "XmlAttribute")); 
                        AttributeAccessor attribute = new AttributeAccessor();
                        attribute.Name = Accessor.EscapeQName(a.XmlAttribute.AttributeName.Length == 0 ? accessorName : a.XmlAttribute.AttributeName); 
                        attribute.Namespace = a.XmlAttribute.Namespace == null ? ns : a.XmlAttribute.Namespace;
                        attribute.Form = a.XmlAttribute.Form;
                        if (attribute.Form == XmlSchemaForm.None && ns != attribute.Namespace) {
                            attribute.Form = XmlSchemaForm.Qualified; 
                        }
                        attribute.CheckSpecial(); 
                        CheckForm(attribute.Form, ns != attribute.Namespace); 
                        attribute.Mapping = ImportTypeMapping(modelScope.GetTypeModel(accessorType), ns, ImportContext.Attribute, a.XmlAttribute.DataType, null);
                        attribute.Default = GetDefaultValue(model.FieldTypeDesc, model.FieldType, a); 
                        attribute.Any = a.XmlAnyAttribute != null;
                        if (attribute.Form == XmlSchemaForm.Qualified && attribute.Namespace != ns) {
                            if (xsdAttributes == null)
                                xsdAttributes = new NameTable(); 
                            attribute = (AttributeAccessor)ReconcileAccessor(attribute, xsdAttributes);
                        } 
                        accessor.Attribute = attribute; 
                    }
                    else { 
                        if (a.XmlText != null) {
                            if (a.XmlText.Type != null && a.XmlText.Type != accessorType)
                                throw new InvalidOperationException(Res.GetString(Res.XmlIllegalType, "XmlText"));
                            TextAccessor text = new TextAccessor(); 
                            text.Name = accessorName; // unused except to make more helpful error messages
                            text.Mapping = ImportTypeMapping(modelScope.GetTypeModel(accessorType), ns, ImportContext.Text, a.XmlText.DataType, null); 
                            accessor.Text = text; 
                        }
                        else if (a.XmlElements.Count == 0) { 
                            a.XmlElements.Add(CreateElementAttribute(accessor.TypeDesc));
                        }

                        for (int i = 0; i < a.XmlElements.Count; i++) { 
                            XmlElementAttribute xmlElement = a.XmlElements[i];
                            if (xmlElement.Type != null) { 
                                if (typeScope.GetTypeDesc(xmlElement.Type) != accessor.TypeDesc) 
                                    throw new InvalidOperationException(Res.GetString(Res.XmlIllegalType, "XmlElement"));
                            } 
                            ElementAccessor element = new ElementAccessor();
                            element.Name = XmlConvert.EncodeLocalName(xmlElement.ElementName.Length == 0 ? accessorName : xmlElement.ElementName);
                            element.Namespace = rpc ? null : xmlElement.Namespace == null ? ns : xmlElement.Namespace;
                            TypeModel typeModel = modelScope.GetTypeModel(accessorType); 
                            element.Mapping = ImportTypeMapping(typeModel, rpc ? ns : element.Namespace, ImportContext.Element, xmlElement.DataType, null);
                            if (element.Mapping.TypeDesc.Kind == TypeKind.Node) { 
                                element.Any = true; 
                            }
                            element.Default = GetDefaultValue(model.FieldTypeDesc, model.FieldType, a); 
                            if (xmlElement.IsNullableSpecified && !xmlElement.IsNullable && typeModel.TypeDesc.IsOptionalValue)
                                //XmlInvalidNotNullable=IsNullable may not be set to 'false' for a Nullable<{0}> type. Consider using '{0}' type or removing the IsNullable property from the XmlElement attribute.
                                throw new InvalidOperationException(Res.GetString(Res.XmlInvalidNotNullable, typeModel.TypeDesc.BaseTypeDesc.FullName, "XmlElement"));
                            element.IsNullable = xmlElement.IsNullableSpecified ? xmlElement.IsNullable : typeModel.TypeDesc.IsOptionalValue; 
                            element.Form = rpc ? XmlSchemaForm.Unqualified : xmlElement.Form == XmlSchemaForm.None ? elementFormDefault : xmlElement.Form;
 
                            CheckNullable(element.IsNullable, accessor.TypeDesc, element.Mapping); 
                            if (!rpc) {
                                CheckForm(element.Form, ns != element.Namespace); 
                                element = ReconcileLocalAccessor(element, ns);
                            }
                            if (xmlElement.Order != -1) {
                                if (xmlElement.Order != sequenceId &&  sequenceId != -1) 
                                    throw new InvalidOperationException(Res.GetString(Res.XmlSequenceMatch, "Order"));
                                sequenceId = xmlElement.Order; 
                            } 
                            AddUniqueAccessor(elements, element);
                            elementList.Add(element); 
                        }
                    }
                }
                else if (a.Xmlns) { 
                    if (flags != XmlAttributeFlags.XmlnsDeclarations)
                        throw new InvalidOperationException(Res.GetString(Res.XmlSoleXmlnsAttribute)); 
 
                    if (accessorType != typeof(XmlSerializerNamespaces)) {
                        throw new InvalidOperationException(Res.GetString(Res.XmlXmlnsInvalidType, accessorName, accessorType.FullName, typeof(XmlSerializerNamespaces).FullName)); 
                    }
                    accessor.Xmlns = new XmlnsAccessor();
                    accessor.Ignore = true;
                } 
                else  {
                    if (a.XmlAttribute != null || a.XmlText != null) { 
                        if (accessor.TypeDesc.Kind == TypeKind.Serializable) { 
                            throw new InvalidOperationException(Res.GetString(Res.XmlIllegalAttrOrTextInterface, accessorName, accessor.TypeDesc.FullName, typeof(IXmlSerializable).Name));
                        } 
                        else {
                            throw new InvalidOperationException(Res.GetString(Res.XmlIllegalAttrOrText, accessorName, accessor.TypeDesc));
                        }
                    } 
                    if (a.XmlElements.Count == 0 && a.XmlAnyElements.Count == 0)
                        a.XmlElements.Add(CreateElementAttribute(accessor.TypeDesc)); 
                    for (int i = 0; i < a.XmlElements.Count; i++) { 
                        XmlElementAttribute xmlElement = a.XmlElements[i];
                        Type targetType = xmlElement.Type == null ? accessorType : xmlElement.Type; 
                        TypeDesc targetTypeDesc = typeScope.GetTypeDesc(targetType);
                        ElementAccessor element = new ElementAccessor();
                        TypeModel typeModel = modelScope.GetTypeModel(targetType);
                        element.Namespace = rpc ? null : xmlElement.Namespace == null ? ns : xmlElement.Namespace; 
                        element.Mapping = ImportTypeMapping(typeModel, rpc ? ns : element.Namespace, ImportContext.Element, xmlElement.DataType, null, false, openModel);
                        if (a.XmlElements.Count == 1) { 
                            element.Name = XmlConvert.EncodeLocalName(xmlElement.ElementName.Length == 0 ? accessorName : xmlElement.ElementName); 
                        }
                        else { 
                            element.Name = xmlElement.ElementName.Length == 0 ? element.Mapping.DefaultElementName : XmlConvert.EncodeLocalName(xmlElement.ElementName);
                        }
                        element.Default = GetDefaultValue(model.FieldTypeDesc, model.FieldType, a);
                        if (xmlElement.IsNullableSpecified && !xmlElement.IsNullable && typeModel.TypeDesc.IsOptionalValue) 
                            //XmlInvalidNotNullable=IsNullable may not be set to 'false' for a Nullable<{0}> type. Consider using '{0}' type or removing the IsNullable property from the XmlElement attribute.
                            throw new InvalidOperationException(Res.GetString(Res.XmlInvalidNotNullable, typeModel.TypeDesc.BaseTypeDesc.FullName, "XmlElement")); 
                        element.IsNullable = xmlElement.IsNullableSpecified ? xmlElement.IsNullable : typeModel.TypeDesc.IsOptionalValue; 
                        element.Form = rpc ? XmlSchemaForm.Unqualified : xmlElement.Form == XmlSchemaForm.None ? elementFormDefault : xmlElement.Form;
                        CheckNullable(element.IsNullable, targetTypeDesc, element.Mapping); 

                        if (!rpc) {
                            CheckForm(element.Form, ns != element.Namespace);
                            element = ReconcileLocalAccessor(element, ns); 
                        }
                        if (xmlElement.Order != -1) { 
                            if (xmlElement.Order != sequenceId &&  sequenceId != -1) 
                                throw new InvalidOperationException(Res.GetString(Res.XmlSequenceMatch, "Order"));
                            sequenceId = xmlElement.Order; 
                        }
                        AddUniqueAccessor(elements, element);
                        elementList.Add(element);
                    } 
                    NameTable anys = new NameTable();
                    for (int i = 0; i < a.XmlAnyElements.Count; i++) 
                    { 
                        XmlAnyElementAttribute xmlAnyElement = a.XmlAnyElements[i];
                        Type targetType = typeof(IXmlSerializable).IsAssignableFrom(accessorType) ? accessorType : typeof(XmlNode).IsAssignableFrom(accessorType) ? accessorType : typeof(XmlElement); 
                        if (!accessorType.IsAssignableFrom(targetType))
                            throw new InvalidOperationException(Res.GetString(Res.XmlIllegalAnyElement, accessorType.FullName));

                        string anyName = xmlAnyElement.Name.Length == 0 ? xmlAnyElement.Name : XmlConvert.EncodeLocalName(xmlAnyElement.Name); 
                        string anyNs = xmlAnyElement.NamespaceSpecified ? xmlAnyElement.Namespace : null;
                        if (anys[anyName, anyNs] != null) 
                        { 
                            // ignore duplicate anys
                            continue; 
                        }
                        anys[anyName, anyNs] = xmlAnyElement;
                        if (elements[anyName, (anyNs == null ? ns : anyNs)] != null)
                        { 
                            throw new InvalidOperationException(Res.GetString(Res.XmlAnyElementDuplicate, accessorName, xmlAnyElement.Name, xmlAnyElement.Namespace == null ? "null" : xmlAnyElement.Namespace));
                        } 
                        ElementAccessor element = new ElementAccessor(); 
                        element.Name = anyName;
                        element.Namespace = anyNs == null ? ns : anyNs; 
                        element.Any = true;
                        element.AnyNamespaces = anyNs;
                        TypeDesc targetTypeDesc = typeScope.GetTypeDesc(targetType);
                        TypeModel typeModel = modelScope.GetTypeModel(targetType); 

                        if (element.Name.Length > 0) 
                            typeModel.TypeDesc.IsMixed = true; 
                        element.Mapping = ImportTypeMapping(typeModel, element.Namespace, ImportContext.Element, String.Empty, null, false, openModel);
                        element.Default = GetDefaultValue(model.FieldTypeDesc, model.FieldType, a); 
                        element.IsNullable = false;
                        element.Form = elementFormDefault;
                        CheckNullable(element.IsNullable, targetTypeDesc, element.Mapping);
                        if (!rpc) { 
                            CheckForm(element.Form, ns != element.Namespace);
                            element = ReconcileLocalAccessor(element, ns); 
                        } 
                        if (xmlAnyElement.Order != -1) {
                            if (xmlAnyElement.Order != sequenceId &&  sequenceId != -1) 
                                throw new InvalidOperationException(Res.GetString(Res.XmlSequenceMatch, "Order"));
                            sequenceId = xmlAnyElement.Order;
                        }
                        elements.Add(element.Name, element.Namespace, element); 
                        elementList.Add(element);
                    } 
                } 
            }
            accessor.Elements = (ElementAccessor[])elementList.ToArray(typeof(ElementAccessor)); 
            accessor.SequenceId = sequenceId;

            if (rpc)
            { 
                if (accessor.TypeDesc.IsArrayLike && accessor.Elements.Length > 0 && !(accessor.Elements[0].Mapping is ArrayMapping))
                    throw new InvalidOperationException(Res.GetString(Res.XmlRpcLitArrayElement, accessor.Elements[0].Name)); 
 
                if (accessor.Xmlns != null)
                    throw new InvalidOperationException(Res.GetString(Res.XmlRpcLitXmlns, accessor.Name)); 
            }

            if (accessor.ChoiceIdentifier != null) {
                // find the enum value corresponding to each element 
                accessor.ChoiceIdentifier.MemberIds = new string[accessor.Elements.Length];
                for (int i = 0; i < accessor.Elements.Length; i++) { 
                    bool found = false; 
                    ElementAccessor element = accessor.Elements[i];
                    EnumMapping choiceMapping = (EnumMapping)accessor.ChoiceIdentifier.Mapping; 
                    for (int j = 0; j < choiceMapping.Constants.Length; j++) {
                        string xmlName = choiceMapping.Constants[j].XmlName;

                        if (element.Any && element.Name.Length == 0) { 
                            string anyNs = element.AnyNamespaces == null ? "##any" : element.AnyNamespaces;
                            if (xmlName.Substring(0, xmlName.Length-1) == anyNs) { 
                                accessor.ChoiceIdentifier.MemberIds[i] = choiceMapping.Constants[j].Name; 
                                found = true;
                                break; 
                            }
                            continue;
                        }
                        int colon = xmlName.LastIndexOf(':'); 
                        string choiceNs = colon < 0 ? choiceMapping.Namespace : xmlName.Substring(0, colon);
                        string choiceName = colon < 0 ? xmlName : xmlName.Substring(colon+1); 
 
                        if (element.Name == choiceName) {
                            if ((element.Form == XmlSchemaForm.Unqualified && string.IsNullOrEmpty(choiceNs)) || element.Namespace == choiceNs) { 
                                accessor.ChoiceIdentifier.MemberIds[i] = choiceMapping.Constants[j].Name;
                                found = true;
                                break;
                            } 
                        }
                    } 
                    if (!found) { 
                        if (element.Any && element.Name.Length == 0) {
                            // Type {0} is missing enumeration value '##any' for XmlAnyElementAttribute. 
                            throw new InvalidOperationException(Res.GetString(Res.XmlChoiceMissingAnyValue, accessor.ChoiceIdentifier.Mapping.TypeDesc.FullName));
                        }
                        else {
                            string id = element.Namespace != null && element.Namespace.Length > 0 ? element.Namespace + ":" + element.Name : element.Name; 
                            // Type {0} is missing value for '{1}'.
                            throw new InvalidOperationException(Res.GetString(Res.XmlChoiceMissingValue, accessor.ChoiceIdentifier.Mapping.TypeDesc.FullName, id, element.Name, element.Namespace)); 
                        } 
                    }
                } 
            }
            arrayNestingLevel = previousNestingLevel;
            savedArrayItemAttributes = previousArrayItemAttributes;
            savedArrayNamespace = previousArrayNamespace; 
        }
 
 
        void CheckTopLevelAttributes(XmlAttributes a, string accessorName) {
            XmlAttributeFlags flags = a.XmlFlags; 

            if ((flags & (XmlAttributeFlags.Attribute | XmlAttributeFlags.AnyAttribute)) != 0)
                throw new InvalidOperationException(Res.GetString(Res.XmlRpcLitAttributeAttributes));
 
            if ((flags & (XmlAttributeFlags.Text | XmlAttributeFlags.AnyElements | XmlAttributeFlags.ChoiceIdentifier)) != 0)
                throw new InvalidOperationException(Res.GetString(Res.XmlRpcLitAttributes)); 
 
            if (a.XmlElements != null && a.XmlElements.Count > 0) {
                if (a.XmlElements.Count > 1) { 
                    throw new InvalidOperationException(Res.GetString(Res.XmlRpcLitElements));
                }
                XmlElementAttribute xmlElement = a.XmlElements[0];
                if (xmlElement.Namespace != null) { 
                    throw new InvalidOperationException(Res.GetString(Res.XmlRpcLitElementNamespace, "Namespace", xmlElement.Namespace));
                } 
                if (xmlElement.IsNullable) { 
                    throw new InvalidOperationException(Res.GetString(Res.XmlRpcLitElementNullable, "IsNullable", "true"));
                } 
            }
            if (a.XmlArray != null && a.XmlArray.Namespace != null) {
                throw new InvalidOperationException(Res.GetString(Res.XmlRpcLitElementNamespace, "Namespace", a.XmlArray.Namespace));
            } 
        }
 
        void CheckAmbiguousChoice(XmlAttributes a, Type accessorType, string accessorName) { 
            Hashtable choiceTypes = new Hashtable();
 
            XmlElementAttributes elements = a.XmlElements;
            if (elements != null && elements.Count >= 2 && a.XmlChoiceIdentifier == null) {
                for (int i = 0; i < elements.Count; i++) {
                    Type type = elements[i].Type == null ? accessorType : elements[i].Type; 
                    if (choiceTypes.Contains(type)) {
                        // You need to add {0} to the '{1}'. 
                        throw new InvalidOperationException(Res.GetString(Res.XmlChoiceIdentiferMissing, typeof(XmlChoiceIdentifierAttribute).Name, accessorName)); 
                    }
                    else { 
                        choiceTypes.Add(type, false);
                    }
                }
            } 
            if (choiceTypes.Contains(typeof(XmlElement)) && a.XmlAnyElements.Count > 0) {
                // You need to add {0} to the '{1}'. 
                throw new InvalidOperationException(Res.GetString(Res.XmlChoiceIdentiferMissing, typeof(XmlChoiceIdentifierAttribute).Name, accessorName)); 
            }
 
            XmlArrayItemAttributes items = a.XmlArrayItems;
            if (items != null && items.Count >= 2) {
                NameTable arrayTypes = new NameTable();
 
                for (int i = 0; i < items.Count; i++) {
                    Type type = items[i].Type == null ? accessorType : items[i].Type; 
                    string ns = items[i].NestingLevel.ToString(CultureInfo.InvariantCulture); 
                    XmlArrayItemAttribute item = (XmlArrayItemAttribute)arrayTypes[type.FullName, ns];
                    if (item != null) { 
                        throw new InvalidOperationException(Res.GetString(Res.XmlArrayItemAmbiguousTypes, accessorName, item.ElementName, items[i].ElementName, typeof(XmlElementAttribute).Name, typeof(XmlChoiceIdentifierAttribute).Name, accessorName));
                    }
                    else {
                        arrayTypes[type.FullName, ns] =  items[i]; 
                    }
                } 
            } 
        }
 
        void CheckChoiceIdentifierMapping(EnumMapping choiceMapping) {
            NameTable ids = new NameTable();
            for (int i = 0; i < choiceMapping.Constants.Length; i++) {
                string choiceId = choiceMapping.Constants[i].XmlName; 
                int colon = choiceId.LastIndexOf(':');
                string choiceName = colon < 0 ? choiceId : choiceId.Substring(colon+1); 
                string choiceNs = colon < 0 ? "" : choiceId.Substring(0, colon); 

                if (ids[choiceName, choiceNs] != null) { 
                    // Enum values in the XmlChoiceIdentifier '{0}' have to be unique.  Value '{1}' already present.
                    throw new InvalidOperationException(Res.GetString(Res.XmlChoiceIdDuplicate, choiceMapping.TypeName, choiceId));
                }
                ids.Add(choiceName, choiceNs, choiceMapping.Constants[i]); 
            }
        } 
 
        object GetDefaultValue(TypeDesc fieldTypeDesc, Type t, XmlAttributes a) {
            if (a.XmlDefaultValue == null || a.XmlDefaultValue == DBNull.Value) return null; 
            if (!(fieldTypeDesc.Kind == TypeKind.Primitive || fieldTypeDesc.Kind == TypeKind.Enum))  {
                //throw new InvalidOperationException(Res.GetString(Res.XmlIllegalDefault));
                a.XmlDefaultValue = null;
                return a.XmlDefaultValue; 
            }
            // for enums validate and return a string representation 
            if (fieldTypeDesc.Kind == TypeKind.Enum) { 
                string strValue = Enum.Format(t, a.XmlDefaultValue, "G").Replace(",", " ");
                string numValue = Enum.Format(t, a.XmlDefaultValue, "D"); 
                if (strValue == numValue) // means enum value wasn't recognized
                    throw new InvalidOperationException(Res.GetString(Res.XmlInvalidDefaultValue, strValue, a.XmlDefaultValue.GetType().FullName));
                return strValue;
            } 
            return a.XmlDefaultValue;
        } 
 
        static XmlArrayItemAttribute CreateArrayItemAttribute(TypeDesc typeDesc, int nestingLevel) {
            XmlArrayItemAttribute xmlArrayItem = new XmlArrayItemAttribute(); 
            xmlArrayItem.NestingLevel = nestingLevel;
            return xmlArrayItem;
        }
 
        static XmlArrayAttribute CreateArrayAttribute(TypeDesc typeDesc) {
            XmlArrayAttribute xmlArrayItem = new XmlArrayAttribute(); 
            return xmlArrayItem; 
        }
 
        static XmlElementAttribute CreateElementAttribute(TypeDesc typeDesc) {
            XmlElementAttribute xmlElement = new XmlElementAttribute();
            xmlElement.IsNullable = typeDesc.IsOptionalValue;
            return xmlElement; 
        }
 
        static void AddUniqueAccessor(INameScope scope, Accessor accessor) { 
            Accessor existing = (Accessor)scope[accessor.Name, accessor.Namespace];
            if (existing != null) { 
                if (accessor is ElementAccessor) {
                    throw new InvalidOperationException(Res.GetString(Res.XmlDuplicateElementName, existing.Name, existing.Namespace));
                }
                else { 
                    #if DEBUG
                    if (!(accessor is AttributeAccessor)) 
                        throw new InvalidOperationException(Res.GetString(Res.XmlInternalErrorDetails, "Bad accessor type " + accessor.GetType().FullName)); 
                    #endif
                    throw new InvalidOperationException(Res.GetString(Res.XmlDuplicateAttributeName, existing.Name, existing.Namespace)); 
                }
            }
            else {
                scope[accessor.Name, accessor.Namespace] = accessor; 
            }
        } 
 
        static void AddUniqueAccessor(MemberMapping member, INameScope elements, INameScope attributes, bool isSequence) {
            if (member.Attribute != null) { 
                AddUniqueAccessor(attributes, member.Attribute);
            }
            else if (!isSequence && member.Elements != null && member.Elements.Length > 0) {
                for (int i = 0; i < member.Elements.Length; i++) { 
                    AddUniqueAccessor(elements, member.Elements[i]);
                } 
            } 
        }
 
        static void CheckForm(XmlSchemaForm form, bool isQualified) {
            if (isQualified && form == XmlSchemaForm.Unqualified) throw new InvalidOperationException(Res.GetString(Res.XmlInvalidFormUnqualified));
        }
 
        static void CheckNullable(bool isNullable, TypeDesc typeDesc, TypeMapping mapping) {
            if (mapping is NullableMapping) return; 
            if (mapping is SerializableMapping) return; 
            if (isNullable && !typeDesc.IsNullable) throw new InvalidOperationException(Res.GetString(Res.XmlInvalidIsNullable, typeDesc.FullName));
        } 

        static ElementAccessor CreateElementAccessor(TypeMapping mapping, string ns) {
            ElementAccessor element = new ElementAccessor();
            bool isAny = mapping.TypeDesc.Kind == TypeKind.Node; 
            if (!isAny && mapping is SerializableMapping) {
                isAny = ((SerializableMapping)mapping).IsAny; 
            } 
            if (isAny) {
                element.Any = true; 
            }
            else {
                element.Name = mapping.DefaultElementName;
                element.Namespace = ns; 
            }
            element.Mapping = mapping; 
            return element; 
        }
 
        // will create a shallow type mapping for a top-level type
        internal static XmlTypeMapping GetTopLevelMapping(Type type, string defaultNamespace) {
            XmlAttributes a = new XmlAttributes(type);
            TypeDesc typeDesc = new TypeScope().GetTypeDesc(type); 
            ElementAccessor element = new ElementAccessor();
 
            if (typeDesc.Kind == TypeKind.Node) { 
                element.Any = true;
            } 
            else {
                string ns = a.XmlRoot == null ? defaultNamespace : a.XmlRoot.Namespace;
                string typeName = string.Empty;
                if (a.XmlType != null) 
                    typeName = a.XmlType.TypeName;
                if (typeName.Length == 0) 
                    typeName = type.Name; 

                element.Name = XmlConvert.EncodeLocalName(typeName); 
                element.Namespace = ns;
            }
            XmlTypeMapping mapping = new XmlTypeMapping(null, element);
            mapping.SetKeyInternal(XmlMapping.GenerateKey(type, a.XmlRoot, defaultNamespace)); 
            return mapping;
        } 
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.


                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK