1 //------------------------------------------------------------------------------
2 // <copyright file="Mappings.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
5 // <owner current="true" primary="true">Microsoft</owner>
6 //------------------------------------------------------------------------------
8 namespace System.Xml.Serialization {
10 using System.Reflection;
11 using System.Collections;
12 using System.Xml.Schema;
15 using System.ComponentModel;
17 using System.CodeDom.Compiler;
19 // These classes represent a mapping between classes and a particular XML format.
20 // There are two class of mapping information: accessors (such as elements and
21 // attributes), and mappings (which specify the type of an accessor).
23 internal abstract class Accessor {
25 object defaultValue = null;
30 bool topLevelInSchema;
33 XmlSchemaForm form = XmlSchemaForm.None;
35 internal Accessor() { }
37 internal TypeMapping Mapping {
38 get { return mapping; }
39 set { mapping = value; }
42 internal object Default {
43 get { return defaultValue; }
44 set { defaultValue = value; }
47 internal bool HasDefault {
48 get { return defaultValue != null && defaultValue != DBNull.Value; }
51 internal virtual string Name {
52 get { return name == null ? string.Empty : name; }
61 internal string AnyNamespaces {
63 set { anyNs = value; }
66 internal string Namespace {
71 internal XmlSchemaForm Form {
76 internal bool IsFixed {
77 get { return isFixed; }
78 set { isFixed = value; }
81 internal bool IsOptional {
82 get { return isOptional; }
83 set { isOptional = value; }
86 internal bool IsTopLevelInSchema {
87 get { return topLevelInSchema; }
88 set { topLevelInSchema = value; }
91 internal static string EscapeName(string name) {
92 if (name == null || name.Length == 0) return name;
93 return XmlConvert.EncodeLocalName(name);
96 internal static string EscapeQName(string name) {
97 if (name == null || name.Length == 0) return name;
98 int colon = name.LastIndexOf(':');
100 return XmlConvert.EncodeLocalName(name);
102 if (colon == 0 || colon == name.Length - 1)
103 throw new ArgumentException(Res.GetString(Res.Xml_InvalidNameChars, name), "name");
104 return new XmlQualifiedName(XmlConvert.EncodeLocalName(name.Substring(colon + 1)), XmlConvert.EncodeLocalName(name.Substring(0, colon))).ToString();
108 internal static string UnescapeName(string name) {
109 return XmlConvert.DecodeName(name);
112 internal string ToString(string defaultNs) {
114 return (Namespace == null ? "##any" : Namespace) + ":" + Name;
117 return Namespace == defaultNs ? Name : Namespace + ":" + Name;
122 internal class ElementAccessor : Accessor {
125 bool unbounded = false;
127 internal bool IsSoap {
128 get { return isSoap; }
129 set { isSoap = value; }
132 internal bool IsNullable {
133 get { return nullable; }
134 set { nullable = value; }
137 internal bool IsUnbounded {
138 get { return unbounded; }
139 set { unbounded = value; }
142 internal ElementAccessor Clone() {
143 ElementAccessor newAccessor = new ElementAccessor();
144 newAccessor.nullable = this.nullable;
145 newAccessor.IsTopLevelInSchema = this.IsTopLevelInSchema;
146 newAccessor.Form = this.Form;
147 newAccessor.isSoap = this.isSoap;
148 newAccessor.Name = this.Name;
149 newAccessor.Default = this.Default;
150 newAccessor.Namespace = this.Namespace;
151 newAccessor.Mapping = this.Mapping;
152 newAccessor.Any = this.Any;
158 internal class ChoiceIdentifierAccessor : Accessor {
161 MemberInfo memberInfo;
163 internal string MemberName {
164 get { return memberName; }
165 set { memberName = value; }
168 internal string[] MemberIds {
169 get { return memberIds; }
170 set { memberIds = value; }
173 internal MemberInfo MemberInfo {
174 get { return memberInfo; }
175 set { memberInfo = value; }
179 internal class TextAccessor : Accessor {
182 internal class XmlnsAccessor : Accessor {
185 internal class AttributeAccessor : Accessor {
189 internal bool IsSpecialXmlNamespace {
190 get { return isSpecial; }
193 internal bool IsList {
194 get { return isList; }
195 set { isList = value; }
198 internal void CheckSpecial() {
199 int colon = Name.LastIndexOf(':');
202 if (!Name.StartsWith("xml:", StringComparison.Ordinal)) {
203 throw new InvalidOperationException(Res.GetString(Res.Xml_InvalidNameChars, Name));
205 Name = Name.Substring("xml:".Length);
206 Namespace = XmlReservedNs.NsXml;
210 if (Namespace == XmlReservedNs.NsXml) {
218 Form = XmlSchemaForm.Qualified;
223 internal abstract class Mapping {
226 internal Mapping() { }
228 protected Mapping(Mapping mapping)
230 this.isSoap = mapping.isSoap;
233 internal bool IsSoap {
234 get { return isSoap; }
235 set { isSoap = value; }
239 internal abstract class TypeMapping : Mapping {
243 bool referencedByElement;
244 bool referencedByTopLevelElement;
245 bool includeInSchema = true;
246 bool reference = false;
248 internal bool ReferencedByTopLevelElement {
249 get { return referencedByTopLevelElement; }
250 set { referencedByTopLevelElement = value; }
253 internal bool ReferencedByElement {
254 get { return referencedByElement || referencedByTopLevelElement; }
255 set { referencedByElement = value; }
257 internal string Namespace {
258 get { return typeNs; }
259 set { typeNs = value; }
262 internal string TypeName {
263 get { return typeName; }
264 set { typeName = value; }
267 internal TypeDesc TypeDesc {
268 get { return typeDesc; }
269 set { typeDesc = value; }
272 internal bool IncludeInSchema {
273 get { return includeInSchema; }
274 set { includeInSchema = value; }
277 internal virtual bool IsList {
278 get { return false; }
282 internal bool IsReference {
283 get { return reference; }
284 set { reference = value; }
287 internal bool IsAnonymousType {
288 get { return typeName == null || typeName.Length == 0; }
291 internal virtual string DefaultElementName {
292 get { return IsAnonymousType ? XmlConvert.EncodeLocalName(typeDesc.Name) : typeName; }
296 internal class PrimitiveMapping : TypeMapping {
299 internal override bool IsList {
300 get { return isList; }
301 set { isList = value; }
305 internal class NullableMapping : TypeMapping {
306 TypeMapping baseMapping;
308 internal TypeMapping BaseMapping {
309 get { return baseMapping; }
310 set { baseMapping = value; }
313 internal override string DefaultElementName {
314 get { return BaseMapping.DefaultElementName; }
318 internal class ArrayMapping : TypeMapping {
319 ElementAccessor[] elements;
320 ElementAccessor[] sortedElements;
322 StructMapping topLevelMapping;
324 internal ElementAccessor[] Elements {
325 get { return elements; }
326 set { elements = value; sortedElements = null; }
329 internal ElementAccessor[] ElementsSortedByDerivation {
331 if (sortedElements != null)
332 return sortedElements;
333 if (elements == null)
335 sortedElements = new ElementAccessor[elements.Length];
336 Array.Copy(elements, 0, sortedElements, 0, elements.Length);
337 AccessorMapping.SortMostToLeastDerived(sortedElements);
338 return sortedElements;
343 internal ArrayMapping Next {
345 set { next = value; }
348 internal StructMapping TopLevelMapping {
349 get { return topLevelMapping; }
350 set { topLevelMapping = value; }
354 internal class EnumMapping : PrimitiveMapping {
355 ConstantMapping[] constants;
358 internal bool IsFlags {
359 get { return isFlags; }
360 set { isFlags = value; }
363 internal ConstantMapping[] Constants {
364 get { return constants; }
365 set { constants = value; }
369 internal class ConstantMapping : Mapping {
374 internal string XmlName {
375 get { return xmlName == null ? string.Empty : xmlName; }
376 set { xmlName = value; }
379 internal string Name {
380 get { return name == null ? string.Empty : name; }
381 set { this.name = value; }
384 internal long Value {
385 get { return value; }
386 set { this.value = value; }
390 internal class StructMapping : TypeMapping, INameScope {
391 MemberMapping[] members;
392 StructMapping baseMapping;
393 StructMapping derivedMappings;
394 StructMapping nextDerivedMapping;
395 MemberMapping xmlnsMember = null;
396 bool hasSimpleContent;
400 NameTable attributes;
401 CodeIdentifiers scope;
403 internal StructMapping BaseMapping {
404 get { return baseMapping; }
407 if (!IsAnonymousType && baseMapping != null) {
408 nextDerivedMapping = baseMapping.derivedMappings;
409 baseMapping.derivedMappings = this;
411 if (value.isSequence && !isSequence) {
413 if (baseMapping.IsSequence) {
414 for (StructMapping derived = derivedMappings; derived != null; derived = derived.NextDerivedMapping) {
415 derived.SetSequence();
422 internal StructMapping DerivedMappings {
423 get { return derivedMappings; }
426 internal bool IsFullyInitialized {
427 get { return baseMapping != null && Members != null; }
430 internal NameTable LocalElements {
432 if (elements == null)
433 elements = new NameTable();
437 internal NameTable LocalAttributes {
439 if (attributes == null)
440 attributes = new NameTable();
444 object INameScope.this[string name, string ns] {
446 object named = LocalElements[name, ns];
449 if (baseMapping != null)
450 return ((INameScope)baseMapping)[name, ns];
454 LocalElements[name, ns] = value;
457 internal StructMapping NextDerivedMapping {
458 get { return nextDerivedMapping; }
461 internal bool HasSimpleContent {
462 get { return hasSimpleContent; }
465 internal bool HasXmlnsMember {
467 StructMapping mapping = this;
468 while (mapping != null) {
469 if (mapping.XmlnsMember != null)
471 mapping = mapping.BaseMapping;
477 internal MemberMapping[] Members {
478 get { return members; }
479 set { members = value; }
482 internal MemberMapping XmlnsMember {
483 get { return xmlnsMember; }
484 set { xmlnsMember = value; }
487 internal bool IsOpenModel {
488 get { return openModel; }
489 set { openModel = value; }
492 internal CodeIdentifiers Scope {
495 scope = new CodeIdentifiers();
498 set { scope = value; }
501 internal MemberMapping FindDeclaringMapping(MemberMapping member, out StructMapping declaringMapping, string parent) {
502 declaringMapping = null;
503 if (BaseMapping != null) {
504 MemberMapping baseMember = BaseMapping.FindDeclaringMapping(member, out declaringMapping, parent);
505 if (baseMember != null) return baseMember;
507 if (members == null) return null;
509 for (int i = 0; i < members.Length; i++) {
510 if (members[i].Name == member.Name) {
511 if (members[i].TypeDesc != member.TypeDesc)
512 throw new InvalidOperationException(Res.GetString(Res.XmlHiddenMember, parent, member.Name, member.TypeDesc.FullName, this.TypeName, members[i].Name, members[i].TypeDesc.FullName));
513 else if (!members[i].Match(member)) {
514 throw new InvalidOperationException(Res.GetString(Res.XmlInvalidXmlOverride, parent, member.Name, this.TypeName, members[i].Name));
516 declaringMapping = this;
522 internal bool Declares(MemberMapping member, string parent) {
524 return (FindDeclaringMapping(member, out m, parent) != null);
527 internal void SetContentModel(TextAccessor text, bool hasElements) {
528 if (BaseMapping == null || BaseMapping.TypeDesc.IsRoot) {
529 hasSimpleContent = !hasElements && text != null && !text.Mapping.IsList;
531 else if (BaseMapping.HasSimpleContent) {
532 if (text != null || hasElements) {
533 // we can only extent a simleContent type with attributes
534 throw new InvalidOperationException(Res.GetString(Res.XmlIllegalSimpleContentExtension, TypeDesc.FullName, BaseMapping.TypeDesc.FullName));
537 hasSimpleContent = true;
541 hasSimpleContent = false;
543 if (!hasSimpleContent && text != null && !text.Mapping.TypeDesc.CanBeTextValue) {
544 throw new InvalidOperationException(Res.GetString(Res.XmlIllegalTypedTextAttribute, TypeDesc.FullName, text.Name, text.Mapping.TypeDesc.FullName));
548 internal bool HasElements {
549 get { return elements != null && elements.Values.Count > 0; }
552 internal bool HasExplicitSequence() {
553 if (members != null) {
554 for (int i = 0; i < members.Length; i++) {
555 if (members[i].IsParticle && members[i].IsSequence) {
560 return (baseMapping != null && baseMapping.HasExplicitSequence());
563 internal void SetSequence() {
567 StructMapping start = this;
569 // find first mapping that does not have the sequence set
570 while (!start.BaseMapping.IsSequence && start.BaseMapping != null && !start.BaseMapping.TypeDesc.IsRoot)
571 start = start.BaseMapping;
573 start.IsSequence = true;
574 for (StructMapping derived = start.DerivedMappings; derived != null; derived = derived.NextDerivedMapping) {
575 derived.SetSequence();
579 internal bool IsSequence {
580 get { return isSequence && !TypeDesc.IsRoot; }
581 set { isSequence = value; }
585 internal abstract class AccessorMapping : Mapping {
587 AttributeAccessor attribute;
588 ElementAccessor[] elements;
589 ElementAccessor[] sortedElements;
591 ChoiceIdentifierAccessor choiceIdentifier;
595 internal AccessorMapping()
598 protected AccessorMapping(AccessorMapping mapping)
601 this.typeDesc = mapping.typeDesc;
602 this.attribute = mapping.attribute;
603 this.elements = mapping.elements;
604 this.sortedElements = mapping.sortedElements;
605 this.text = mapping.text;
606 this.choiceIdentifier = mapping.choiceIdentifier;
607 this.xmlns = mapping.xmlns;
608 this.ignore = mapping.ignore;
611 internal bool IsAttribute {
612 get { return attribute != null; }
615 internal bool IsText {
616 get { return text != null && (elements == null || elements.Length == 0); }
619 internal bool IsParticle {
620 get { return (elements != null && elements.Length > 0); }
623 internal TypeDesc TypeDesc {
624 get { return typeDesc; }
625 set { typeDesc = value; }
628 internal AttributeAccessor Attribute {
629 get { return attribute; }
630 set { attribute = value; }
633 internal ElementAccessor[] Elements {
634 get { return elements; }
635 set { elements = value; sortedElements = null; }
638 internal static void SortMostToLeastDerived(ElementAccessor[] elements) {
639 Array.Sort(elements, new AccessorComparer());
642 internal class AccessorComparer : IComparer {
643 public int Compare(object o1, object o2) {
646 Accessor a1 = (Accessor)o1;
647 Accessor a2 = (Accessor)o2;
648 int w1 = a1.Mapping.TypeDesc.Weight;
649 int w2 = a2.Mapping.TypeDesc.Weight;
658 internal ElementAccessor[] ElementsSortedByDerivation {
660 if (sortedElements != null)
661 return sortedElements;
662 if (elements == null)
664 sortedElements = new ElementAccessor[elements.Length];
665 Array.Copy(elements, 0, sortedElements, 0, elements.Length);
666 SortMostToLeastDerived(sortedElements);
667 return sortedElements;
671 internal TextAccessor Text {
673 set { text = value; }
676 internal ChoiceIdentifierAccessor ChoiceIdentifier {
677 get { return choiceIdentifier; }
678 set { choiceIdentifier = value; }
681 internal XmlnsAccessor Xmlns {
682 get { return xmlns; }
683 set { xmlns = value; }
686 internal bool Ignore {
687 get { return ignore; }
688 set { ignore = value; }
691 internal Accessor Accessor {
693 if (xmlns != null) return xmlns;
694 if (attribute != null) return attribute;
695 if (elements != null && elements.Length > 0) return elements[0];
700 static bool IsNeedNullableMember(ElementAccessor element) {
701 if (element.Mapping is ArrayMapping) {
702 ArrayMapping arrayMapping = (ArrayMapping)element.Mapping;
703 if (arrayMapping.Elements != null && arrayMapping.Elements.Length == 1) {
704 return IsNeedNullableMember(arrayMapping.Elements[0]);
709 return element.IsNullable && element.Mapping.TypeDesc.IsValueType;
713 internal bool IsNeedNullable {
715 if (xmlns != null) return false;
716 if (attribute != null) return false;
717 if (elements != null && elements.Length == 1) {
718 return IsNeedNullableMember(elements[0]);
724 internal static bool ElementsMatch(ElementAccessor[] a, ElementAccessor[] b) {
732 if (a.Length != b.Length)
734 for (int i = 0; i < a.Length; i++) {
735 if (a[i].Name != b[i].Name || a[i].Namespace != b[i].Namespace || a[i].Form != b[i].Form || a[i].IsNullable != b[i].IsNullable)
741 internal bool Match(AccessorMapping mapping) {
742 if (Elements != null && Elements.Length > 0) {
743 if (!ElementsMatch(Elements, mapping.Elements)) {
747 return (mapping.Text == null);
750 if (Attribute != null) {
751 if (mapping.Attribute == null)
753 return (Attribute.Name == mapping.Attribute.Name && Attribute.Namespace == mapping.Attribute.Namespace && Attribute.Form == mapping.Attribute.Form);
756 return (mapping.Text != null);
758 return (mapping.Accessor == null);
762 internal class MemberMappingComparer : IComparer {
763 public int Compare(object o1, object o2) {
764 MemberMapping m1 = (MemberMapping)o1;
765 MemberMapping m2 = (MemberMapping)o2;
767 bool m1Text = m1.IsText;
776 if (m1.SequenceId < 0 && m2.SequenceId < 0)
778 if (m1.SequenceId < 0)
780 if (m2.SequenceId < 0)
782 if (m1.SequenceId < m2.SequenceId)
784 if (m1.SequenceId > m2.SequenceId)
790 internal class MemberMapping : AccessorMapping {
792 bool checkShouldPersist;
793 SpecifiedAccessor checkSpecified;
795 bool readOnly = false;
797 MemberInfo memberInfo;
798 MemberInfo checkSpecifiedMemberInfo;
799 MethodInfo checkShouldPersistMethodInfo;
801 internal MemberMapping() { }
803 MemberMapping(MemberMapping mapping)
806 this.name = mapping.name;
807 this.checkShouldPersist = mapping.checkShouldPersist;
808 this.checkSpecified = mapping.checkSpecified;
809 this.isReturnValue = mapping.isReturnValue;
810 this.readOnly = mapping.readOnly;
811 this.sequenceId = mapping.sequenceId;
812 this.memberInfo = mapping.memberInfo;
813 this.checkSpecifiedMemberInfo = mapping.checkSpecifiedMemberInfo;
814 this.checkShouldPersistMethodInfo = mapping.checkShouldPersistMethodInfo;
817 internal bool CheckShouldPersist {
818 get { return checkShouldPersist; }
819 set { checkShouldPersist = value; }
822 internal SpecifiedAccessor CheckSpecified {
823 get { return checkSpecified; }
824 set { checkSpecified = value; }
827 internal string Name {
828 get { return name == null ? string.Empty : name; }
829 set { name = value; }
832 internal MemberInfo MemberInfo {
833 get { return memberInfo; }
834 set { memberInfo = value; }
837 internal MemberInfo CheckSpecifiedMemberInfo {
838 get { return checkSpecifiedMemberInfo; }
839 set { checkSpecifiedMemberInfo = value; }
842 internal MethodInfo CheckShouldPersistMethodInfo {
843 get { return checkShouldPersistMethodInfo; }
844 set { checkShouldPersistMethodInfo = value; }
847 internal bool IsReturnValue {
848 get { return isReturnValue; }
849 set { isReturnValue = value; }
852 internal bool ReadOnly {
853 get { return readOnly; }
854 set { readOnly = value; }
857 internal bool IsSequence {
858 get { return sequenceId >= 0; }
861 internal int SequenceId {
862 get { return sequenceId; }
863 set { sequenceId = value; }
866 string GetNullableType(TypeDesc td) {
867 // SOAP encoded arrays not mapped to Nullable<T> since they always derive from soapenc:Array
868 if (td.IsMappedType || (!td.IsValueType && (Elements[0].IsSoap || td.ArrayElementTypeDesc == null)))
870 if (td.ArrayElementTypeDesc != null) {
871 return GetNullableType(td.ArrayElementTypeDesc) + "[]";
873 return "System.Nullable`1[" + td.FullName + "]";
876 internal MemberMapping Clone()
878 return new MemberMapping(this);
881 internal string GetTypeName(CodeDomProvider codeProvider) {
882 if (IsNeedNullable && codeProvider.Supports(GeneratorSupport.GenericTypeReference)) {
883 return GetNullableType(TypeDesc);
885 return TypeDesc.FullName;
889 internal class MembersMapping : TypeMapping {
890 MemberMapping[] members;
891 bool hasWrapperElement = true;
892 bool validateRpcWrapperElement;
893 bool writeAccessors = true;
894 MemberMapping xmlnsMember = null;
896 internal MemberMapping[] Members {
897 get { return members; }
898 set { members = value; }
901 internal MemberMapping XmlnsMember {
902 get { return xmlnsMember; }
903 set { xmlnsMember = value; }
906 internal bool HasWrapperElement {
907 get { return hasWrapperElement; }
908 set { hasWrapperElement = value; }
911 internal bool ValidateRpcWrapperElement {
912 get { return validateRpcWrapperElement; }
913 set { validateRpcWrapperElement = value; }
916 internal bool WriteAccessors {
917 get { return writeAccessors; }
918 set { writeAccessors = value; }
922 internal class SpecialMapping : TypeMapping {
925 internal bool NamedAny {
926 get { return namedAny; }
927 set { namedAny = value; }
931 internal class SerializableMapping : SpecialMapping {
934 bool needSchema = true;
936 // new implementation of the IXmlSerializable
937 MethodInfo getSchemaMethod;
938 XmlQualifiedName xsiType;
939 XmlSchemaType xsdType;
940 XmlSchemaSet schemas;
944 SerializableMapping baseMapping;
945 SerializableMapping derivedMappings;
946 SerializableMapping nextDerivedMapping;
947 SerializableMapping next; // all mappings with the same qname
949 internal SerializableMapping() { }
950 internal SerializableMapping(MethodInfo getSchemaMethod, bool any, string ns) {
951 this.getSchemaMethod = getSchemaMethod;
954 needSchema = getSchemaMethod != null;
957 internal SerializableMapping(XmlQualifiedName xsiType, XmlSchemaSet schemas) {
958 this.xsiType = xsiType;
959 this.schemas = schemas;
960 this.TypeName = xsiType.Name;
961 this.Namespace = xsiType.Namespace;
965 internal void SetBaseMapping(SerializableMapping mapping) {
966 baseMapping = mapping;
967 if (baseMapping != null) {
968 nextDerivedMapping = baseMapping.derivedMappings;
969 baseMapping.derivedMappings = this;
970 if (this == nextDerivedMapping) {
971 throw new InvalidOperationException(Res.GetString(Res.XmlCircularDerivation, TypeDesc.FullName));
976 internal bool IsAny {
980 if (getSchemaMethod == null)
982 if (needSchema && typeof(XmlSchemaType).IsAssignableFrom(getSchemaMethod.ReturnType))
984 RetrieveSerializableSchema();
989 internal string NamespaceList {
991 RetrieveSerializableSchema();
992 if (namespaces == null) {
993 if (schemas != null) {
994 StringBuilder anyNamespaces = new StringBuilder();
995 foreach (XmlSchema s in schemas.Schemas()) {
996 if (s.TargetNamespace != null && s.TargetNamespace.Length > 0) {
997 if (anyNamespaces.Length > 0)
998 anyNamespaces.Append(" ");
999 anyNamespaces.Append(s.TargetNamespace);
1002 namespaces = anyNamespaces.ToString();
1005 namespaces = string.Empty;
1012 internal SerializableMapping DerivedMappings {
1014 return derivedMappings;
1018 internal SerializableMapping NextDerivedMapping {
1020 return nextDerivedMapping;
1024 internal SerializableMapping Next {
1025 get { return next; }
1026 set { next = value; }
1029 internal Type Type {
1030 get { return type; }
1031 set { type = value; }
1034 internal XmlSchemaSet Schemas {
1036 RetrieveSerializableSchema();
1041 internal XmlSchema Schema {
1043 RetrieveSerializableSchema();
1048 internal XmlQualifiedName XsiType {
1052 if (getSchemaMethod == null)
1054 if (typeof(XmlSchemaType).IsAssignableFrom(getSchemaMethod.ReturnType))
1056 RetrieveSerializableSchema();
1061 internal XmlSchemaType XsdType {
1063 RetrieveSerializableSchema();
1068 internal static void ValidationCallbackWithErrorCode(object sender, ValidationEventArgs args) {
1070 if (args.Severity == XmlSeverityType.Error)
1071 throw new InvalidOperationException(Res.GetString(Res.XmlSerializableSchemaError, typeof(IXmlSerializable).Name, args.Message));
1074 internal void CheckDuplicateElement(XmlSchemaElement element, string elementNs) {
1075 if (element == null)
1078 // only check duplicate definitions for top-level element
1079 if (element.Parent == null || !(element.Parent is XmlSchema))
1082 XmlSchemaObjectTable elements = null;
1083 if (Schema != null && Schema.TargetNamespace == elementNs) {
1084 XmlSchemas.Preprocess(Schema);
1085 elements = Schema.Elements;
1087 else if (Schemas != null) {
1088 elements = Schemas.GlobalElements;
1093 foreach (XmlSchemaElement e in elements.Values) {
1094 if (e.Name == element.Name && e.QualifiedName.Namespace == elementNs) {
1095 if (Match(e, element))
1097 // XmlSerializableRootDupName=Cannot reconcile schema for '{0}'. Please use [XmlRoot] attribute to change name or namepace of the top-level element to avoid duplicate element declarations: element name='{1} namespace='{2}'.
1098 throw new InvalidOperationException(Res.GetString(Res.XmlSerializableRootDupName, getSchemaMethod.DeclaringType.FullName, e.Name, elementNs));
1103 bool Match(XmlSchemaElement e1, XmlSchemaElement e2) {
1104 if (e1.IsNillable != e2.IsNillable)
1106 if (e1.RefName != e2.RefName)
1108 if (e1.SchemaType != e2.SchemaType)
1110 if (e1.SchemaTypeName != e2.SchemaTypeName)
1112 if (e1.MinOccurs != e2.MinOccurs)
1114 if (e1.MaxOccurs != e2.MaxOccurs)
1116 if (e1.IsAbstract != e2.IsAbstract)
1118 if (e1.DefaultValue != e2.DefaultValue)
1120 if (e1.SubstitutionGroup != e2.SubstitutionGroup)
1125 void RetrieveSerializableSchema() {
1128 if (getSchemaMethod != null) {
1129 // get the type info
1130 if (schemas == null)
1131 schemas = new XmlSchemaSet();
1132 object typeInfo = getSchemaMethod.Invoke(null, new object[] { schemas });
1133 xsiType = XmlQualifiedName.Empty;
1135 if (typeInfo != null) {
1136 if (typeof(XmlSchemaType).IsAssignableFrom(getSchemaMethod.ReturnType)) {
1137 xsdType = (XmlSchemaType)typeInfo;
1138 // check if type is named
1139 xsiType = xsdType.QualifiedName;
1141 else if (typeof(XmlQualifiedName).IsAssignableFrom(getSchemaMethod.ReturnType)) {
1142 xsiType = (XmlQualifiedName)typeInfo;
1143 if (xsiType.IsEmpty) {
1144 throw new InvalidOperationException(Res.GetString(Res.XmlGetSchemaEmptyTypeName, type.FullName, getSchemaMethod.Name));
1148 throw new InvalidOperationException(Res.GetString(Res.XmlGetSchemaMethodReturnType, type.Name, getSchemaMethod.Name, typeof(XmlSchemaProviderAttribute).Name, typeof(XmlQualifiedName).FullName));
1155 // make sure that user-specified schemas are valid
1156 schemas.ValidationEventHandler += new ValidationEventHandler(ValidationCallbackWithErrorCode);
1158 // at this point we verified that the information returned by the IXmlSerializable is valid
1159 // Now check to see if the type was referenced before:
1161 if (!xsiType.IsEmpty) {
1162 // try to find the type in the schemas collection
1163 if (xsiType.Namespace != XmlSchema.Namespace) {
1164 ArrayList srcSchemas = (ArrayList)schemas.Schemas(xsiType.Namespace);
1166 if (srcSchemas.Count == 0) {
1167 throw new InvalidOperationException(Res.GetString(Res.XmlMissingSchema, xsiType.Namespace));
1169 if (srcSchemas.Count > 1) {
1170 throw new InvalidOperationException(Res.GetString(Res.XmlGetSchemaInclude, xsiType.Namespace, getSchemaMethod.DeclaringType.FullName, getSchemaMethod.Name));
1172 XmlSchema s = (XmlSchema)srcSchemas[0];
1174 throw new InvalidOperationException(Res.GetString(Res.XmlMissingSchema, xsiType.Namespace));
1176 xsdType = (XmlSchemaType)s.SchemaTypes[xsiType];
1177 if (xsdType == null) {
1178 throw new InvalidOperationException(Res.GetString(Res.XmlGetSchemaTypeMissing, getSchemaMethod.DeclaringType.FullName, getSchemaMethod.Name, xsiType.Name, xsiType.Namespace));
1180 xsdType = xsdType.Redefined != null ? xsdType.Redefined : xsdType;
1185 IXmlSerializable serializable = (IXmlSerializable)Activator.CreateInstance(type);
1186 schema = serializable.GetSchema();
1188 if (schema != null) {
1189 if (schema.Id == null || schema.Id.Length == 0) throw new InvalidOperationException(Res.GetString(Res.XmlSerializableNameMissing1, type.FullName));