94b2861243
Former-commit-id: 5f9c6ae75f295e057a7d2971f3a6df4656fa8850
1145 lines
42 KiB
C#
1145 lines
42 KiB
C#
//
|
|
// System.Xml.Serialization.XmlReflectionImporter
|
|
//
|
|
// Author:
|
|
// Tim Coleman (tim@timcoleman.com)
|
|
// Erik LeBel (eriklebel@yahoo.ca)
|
|
// Lluis Sanchez Gual (lluis@ximian.com)
|
|
//
|
|
// Copyright (C) Tim Coleman, 2002
|
|
// (C) 2003 Erik LeBel
|
|
//
|
|
//
|
|
// Permission is hereby granted, free of charge, to any person obtaining
|
|
// a copy of this software and associated documentation files (the
|
|
// "Software"), to deal in the Software without restriction, including
|
|
// without limitation the rights to use, copy, modify, merge, publish,
|
|
// distribute, sublicense, and/or sell copies of the Software, and to
|
|
// permit persons to whom the Software is furnished to do so, subject to
|
|
// the following conditions:
|
|
//
|
|
// The above copyright notice and this permission notice shall be
|
|
// included in all copies or substantial portions of the Software.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
//
|
|
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.Globalization;
|
|
using System.Reflection;
|
|
using System.Xml.Schema;
|
|
|
|
namespace System.Xml.Serialization {
|
|
public class XmlReflectionImporter {
|
|
|
|
string initialDefaultNamespace;
|
|
XmlAttributeOverrides attributeOverrides;
|
|
ArrayList includedTypes;
|
|
ReflectionHelper helper = new ReflectionHelper();
|
|
int arrayChoiceCount = 1;
|
|
ArrayList relatedMaps = new ArrayList ();
|
|
bool allowPrivateTypes = false;
|
|
|
|
static readonly string errSimple = "Cannot serialize object of type '{0}'. Base " +
|
|
"type '{1}' has simpleContent and can be only extended by adding XmlAttribute " +
|
|
"elements. Please consider changing XmlText member of the base class to string array";
|
|
|
|
static readonly string errSimple2 = "Cannot serialize object of type '{0}'. " +
|
|
"Consider changing type of XmlText member '{1}' from '{2}' to string or string array";
|
|
|
|
#region Constructors
|
|
|
|
public XmlReflectionImporter ()
|
|
: this (null, null)
|
|
{
|
|
}
|
|
|
|
public XmlReflectionImporter (string defaultNamespace)
|
|
: this (null, defaultNamespace)
|
|
{
|
|
}
|
|
|
|
public XmlReflectionImporter (XmlAttributeOverrides attributeOverrides)
|
|
: this (attributeOverrides, null)
|
|
{
|
|
}
|
|
|
|
public XmlReflectionImporter (XmlAttributeOverrides attributeOverrides, string defaultNamespace)
|
|
{
|
|
if (defaultNamespace == null)
|
|
this.initialDefaultNamespace = String.Empty;
|
|
else
|
|
this.initialDefaultNamespace = defaultNamespace;
|
|
|
|
if (attributeOverrides == null)
|
|
this.attributeOverrides = new XmlAttributeOverrides();
|
|
else
|
|
this.attributeOverrides = attributeOverrides;
|
|
}
|
|
|
|
/* void Reset ()
|
|
{
|
|
helper = new ReflectionHelper();
|
|
arrayChoiceCount = 1;
|
|
}
|
|
*/
|
|
|
|
internal bool AllowPrivateTypes
|
|
{
|
|
get { return allowPrivateTypes; }
|
|
set { allowPrivateTypes = value; }
|
|
}
|
|
|
|
#endregion // Constructors
|
|
|
|
#region Methods
|
|
|
|
public XmlMembersMapping ImportMembersMapping (string elementName,
|
|
string ns,
|
|
XmlReflectionMember [] members,
|
|
bool hasWrapperElement)
|
|
{
|
|
return ImportMembersMapping (elementName, ns, members, hasWrapperElement, true);
|
|
}
|
|
|
|
[MonoTODO]
|
|
public
|
|
XmlMembersMapping ImportMembersMapping (string elementName,
|
|
string ns,
|
|
XmlReflectionMember[] members,
|
|
bool hasWrapperElement,
|
|
bool rpc)
|
|
{
|
|
return ImportMembersMapping (elementName, ns, members, hasWrapperElement, rpc, true);
|
|
}
|
|
|
|
[MonoTODO]
|
|
public
|
|
XmlMembersMapping ImportMembersMapping (string elementName,
|
|
string ns,
|
|
XmlReflectionMember[] members,
|
|
bool hasWrapperElement,
|
|
bool rpc,
|
|
bool openModel)
|
|
{
|
|
return ImportMembersMapping (elementName, ns, members, hasWrapperElement, rpc, openModel, XmlMappingAccess.Read | XmlMappingAccess.Write);
|
|
}
|
|
|
|
[MonoTODO] // FIXME: handle writeAccessors, validate, and mapping access
|
|
public
|
|
XmlMembersMapping ImportMembersMapping (string elementName,
|
|
string ns,
|
|
XmlReflectionMember[] members,
|
|
bool hasWrapperElement,
|
|
bool rpc,
|
|
bool openModel,
|
|
XmlMappingAccess access)
|
|
{
|
|
// Reset (); Disabled. See ChangeLog
|
|
|
|
ArrayList mapping = new ArrayList ();
|
|
for (int n=0; n<members.Length; n++)
|
|
{
|
|
XmlTypeMapMember mapMem = CreateMapMember (null, members[n], ns);
|
|
mapMem.GlobalIndex = n;
|
|
mapMem.CheckOptionalValueType (members);
|
|
mapping.Add (new XmlMemberMapping (members[n].MemberName, ns, mapMem, false));
|
|
}
|
|
elementName = XmlConvert.EncodeLocalName (elementName);
|
|
XmlMembersMapping mps = new XmlMembersMapping (elementName, ns, hasWrapperElement, false, (XmlMemberMapping[])mapping.ToArray (typeof(XmlMemberMapping)));
|
|
mps.RelatedMaps = relatedMaps;
|
|
mps.Format = SerializationFormat.Literal;
|
|
Type[] extraTypes = includedTypes != null ? (Type[])includedTypes.ToArray(typeof(Type)) : null;
|
|
#if !MOBILE
|
|
mps.Source = new MembersSerializationSource (elementName, hasWrapperElement, members, false, true, ns, extraTypes);
|
|
if (allowPrivateTypes) mps.Source.CanBeGenerated = false;
|
|
#endif
|
|
return mps;
|
|
}
|
|
|
|
public XmlTypeMapping ImportTypeMapping (Type type)
|
|
{
|
|
return ImportTypeMapping (type, null, null);
|
|
}
|
|
|
|
public XmlTypeMapping ImportTypeMapping (Type type, string defaultNamespace)
|
|
{
|
|
return ImportTypeMapping (type, null, defaultNamespace);
|
|
}
|
|
|
|
public XmlTypeMapping ImportTypeMapping (Type type, XmlRootAttribute root)
|
|
{
|
|
return ImportTypeMapping (type, root, null);
|
|
}
|
|
|
|
public XmlTypeMapping ImportTypeMapping (Type type, XmlRootAttribute root, string defaultNamespace)
|
|
{
|
|
if (type == null)
|
|
throw new ArgumentNullException ("type");
|
|
|
|
if (type == typeof (void))
|
|
throw new NotSupportedException ("The type " + type.FullName + " may not be serialized.");
|
|
|
|
return ImportTypeMapping (TypeTranslator.GetTypeData (type), root,
|
|
defaultNamespace);
|
|
}
|
|
|
|
internal XmlTypeMapping ImportTypeMapping (TypeData typeData, string defaultNamespace)
|
|
{
|
|
return ImportTypeMapping (typeData, (XmlRootAttribute) null,
|
|
defaultNamespace);
|
|
}
|
|
|
|
private XmlTypeMapping ImportTypeMapping (TypeData typeData, XmlRootAttribute root, string defaultNamespace)
|
|
{
|
|
if (typeData == null)
|
|
throw new ArgumentNullException ("typeData");
|
|
|
|
if (typeData.Type == null)
|
|
throw new ArgumentException ("Specified TypeData instance does not have Type set.");
|
|
|
|
if (defaultNamespace == null) defaultNamespace = initialDefaultNamespace;
|
|
if (defaultNamespace == null) defaultNamespace = string.Empty;
|
|
|
|
try {
|
|
XmlTypeMapping map;
|
|
|
|
switch (typeData.SchemaType) {
|
|
case SchemaTypes.Class: map = ImportClassMapping (typeData, root, defaultNamespace); break;
|
|
case SchemaTypes.Array: map = ImportListMapping (typeData, root, defaultNamespace, null, 0); break;
|
|
case SchemaTypes.XmlNode: map = ImportXmlNodeMapping (typeData, root, defaultNamespace); break;
|
|
case SchemaTypes.Primitive: map = ImportPrimitiveMapping (typeData, root, defaultNamespace); break;
|
|
case SchemaTypes.Enum: map = ImportEnumMapping (typeData, root, defaultNamespace); break;
|
|
case SchemaTypes.XmlSerializable: map = ImportXmlSerializableMapping (typeData, root, defaultNamespace); break;
|
|
default: throw new NotSupportedException ("Type " + typeData.Type.FullName + " not supported for XML stialization");
|
|
}
|
|
|
|
// bug #372780
|
|
map.SetKey (typeData.Type.ToString ());
|
|
map.RelatedMaps = relatedMaps;
|
|
map.Format = SerializationFormat.Literal;
|
|
Type[] extraTypes = includedTypes != null ? (Type[]) includedTypes.ToArray (typeof (Type)) : null;
|
|
#if !MOBILE
|
|
map.Source = new XmlTypeSerializationSource (typeData.Type, root, attributeOverrides, defaultNamespace, extraTypes);
|
|
if (allowPrivateTypes) map.Source.CanBeGenerated = false;
|
|
#endif
|
|
return map;
|
|
} catch (InvalidOperationException ex) {
|
|
throw new InvalidOperationException (string.Format (CultureInfo.InvariantCulture,
|
|
"There was an error reflecting type '{0}'.", typeData.Type.FullName), ex);
|
|
}
|
|
}
|
|
|
|
XmlTypeMapping CreateTypeMapping (TypeData typeData, XmlRootAttribute root, string defaultXmlType, string defaultNamespace)
|
|
{
|
|
bool hasTypeNamespace = !string.IsNullOrEmpty (defaultNamespace);
|
|
string rootNamespace = null;
|
|
string typeNamespace = null;
|
|
string elementName;
|
|
bool includeInSchema = true;
|
|
XmlAttributes atts = null;
|
|
bool nullable = CanBeNull (typeData);
|
|
|
|
if (defaultXmlType == null) defaultXmlType = typeData.XmlType;
|
|
|
|
if (!typeData.IsListType)
|
|
{
|
|
if (attributeOverrides != null)
|
|
atts = attributeOverrides[typeData.Type];
|
|
|
|
if (atts != null && typeData.SchemaType == SchemaTypes.Primitive)
|
|
throw new InvalidOperationException ("XmlRoot and XmlType attributes may not be specified for the type " + typeData.FullTypeName);
|
|
}
|
|
|
|
if (atts == null)
|
|
atts = new XmlAttributes (typeData.Type);
|
|
|
|
if (atts.XmlRoot != null && root == null)
|
|
root = atts.XmlRoot;
|
|
|
|
if (atts.XmlType != null)
|
|
{
|
|
if (atts.XmlType.Namespace != null) {
|
|
typeNamespace = atts.XmlType.Namespace;
|
|
hasTypeNamespace = true;
|
|
}
|
|
|
|
if (atts.XmlType.TypeName != null && atts.XmlType.TypeName != string.Empty)
|
|
defaultXmlType = XmlConvert.EncodeLocalName (atts.XmlType.TypeName);
|
|
|
|
includeInSchema = atts.XmlType.IncludeInSchema;
|
|
}
|
|
|
|
elementName = defaultXmlType;
|
|
|
|
if (root != null)
|
|
{
|
|
if (root.ElementName.Length != 0)
|
|
elementName = XmlConvert.EncodeLocalName(root.ElementName);
|
|
if (root.Namespace != null) {
|
|
rootNamespace = root.Namespace;
|
|
hasTypeNamespace = true;
|
|
}
|
|
nullable = root.IsNullable;
|
|
}
|
|
|
|
rootNamespace = rootNamespace ?? defaultNamespace ?? string.Empty;
|
|
typeNamespace = typeNamespace ?? rootNamespace;
|
|
|
|
XmlTypeMapping map;
|
|
switch (typeData.SchemaType) {
|
|
case SchemaTypes.XmlSerializable:
|
|
map = new XmlSerializableMapping (root, elementName, rootNamespace, typeData, defaultXmlType, typeNamespace);
|
|
break;
|
|
case SchemaTypes.Primitive:
|
|
if (!typeData.IsXsdType)
|
|
map = new XmlTypeMapping (elementName, rootNamespace,
|
|
typeData, defaultXmlType, XmlSerializer.WsdlTypesNamespace);
|
|
else
|
|
map = new XmlTypeMapping (elementName, rootNamespace,
|
|
typeData, defaultXmlType, typeNamespace);
|
|
break;
|
|
default:
|
|
map = new XmlTypeMapping (elementName, rootNamespace, typeData, defaultXmlType, hasTypeNamespace ? typeNamespace : null);
|
|
break;
|
|
}
|
|
|
|
map.IncludeInSchema = includeInSchema;
|
|
map.IsNullable = nullable;
|
|
relatedMaps.Add (map);
|
|
|
|
return map;
|
|
}
|
|
|
|
XmlTypeMapping ImportClassMapping (Type type, XmlRootAttribute root, string defaultNamespace, bool isBaseType = false)
|
|
{
|
|
TypeData typeData = TypeTranslator.GetTypeData (type);
|
|
return ImportClassMapping (typeData, root, defaultNamespace, isBaseType);
|
|
}
|
|
|
|
XmlTypeMapping ImportClassMapping (TypeData typeData, XmlRootAttribute root, string defaultNamespace, bool isBaseType = false)
|
|
{
|
|
Type type = typeData.Type;
|
|
|
|
if (!allowPrivateTypes && !isBaseType)
|
|
ReflectionHelper.CheckSerializableType (type, false);
|
|
|
|
XmlTypeMapping map = helper.GetRegisteredClrType (type, GetTypeNamespace (typeData, root, defaultNamespace));
|
|
if (map != null) return map;
|
|
|
|
map = CreateTypeMapping (typeData, root, null, defaultNamespace);
|
|
helper.RegisterClrType (map, type, map.XmlTypeNamespace);
|
|
helper.RegisterSchemaType (map, map.XmlType, map.XmlTypeNamespace);
|
|
|
|
// Import members
|
|
|
|
ClassMap classMap = new ClassMap ();
|
|
map.ObjectMap = classMap;
|
|
|
|
var members = GetReflectionMembers (type);
|
|
bool? isOrderExplicit = null;
|
|
foreach (XmlReflectionMember rmember in members)
|
|
{
|
|
int? order = rmember.XmlAttributes.Order;
|
|
if (isOrderExplicit == null)
|
|
{
|
|
if (order != null)
|
|
isOrderExplicit = (int) order >= 0;
|
|
}
|
|
else if (order != null && isOrderExplicit != ((int) order >= 0))
|
|
throw new InvalidOperationException ("Inconsistent XML sequence was detected. If there are XmlElement/XmlArray/XmlAnyElement attributes with explicit Order, then every other member must have an explicit order too.");
|
|
}
|
|
if (isOrderExplicit == true)
|
|
members.Sort ((m1, m2) => (int) m1.XmlAttributes.SortableOrder - (int) m2.XmlAttributes.SortableOrder);
|
|
|
|
foreach (XmlReflectionMember rmember in members)
|
|
{
|
|
string ns = map.XmlTypeNamespace;
|
|
if (rmember.XmlAttributes.XmlIgnore) continue;
|
|
if (rmember.DeclaringType != null && rmember.DeclaringType != type) {
|
|
XmlTypeMapping bmap = ImportClassMapping (rmember.DeclaringType, root, defaultNamespace, true);
|
|
if (bmap.HasXmlTypeNamespace)
|
|
ns = bmap.XmlTypeNamespace;
|
|
}
|
|
|
|
try {
|
|
XmlTypeMapMember mem = CreateMapMember (type, rmember, ns);
|
|
mem.CheckOptionalValueType (type);
|
|
classMap.AddMember (mem);
|
|
} catch (Exception ex) {
|
|
throw new InvalidOperationException (string.Format (
|
|
CultureInfo.InvariantCulture, "There was an error" +
|
|
" reflecting field '{0}'.", rmember.MemberName), ex);
|
|
}
|
|
}
|
|
|
|
// Import extra classes
|
|
|
|
if (type == typeof (object) && includedTypes != null)
|
|
{
|
|
foreach (Type intype in includedTypes)
|
|
map.DerivedTypes.Add (ImportTypeMapping (intype, defaultNamespace));
|
|
}
|
|
|
|
// Register inheritance relations
|
|
|
|
if (type.BaseType != null)
|
|
{
|
|
XmlTypeMapping bmap = ImportClassMapping (type.BaseType, root, defaultNamespace, true);
|
|
ClassMap cbmap = bmap.ObjectMap as ClassMap;
|
|
|
|
if (type.BaseType != typeof (object)) {
|
|
map.BaseMap = bmap;
|
|
if (!cbmap.HasSimpleContent)
|
|
classMap.SetCanBeSimpleType (false);
|
|
}
|
|
|
|
// At this point, derived classes of this map must be already registered
|
|
|
|
RegisterDerivedMap (bmap, map);
|
|
|
|
if (cbmap.HasSimpleContent && classMap.ElementMembers != null && classMap.ElementMembers.Count != 1)
|
|
throw new InvalidOperationException (String.Format (errSimple, map.TypeData.TypeName, map.BaseMap.TypeData.TypeName));
|
|
}
|
|
|
|
ImportIncludedTypes (type, defaultNamespace);
|
|
|
|
if (classMap.XmlTextCollector != null && !classMap.HasSimpleContent)
|
|
{
|
|
XmlTypeMapMember mem = classMap.XmlTextCollector;
|
|
if (mem.TypeData.Type != typeof(string) &&
|
|
mem.TypeData.Type != typeof(string[]) &&
|
|
mem.TypeData.Type != typeof(XmlNode[]) &&
|
|
mem.TypeData.Type != typeof(object[]))
|
|
|
|
throw new InvalidOperationException (String.Format (errSimple2, map.TypeData.TypeName, mem.Name, mem.TypeData.TypeName));
|
|
}
|
|
|
|
return map;
|
|
}
|
|
|
|
void RegisterDerivedMap (XmlTypeMapping map, XmlTypeMapping derivedMap)
|
|
{
|
|
map.DerivedTypes.Add (derivedMap);
|
|
map.DerivedTypes.AddRange (derivedMap.DerivedTypes);
|
|
|
|
if (map.BaseMap != null)
|
|
RegisterDerivedMap (map.BaseMap, derivedMap);
|
|
else {
|
|
XmlTypeMapping obmap = ImportTypeMapping (typeof(object));
|
|
if (obmap != map)
|
|
obmap.DerivedTypes.Add (derivedMap);
|
|
}
|
|
}
|
|
|
|
string GetTypeNamespace (TypeData typeData, XmlRootAttribute root, string defaultNamespace)
|
|
{
|
|
string typeNamespace = null;
|
|
|
|
XmlAttributes atts = null;
|
|
if (!typeData.IsListType)
|
|
{
|
|
if (attributeOverrides != null)
|
|
atts = attributeOverrides[typeData.Type];
|
|
}
|
|
|
|
if (atts == null)
|
|
atts = new XmlAttributes (typeData.Type);
|
|
|
|
if (atts.XmlType != null)
|
|
{
|
|
if (atts.XmlType.Namespace != null && atts.XmlType.Namespace.Length != 0 && typeData.SchemaType != SchemaTypes.Enum)
|
|
typeNamespace = atts.XmlType.Namespace;
|
|
}
|
|
|
|
if (typeNamespace != null && typeNamespace.Length != 0) return typeNamespace;
|
|
|
|
if (atts.XmlRoot != null && root == null)
|
|
root = atts.XmlRoot;
|
|
|
|
if (root != null)
|
|
{
|
|
if (root.Namespace != null && root.Namespace.Length != 0)
|
|
return root.Namespace;
|
|
}
|
|
|
|
if (defaultNamespace == null) return "";
|
|
else return defaultNamespace;
|
|
}
|
|
|
|
XmlTypeMapping ImportListMapping (Type type, XmlRootAttribute root, string defaultNamespace, XmlAttributes atts, int nestingLevel)
|
|
{
|
|
TypeData typeData = TypeTranslator.GetTypeData (type);
|
|
return ImportListMapping (typeData, root, defaultNamespace, atts, nestingLevel);
|
|
}
|
|
|
|
XmlTypeMapping ImportListMapping (TypeData typeData, XmlRootAttribute root, string defaultNamespace, XmlAttributes atts, int nestingLevel)
|
|
{
|
|
Type type = typeData.Type;
|
|
ListMap obmap = new ListMap ();
|
|
|
|
if (!allowPrivateTypes)
|
|
ReflectionHelper.CheckSerializableType (type, true);
|
|
|
|
if (atts == null) atts = new XmlAttributes();
|
|
Type itemType = typeData.ListItemType;
|
|
|
|
// warning: byte[][] should not be considered multiarray
|
|
bool isMultiArray = (type.IsArray && (TypeTranslator.GetTypeData(itemType).SchemaType == SchemaTypes.Array) && itemType.IsArray);
|
|
|
|
XmlTypeMapElementInfoList list = new XmlTypeMapElementInfoList();
|
|
|
|
foreach (XmlArrayItemAttribute att in atts.XmlArrayItems)
|
|
{
|
|
if (att.Namespace != null && att.Form == XmlSchemaForm.Unqualified)
|
|
throw new InvalidOperationException ("XmlArrayItemAttribute.Form must not be Unqualified when it has an explicit Namespace value.");
|
|
if (att.NestingLevel != nestingLevel) continue;
|
|
Type elemType = (att.Type != null) ? att.Type : itemType;
|
|
XmlTypeMapElementInfo elem = new XmlTypeMapElementInfo (null, TypeTranslator.GetTypeData(elemType, att.DataType));
|
|
elem.Namespace = att.Namespace != null ? att.Namespace : defaultNamespace;
|
|
if (elem.Namespace == null) elem.Namespace = "";
|
|
elem.Form = att.Form;
|
|
if (att.Form == XmlSchemaForm.Unqualified)
|
|
elem.Namespace = string.Empty;
|
|
elem.IsNullable = (!att.IsNullableSpecified || att.IsNullable) && CanBeNull (elem.TypeData);
|
|
elem.NestingLevel = att.NestingLevel;
|
|
|
|
if (isMultiArray) {
|
|
elem.MappedType = ImportListMapping (elemType, null, elem.Namespace, atts, nestingLevel + 1);
|
|
} else if (elem.TypeData.IsComplexType) {
|
|
elem.MappedType = ImportTypeMapping (elemType, null, elem.Namespace);
|
|
}
|
|
|
|
if (att.ElementName.Length != 0) {
|
|
elem.ElementName = XmlConvert.EncodeLocalName (att.ElementName);
|
|
} else if (elem.MappedType != null) {
|
|
elem.ElementName = elem.MappedType.ElementName;
|
|
} else {
|
|
elem.ElementName = TypeTranslator.GetTypeData (elemType).XmlType;
|
|
}
|
|
|
|
list.Add (elem);
|
|
}
|
|
|
|
if (list.Count == 0)
|
|
{
|
|
XmlTypeMapElementInfo elem = new XmlTypeMapElementInfo (null, TypeTranslator.GetTypeData (itemType));
|
|
if (isMultiArray)
|
|
elem.MappedType = ImportListMapping (itemType, null, defaultNamespace, atts, nestingLevel + 1);
|
|
else if (elem.TypeData.IsComplexType)
|
|
elem.MappedType = ImportTypeMapping (itemType, null, defaultNamespace);
|
|
|
|
if (elem.MappedType != null) {
|
|
elem.ElementName = elem.MappedType.XmlType;
|
|
} else {
|
|
elem.ElementName = TypeTranslator.GetTypeData (itemType).XmlType;
|
|
}
|
|
|
|
elem.Namespace = (defaultNamespace != null) ? defaultNamespace : "";
|
|
elem.IsNullable = CanBeNull (elem.TypeData);
|
|
list.Add (elem);
|
|
}
|
|
|
|
obmap.ItemInfo = list;
|
|
|
|
// If there can be different element names (types) in the array, then its name cannot
|
|
// be "ArrayOfXXX" it must be something like ArrayOfChoiceNNN
|
|
|
|
string baseName;
|
|
if (list.Count > 1) {
|
|
baseName = "ArrayOfChoice" + (arrayChoiceCount++);
|
|
} else {
|
|
XmlTypeMapElementInfo elem = ((XmlTypeMapElementInfo) list[0]);
|
|
if (elem.MappedType != null) {
|
|
baseName = TypeTranslator.GetArrayName (elem.MappedType.XmlType);
|
|
} else {
|
|
baseName = TypeTranslator.GetArrayName (elem.ElementName);
|
|
}
|
|
}
|
|
|
|
// Avoid name colisions
|
|
|
|
int nameCount = 1;
|
|
string name = baseName;
|
|
|
|
do {
|
|
XmlTypeMapping foundMap = helper.GetRegisteredSchemaType (name, defaultNamespace);
|
|
if (foundMap == null) nameCount = -1;
|
|
else if (obmap.Equals (foundMap.ObjectMap) && typeData.Type == foundMap.TypeData.Type) return foundMap;
|
|
else name = baseName + (nameCount++);
|
|
}
|
|
while (nameCount != -1);
|
|
|
|
XmlTypeMapping map = CreateTypeMapping (typeData, root, name, defaultNamespace);
|
|
map.ObjectMap = obmap;
|
|
|
|
// Register any of the including types as a derived class of object
|
|
XmlIncludeAttribute[] includes = (XmlIncludeAttribute[])type.GetCustomAttributes (typeof (XmlIncludeAttribute), false);
|
|
|
|
XmlTypeMapping objectMapping = ImportTypeMapping (typeof(object));
|
|
for (int i = 0; i < includes.Length; i++)
|
|
{
|
|
Type includedType = includes[i].Type;
|
|
objectMapping.DerivedTypes.Add(ImportTypeMapping (includedType, null, defaultNamespace));
|
|
}
|
|
|
|
// Register this map as a derived class of object
|
|
|
|
helper.RegisterSchemaType (map, name, defaultNamespace);
|
|
ImportTypeMapping (typeof(object)).DerivedTypes.Add (map);
|
|
|
|
return map;
|
|
}
|
|
|
|
XmlTypeMapping ImportXmlNodeMapping (TypeData typeData, XmlRootAttribute root, string defaultNamespace)
|
|
{
|
|
Type type = typeData.Type;
|
|
XmlTypeMapping map = helper.GetRegisteredClrType (type, GetTypeNamespace (typeData, root, defaultNamespace));
|
|
if (map != null) return map;
|
|
|
|
map = CreateTypeMapping (typeData, root, null, defaultNamespace);
|
|
helper.RegisterClrType (map, type, map.XmlTypeNamespace);
|
|
|
|
if (type.BaseType != null)
|
|
{
|
|
XmlTypeMapping bmap = ImportTypeMapping (type.BaseType, root, defaultNamespace);
|
|
if (type.BaseType != typeof (object))
|
|
map.BaseMap = bmap;
|
|
|
|
RegisterDerivedMap (bmap, map);
|
|
}
|
|
|
|
return map;
|
|
}
|
|
|
|
XmlTypeMapping ImportPrimitiveMapping (TypeData typeData, XmlRootAttribute root, string defaultNamespace)
|
|
{
|
|
Type type = typeData.Type;
|
|
XmlTypeMapping map = helper.GetRegisteredClrType (type, GetTypeNamespace (typeData, root, defaultNamespace));
|
|
if (map != null) return map;
|
|
map = CreateTypeMapping (typeData, root, null, defaultNamespace);
|
|
helper.RegisterClrType (map, type, map.XmlTypeNamespace);
|
|
return map;
|
|
}
|
|
|
|
XmlTypeMapping ImportEnumMapping (TypeData typeData, XmlRootAttribute root, string defaultNamespace)
|
|
{
|
|
Type type = typeData.Type;
|
|
XmlTypeMapping map = helper.GetRegisteredClrType (type, GetTypeNamespace (typeData, root, defaultNamespace));
|
|
if (map != null) return map;
|
|
|
|
if (!allowPrivateTypes)
|
|
ReflectionHelper.CheckSerializableType (type, false);
|
|
|
|
map = CreateTypeMapping (typeData, root, null, defaultNamespace);
|
|
map.IsNullable = false;
|
|
helper.RegisterClrType (map, type, map.XmlTypeNamespace);
|
|
|
|
ArrayList members = new ArrayList();
|
|
string [] names = Enum.GetNames (type);
|
|
foreach (string name in names) {
|
|
FieldInfo field = type.GetField (name);
|
|
string xmlName = null;
|
|
if (field.IsDefined(typeof(XmlIgnoreAttribute), false))
|
|
continue;
|
|
object[] atts = field.GetCustomAttributes (typeof(XmlEnumAttribute), false);
|
|
if (atts.Length > 0) xmlName = ((XmlEnumAttribute)atts[0]).Name;
|
|
if (xmlName == null) xmlName = name;
|
|
long value = ((IConvertible) field.GetValue (null)).ToInt64 (CultureInfo.InvariantCulture);
|
|
members.Add (new EnumMap.EnumMapMember (xmlName, name, value));
|
|
}
|
|
|
|
bool isFlags = type.IsDefined (typeof (FlagsAttribute), false);
|
|
map.ObjectMap = new EnumMap ((EnumMap.EnumMapMember[])members.ToArray (typeof(EnumMap.EnumMapMember)), isFlags);
|
|
ImportTypeMapping (typeof(object)).DerivedTypes.Add (map);
|
|
return map;
|
|
}
|
|
|
|
XmlTypeMapping ImportXmlSerializableMapping (TypeData typeData, XmlRootAttribute root, string defaultNamespace)
|
|
{
|
|
Type type = typeData.Type;
|
|
XmlTypeMapping map = helper.GetRegisteredClrType (type, GetTypeNamespace (typeData, root, defaultNamespace));
|
|
if (map != null) return map;
|
|
|
|
if (!allowPrivateTypes)
|
|
ReflectionHelper.CheckSerializableType (type, false);
|
|
|
|
map = CreateTypeMapping (typeData, root, null, defaultNamespace);
|
|
helper.RegisterClrType (map, type, map.XmlTypeNamespace);
|
|
return map;
|
|
}
|
|
|
|
void ImportIncludedTypes (Type type, string defaultNamespace)
|
|
{
|
|
XmlIncludeAttribute[] includes = (XmlIncludeAttribute[])type.GetCustomAttributes (typeof (XmlIncludeAttribute), false);
|
|
for (int n=0; n<includes.Length; n++)
|
|
{
|
|
Type includedType = includes[n].Type;
|
|
ImportTypeMapping (includedType, null, defaultNamespace);
|
|
}
|
|
}
|
|
|
|
List<XmlReflectionMember> GetReflectionMembers (Type type)
|
|
{
|
|
// First we want to find the inheritance hierarchy in reverse order.
|
|
Type currentType = type;
|
|
ArrayList typeList = new ArrayList();
|
|
typeList.Add(currentType);
|
|
while (currentType != typeof(object))
|
|
{
|
|
currentType = currentType.BaseType; // Read the base type.
|
|
typeList.Insert(0, currentType); // Insert at 0 to reverse the order.
|
|
}
|
|
|
|
// Read all Fields via reflection.
|
|
ArrayList fieldList = new ArrayList();
|
|
FieldInfo[] tfields = type.GetFields (BindingFlags.Instance | BindingFlags.Public);
|
|
currentType = null;
|
|
int currentIndex = 0;
|
|
foreach (FieldInfo field in tfields)
|
|
{
|
|
// This statement ensures fields are ordered starting from the base type.
|
|
if (currentType != field.DeclaringType)
|
|
{
|
|
currentType = field.DeclaringType;
|
|
currentIndex=0;
|
|
}
|
|
fieldList.Insert(currentIndex++, field);
|
|
}
|
|
// Read all Properties via reflection.
|
|
ArrayList propList = new ArrayList();
|
|
PropertyInfo[] tprops = type.GetProperties (BindingFlags.Instance | BindingFlags.Public);
|
|
currentType = null;
|
|
currentIndex = 0;
|
|
foreach (PropertyInfo prop in tprops)
|
|
{
|
|
// This statement ensures properties are ordered starting from the base type.
|
|
if (currentType != prop.DeclaringType)
|
|
{
|
|
currentType = prop.DeclaringType;
|
|
currentIndex = 0;
|
|
}
|
|
if (!prop.CanRead) continue;
|
|
if (prop.GetIndexParameters().Length > 0) continue;
|
|
propList.Insert(currentIndex++, prop);
|
|
}
|
|
var members = new List<XmlReflectionMember>();
|
|
int fieldIndex=0;
|
|
int propIndex=0;
|
|
// We now step through the type hierarchy from the base (object) through
|
|
// to the supplied class, as each step outputting all Fields, and then
|
|
// all Properties. This is the exact same ordering as .NET 1.0/1.1.
|
|
foreach (Type t in typeList)
|
|
{
|
|
// Add any fields matching the current DeclaringType.
|
|
while (fieldIndex < fieldList.Count)
|
|
{
|
|
FieldInfo field = (FieldInfo)fieldList[fieldIndex];
|
|
if (field.DeclaringType==t)
|
|
{
|
|
fieldIndex++;
|
|
XmlAttributes atts = attributeOverrides[type, field.Name];
|
|
if (atts == null) atts = new XmlAttributes (field);
|
|
if (atts.XmlIgnore) continue;
|
|
XmlReflectionMember member = new XmlReflectionMember(field.Name, field.FieldType, atts);
|
|
member.DeclaringType = field.DeclaringType;
|
|
members.Add(member);
|
|
}
|
|
else break;
|
|
}
|
|
|
|
// Add any properties matching the current DeclaringType.
|
|
while (propIndex < propList.Count)
|
|
{
|
|
PropertyInfo prop = (PropertyInfo)propList[propIndex];
|
|
if (prop.DeclaringType==t)
|
|
{
|
|
propIndex++;
|
|
XmlAttributes atts = attributeOverrides[type, prop.Name];
|
|
if (atts == null) atts = new XmlAttributes (prop);
|
|
if (atts.XmlIgnore) continue;
|
|
if (!prop.CanWrite) {
|
|
if (prop.PropertyType.IsInterface && typeof (IEnumerable).IsAssignableFrom (prop.PropertyType)) continue;
|
|
if (prop.PropertyType.IsGenericType && TypeData.GetGenericListItemType (prop.PropertyType) == null) continue; // check this before calling GetTypeData() which raises error for missing Add(). See bug #704813.
|
|
if (TypeTranslator.GetTypeData (prop.PropertyType).SchemaType != SchemaTypes.Array || prop.PropertyType.IsArray) continue;
|
|
}
|
|
XmlReflectionMember member = new XmlReflectionMember(prop.Name, prop.PropertyType, atts);
|
|
member.DeclaringType = prop.DeclaringType;
|
|
members.Add(member);
|
|
}
|
|
else break;
|
|
}
|
|
}
|
|
|
|
return members;
|
|
}
|
|
|
|
private XmlTypeMapMember CreateMapMember (Type declaringType, XmlReflectionMember rmember, string defaultNamespace)
|
|
{
|
|
XmlTypeMapMember mapMember;
|
|
XmlAttributes atts = rmember.XmlAttributes;
|
|
TypeData typeData = TypeTranslator.GetTypeData (rmember.MemberType);
|
|
|
|
if (atts.XmlArray != null) {
|
|
if (atts.XmlArray.Namespace != null && atts.XmlArray.Form == XmlSchemaForm.Unqualified)
|
|
throw new InvalidOperationException ("XmlArrayAttribute.Form must not be Unqualified when it has an explicit Namespace value.");
|
|
if (typeData.SchemaType != SchemaTypes.Array &&
|
|
!(typeData.SchemaType == SchemaTypes.Primitive && typeData.Type == typeof (byte [])))
|
|
throw new InvalidOperationException ("XmlArrayAttribute can be applied to members of array or collection type.");
|
|
}
|
|
|
|
if (atts.XmlAnyAttribute != null)
|
|
{
|
|
if ( (rmember.MemberType.FullName == "System.Xml.XmlAttribute[]") ||
|
|
(rmember.MemberType.FullName == "System.Xml.XmlNode[]") )
|
|
{
|
|
mapMember = new XmlTypeMapMemberAnyAttribute();
|
|
}
|
|
else
|
|
throw new InvalidOperationException ("XmlAnyAttributeAttribute can only be applied to members of type XmlAttribute[] or XmlNode[]");
|
|
}
|
|
else
|
|
if (atts.XmlAnyElements != null && atts.XmlAnyElements.Count > 0)
|
|
{
|
|
// no XmlNode type check is done here (seealso: bug #553032).
|
|
XmlTypeMapMemberAnyElement member = new XmlTypeMapMemberAnyElement();
|
|
member.ElementInfo = ImportAnyElementInfo (defaultNamespace, rmember, member, atts);
|
|
mapMember = member;
|
|
}
|
|
else if (atts.Xmlns)
|
|
{
|
|
XmlTypeMapMemberNamespaces mapNamespaces = new XmlTypeMapMemberNamespaces ();
|
|
mapMember = mapNamespaces;
|
|
}
|
|
else if (atts.XmlAttribute != null)
|
|
{
|
|
// An attribute
|
|
|
|
if (atts.XmlElements != null && atts.XmlElements.Count > 0)
|
|
throw new Exception ("XmlAttributeAttribute and XmlElementAttribute cannot be applied to the same member");
|
|
|
|
XmlTypeMapMemberAttribute mapAttribute = new XmlTypeMapMemberAttribute ();
|
|
if (atts.XmlAttribute.AttributeName.Length == 0)
|
|
mapAttribute.AttributeName = rmember.MemberName;
|
|
else
|
|
mapAttribute.AttributeName = atts.XmlAttribute.AttributeName;
|
|
|
|
mapAttribute.AttributeName = XmlConvert.EncodeName (mapAttribute.AttributeName);
|
|
|
|
if (typeData.IsComplexType)
|
|
mapAttribute.MappedType = ImportTypeMapping (typeData.Type, null, defaultNamespace);
|
|
|
|
if (atts.XmlAttribute.Namespace != null && atts.XmlAttribute.Namespace != defaultNamespace)
|
|
{
|
|
if (atts.XmlAttribute.Form == XmlSchemaForm.Unqualified)
|
|
throw new InvalidOperationException ("The Form property may not be 'Unqualified' when an explicit Namespace property is present");
|
|
mapAttribute.Form = XmlSchemaForm.Qualified;
|
|
mapAttribute.Namespace = atts.XmlAttribute.Namespace;
|
|
}
|
|
else
|
|
{
|
|
mapAttribute.Form = atts.XmlAttribute.Form;
|
|
if (atts.XmlAttribute.Form == XmlSchemaForm.Qualified)
|
|
mapAttribute.Namespace = defaultNamespace;
|
|
else
|
|
mapAttribute.Namespace = "";
|
|
}
|
|
|
|
typeData = TypeTranslator.GetTypeData(rmember.MemberType, atts.XmlAttribute.DataType);
|
|
mapMember = mapAttribute;
|
|
}
|
|
else if (typeData.SchemaType == SchemaTypes.Array)
|
|
{
|
|
// If the member has a single XmlElementAttribute and the type is the type of the member,
|
|
// then it is not a flat list
|
|
|
|
if (atts.XmlElements.Count > 1 ||
|
|
(atts.XmlElements.Count == 1 && atts.XmlElements[0].Type != typeData.Type) ||
|
|
(atts.XmlText != null))
|
|
{
|
|
// A flat list
|
|
|
|
// check that it does not have XmlArrayAttribute
|
|
if (atts.XmlArray != null)
|
|
throw new InvalidOperationException ("XmlArrayAttribute cannot be used with members which also attributed with XmlElementAttribute or XmlTextAttribute.");
|
|
|
|
XmlTypeMapMemberFlatList member = new XmlTypeMapMemberFlatList ();
|
|
member.ListMap = new ListMap ();
|
|
member.ListMap.ItemInfo = ImportElementInfo (declaringType, XmlConvert.EncodeLocalName (rmember.MemberName), defaultNamespace, typeData.ListItemType, member, atts);
|
|
member.ElementInfo = member.ListMap.ItemInfo;
|
|
member.ListMap.ChoiceMember = member.ChoiceMember;
|
|
mapMember = member;
|
|
}
|
|
else
|
|
{
|
|
// A list
|
|
|
|
XmlTypeMapMemberList member = new XmlTypeMapMemberList ();
|
|
|
|
// Creates an ElementInfo that identifies the array instance.
|
|
member.ElementInfo = new XmlTypeMapElementInfoList();
|
|
XmlTypeMapElementInfo elem = new XmlTypeMapElementInfo (member, typeData);
|
|
elem.ElementName = XmlConvert.EncodeLocalName((atts.XmlArray != null && atts.XmlArray.ElementName.Length != 0) ? atts.XmlArray.ElementName : rmember.MemberName);
|
|
// note that it could be changed below (when Form is Unqualified)
|
|
elem.Namespace = (atts.XmlArray != null && atts.XmlArray.Namespace != null) ? atts.XmlArray.Namespace : defaultNamespace;
|
|
elem.MappedType = ImportListMapping (rmember.MemberType, null, elem.Namespace, atts, 0);
|
|
elem.IsNullable = (atts.XmlArray != null) ? atts.XmlArray.IsNullable : false;
|
|
elem.Form = (atts.XmlArray != null) ? atts.XmlArray.Form : XmlSchemaForm.Qualified;
|
|
elem.ExplicitOrder = (atts.XmlArray != null) ? atts.XmlArray.Order : -1;
|
|
// This is a bit tricky, but is done
|
|
// after filling descendant members, so
|
|
// that array items could be serialized
|
|
// with proper namespace.
|
|
if (atts.XmlArray != null && atts.XmlArray.Form == XmlSchemaForm.Unqualified)
|
|
elem.Namespace = String.Empty;
|
|
|
|
member.ElementInfo.Add (elem);
|
|
mapMember = member;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// An element
|
|
|
|
XmlTypeMapMemberElement member = new XmlTypeMapMemberElement ();
|
|
member.ElementInfo = ImportElementInfo (declaringType, XmlConvert.EncodeLocalName(rmember.MemberName), defaultNamespace, rmember.MemberType, member, atts);
|
|
mapMember = member;
|
|
}
|
|
|
|
mapMember.DefaultValue = GetDefaultValue (typeData, atts.XmlDefaultValue);
|
|
mapMember.TypeData = typeData;
|
|
mapMember.Name = rmember.MemberName;
|
|
mapMember.IsReturnValue = rmember.IsReturnValue;
|
|
return mapMember;
|
|
}
|
|
|
|
XmlTypeMapElementInfoList ImportElementInfo (Type cls, string defaultName, string defaultNamespace, Type defaultType, XmlTypeMapMemberElement member, XmlAttributes atts)
|
|
{
|
|
EnumMap choiceEnumMap = null;
|
|
Type choiceEnumType = null;
|
|
|
|
XmlTypeMapElementInfoList list = new XmlTypeMapElementInfoList();
|
|
ImportTextElementInfo (list, defaultType, member, atts, defaultNamespace);
|
|
|
|
if (atts.XmlChoiceIdentifier != null) {
|
|
if (cls == null)
|
|
throw new InvalidOperationException ("XmlChoiceIdentifierAttribute not supported in this context.");
|
|
|
|
member.ChoiceMember = atts.XmlChoiceIdentifier.MemberName;
|
|
MemberInfo[] mems = cls.GetMember (member.ChoiceMember, BindingFlags.Instance|BindingFlags.Public);
|
|
|
|
if (mems.Length == 0)
|
|
throw new InvalidOperationException ("Choice member '" + member.ChoiceMember + "' not found in class '" + cls);
|
|
|
|
if (mems[0] is PropertyInfo) {
|
|
PropertyInfo pi = (PropertyInfo)mems[0];
|
|
if (!pi.CanWrite || !pi.CanRead)
|
|
throw new InvalidOperationException ("Choice property '" + member.ChoiceMember + "' must be read/write.");
|
|
choiceEnumType = pi.PropertyType;
|
|
}
|
|
else choiceEnumType = ((FieldInfo)mems[0]).FieldType;
|
|
|
|
member.ChoiceTypeData = TypeTranslator.GetTypeData (choiceEnumType);
|
|
|
|
if (choiceEnumType.IsArray)
|
|
choiceEnumType = choiceEnumType.GetElementType ();
|
|
|
|
choiceEnumMap = ImportTypeMapping (choiceEnumType).ObjectMap as EnumMap;
|
|
if (choiceEnumMap == null)
|
|
throw new InvalidOperationException ("The member '" + mems[0].Name + "' is not a valid target for XmlChoiceIdentifierAttribute.");
|
|
}
|
|
|
|
if (atts.XmlElements.Count == 0 && list.Count == 0)
|
|
{
|
|
XmlTypeMapElementInfo elem = new XmlTypeMapElementInfo (member, TypeTranslator.GetTypeData(defaultType));
|
|
elem.ElementName = defaultName;
|
|
elem.Namespace = defaultNamespace;
|
|
if (elem.TypeData.IsComplexType)
|
|
elem.MappedType = ImportTypeMapping (defaultType, null, defaultNamespace);
|
|
list.Add (elem);
|
|
}
|
|
|
|
bool multiType = (atts.XmlElements.Count > 1);
|
|
foreach (XmlElementAttribute att in atts.XmlElements)
|
|
{
|
|
Type elemType = (att.Type != null) ? att.Type : defaultType;
|
|
XmlTypeMapElementInfo elem = new XmlTypeMapElementInfo (member, TypeTranslator.GetTypeData(elemType, att.DataType));
|
|
elem.Form = att.Form;
|
|
if (elem.Form != XmlSchemaForm.Unqualified)
|
|
elem.Namespace = (att.Namespace != null) ? att.Namespace : defaultNamespace;
|
|
|
|
// elem may already be nullable, and IsNullable property in XmlElement is false by default
|
|
if (att.IsNullable && !elem.IsNullable)
|
|
elem.IsNullable = att.IsNullable;
|
|
|
|
elem.ExplicitOrder = att.Order;
|
|
|
|
if (elem.IsNullable && !elem.TypeData.IsNullable)
|
|
throw new InvalidOperationException ("IsNullable may not be 'true' for value type " + elem.TypeData.FullTypeName + " in member '" + defaultName + "'");
|
|
|
|
if (elem.TypeData.IsComplexType)
|
|
{
|
|
if (att.DataType.Length != 0) throw new InvalidOperationException (
|
|
string.Format(CultureInfo.InvariantCulture, "'{0}' is "
|
|
+ "an invalid value for '{1}.{2}' of type '{3}'. "
|
|
+ "The property may only be specified for primitive types.",
|
|
att.DataType, cls.FullName, defaultName,
|
|
elem.TypeData.FullTypeName));
|
|
elem.MappedType = ImportTypeMapping (elemType, null, elem.Namespace);
|
|
}
|
|
|
|
if (att.ElementName.Length != 0) {
|
|
elem.ElementName = XmlConvert.EncodeLocalName(att.ElementName);
|
|
} else if (multiType) {
|
|
if (elem.MappedType != null) {
|
|
elem.ElementName = elem.MappedType.ElementName;
|
|
} else {
|
|
elem.ElementName = TypeTranslator.GetTypeData (elemType).XmlType;
|
|
}
|
|
} else {
|
|
elem.ElementName = defaultName;
|
|
}
|
|
|
|
if (choiceEnumMap != null) {
|
|
string cname = choiceEnumMap.GetEnumName (choiceEnumType.FullName, elem.ElementName);
|
|
if (cname == null && elem.Namespace != null)
|
|
cname = choiceEnumMap.GetEnumName (choiceEnumType.FullName,
|
|
elem.Namespace.ToString () + ":" + elem.ElementName);
|
|
if (cname == null)
|
|
throw new InvalidOperationException (string.Format (
|
|
CultureInfo.InvariantCulture, "Type {0} is missing"
|
|
+ " enumeration value '{1}' for element '{1} from"
|
|
+ " namespace '{2}'.", choiceEnumType, elem.ElementName,
|
|
elem.Namespace));
|
|
elem.ChoiceValue = Enum.Parse (choiceEnumType, cname, false);
|
|
}
|
|
|
|
list.Add (elem);
|
|
}
|
|
return list;
|
|
}
|
|
|
|
XmlTypeMapElementInfoList ImportAnyElementInfo (string defaultNamespace, XmlReflectionMember rmember, XmlTypeMapMemberElement member, XmlAttributes atts)
|
|
{
|
|
XmlTypeMapElementInfoList list = new XmlTypeMapElementInfoList();
|
|
|
|
ImportTextElementInfo (list, rmember.MemberType, member, atts, defaultNamespace);
|
|
|
|
foreach (XmlAnyElementAttribute att in atts.XmlAnyElements)
|
|
{
|
|
XmlTypeMapElementInfo elem = new XmlTypeMapElementInfo (member, TypeTranslator.GetTypeData(typeof(XmlElement)));
|
|
if (att.Name.Length != 0)
|
|
{
|
|
elem.ElementName = XmlConvert.EncodeLocalName(att.Name);
|
|
elem.Namespace = (att.Namespace != null) ? att.Namespace : "";
|
|
}
|
|
else
|
|
{
|
|
elem.IsUnnamedAnyElement = true;
|
|
elem.Namespace = defaultNamespace;
|
|
if (att.Namespace != null)
|
|
throw new InvalidOperationException ("The element " + rmember.MemberName + " has been attributed with an XmlAnyElementAttribute and a namespace '" + att.Namespace + "', but no name. When a namespace is supplied, a name is also required. Supply a name or remove the namespace.");
|
|
}
|
|
elem.ExplicitOrder = att.Order;
|
|
list.Add (elem);
|
|
}
|
|
return list;
|
|
}
|
|
|
|
void ImportTextElementInfo (XmlTypeMapElementInfoList list, Type defaultType, XmlTypeMapMemberElement member, XmlAttributes atts, string defaultNamespace)
|
|
{
|
|
if (atts.XmlText != null)
|
|
{
|
|
member.IsXmlTextCollector = true;
|
|
if (atts.XmlText.Type != null) {
|
|
TypeData td = TypeTranslator.GetTypeData (defaultType);
|
|
if ((td.SchemaType == SchemaTypes.Primitive || td.SchemaType == SchemaTypes.Enum) && atts.XmlText.Type != defaultType) {
|
|
throw new InvalidOperationException ("The type for XmlText may not be specified for primitive types.");
|
|
}
|
|
defaultType = atts.XmlText.Type;
|
|
}
|
|
if (defaultType == typeof(XmlNode)) defaultType = typeof(XmlText); // Nodes must be text nodes
|
|
|
|
XmlTypeMapElementInfo elem = new XmlTypeMapElementInfo (member, TypeTranslator.GetTypeData(defaultType, atts.XmlText.DataType));
|
|
|
|
if (elem.TypeData.SchemaType != SchemaTypes.Primitive &&
|
|
elem.TypeData.SchemaType != SchemaTypes.Enum &&
|
|
elem.TypeData.SchemaType != SchemaTypes.XmlNode &&
|
|
!(elem.TypeData.SchemaType == SchemaTypes.Array && elem.TypeData.ListItemTypeData.SchemaType == SchemaTypes.XmlNode)
|
|
)
|
|
throw new InvalidOperationException ("XmlText cannot be used to encode complex types");
|
|
|
|
if (elem.TypeData.IsComplexType)
|
|
elem.MappedType = ImportTypeMapping (defaultType, null, defaultNamespace);
|
|
elem.IsTextElement = true;
|
|
elem.WrappedElement = false;
|
|
list.Add (elem);
|
|
}
|
|
}
|
|
|
|
bool CanBeNull (TypeData type)
|
|
{
|
|
return !type.Type.IsValueType || type.IsNullable;
|
|
}
|
|
|
|
public void IncludeType (Type type)
|
|
{
|
|
if (type == null)
|
|
throw new ArgumentNullException ("type");
|
|
|
|
if (includedTypes == null) includedTypes = new ArrayList ();
|
|
if (!includedTypes.Contains (type))
|
|
includedTypes.Add (type);
|
|
|
|
if (relatedMaps.Count > 0) {
|
|
foreach (XmlTypeMapping map in (ArrayList) relatedMaps.Clone ()) {
|
|
if (map.TypeData.Type == typeof(object))
|
|
map.DerivedTypes.Add (ImportTypeMapping (type));
|
|
}
|
|
}
|
|
}
|
|
|
|
public void IncludeTypes (ICustomAttributeProvider provider)
|
|
{
|
|
object[] ats = provider.GetCustomAttributes (typeof(XmlIncludeAttribute), true);
|
|
|
|
foreach (XmlIncludeAttribute at in ats)
|
|
IncludeType (at.Type);
|
|
}
|
|
|
|
private object GetDefaultValue (TypeData typeData, object defaultValue)
|
|
{
|
|
if (defaultValue == DBNull.Value || typeData.SchemaType != SchemaTypes.Enum)
|
|
return defaultValue;
|
|
|
|
// get string representation of enum value
|
|
string namedValue = Enum.Format (typeData.Type, defaultValue, "g");
|
|
// get decimal representation of enum value
|
|
string decimalValue = Enum.Format (typeData.Type, defaultValue, "d");
|
|
// if decimal representation matches string representation, then
|
|
// the value is not defined in the enum type (as the "g" format
|
|
// will return the decimal equivalent of the value if the value
|
|
// is not equal to a combination of named enumerated constants
|
|
if (namedValue == decimalValue) {
|
|
string msg = string.Format (CultureInfo.InvariantCulture,
|
|
"Value '{0}' cannot be converted to {1}.", defaultValue,
|
|
defaultValue.GetType ().FullName);
|
|
throw new InvalidOperationException (msg);
|
|
}
|
|
|
|
// XmlSerializer expects integral enum value
|
|
//return namedValue.Replace (',', ' ');
|
|
return defaultValue;
|
|
}
|
|
|
|
#endregion // Methods
|
|
}
|
|
}
|