|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace Microsoft.Xml.Serialization
{
using System.Reflection;
using System.Collections;
using Microsoft.Xml.Schema;
using System;
using System.Text;
using System.ComponentModel;
using Microsoft.Xml;
using Microsoft.CodeDom.Compiler;
// These classes represent a mapping between classes and a particular XML format.
// There are two class of mapping information: accessors (such as elements and
// attributes), and mappings (which specify the type of an accessor).
internal abstract class Accessor
{
private string _name;
private object _defaultValue = null;
private string _ns;
private TypeMapping _mapping;
private bool _any;
private string _anyNs;
private bool _topLevelInSchema;
private bool _isFixed;
private bool _isOptional;
private XmlSchemaForm _form = XmlSchemaForm.None;
internal Accessor() { }
internal TypeMapping Mapping
{
get { return _mapping; }
set { _mapping = value; }
}
internal object Default
{
get { return _defaultValue; }
set { _defaultValue = value; }
}
internal bool HasDefault
{
get { return _defaultValue != null && _defaultValue != DBNull.Value; }
}
internal virtual string Name
{
get { return _name == null ? string.Empty : _name; }
set { _name = value; }
}
internal bool Any
{
get { return _any; }
set { _any = value; }
}
internal string AnyNamespaces
{
get { return _anyNs; }
set { _anyNs = value; }
}
internal string Namespace
{
get { return _ns; }
set { _ns = value; }
}
internal XmlSchemaForm Form
{
get { return _form; }
set { _form = value; }
}
internal bool IsFixed
{
get { return _isFixed; }
set { _isFixed = value; }
}
internal bool IsOptional
{
get { return _isOptional; }
set { _isOptional = value; }
}
internal bool IsTopLevelInSchema
{
get { return _topLevelInSchema; }
set { _topLevelInSchema = value; }
}
internal static string EscapeName(string name)
{
if (name == null || name.Length == 0) return name;
return XmlConvert.EncodeLocalName(name);
}
internal static string EscapeQName(string name)
{
if (name == null || name.Length == 0) return name;
int colon = name.LastIndexOf(':');
if (colon < 0)
return XmlConvert.EncodeLocalName(name);
else
{
if (colon == 0 || colon == name.Length - 1)
throw new ArgumentException(string.Format(ResXml.Xml_InvalidNameChars, name), "name");
return new XmlQualifiedName(XmlConvert.EncodeLocalName(name.Substring(colon + 1)), XmlConvert.EncodeLocalName(name.Substring(0, colon))).ToString();
}
}
internal static string UnescapeName(string name)
{
return XmlConvert.DecodeName(name);
}
internal string ToString(string defaultNs)
{
if (Any)
{
return (Namespace == null ? "##any" : Namespace) + ":" + Name;
}
else
{
return Namespace == defaultNs ? Name : Namespace + ":" + Name;
}
}
}
internal class ElementAccessor : Accessor
{
private bool _nullable;
private bool _isSoap;
private bool _unbounded = false;
internal bool IsSoap
{
get { return _isSoap; }
set { _isSoap = value; }
}
internal bool IsNullable
{
get { return _nullable; }
set { _nullable = value; }
}
internal bool IsUnbounded
{
get { return _unbounded; }
set { _unbounded = value; }
}
internal ElementAccessor Clone()
{
ElementAccessor newAccessor = new ElementAccessor();
newAccessor._nullable = _nullable;
newAccessor.IsTopLevelInSchema = this.IsTopLevelInSchema;
newAccessor.Form = this.Form;
newAccessor._isSoap = _isSoap;
newAccessor.Name = this.Name;
newAccessor.Default = this.Default;
newAccessor.Namespace = this.Namespace;
newAccessor.Mapping = this.Mapping;
newAccessor.Any = this.Any;
return newAccessor;
}
}
internal class ChoiceIdentifierAccessor : Accessor
{
private string _memberName;
private string[] _memberIds;
private MemberInfo _memberInfo;
internal string MemberName
{
get { return _memberName; }
set { _memberName = value; }
}
internal string[] MemberIds
{
get { return _memberIds; }
set { _memberIds = value; }
}
internal MemberInfo MemberInfo
{
get { return _memberInfo; }
set { _memberInfo = value; }
}
}
internal class TextAccessor : Accessor
{
}
internal class XmlnsAccessor : Accessor
{
}
internal class AttributeAccessor : Accessor
{
private bool _isSpecial;
private bool _isList;
internal bool IsSpecialXmlNamespace
{
get { return _isSpecial; }
}
internal bool IsList
{
get { return _isList; }
set { _isList = value; }
}
internal void CheckSpecial()
{
int colon = Name.LastIndexOf(':');
if (colon >= 0)
{
if (!Name.StartsWith("xml:", StringComparison.Ordinal))
{
throw new InvalidOperationException(string.Format(ResXml.Xml_InvalidNameChars, Name));
}
Name = Name.Substring("xml:".Length);
Namespace = XmlReservedNs.NsXml;
_isSpecial = true;
}
else
{
if (Namespace == XmlReservedNs.NsXml)
{
_isSpecial = true;
}
else
{
_isSpecial = false;
}
}
if (_isSpecial)
{
Form = XmlSchemaForm.Qualified;
}
}
}
internal abstract class Mapping
{
private bool _isSoap;
internal Mapping() { }
protected Mapping(Mapping mapping)
{
_isSoap = mapping._isSoap;
}
internal bool IsSoap
{
get { return _isSoap; }
set { _isSoap = value; }
}
}
internal abstract class TypeMapping : Mapping
{
private TypeDesc _typeDesc;
private string _typeNs;
private string _typeName;
private bool _referencedByElement;
private bool _referencedByTopLevelElement;
private bool _includeInSchema = true;
private bool _reference = false;
internal bool ReferencedByTopLevelElement
{
get { return _referencedByTopLevelElement; }
set { _referencedByTopLevelElement = value; }
}
internal bool ReferencedByElement
{
get { return _referencedByElement || _referencedByTopLevelElement; }
set { _referencedByElement = value; }
}
internal string Namespace
{
get { return _typeNs; }
set { _typeNs = value; }
}
internal string TypeName
{
get { return _typeName; }
set { _typeName = value; }
}
internal TypeDesc TypeDesc
{
get { return _typeDesc; }
set { _typeDesc = value; }
}
internal bool IncludeInSchema
{
get { return _includeInSchema; }
set { _includeInSchema = value; }
}
internal virtual bool IsList
{
get { return false; }
set { }
}
internal bool IsReference
{
get { return _reference; }
set { _reference = value; }
}
internal bool IsAnonymousType
{
get { return _typeName == null || _typeName.Length == 0; }
}
internal virtual string DefaultElementName
{
get { return IsAnonymousType ? XmlConvert.EncodeLocalName(_typeDesc.Name) : _typeName; }
}
}
internal class PrimitiveMapping : TypeMapping
{
private bool _isList;
internal override bool IsList
{
get { return _isList; }
set { _isList = value; }
}
}
internal class NullableMapping : TypeMapping
{
private TypeMapping _baseMapping;
internal TypeMapping BaseMapping
{
get { return _baseMapping; }
set { _baseMapping = value; }
}
internal override string DefaultElementName
{
get { return BaseMapping.DefaultElementName; }
}
}
internal class ArrayMapping : TypeMapping
{
private ElementAccessor[] _elements;
private ElementAccessor[] _sortedElements;
private ArrayMapping _next;
private StructMapping _topLevelMapping;
internal ElementAccessor[] Elements
{
get { return _elements; }
set { _elements = value; _sortedElements = null; }
}
internal ElementAccessor[] ElementsSortedByDerivation
{
get
{
if (_sortedElements != null)
return _sortedElements;
if (_elements == null)
return null;
_sortedElements = new ElementAccessor[_elements.Length];
Array.Copy(_elements, 0, _sortedElements, 0, _elements.Length);
AccessorMapping.SortMostToLeastDerived(_sortedElements);
return _sortedElements;
}
}
internal ArrayMapping Next
{
get { return _next; }
set { _next = value; }
}
internal StructMapping TopLevelMapping
{
get { return _topLevelMapping; }
set { _topLevelMapping = value; }
}
}
internal class EnumMapping : PrimitiveMapping
{
private ConstantMapping[] _constants;
private bool _isFlags;
internal bool IsFlags
{
get { return _isFlags; }
set { _isFlags = value; }
}
internal ConstantMapping[] Constants
{
get { return _constants; }
set { _constants = value; }
}
}
internal class ConstantMapping : Mapping
{
private string _xmlName;
private string _name;
private long _value;
internal string XmlName
{
get { return _xmlName == null ? string.Empty : _xmlName; }
set { _xmlName = value; }
}
internal string Name
{
get { return _name == null ? string.Empty : _name; }
set { _name = value; }
}
internal long Value
{
get { return _value; }
set { _value = value; }
}
}
internal class StructMapping : TypeMapping, INameScope
{
private MemberMapping[] _members;
private StructMapping _baseMapping;
private StructMapping _derivedMappings;
private StructMapping _nextDerivedMapping;
private MemberMapping _xmlnsMember = null;
private bool _hasSimpleContent;
private bool _openModel;
private bool _isSequence;
private NameTable _elements;
private NameTable _attributes;
private CodeIdentifiers _scope;
internal StructMapping BaseMapping
{
get { return _baseMapping; }
set
{
_baseMapping = value;
if (!IsAnonymousType && _baseMapping != null)
{
_nextDerivedMapping = _baseMapping._derivedMappings;
_baseMapping._derivedMappings = this;
}
if (value._isSequence && !_isSequence)
{
_isSequence = true;
if (_baseMapping.IsSequence)
{
for (StructMapping derived = _derivedMappings; derived != null; derived = derived.NextDerivedMapping)
{
derived.SetSequence();
}
}
}
}
}
internal StructMapping DerivedMappings
{
get { return _derivedMappings; }
}
internal bool IsFullyInitialized
{
get { return _baseMapping != null && Members != null; }
}
internal NameTable LocalElements
{
get
{
if (_elements == null)
_elements = new NameTable();
return _elements;
}
}
internal NameTable LocalAttributes
{
get
{
if (_attributes == null)
_attributes = new NameTable();
return _attributes;
}
}
object INameScope.this[string name, string ns]
{
get
{
object named = LocalElements[name, ns];
if (named != null)
return named;
if (_baseMapping != null)
return ((INameScope)_baseMapping)[name, ns];
return null;
}
set
{
LocalElements[name, ns] = value;
}
}
internal StructMapping NextDerivedMapping
{
get { return _nextDerivedMapping; }
}
internal bool HasSimpleContent
{
get { return _hasSimpleContent; }
}
internal bool HasXmlnsMember
{
get
{
StructMapping mapping = this;
while (mapping != null)
{
if (mapping.XmlnsMember != null)
return true;
mapping = mapping.BaseMapping;
}
return false;
}
}
internal MemberMapping[] Members
{
get { return _members; }
set { _members = value; }
}
internal MemberMapping XmlnsMember
{
get { return _xmlnsMember; }
set { _xmlnsMember = value; }
}
internal bool IsOpenModel
{
get { return _openModel; }
set { _openModel = value; }
}
internal CodeIdentifiers Scope
{
get
{
if (_scope == null)
_scope = new CodeIdentifiers();
return _scope;
}
set { _scope = value; }
}
internal MemberMapping FindDeclaringMapping(MemberMapping member, out StructMapping declaringMapping, string parent)
{
declaringMapping = null;
if (BaseMapping != null)
{
MemberMapping baseMember = BaseMapping.FindDeclaringMapping(member, out declaringMapping, parent);
if (baseMember != null) return baseMember;
}
if (_members == null) return null;
for (int i = 0; i < _members.Length; i++)
{
if (_members[i].Name == member.Name)
{
if (_members[i].TypeDesc != member.TypeDesc)
throw new InvalidOperationException(string.Format(ResXml.XmlHiddenMember, parent, member.Name, member.TypeDesc.FullName, this.TypeName, _members[i].Name, _members[i].TypeDesc.FullName));
else if (!_members[i].Match(member))
{
throw new InvalidOperationException(string.Format(ResXml.XmlInvalidXmlOverride, parent, member.Name, this.TypeName, _members[i].Name));
}
declaringMapping = this;
return _members[i];
}
}
return null;
}
internal bool Declares(MemberMapping member, string parent)
{
StructMapping m;
return (FindDeclaringMapping(member, out m, parent) != null);
}
internal void SetContentModel(TextAccessor text, bool hasElements)
{
if (BaseMapping == null || BaseMapping.TypeDesc.IsRoot)
{
_hasSimpleContent = !hasElements && text != null && !text.Mapping.IsList;
}
else if (BaseMapping.HasSimpleContent)
{
if (text != null || hasElements)
{
// we can only extent a simleContent type with attributes
throw new InvalidOperationException(string.Format(ResXml.XmlIllegalSimpleContentExtension, TypeDesc.FullName, BaseMapping.TypeDesc.FullName));
}
else
{
_hasSimpleContent = true;
}
}
else
{
_hasSimpleContent = false;
}
if (!_hasSimpleContent && text != null && !text.Mapping.TypeDesc.CanBeTextValue)
{
throw new InvalidOperationException(string.Format(ResXml.XmlIllegalTypedTextAttribute, TypeDesc.FullName, text.Name, text.Mapping.TypeDesc.FullName));
}
}
internal bool HasElements
{
get { return _elements != null && _elements.Values.Count > 0; }
}
internal bool HasExplicitSequence()
{
if (_members != null)
{
for (int i = 0; i < _members.Length; i++)
{
if (_members[i].IsParticle && _members[i].IsSequence)
{
return true;
}
}
}
return (_baseMapping != null && _baseMapping.HasExplicitSequence());
}
internal void SetSequence()
{
if (TypeDesc.IsRoot)
return;
StructMapping start = this;
// find first mapping that does not have the sequence set
while (!start.BaseMapping.IsSequence && start.BaseMapping != null && !start.BaseMapping.TypeDesc.IsRoot)
start = start.BaseMapping;
start.IsSequence = true;
for (StructMapping derived = start.DerivedMappings; derived != null; derived = derived.NextDerivedMapping)
{
derived.SetSequence();
}
}
internal bool IsSequence
{
get { return _isSequence && !TypeDesc.IsRoot; }
set { _isSequence = value; }
}
}
internal abstract class AccessorMapping : Mapping
{
private TypeDesc _typeDesc;
private AttributeAccessor _attribute;
private ElementAccessor[] _elements;
private ElementAccessor[] _sortedElements;
private TextAccessor _text;
private ChoiceIdentifierAccessor _choiceIdentifier;
private XmlnsAccessor _xmlns;
private bool _ignore;
internal AccessorMapping()
{ }
protected AccessorMapping(AccessorMapping mapping)
: base(mapping)
{
_typeDesc = mapping._typeDesc;
_attribute = mapping._attribute;
_elements = mapping._elements;
_sortedElements = mapping._sortedElements;
_text = mapping._text;
_choiceIdentifier = mapping._choiceIdentifier;
_xmlns = mapping._xmlns;
_ignore = mapping._ignore;
}
internal bool IsAttribute
{
get { return _attribute != null; }
}
internal bool IsText
{
get { return _text != null && (_elements == null || _elements.Length == 0); }
}
internal bool IsParticle
{
get { return (_elements != null && _elements.Length > 0); }
}
internal TypeDesc TypeDesc
{
get { return _typeDesc; }
set { _typeDesc = value; }
}
internal AttributeAccessor Attribute
{
get { return _attribute; }
set { _attribute = value; }
}
internal ElementAccessor[] Elements
{
get { return _elements; }
set { _elements = value; _sortedElements = null; }
}
internal static void SortMostToLeastDerived(ElementAccessor[] elements)
{
Array.Sort(elements, new AccessorComparer());
}
internal class AccessorComparer : IComparer
{
public int Compare(object o1, object o2)
{
if (o1 == o2)
return 0;
Accessor a1 = (Accessor)o1;
Accessor a2 = (Accessor)o2;
int w1 = a1.Mapping.TypeDesc.Weight;
int w2 = a2.Mapping.TypeDesc.Weight;
if (w1 == w2)
return 0;
if (w1 < w2)
return 1;
return -1;
}
}
internal ElementAccessor[] ElementsSortedByDerivation
{
get
{
if (_sortedElements != null)
return _sortedElements;
if (_elements == null)
return null;
_sortedElements = new ElementAccessor[_elements.Length];
Array.Copy(_elements, 0, _sortedElements, 0, _elements.Length);
SortMostToLeastDerived(_sortedElements);
return _sortedElements;
}
}
internal TextAccessor Text
{
get { return _text; }
set { _text = value; }
}
internal ChoiceIdentifierAccessor ChoiceIdentifier
{
get { return _choiceIdentifier; }
set { _choiceIdentifier = value; }
}
internal XmlnsAccessor Xmlns
{
get { return _xmlns; }
set { _xmlns = value; }
}
internal bool Ignore
{
get { return _ignore; }
set { _ignore = value; }
}
internal Accessor Accessor
{
get
{
if (_xmlns != null) return _xmlns;
if (_attribute != null) return _attribute;
if (_elements != null && _elements.Length > 0) return _elements[0];
return _text;
}
}
private static bool IsNeedNullableMember(ElementAccessor element)
{
if (element.Mapping is ArrayMapping)
{
ArrayMapping arrayMapping = (ArrayMapping)element.Mapping;
if (arrayMapping.Elements != null && arrayMapping.Elements.Length == 1)
{
return IsNeedNullableMember(arrayMapping.Elements[0]);
}
return false;
}
else
{
return element.IsNullable && element.Mapping.TypeDesc.IsValueType;
}
}
internal bool IsNeedNullable
{
get
{
if (_xmlns != null) return false;
if (_attribute != null) return false;
if (_elements != null && _elements.Length == 1)
{
return IsNeedNullableMember(_elements[0]);
}
return false;
}
}
internal static bool ElementsMatch(ElementAccessor[] a, ElementAccessor[] b)
{
if (a == null)
{
if (b == null)
return true;
return false;
}
if (b == null)
return false;
if (a.Length != b.Length)
return false;
for (int i = 0; i < a.Length; i++)
{
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)
return false;
}
return true;
}
internal bool Match(AccessorMapping mapping)
{
if (Elements != null && Elements.Length > 0)
{
if (!ElementsMatch(Elements, mapping.Elements))
{
return false;
}
if (Text == null)
{
return (mapping.Text == null);
}
}
if (Attribute != null)
{
if (mapping.Attribute == null)
return false;
return (Attribute.Name == mapping.Attribute.Name && Attribute.Namespace == mapping.Attribute.Namespace && Attribute.Form == mapping.Attribute.Form);
}
if (Text != null)
{
return (mapping.Text != null);
}
return (mapping.Accessor == null);
}
}
internal class MemberMappingComparer : IComparer
{
public int Compare(object o1, object o2)
{
MemberMapping m1 = (MemberMapping)o1;
MemberMapping m2 = (MemberMapping)o2;
bool m1Text = m1.IsText;
if (m1Text)
{
if (m2.IsText)
return 0;
return 1;
}
else if (m2.IsText)
return -1;
if (m1.SequenceId < 0 && m2.SequenceId < 0)
return 0;
if (m1.SequenceId < 0)
return 1;
if (m2.SequenceId < 0)
return -1;
if (m1.SequenceId < m2.SequenceId)
return -1;
if (m1.SequenceId > m2.SequenceId)
return 1;
return 0;
}
}
internal class MemberMapping : AccessorMapping
{
private string _name;
private bool _checkShouldPersist;
private SpecifiedAccessor _checkSpecified;
private bool _isReturnValue;
private bool _readOnly = false;
private int _sequenceId = -1;
private MemberInfo _memberInfo;
private MemberInfo _checkSpecifiedMemberInfo;
private MethodInfo _checkShouldPersistMethodInfo;
internal MemberMapping() { }
private MemberMapping(MemberMapping mapping)
: base(mapping)
{
_name = mapping._name;
_checkShouldPersist = mapping._checkShouldPersist;
_checkSpecified = mapping._checkSpecified;
_isReturnValue = mapping._isReturnValue;
_readOnly = mapping._readOnly;
_sequenceId = mapping._sequenceId;
_memberInfo = mapping._memberInfo;
_checkSpecifiedMemberInfo = mapping._checkSpecifiedMemberInfo;
_checkShouldPersistMethodInfo = mapping._checkShouldPersistMethodInfo;
}
internal bool CheckShouldPersist
{
get { return _checkShouldPersist; }
set { _checkShouldPersist = value; }
}
internal SpecifiedAccessor CheckSpecified
{
get { return _checkSpecified; }
set { _checkSpecified = value; }
}
internal string Name
{
get { return _name == null ? string.Empty : _name; }
set { _name = value; }
}
internal MemberInfo MemberInfo
{
get { return _memberInfo; }
set { _memberInfo = value; }
}
internal MemberInfo CheckSpecifiedMemberInfo
{
get { return _checkSpecifiedMemberInfo; }
set { _checkSpecifiedMemberInfo = value; }
}
internal MethodInfo CheckShouldPersistMethodInfo
{
get { return _checkShouldPersistMethodInfo; }
set { _checkShouldPersistMethodInfo = value; }
}
internal bool IsReturnValue
{
get { return _isReturnValue; }
set { _isReturnValue = value; }
}
internal bool ReadOnly
{
get { return _readOnly; }
set { _readOnly = value; }
}
internal bool IsSequence
{
get { return _sequenceId >= 0; }
}
internal int SequenceId
{
get { return _sequenceId; }
set { _sequenceId = value; }
}
private string GetNullableType(TypeDesc td)
{
// SOAP encoded arrays not mapped to Nullable<T> since they always derive from soapenc:Array
if (td.IsMappedType || (!td.IsValueType && (Elements[0].IsSoap || td.ArrayElementTypeDesc == null)))
return td.FullName;
if (td.ArrayElementTypeDesc != null)
{
return GetNullableType(td.ArrayElementTypeDesc) + "[]";
}
return "System.Nullable`1[" + td.FullName + "]";
}
internal MemberMapping Clone()
{
return new MemberMapping(this);
}
internal string GetTypeName(CodeDomProvider codeProvider)
{
if (IsNeedNullable && codeProvider.Supports(GeneratorSupport.GenericTypeReference))
{
return GetNullableType(TypeDesc);
}
return TypeDesc.FullName;
}
}
internal class MembersMapping : TypeMapping
{
private MemberMapping[] _members;
private bool _hasWrapperElement = true;
private bool _validateRpcWrapperElement;
private bool _writeAccessors = true;
private MemberMapping _xmlnsMember = null;
internal MemberMapping[] Members
{
get { return _members; }
set { _members = value; }
}
internal MemberMapping XmlnsMember
{
get { return _xmlnsMember; }
set { _xmlnsMember = value; }
}
internal bool HasWrapperElement
{
get { return _hasWrapperElement; }
set { _hasWrapperElement = value; }
}
internal bool ValidateRpcWrapperElement
{
get { return _validateRpcWrapperElement; }
set { _validateRpcWrapperElement = value; }
}
internal bool WriteAccessors
{
get { return _writeAccessors; }
set { _writeAccessors = value; }
}
}
internal class SpecialMapping : TypeMapping
{
private bool _namedAny;
internal bool NamedAny
{
get { return _namedAny; }
set { _namedAny = value; }
}
}
internal class SerializableMapping : SpecialMapping
{
private XmlSchema _schema;
private Type _type;
private bool _needSchema = true;
// new implementation of the IXmlSerializable
private MethodInfo _getSchemaMethod;
private XmlQualifiedName _xsiType;
private XmlSchemaType _xsdType;
private XmlSchemaSet _schemas;
private bool _any;
private string _namespaces;
private SerializableMapping _baseMapping;
private SerializableMapping _derivedMappings;
private SerializableMapping _nextDerivedMapping;
private SerializableMapping _next; // all mappings with the same qname
internal SerializableMapping() { }
internal SerializableMapping(MethodInfo getSchemaMethod, bool any, string ns)
{
_getSchemaMethod = getSchemaMethod;
_any = any;
this.Namespace = ns;
_needSchema = getSchemaMethod != null;
}
internal SerializableMapping(XmlQualifiedName xsiType, XmlSchemaSet schemas)
{
_xsiType = xsiType;
_schemas = schemas;
this.TypeName = xsiType.Name;
this.Namespace = xsiType.Namespace;
_needSchema = false;
}
internal void SetBaseMapping(SerializableMapping mapping)
{
_baseMapping = mapping;
if (_baseMapping != null)
{
_nextDerivedMapping = _baseMapping._derivedMappings;
_baseMapping._derivedMappings = this;
if (this == _nextDerivedMapping)
{
throw new InvalidOperationException(string.Format(ResXml.XmlCircularDerivation, TypeDesc.FullName));
}
}
}
internal bool IsAny
{
get
{
if (_any)
return true;
if (_getSchemaMethod == null)
return false;
if (_needSchema && typeof(XmlSchemaType).IsAssignableFrom(_getSchemaMethod.ReturnType))
return false;
RetrieveSerializableSchema();
return _any;
}
}
internal string NamespaceList
{
get
{
RetrieveSerializableSchema();
if (_namespaces == null)
{
if (_schemas != null)
{
StringBuilder anyNamespaces = new StringBuilder();
foreach (XmlSchema s in _schemas.Schemas())
{
if (s.TargetNamespace != null && s.TargetNamespace.Length > 0)
{
if (anyNamespaces.Length > 0)
anyNamespaces.Append(" ");
anyNamespaces.Append(s.TargetNamespace);
}
}
_namespaces = anyNamespaces.ToString();
}
else
{
_namespaces = string.Empty;
}
}
return _namespaces;
}
}
internal SerializableMapping DerivedMappings
{
get
{
return _derivedMappings;
}
}
internal SerializableMapping NextDerivedMapping
{
get
{
return _nextDerivedMapping;
}
}
internal SerializableMapping Next
{
get { return _next; }
set { _next = value; }
}
internal Type Type
{
get { return _type; }
set { _type = value; }
}
internal XmlSchemaSet Schemas
{
get
{
RetrieveSerializableSchema();
return _schemas;
}
}
internal XmlSchema Schema
{
get
{
RetrieveSerializableSchema();
return _schema;
}
}
internal XmlQualifiedName XsiType
{
get
{
if (!_needSchema)
return _xsiType;
if (_getSchemaMethod == null)
return null;
if (typeof(XmlSchemaType).IsAssignableFrom(_getSchemaMethod.ReturnType))
return null;
RetrieveSerializableSchema();
return _xsiType;
}
}
internal XmlSchemaType XsdType
{
get
{
RetrieveSerializableSchema();
return _xsdType;
}
}
internal static void ValidationCallbackWithErrorCode(object sender, ValidationEventArgs args)
{
// CONSIDER: need the real type name
if (args.Severity == XmlSeverityType.Error)
throw new InvalidOperationException(string.Format(ResXml.XmlSerializableSchemaError, typeof(IXmlSerializable).Name, args.Message));
}
internal void CheckDuplicateElement(XmlSchemaElement element, string elementNs)
{
if (element == null)
return;
// only check duplicate definitions for top-level element
if (element.Parent == null || !(element.Parent is XmlSchema))
return;
XmlSchemaObjectTable elements = null;
if (Schema != null && Schema.TargetNamespace == elementNs)
{
XmlSchemas.Preprocess(Schema);
elements = Schema.Elements;
}
else if (Schemas != null)
{
elements = Schemas.GlobalElements;
}
else
{
return;
}
foreach (XmlSchemaElement e in elements.Values)
{
if (e.Name == element.Name && e.QualifiedName.Namespace == elementNs)
{
if (Match(e, element))
return;
// 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}'.
throw new InvalidOperationException(string.Format(ResXml.XmlSerializableRootDupName, _getSchemaMethod.DeclaringType.FullName, e.Name, elementNs));
}
}
}
private bool Match(XmlSchemaElement e1, XmlSchemaElement e2)
{
if (e1.IsNillable != e2.IsNillable)
return false;
if (e1.RefName != e2.RefName)
return false;
if (e1.SchemaType != e2.SchemaType)
return false;
if (e1.SchemaTypeName != e2.SchemaTypeName)
return false;
if (e1.MinOccurs != e2.MinOccurs)
return false;
if (e1.MaxOccurs != e2.MaxOccurs)
return false;
if (e1.IsAbstract != e2.IsAbstract)
return false;
if (e1.DefaultValue != e2.DefaultValue)
return false;
if (e1.SubstitutionGroup != e2.SubstitutionGroup)
return false;
return true;
}
private void RetrieveSerializableSchema()
{
if (_needSchema)
{
_needSchema = false;
if (_getSchemaMethod != null)
{
// get the type info
if (_schemas == null)
_schemas = new XmlSchemaSet();
object typeInfo = _getSchemaMethod.Invoke(null, new object[] { _schemas });
_xsiType = XmlQualifiedName.Empty;
if (typeInfo != null)
{
if (typeof(XmlSchemaType).IsAssignableFrom(_getSchemaMethod.ReturnType))
{
_xsdType = (XmlSchemaType)typeInfo;
// check if type is named
_xsiType = _xsdType.QualifiedName;
}
else if (typeof(XmlQualifiedName).IsAssignableFrom(_getSchemaMethod.ReturnType))
{
_xsiType = (XmlQualifiedName)typeInfo;
if (_xsiType.IsEmpty)
{
throw new InvalidOperationException(string.Format(ResXml.XmlGetSchemaEmptyTypeName, _type.FullName, _getSchemaMethod.Name));
}
}
else
{
throw new InvalidOperationException(string.Format(ResXml.XmlGetSchemaMethodReturnType, _type.Name, _getSchemaMethod.Name, typeof(XmlSchemaProviderAttribute).Name, typeof(XmlQualifiedName).FullName));
}
}
else
{
_any = true;
}
// make sure that user-specified schemas are valid
_schemas.ValidationEventHandler += new ValidationEventHandler(ValidationCallbackWithErrorCode);
_schemas.Compile();
// at this point we verified that the information returned by the IXmlSerializable is valid
// Now check to see if the type was referenced before:
// UNDONE check for the duplcate types
if (!_xsiType.IsEmpty)
{
// try to find the type in the schemas collection
if (_xsiType.Namespace != XmlSchema.Namespace)
{
ArrayList srcSchemas = (ArrayList)_schemas.Schemas(_xsiType.Namespace);
if (srcSchemas.Count == 0)
{
throw new InvalidOperationException(string.Format(ResXml.XmlMissingSchema, _xsiType.Namespace));
}
if (srcSchemas.Count > 1)
{
throw new InvalidOperationException(string.Format(ResXml.XmlGetSchemaInclude, _xsiType.Namespace, _getSchemaMethod.DeclaringType.FullName, _getSchemaMethod.Name));
}
XmlSchema s = (XmlSchema)srcSchemas[0];
if (s == null)
{
throw new InvalidOperationException(string.Format(ResXml.XmlMissingSchema, _xsiType.Namespace));
}
_xsdType = (XmlSchemaType)s.SchemaTypes[_xsiType];
if (_xsdType == null)
{
throw new InvalidOperationException(string.Format(ResXml.XmlGetSchemaTypeMissing, _getSchemaMethod.DeclaringType.FullName, _getSchemaMethod.Name, _xsiType.Name, _xsiType.Namespace));
}
_xsdType = _xsdType.Redefined != null ? _xsdType.Redefined : _xsdType;
}
}
}
else
{
IXmlSerializable serializable = (IXmlSerializable)Activator.CreateInstance(_type);
_schema = serializable.GetSchema();
if (_schema != null)
{
if (_schema.Id == null || _schema.Id.Length == 0) throw new InvalidOperationException(string.Format(ResXml.XmlSerializableNameMissing1, _type.FullName));
}
}
}
}
}
}
|