//------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. // // Microsoft //------------------------------------------------------------------------------ namespace System.Xml.Serialization { using System; using System.Collections; using System.IO; using System.ComponentModel; using System.Xml.Schema; using System.CodeDom; using System.CodeDom.Compiler; using System.Reflection; using System.Globalization; using System.Diagnostics; using System.Security.Permissions; using System.Xml.Serialization.Advanced; /// /// /// /// [To be supplied.] /// public class XmlCodeExporter : CodeExporter { /// /// /// [To be supplied.] /// public XmlCodeExporter(CodeNamespace codeNamespace) : base(codeNamespace, null, null, CodeGenerationOptions.GenerateProperties, null) {} /// /// /// [To be supplied.] /// public XmlCodeExporter(CodeNamespace codeNamespace, CodeCompileUnit codeCompileUnit) : base(codeNamespace, codeCompileUnit, null, CodeGenerationOptions.GenerateProperties, null) {} /// /// /// [To be supplied.] /// public XmlCodeExporter(CodeNamespace codeNamespace, CodeCompileUnit codeCompileUnit, CodeGenerationOptions options) : base(codeNamespace, codeCompileUnit, null, options, null) {} /// /// /// [To be supplied.] /// public XmlCodeExporter(CodeNamespace codeNamespace, CodeCompileUnit codeCompileUnit, CodeGenerationOptions options, Hashtable mappings) : base(codeNamespace, codeCompileUnit, null, options, mappings) {} /// /// /// [To be supplied.] /// public XmlCodeExporter(CodeNamespace codeNamespace, CodeCompileUnit codeCompileUnit, CodeDomProvider codeProvider, CodeGenerationOptions options, Hashtable mappings) : base(codeNamespace, codeCompileUnit, codeProvider, options, mappings) {} /// /// /// [To be supplied.] /// public void ExportTypeMapping(XmlTypeMapping xmlTypeMapping) { xmlTypeMapping.CheckShallow(); CheckScope(xmlTypeMapping.Scope); if (xmlTypeMapping.Accessor.Any) throw new InvalidOperationException(Res.GetString(Res.XmlIllegalWildcard)); ExportElement(xmlTypeMapping.Accessor); } /// /// /// [To be supplied.] /// public void ExportMembersMapping(XmlMembersMapping xmlMembersMapping) { xmlMembersMapping.CheckShallow(); CheckScope(xmlMembersMapping.Scope); for (int i = 0; i < xmlMembersMapping.Count; i++) { AccessorMapping mapping = xmlMembersMapping[i].Mapping; if (mapping.Xmlns == null) { if (mapping.Attribute != null) { ExportType(mapping.Attribute.Mapping, Accessor.UnescapeName(mapping.Attribute.Name), mapping.Attribute.Namespace, null, false); } if (mapping.Elements != null) { for (int j = 0; j < mapping.Elements.Length; j++) { ElementAccessor element = mapping.Elements[j]; ExportType(element.Mapping, Accessor.UnescapeName(element.Name), element.Namespace, null, false); } } if (mapping.Text != null) { ExportType(mapping.Text.Mapping, Accessor.UnescapeName(mapping.Text.Name), mapping.Text.Namespace, null, false); } } } } void ExportElement(ElementAccessor element) { ExportType(element.Mapping, Accessor.UnescapeName(element.Name), element.Namespace, element, true); } void ExportType(TypeMapping mapping, string ns) { ExportType(mapping, null, ns, null, true); } void ExportType(TypeMapping mapping, string name, string ns, ElementAccessor rootElement, bool checkReference) { if (mapping.IsReference && mapping.Namespace != Soap.Encoding) return; if (mapping is StructMapping && checkReference && ((StructMapping)mapping).ReferencedByTopLevelElement && rootElement == null) return; if (mapping is ArrayMapping && rootElement != null && rootElement.IsTopLevelInSchema && ((ArrayMapping)mapping).TopLevelMapping != null) { mapping = ((ArrayMapping)mapping).TopLevelMapping; } CodeTypeDeclaration codeClass = null; if (ExportedMappings[mapping] == null) { ExportedMappings.Add(mapping, mapping); if (mapping.TypeDesc.IsMappedType) { codeClass = mapping.TypeDesc.ExtendedType.ExportTypeDefinition(CodeNamespace, CodeCompileUnit); } else if (mapping is EnumMapping) { codeClass = ExportEnum((EnumMapping)mapping, typeof(XmlEnumAttribute)); } else if (mapping is StructMapping) { codeClass = ExportStruct((StructMapping)mapping); } else if (mapping is ArrayMapping) { EnsureTypesExported(((ArrayMapping)mapping).Elements, ns); } if (codeClass != null) { if (!mapping.TypeDesc.IsMappedType) { // Add [GeneratedCodeAttribute(Tool=.., Version=..)] codeClass.CustomAttributes.Add(GeneratedCodeAttribute); // Add [SerializableAttribute] codeClass.CustomAttributes.Add(new CodeAttributeDeclaration(typeof(SerializableAttribute).FullName)); if (!codeClass.IsEnum) { // Add [DebuggerStepThrough] codeClass.CustomAttributes.Add(new CodeAttributeDeclaration(typeof(DebuggerStepThroughAttribute).FullName)); // Add [DesignerCategory("code")] codeClass.CustomAttributes.Add(new CodeAttributeDeclaration(typeof(DesignerCategoryAttribute).FullName, new CodeAttributeArgument[] {new CodeAttributeArgument(new CodePrimitiveExpression("code"))})); } AddTypeMetadata(codeClass.CustomAttributes, typeof(XmlTypeAttribute), mapping.TypeDesc.Name, Accessor.UnescapeName(mapping.TypeName), mapping.Namespace, mapping.IncludeInSchema); } else if (FindAttributeDeclaration(typeof(GeneratedCodeAttribute), codeClass.CustomAttributes) == null) { // Add [GeneratedCodeAttribute(Tool=.., Version=..)] codeClass.CustomAttributes.Add(GeneratedCodeAttribute); } ExportedClasses.Add(mapping, codeClass); } } else codeClass = (CodeTypeDeclaration)ExportedClasses[mapping]; if (codeClass != null && rootElement != null) AddRootMetadata(codeClass.CustomAttributes, mapping, name, ns, rootElement); } void AddRootMetadata(CodeAttributeDeclarationCollection metadata, TypeMapping typeMapping, string name, string ns, ElementAccessor rootElement) { string rootAttrName = typeof(XmlRootAttribute).FullName; // check that we haven't already added a root attribute since we can only add one foreach (CodeAttributeDeclaration attr in metadata) { if (attr.Name == rootAttrName) return; } CodeAttributeDeclaration attribute = new CodeAttributeDeclaration(rootAttrName); if (typeMapping.TypeDesc.Name != name) { attribute.Arguments.Add(new CodeAttributeArgument(new CodePrimitiveExpression(name))); } if (ns != null) { attribute.Arguments.Add(new CodeAttributeArgument("Namespace", new CodePrimitiveExpression(ns))); } if (typeMapping.TypeDesc != null && typeMapping.TypeDesc.IsAmbiguousDataType) { attribute.Arguments.Add(new CodeAttributeArgument("DataType", new CodePrimitiveExpression(typeMapping.TypeDesc.DataType.Name))); } if ((object)(rootElement.IsNullable) != null) { attribute.Arguments.Add(new CodeAttributeArgument("IsNullable", new CodePrimitiveExpression((bool)rootElement.IsNullable))); } metadata.Add(attribute); } CodeAttributeArgument[] GetDefaultValueArguments(PrimitiveMapping mapping, object value, out CodeExpression initExpression) { initExpression = null; if (value == null) return null; CodeExpression valueExpression = null; CodeExpression typeofValue = null; Type type = value.GetType(); CodeAttributeArgument[] arguments = null; if (mapping is EnumMapping) { #if DEBUG // use exception in the place of Debug.Assert to avoid throwing asserts from a server process such as aspnet_ewp.exe if (value.GetType() != typeof(string)) throw new InvalidOperationException(Res.GetString(Res.XmlInternalErrorDetails, "Invalid enumeration type " + value.GetType().Name)); #endif if (((EnumMapping)mapping).IsFlags) { string[] values = ((string)value).Split(null); for (int i = 0; i < values.Length; i++) { if (values[i].Length == 0) continue; CodeExpression enumRef = new CodeFieldReferenceExpression(new CodeTypeReferenceExpression(mapping.TypeDesc.FullName), values[i]); if (valueExpression != null) valueExpression = new CodeBinaryOperatorExpression(valueExpression, CodeBinaryOperatorType.BitwiseOr, enumRef); else valueExpression = enumRef; } } else { valueExpression = new CodeFieldReferenceExpression(new CodeTypeReferenceExpression(mapping.TypeDesc.FullName), (string)value); } initExpression = valueExpression; arguments = new CodeAttributeArgument[] {new CodeAttributeArgument(valueExpression)}; } else if (type == typeof(bool) || type == typeof(Int32) || type == typeof(string) || type == typeof(double)) { initExpression = valueExpression = new CodePrimitiveExpression(value); arguments = new CodeAttributeArgument[] {new CodeAttributeArgument(valueExpression)}; } else if (type == typeof(Int16) || type == typeof(Int64) || type == typeof(float) || type == typeof(byte) || type == typeof(decimal)) { valueExpression = new CodePrimitiveExpression(Convert.ToString(value, NumberFormatInfo.InvariantInfo)); typeofValue = new CodeTypeOfExpression(type.FullName); arguments = new CodeAttributeArgument[] {new CodeAttributeArgument(typeofValue), new CodeAttributeArgument(valueExpression)}; initExpression = new CodeCastExpression(type.FullName, new CodePrimitiveExpression(value)); } else if (type == typeof(sbyte) || type == typeof(UInt16) || type == typeof(UInt32) || type == typeof(UInt64)) { // need to promote the non-CLS complient types value = PromoteType(type, value); valueExpression = new CodePrimitiveExpression(Convert.ToString(value, NumberFormatInfo.InvariantInfo)); typeofValue = new CodeTypeOfExpression(type.FullName); arguments = new CodeAttributeArgument[] {new CodeAttributeArgument(typeofValue), new CodeAttributeArgument(valueExpression)}; initExpression = new CodeCastExpression(type.FullName, new CodePrimitiveExpression(value)); } else if (type == typeof(DateTime)) { DateTime dt = (DateTime)value; string dtString; long ticks; if (mapping.TypeDesc.FormatterName == "Date") { dtString = XmlCustomFormatter.FromDate(dt); ticks = (new DateTime(dt.Year, dt.Month, dt.Day)).Ticks; } else if (mapping.TypeDesc.FormatterName == "Time") { dtString = XmlCustomFormatter.FromDateTime(dt); ticks = dt.Ticks; } else { dtString = XmlCustomFormatter.FromDateTime(dt); ticks = dt.Ticks; } valueExpression = new CodePrimitiveExpression(dtString); typeofValue = new CodeTypeOfExpression(type.FullName); arguments = new CodeAttributeArgument[] {new CodeAttributeArgument(typeofValue), new CodeAttributeArgument(valueExpression)}; initExpression = new CodeObjectCreateExpression(new CodeTypeReference(typeof(DateTime)), new CodeExpression[] {new CodePrimitiveExpression(ticks)}); } else if (type == typeof(Guid)) { valueExpression = new CodePrimitiveExpression(Convert.ToString(value, NumberFormatInfo.InvariantInfo)); typeofValue = new CodeTypeOfExpression(type.FullName); arguments = new CodeAttributeArgument[] {new CodeAttributeArgument(typeofValue), new CodeAttributeArgument(valueExpression)}; initExpression = new CodeObjectCreateExpression(new CodeTypeReference(typeof(Guid)), new CodeExpression[] {valueExpression}); } if (mapping.TypeDesc.FullName != type.ToString() && !(mapping is EnumMapping)) { // generate cast initExpression = new CodeCastExpression(mapping.TypeDesc.FullName, initExpression); } return arguments; } object ImportDefault(TypeMapping mapping, string defaultValue) { if (defaultValue == null) return null; if (mapping.IsList) { string[] vals = defaultValue.Trim().Split(null); // count all non-zero length values; int count = 0; for (int i = 0; i < vals.Length; i++) { if (vals[i] != null && vals[i].Length > 0) count++; } object[] values = new object[count]; count = 0; for (int i = 0; i < vals.Length; i++) { if (vals[i] != null && vals[i].Length > 0) { values[count++] = ImportDefaultValue(mapping, vals[i]); } } return values; } return ImportDefaultValue(mapping, defaultValue); } object ImportDefaultValue(TypeMapping mapping, string defaultValue) { if (defaultValue == null) return null; if (!(mapping is PrimitiveMapping)) return DBNull.Value; if (mapping is EnumMapping) { EnumMapping em = (EnumMapping)mapping; ConstantMapping[] c = em.Constants; if (em.IsFlags) { Hashtable values = new Hashtable(); string[] names = new string[c.Length]; long[] ids = new long[c.Length]; for (int i = 0; i < c.Length; i++) { ids[i] = em.IsFlags ? 1L << i : (long)i; names[i] = c[i].Name; values.Add(c[i].Name, ids[i]); } // this validates the values long val = XmlCustomFormatter.ToEnum(defaultValue, values, em.TypeName, true); return XmlCustomFormatter.FromEnum(val, names, ids, em.TypeDesc.FullName); } else { for (int i = 0; i < c.Length; i++) { if (c[i].XmlName == defaultValue) return c[i].Name; } } throw new InvalidOperationException(Res.GetString(Res.XmlInvalidDefaultValue, defaultValue, em.TypeDesc.FullName)); } // Primitive mapping PrimitiveMapping pm = (PrimitiveMapping)mapping; if (!pm.TypeDesc.HasCustomFormatter) { if (pm.TypeDesc.FormatterName == "String") return defaultValue; if (pm.TypeDesc.FormatterName == "DateTime") return XmlCustomFormatter.ToDateTime(defaultValue); Type formatter = typeof(XmlConvert); MethodInfo format = formatter.GetMethod("To" + pm.TypeDesc.FormatterName, new Type[] {typeof(string)}); if (format != null) { return format.Invoke(formatter, new Object[] {defaultValue}); } #if DEBUG Debug.WriteLineIf(DiagnosticsSwitches.XmlSerialization.TraceVerbose, "XmlSerialization::Failed to GetMethod " + formatter.Name + ".To" + pm.TypeDesc.FormatterName); #endif } else { if (pm.TypeDesc.HasDefaultSupport) { return XmlCustomFormatter.ToDefaultValue(defaultValue, pm.TypeDesc.FormatterName); } } return DBNull.Value; } void AddDefaultValueAttribute(CodeMemberField field, CodeAttributeDeclarationCollection metadata, object defaultValue, TypeMapping mapping, CodeCommentStatementCollection comments, TypeDesc memberTypeDesc, Accessor accessor, CodeConstructor ctor) { string attributeName = accessor.IsFixed ? "fixed" : "default"; if (!memberTypeDesc.HasDefaultSupport) { if (comments != null && defaultValue is string) { DropDefaultAttribute(accessor, comments, memberTypeDesc.FullName); // do not generate intializers for the user prefered types if they do not have default capability AddWarningComment(comments, Res.GetString(Res.XmlDropAttributeValue, attributeName, mapping.TypeName, defaultValue.ToString())); } return; } if (memberTypeDesc.IsArrayLike && accessor is ElementAccessor) { if (comments != null && defaultValue is string) { DropDefaultAttribute(accessor, comments, memberTypeDesc.FullName); // do not generate intializers for array-like types AddWarningComment(comments, Res.GetString(Res.XmlDropArrayAttributeValue, attributeName, defaultValue.ToString(), ((ElementAccessor)accessor).Name)); } return; } if (mapping.TypeDesc.IsMappedType && field != null && defaultValue is string) { SchemaImporterExtension extension = mapping.TypeDesc.ExtendedType.Extension; CodeExpression init = extension.ImportDefaultValue((string)defaultValue, mapping.TypeDesc.FullName); if (init != null) { if (ctor != null) { AddInitializationStatement(ctor, field, init); } else { field.InitExpression = extension.ImportDefaultValue((string)defaultValue, mapping.TypeDesc.FullName); } } if (comments != null) { DropDefaultAttribute(accessor, comments, mapping.TypeDesc.FullName); if (init == null) { AddWarningComment(comments, Res.GetString(Res.XmlNotKnownDefaultValue, extension.GetType().FullName, attributeName, (string)defaultValue, mapping.TypeName, mapping.Namespace)); } } return; } object value = null; if (defaultValue is string || defaultValue == null) { value = ImportDefault(mapping, (string)defaultValue); } if (value == null) return; if (!(mapping is PrimitiveMapping)) { if (comments != null) { DropDefaultAttribute(accessor, comments, memberTypeDesc.FullName); AddWarningComment(comments, Res.GetString(Res.XmlDropNonPrimitiveAttributeValue, attributeName, defaultValue.ToString())); } return; } PrimitiveMapping pm = (PrimitiveMapping)mapping; if (comments != null && !pm.TypeDesc.HasDefaultSupport && pm.TypeDesc.IsMappedType) { // do not generate intializers for the user prefered types if they do not have default capability DropDefaultAttribute(accessor, comments, pm.TypeDesc.FullName); return; } if (value == DBNull.Value) { if (comments != null) { AddWarningComment(comments, Res.GetString(Res.XmlDropAttributeValue, attributeName, pm.TypeName, defaultValue.ToString())); } return; } CodeAttributeArgument[] arguments = null; CodeExpression initExpression = null; if (pm.IsList) { #if DEBUG // use exception in the place of Debug.Assert to avoid throwing asserts from a server process such as aspnet_ewp.exe if (value.GetType() != typeof(object[])) throw new InvalidOperationException(Res.GetString(Res.XmlInternalErrorDetails, "Default value for list should be object[], not " + value.GetType().Name)); #endif object[] vals = (object[])value; CodeExpression[] initializers = new CodeExpression[vals.Length]; for (int i = 0; i < vals.Length; i++) { GetDefaultValueArguments(pm, vals[i], out initializers[i]); } initExpression = new CodeArrayCreateExpression(field.Type, initializers); } else { arguments = GetDefaultValueArguments(pm, value, out initExpression); } if (field != null) { if (ctor != null) { AddInitializationStatement(ctor, field, initExpression); } else { field.InitExpression = initExpression; } } if (arguments != null && pm.TypeDesc.HasDefaultSupport && accessor.IsOptional && !accessor.IsFixed) { // Add [DefaultValueAttribute] CodeAttributeDeclaration attribute = new CodeAttributeDeclaration(typeof(DefaultValueAttribute).FullName, arguments); metadata.Add(attribute); } else if (comments != null) { DropDefaultAttribute(accessor, comments, memberTypeDesc.FullName); } } static void AddInitializationStatement(CodeConstructor ctor, CodeMemberField field, CodeExpression init) { CodeAssignStatement assign = new CodeAssignStatement(); assign.Left = new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), field.Name); assign.Right = init; ctor.Statements.Add(assign); } static void DropDefaultAttribute(Accessor accessor, CodeCommentStatementCollection comments, string type) { if (!accessor.IsFixed && accessor.IsOptional) { AddWarningComment(comments, Res.GetString(Res.XmlDropDefaultAttribute, type)); } } CodeTypeDeclaration ExportStruct(StructMapping mapping) { if (mapping.TypeDesc.IsRoot) { ExportRoot(mapping, typeof(XmlIncludeAttribute)); return null; } string className = mapping.TypeDesc.Name; string baseName = mapping.TypeDesc.BaseTypeDesc == null || mapping.TypeDesc.BaseTypeDesc.IsRoot ? string.Empty : mapping.TypeDesc.BaseTypeDesc.FullName; CodeTypeDeclaration codeClass = new CodeTypeDeclaration(className); codeClass.IsPartial = CodeProvider.Supports(GeneratorSupport.PartialTypes); codeClass.Comments.Add(new CodeCommentStatement(Res.GetString(Res.XmlRemarks), true)); CodeNamespace.Types.Add(codeClass); CodeConstructor ctor = new CodeConstructor(); ctor.Attributes = (ctor.Attributes & ~MemberAttributes.AccessMask) | MemberAttributes.Public; codeClass.Members.Add(ctor); if (mapping.TypeDesc.IsAbstract) { ctor.Attributes |= MemberAttributes.Abstract; } if (baseName != null && baseName.Length > 0) { codeClass.BaseTypes.Add(baseName); } else AddPropertyChangedNotifier(codeClass); codeClass.TypeAttributes |= TypeAttributes.Public; if (mapping.TypeDesc.IsAbstract) { codeClass.TypeAttributes |= TypeAttributes.Abstract; } AddIncludeMetadata(codeClass.CustomAttributes, mapping, typeof(XmlIncludeAttribute)); if (mapping.IsSequence) { int generatedSequence = 0; for (int i = 0; i < mapping.Members.Length; i++) { MemberMapping member = mapping.Members[i]; if (member.IsParticle && member.SequenceId < 0) member.SequenceId = generatedSequence++; } } if (GenerateProperties) { for (int i = 0; i < mapping.Members.Length; i++) { ExportProperty(codeClass, mapping.Members[i], mapping.Namespace, mapping.Scope, ctor); } } else { for (int i = 0; i < mapping.Members.Length; i++) { ExportMember(codeClass, mapping.Members[i], mapping.Namespace, ctor); } } for (int i = 0; i < mapping.Members.Length; i++) { if (mapping.Members[i].Xmlns != null) continue; EnsureTypesExported(mapping.Members[i].Elements, mapping.Namespace); EnsureTypesExported(mapping.Members[i].Attribute, mapping.Namespace); EnsureTypesExported(mapping.Members[i].Text, mapping.Namespace); } if (mapping.BaseMapping != null) ExportType(mapping.BaseMapping, null, mapping.Namespace, null, false); ExportDerivedStructs(mapping); CodeGenerator.ValidateIdentifiers(codeClass); if (ctor.Statements.Count == 0) codeClass.Members.Remove(ctor); return codeClass; } [PermissionSet(SecurityAction.InheritanceDemand, Name="FullTrust")] internal override void ExportDerivedStructs(StructMapping mapping) { for (StructMapping derived = mapping.DerivedMappings; derived != null; derived = derived.NextDerivedMapping) ExportType(derived, mapping.Namespace); } /// /// /// [To be supplied.] /// public void AddMappingMetadata(CodeAttributeDeclarationCollection metadata, XmlTypeMapping mapping, string ns) { mapping.CheckShallow(); CheckScope(mapping.Scope); // For struct or enum mappings, we generate the XmlRoot on the struct/class/enum. For primitives // or arrays, there is nowhere to generate the XmlRoot, so we generate it elsewhere (on the // method for web services get/post). if (mapping.Mapping is StructMapping || mapping.Mapping is EnumMapping) return; AddRootMetadata(metadata, mapping.Mapping, Accessor.UnescapeName(mapping.Accessor.Name), mapping.Accessor.Namespace, mapping.Accessor); } /// /// /// [To be supplied.] /// public void AddMappingMetadata(CodeAttributeDeclarationCollection metadata, XmlMemberMapping member, string ns, bool forceUseMemberName) { AddMemberMetadata(null, metadata, member.Mapping, ns, forceUseMemberName, null, null); } /// /// /// [To be supplied.] /// public void AddMappingMetadata(CodeAttributeDeclarationCollection metadata, XmlMemberMapping member, string ns) { AddMemberMetadata(null, metadata, member.Mapping, ns, false, null, null); } void ExportArrayElements(CodeAttributeDeclarationCollection metadata, ArrayMapping array, string ns, TypeDesc elementTypeDesc, int nestingLevel) { for (int i = 0; i < array.Elements.Length; i++) { ElementAccessor arrayElement = array.Elements[i]; TypeMapping elementMapping = arrayElement.Mapping; string elementName = Accessor.UnescapeName(arrayElement.Name); bool sameName = arrayElement.Mapping.TypeDesc.IsArray ? false : elementName == arrayElement.Mapping.TypeName; bool sameElementType = elementMapping.TypeDesc == elementTypeDesc; bool sameElementNs = arrayElement.Form == XmlSchemaForm.Unqualified || arrayElement.Namespace == ns; bool sameNullable = arrayElement.IsNullable == elementMapping.TypeDesc.IsNullable; bool defaultForm = arrayElement.Form != XmlSchemaForm.Unqualified; if (!sameName || !sameElementType || !sameElementNs || !sameNullable || !defaultForm || nestingLevel > 0) ExportArrayItem(metadata, sameName ? null : elementName, sameElementNs ? null : arrayElement.Namespace, sameElementType ? null : elementMapping.TypeDesc, elementMapping.TypeDesc, arrayElement.IsNullable, defaultForm ? XmlSchemaForm.None : arrayElement.Form, nestingLevel); if (elementMapping is ArrayMapping) ExportArrayElements(metadata, (ArrayMapping) elementMapping, ns, elementTypeDesc.ArrayElementTypeDesc, nestingLevel+1); } } void AddMemberMetadata(CodeMemberField field, CodeAttributeDeclarationCollection metadata, MemberMapping member, string ns, bool forceUseMemberName, CodeCommentStatementCollection comments, CodeConstructor ctor) { if (member.Xmlns != null) { CodeAttributeDeclaration attribute = new CodeAttributeDeclaration(typeof(XmlNamespaceDeclarationsAttribute).FullName); metadata.Add(attribute); } else if (member.Attribute != null) { AttributeAccessor attribute = member.Attribute; if (attribute.Any) ExportAnyAttribute(metadata); else { TypeMapping mapping = (TypeMapping)attribute.Mapping; string attrName = Accessor.UnescapeName(attribute.Name); bool sameType = mapping.TypeDesc == member.TypeDesc || (member.TypeDesc.IsArrayLike && mapping.TypeDesc == member.TypeDesc.ArrayElementTypeDesc); bool sameName = attrName == member.Name && !forceUseMemberName; bool sameNs = attribute.Namespace == ns; bool defaultForm = attribute.Form != XmlSchemaForm.Qualified; ExportAttribute(metadata, sameName ? null : attrName, sameNs || defaultForm ? null : attribute.Namespace, sameType ? null : mapping.TypeDesc, mapping.TypeDesc, defaultForm ? XmlSchemaForm.None : attribute.Form); AddDefaultValueAttribute(field, metadata, attribute.Default, mapping, comments, member.TypeDesc, attribute, ctor); } } else { if (member.Text != null) { TypeMapping mapping = (TypeMapping)member.Text.Mapping; bool sameType = mapping.TypeDesc == member.TypeDesc || (member.TypeDesc.IsArrayLike && mapping.TypeDesc == member.TypeDesc.ArrayElementTypeDesc); ExportText(metadata, sameType ? null : mapping.TypeDesc, mapping.TypeDesc.IsAmbiguousDataType ? mapping.TypeDesc.DataType.Name : null); } if (member.Elements.Length == 1) { ElementAccessor element = member.Elements[0]; TypeMapping mapping = (TypeMapping)element.Mapping; string elemName = Accessor.UnescapeName(element.Name); bool sameName = ((elemName == member.Name) && !forceUseMemberName); bool isArray = mapping is ArrayMapping; bool sameNs = element.Namespace == ns; bool defaultForm = element.Form != XmlSchemaForm.Unqualified; if (element.Any) ExportAnyElement(metadata, elemName, element.Namespace, member.SequenceId); else if (isArray) { bool sameType = mapping.TypeDesc == member.TypeDesc; ArrayMapping array = (ArrayMapping)mapping; if (!sameName || !sameNs || element.IsNullable || !defaultForm || member.SequenceId != -1) ExportArray(metadata, sameName ? null : elemName, sameNs ? null : element.Namespace, element.IsNullable, defaultForm ? XmlSchemaForm.None : element.Form, member.SequenceId); else if (mapping.TypeDesc.ArrayElementTypeDesc == new TypeScope().GetTypeDesc(typeof(byte))) { // 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. ExportArray(metadata, null, null, false, XmlSchemaForm.None, member.SequenceId); } ExportArrayElements(metadata, array, element.Namespace, member.TypeDesc.ArrayElementTypeDesc, 0); } else { bool sameType = mapping.TypeDesc == member.TypeDesc || (member.TypeDesc.IsArrayLike && mapping.TypeDesc == member.TypeDesc.ArrayElementTypeDesc); if (member.TypeDesc.IsArrayLike) sameName = false; ExportElement(metadata, sameName ? null : elemName, sameNs ? null : element.Namespace, sameType ? null : mapping.TypeDesc, mapping.TypeDesc, element.IsNullable, defaultForm ? XmlSchemaForm.None : element.Form, member.SequenceId); } AddDefaultValueAttribute(field, metadata, element.Default, mapping, comments, member.TypeDesc, element, ctor); } else { for (int i = 0; i < member.Elements.Length; i++) { ElementAccessor element = member.Elements[i]; string elemName = Accessor.UnescapeName(element.Name); bool sameNs = element.Namespace == ns; if (element.Any) ExportAnyElement(metadata, elemName, element.Namespace, member.SequenceId); else { bool defaultForm = element.Form != XmlSchemaForm.Unqualified; ExportElement(metadata, elemName, sameNs ? null : element.Namespace, ((TypeMapping)element.Mapping).TypeDesc, ((TypeMapping)element.Mapping).TypeDesc, element.IsNullable, defaultForm ? XmlSchemaForm.None : element.Form, member.SequenceId); } } } if (member.ChoiceIdentifier != null) { CodeAttributeDeclaration attribute = new CodeAttributeDeclaration(typeof(XmlChoiceIdentifierAttribute).FullName); attribute.Arguments.Add(new CodeAttributeArgument(new CodePrimitiveExpression(member.ChoiceIdentifier.MemberName))); metadata.Add(attribute); } if (member.Ignore) { CodeAttributeDeclaration attribute = new CodeAttributeDeclaration(typeof(XmlIgnoreAttribute).FullName); metadata.Add(attribute); } } } void ExportMember(CodeTypeDeclaration codeClass, MemberMapping member, string ns, CodeConstructor ctor) { string fieldType = member.GetTypeName(CodeProvider); CodeMemberField field = new CodeMemberField(fieldType, member.Name); field.Attributes = (field.Attributes & ~MemberAttributes.AccessMask) | MemberAttributes.Public; field.Comments.Add(new CodeCommentStatement(Res.GetString(Res.XmlRemarks), true)); codeClass.Members.Add(field); AddMemberMetadata(field, field.CustomAttributes, member, ns, false, field.Comments, ctor); if (member.CheckSpecified != SpecifiedAccessor.None) { field = new CodeMemberField(typeof(bool).FullName, member.Name + "Specified"); field.Attributes = (field.Attributes & ~MemberAttributes.AccessMask) | MemberAttributes.Public; field.Comments.Add(new CodeCommentStatement(Res.GetString(Res.XmlRemarks), true)); CodeAttributeDeclaration attribute = new CodeAttributeDeclaration(typeof(XmlIgnoreAttribute).FullName); field.CustomAttributes.Add(attribute); codeClass.Members.Add(field); } } void ExportProperty(CodeTypeDeclaration codeClass, MemberMapping member, string ns, CodeIdentifiers memberScope, CodeConstructor ctor) { string fieldName = memberScope.AddUnique(MakeFieldName(member.Name), member); string fieldType = member.GetTypeName(CodeProvider); // need to create a private field CodeMemberField field = new CodeMemberField(fieldType, fieldName); field.Attributes = MemberAttributes.Private; codeClass.Members.Add(field); CodeMemberProperty prop = CreatePropertyDeclaration(field, member.Name, fieldType); prop.Comments.Add(new CodeCommentStatement(Res.GetString(Res.XmlRemarks), true)); AddMemberMetadata(field, prop.CustomAttributes, member, ns, false, prop.Comments, ctor); codeClass.Members.Add(prop); if (member.CheckSpecified != SpecifiedAccessor.None) { field = new CodeMemberField(typeof(bool).FullName, fieldName + "Specified"); field.Attributes = MemberAttributes.Private; codeClass.Members.Add(field); prop = CreatePropertyDeclaration(field, member.Name + "Specified", typeof(bool).FullName); prop.Comments.Add(new CodeCommentStatement(Res.GetString(Res.XmlRemarks), true)); CodeAttributeDeclaration attribute = new CodeAttributeDeclaration(typeof(XmlIgnoreAttribute).FullName); prop.CustomAttributes.Add(attribute); codeClass.Members.Add(prop); } } void ExportText(CodeAttributeDeclarationCollection metadata, TypeDesc typeDesc, string dataType) { CodeAttributeDeclaration attribute = new CodeAttributeDeclaration(typeof(XmlTextAttribute).FullName); if (typeDesc != null) { attribute.Arguments.Add(new CodeAttributeArgument(new CodeTypeOfExpression(typeDesc.FullName))); } if (dataType != null) { attribute.Arguments.Add(new CodeAttributeArgument("DataType", new CodePrimitiveExpression(dataType))); } metadata.Add(attribute); } void ExportAttribute(CodeAttributeDeclarationCollection metadata, string name, string ns, TypeDesc typeDesc, TypeDesc dataTypeDesc, XmlSchemaForm form) { ExportMetadata(metadata, typeof(XmlAttributeAttribute), name, ns, typeDesc, dataTypeDesc, null, form, 0, -1); } void ExportArrayItem(CodeAttributeDeclarationCollection metadata, string name, string ns, TypeDesc typeDesc, TypeDesc dataTypeDesc, bool isNullable, XmlSchemaForm form, int nestingLevel) { ExportMetadata(metadata, typeof(XmlArrayItemAttribute), name, ns, typeDesc, dataTypeDesc, isNullable ? null : (object)false, form, nestingLevel, -1); } void ExportElement(CodeAttributeDeclarationCollection metadata, string name, string ns, TypeDesc typeDesc, TypeDesc dataTypeDesc, bool isNullable, XmlSchemaForm form, int sequenceId) { ExportMetadata(metadata, typeof(XmlElementAttribute), name, ns, typeDesc, dataTypeDesc, isNullable ? (object)true : null, form, 0, sequenceId); } void ExportArray(CodeAttributeDeclarationCollection metadata, string name, string ns, bool isNullable, XmlSchemaForm form, int sequenceId) { ExportMetadata(metadata, typeof(XmlArrayAttribute), name, ns, null, null, isNullable ? (object)true : null, form, 0, sequenceId); } void ExportMetadata(CodeAttributeDeclarationCollection metadata, Type attributeType, string name, string ns, TypeDesc typeDesc, TypeDesc dataTypeDesc, object isNullable, XmlSchemaForm form, int nestingLevel, int sequenceId) { CodeAttributeDeclaration attribute = new CodeAttributeDeclaration(attributeType.FullName); if (name != null) { attribute.Arguments.Add(new CodeAttributeArgument(new CodePrimitiveExpression(name))); } if (typeDesc != null) { if (isNullable != null && (bool)isNullable && typeDesc.IsValueType && !typeDesc.IsMappedType && CodeProvider.Supports(GeneratorSupport.GenericTypeReference)) { attribute.Arguments.Add(new CodeAttributeArgument(new CodeTypeOfExpression("System.Nullable`1[" + typeDesc.FullName + "]"))); isNullable = null; } else { attribute.Arguments.Add(new CodeAttributeArgument(new CodeTypeOfExpression(typeDesc.FullName))); } } if (form != XmlSchemaForm.None) { attribute.Arguments.Add(new CodeAttributeArgument("Form", new CodeFieldReferenceExpression(new CodeTypeReferenceExpression(typeof(XmlSchemaForm).FullName), Enum.Format(typeof(XmlSchemaForm), form, "G")))); if (form == XmlSchemaForm.Unqualified && ns != null && ns.Length == 0) { ns = null; } } if (ns != null ) { attribute.Arguments.Add(new CodeAttributeArgument("Namespace", new CodePrimitiveExpression(ns))); } if (dataTypeDesc != null && dataTypeDesc.IsAmbiguousDataType && !dataTypeDesc.IsMappedType) { attribute.Arguments.Add(new CodeAttributeArgument("DataType", new CodePrimitiveExpression(dataTypeDesc.DataType.Name))); } if (isNullable != null) { attribute.Arguments.Add(new CodeAttributeArgument("IsNullable", new CodePrimitiveExpression((bool)isNullable))); } if (nestingLevel > 0) { attribute.Arguments.Add(new CodeAttributeArgument("NestingLevel", new CodePrimitiveExpression(nestingLevel))); } if (sequenceId >= 0) { attribute.Arguments.Add(new CodeAttributeArgument("Order", new CodePrimitiveExpression(sequenceId))); } if (attribute.Arguments.Count == 0 && attributeType == typeof(XmlElementAttribute)) return; metadata.Add(attribute); } void ExportAnyElement(CodeAttributeDeclarationCollection metadata, string name, string ns, int sequenceId) { CodeAttributeDeclaration attribute = new CodeAttributeDeclaration(typeof(XmlAnyElementAttribute).FullName); if (name != null && name.Length > 0) { attribute.Arguments.Add(new CodeAttributeArgument("Name", new CodePrimitiveExpression(name))); } if (ns != null) { attribute.Arguments.Add(new CodeAttributeArgument("Namespace", new CodePrimitiveExpression(ns))); } if (sequenceId >= 0) { attribute.Arguments.Add(new CodeAttributeArgument("Order", new CodePrimitiveExpression(sequenceId))); } metadata.Add(attribute); } void ExportAnyAttribute(CodeAttributeDeclarationCollection metadata) { metadata.Add(new CodeAttributeDeclaration(typeof(XmlAnyAttributeAttribute).FullName)); } internal override void EnsureTypesExported(Accessor[] accessors, string ns) { if (accessors == null) return; for (int i = 0; i < accessors.Length; i++) EnsureTypesExported(accessors[i], ns); } void EnsureTypesExported(Accessor accessor, string ns) { if (accessor == null) return; ExportType(accessor.Mapping, null, ns, null, false); } } }