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
));