using System.Reflection;
using System.Collections;
+using System.Xml.Schema;
namespace System.Xml.Serialization {
public class XmlReflectionImporter {
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 XmlTextMember of the base class to string array";
+ "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
XmlMembersMapping mps = new XmlMembersMapping (elementName, ns, hasWrapperElement, false, mapping);
mps.RelatedMaps = relatedMaps;
mps.Format = SerializationFormat.Literal;
+ mps.Source = new MembersSerializationSource (elementName, hasWrapperElement, members, false, true, ns, includedTypes);
+ if (allowPrivateTypes) mps.Source.CanBeGenerated = false;
return mps;
}
map.RelatedMaps = relatedMaps;
map.Format = SerializationFormat.Literal;
+ map.Source = new XmlTypeSerializationSource (type, root, attributeOverrides, defaultNamespace, includedTypes);
+ if (allowPrivateTypes) map.Source.CanBeGenerated = false;
return map;
}
XmlTypeMapping CreateTypeMapping (TypeData typeData, XmlRootAttribute root, string defaultXmlType, string defaultNamespace)
{
- string membersNamespace;
+ string rootNamespace = defaultNamespace;
+ string typeNamespace = null;
+
string elementName;
bool includeInSchema = true;
XmlAttributes atts = null;
if (atts.XmlType != null)
{
if (atts.XmlType.Namespace != null && atts.XmlType.Namespace != string.Empty && typeData.SchemaType != SchemaTypes.Enum)
- defaultNamespace = atts.XmlType.Namespace;
+ typeNamespace = atts.XmlType.Namespace;
if (atts.XmlType.TypeName != null && atts.XmlType.TypeName != string.Empty)
defaultXmlType = atts.XmlType.TypeName;
includeInSchema = atts.XmlType.IncludeInSchema;
}
- membersNamespace = defaultNamespace;
elementName = defaultXmlType;
if (root != null)
if (root.ElementName != null && root.ElementName != String.Empty)
elementName = root.ElementName;
if (root.Namespace != null && root.Namespace != String.Empty)
- membersNamespace = root.Namespace;
+ rootNamespace = root.Namespace;
}
- if (membersNamespace == null) membersNamespace = "";
- XmlTypeMapping map = new XmlTypeMapping (elementName, membersNamespace, typeData, defaultXmlType, defaultNamespace);
+ if (rootNamespace == null) rootNamespace = "";
+ if (typeNamespace == null || typeNamespace.Length == 0) typeNamespace = rootNamespace;
+
+ XmlTypeMapping map = new XmlTypeMapping (elementName, rootNamespace, typeData, defaultXmlType, typeNamespace);
map.IncludeInSchema = includeInSchema;
relatedMaps.Add (map);
ReflectionHelper.CheckSerializableType (type);
map = CreateTypeMapping (typeData, root, null, defaultNamespace);
- helper.RegisterClrType (map, type, map.Namespace);
- helper.RegisterSchemaType (map, map.XmlType, map.Namespace);
+ helper.RegisterClrType (map, type, map.XmlTypeNamespace);
+ helper.RegisterSchemaType (map, map.XmlType, map.XmlTypeNamespace);
// Import members
foreach (XmlReflectionMember rmember in members)
{
if (rmember.XmlAttributes.XmlIgnore) continue;
- classMap.AddMember (CreateMapMember (rmember, map.Namespace));
+ XmlTypeMapMember mem = CreateMapMember (rmember, map.XmlTypeNamespace);
+ mem.CheckOptionalValueType (type);
+ classMap.AddMember (mem);
}
// }
// catch (Exception ex) {
{
XmlTypeMapping bmap = ImportClassMapping (type.BaseType, root, defaultNamespace);
- if (type.BaseType != typeof (object))
+ if (type.BaseType != typeof (object)) {
map.BaseMap = bmap;
+ classMap.SetCanBeSimpleType (false);
+ }
// At this point, derived classes of this map must be already registered
- bmap.DerivedTypes.Add (map);
- bmap.DerivedTypes.AddRange (map.DerivedTypes);
+ RegisterDerivedMap (bmap, map);
if (((ClassMap)bmap.ObjectMap).HasSimpleContent && classMap.ElementMembers != null && classMap.ElementMembers.Count != 1)
throw new InvalidOperationException (String.Format (errSimple, map.TypeData.TypeName, map.BaseMap.TypeData.TypeName));
}
+ 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(object[]) &&
+ mem.TypeData.Type != typeof(XmlNode[]))
+
+ 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 mapNamespace = defaultNamespace;
-
+ string typeNamespace = null;
+
XmlAttributes atts = null;
if (!typeData.IsListType)
{
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 && atts.XmlType.Namespace != string.Empty)
- mapNamespace = atts.XmlType.Namespace;
+ 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 != String.Empty)
- mapNamespace = root.Namespace;
+ if (root.Namespace != null && root.Namespace.Length != 0)
+ return root.Namespace;
}
- if (mapNamespace == null) return "";
- else return mapNamespace;
+ if (defaultNamespace == null) return "";
+ else return defaultNamespace;
}
XmlTypeMapping ImportListMapping (Type type, XmlRootAttribute root, string defaultNamespace, XmlAttributes atts, int nestingLevel)
else if (elem.TypeData.IsComplexType)
elem.MappedType = ImportTypeMapping (itemType, null, defaultNamespace);
- if (elem.MappedType != null) elem.ElementName = elem.MappedType.ElementName;
+ if (elem.MappedType != null) elem.ElementName = elem.MappedType.XmlType;
else elem.ElementName = TypeTranslator.GetTypeData(itemType).XmlType ;
elem.Namespace = (defaultNamespace != null) ? defaultNamespace : "";
else
{
XmlTypeMapElementInfo elem = ((XmlTypeMapElementInfo)list[0]);
- if (elem.MappedType != null) baseName = TypeTranslator.GetArrayName (elem.MappedType.ElementName);
+ if (elem.MappedType != null) baseName = TypeTranslator.GetArrayName (elem.MappedType.XmlType);
else baseName = TypeTranslator.GetArrayName (elem.ElementName);
}
// Registers the maps for XmlNode and XmlElement
XmlTypeMapping nodeMap = CreateTypeMapping (TypeTranslator.GetTypeData (typeof(XmlNode)), root, null, defaultNamespace);
- helper.RegisterClrType (nodeMap, typeof(XmlNode), nodeMap.Namespace);
+ helper.RegisterClrType (nodeMap, typeof(XmlNode), nodeMap.XmlTypeNamespace);
XmlTypeMapping elemMap = CreateTypeMapping (TypeTranslator.GetTypeData (typeof(XmlElement)), root, null, defaultNamespace);
- helper.RegisterClrType (elemMap, typeof(XmlElement), elemMap.Namespace);
+ helper.RegisterClrType (elemMap, typeof(XmlElement), elemMap.XmlTypeNamespace);
XmlTypeMapping textMap = CreateTypeMapping (TypeTranslator.GetTypeData (typeof(XmlText)), root, null, defaultNamespace);
- helper.RegisterClrType (elemMap, typeof(XmlText), textMap.Namespace);
+ helper.RegisterClrType (elemMap, typeof(XmlText), textMap.XmlTypeNamespace);
XmlTypeMapping obmap = ImportTypeMapping (typeof(object));
obmap.DerivedTypes.Add (nodeMap);
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.Namespace);
+ helper.RegisterClrType (map, type, map.XmlTypeNamespace);
return map;
}
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.Namespace);
+ helper.RegisterClrType (map, type, map.XmlTypeNamespace);
string [] names = Enum.GetNames (type);
ArrayList members = new ArrayList();
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.Namespace);
+ helper.RegisterClrType (map, type, map.XmlTypeNamespace);
return map;
}
}
}
- public ICollection GetReflectionMembers (Type type)
+ ICollection GetReflectionMembers (Type type)
{
ArrayList members = new ArrayList();
- PropertyInfo[] properties = type.GetProperties (BindingFlags.Instance | BindingFlags.Public);
- foreach (PropertyInfo prop in properties)
- {
- if (!prop.CanRead) continue;
- if (!prop.CanWrite && TypeTranslator.GetTypeData (prop.PropertyType).SchemaType != SchemaTypes.Array)
- continue;
- if (prop.GetIndexParameters().Length > 0) continue;
-
- XmlAttributes atts = attributeOverrides[type, prop.Name];
- if (atts == null) atts = new XmlAttributes (prop);
- if (atts.XmlIgnore) continue;
- XmlReflectionMember member = new XmlReflectionMember(prop.Name, prop.PropertyType, atts);
- members.Add (member);
- }
-
- FieldInfo[] fields = type.GetFields (BindingFlags.Instance | BindingFlags.Public);
- foreach (FieldInfo field in fields)
+ MemberInfo[] tmembers = type.GetMembers (BindingFlags.Instance | BindingFlags.Public);
+ int currentTypePos = 0;
+ Type currentType = null;
+
+ foreach (MemberInfo tmember in tmembers)
{
- 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);
- members.Add (member);
+ if (currentType != tmember.DeclaringType)
+ {
+ currentType = tmember.DeclaringType;
+ currentTypePos = 0;
+ }
+
+ if (tmember is FieldInfo)
+ {
+ FieldInfo field = tmember as FieldInfo;
+ 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);
+ members.Insert (currentTypePos, member);
+ currentTypePos++;
+ }
+ else if (tmember is PropertyInfo)
+ {
+ PropertyInfo prop = tmember as PropertyInfo;
+ if (!prop.CanRead) continue;
+ if (!prop.CanWrite && TypeTranslator.GetTypeData (prop.PropertyType).SchemaType != SchemaTypes.Array)
+ continue;
+ if (prop.GetIndexParameters().Length > 0) continue;
+
+ XmlAttributes atts = attributeOverrides[type, prop.Name];
+ if (atts == null) atts = new XmlAttributes (prop);
+ if (atts.XmlIgnore) continue;
+ XmlReflectionMember member = new XmlReflectionMember(prop.Name, prop.PropertyType, atts);
+ members.Insert (currentTypePos, member);
+ currentTypePos++;
+ }
}
return members;
}
(rmember.MemberType.FullName == "System.Xml.XmlElement"))
{
XmlTypeMapMemberAnyElement member = new XmlTypeMapMemberAnyElement();
- member.ElementInfo = ImportAnyElementInfo (defaultNamespace, rmember.MemberType, member, atts);
+ member.ElementInfo = ImportAnyElementInfo (defaultNamespace, rmember, member, atts);
mapMember = member;
}
else
else
mapAttribute.AttributeName = atts.XmlAttribute.AttributeName;
- mapAttribute.Form = atts.XmlAttribute.Form;
- mapAttribute.Namespace = (atts.XmlAttribute.Namespace != null) ? atts.XmlAttribute.Namespace : "";
if (typeData.IsComplexType)
mapAttribute.MappedType = ImportTypeMapping (typeData.Type, null, mapAttribute.Namespace);
-
+
+ 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;
}
elem.ElementName = (atts.XmlArray != null && atts.XmlArray.ElementName != null) ? atts.XmlArray.ElementName : rmember.MemberName;
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;
+
member.ElementInfo.Add (elem);
mapMember = member;
}
elem.Namespace = (att.Namespace != null) ? att.Namespace : defaultNamespace;
elem.Form = att.Form;
elem.IsNullable = att.IsNullable;
+
+ if (elem.IsNullable && elem.TypeData.IsValueType)
+ throw new InvalidOperationException ("IsNullable may not be 'true' for value type " + elem.TypeData.FullTypeName + " in member '" + defaultName + "'");
+
if (elem.TypeData.IsComplexType)
{
if (att.DataType != null) throw new InvalidOperationException ("'" + att.DataType + "' is an invalid value for the XmlElementAttribute.DateTime property. The property may only be specified for primitive types.");
return list;
}
- XmlTypeMapElementInfoList ImportAnyElementInfo (string defaultNamespace, Type defaultType, XmlTypeMapMemberElement member, XmlAttributes atts)
+ XmlTypeMapElementInfoList ImportAnyElementInfo (string defaultNamespace, XmlReflectionMember rmember, XmlTypeMapMemberElement member, XmlAttributes atts)
{
XmlTypeMapElementInfoList list = new XmlTypeMapElementInfoList();
- ImportTextElementInfo (list, defaultType, member, atts);
+ ImportTextElementInfo (list, rmember.MemberType, member, atts);
foreach (XmlAnyElementAttribute att in atts.XmlAnyElements)
{
XmlTypeMapElementInfo elem = new XmlTypeMapElementInfo (member, TypeTranslator.GetTypeData(typeof(XmlElement)));
- if (att.Name != null && att.Name != string.Empty) elem.ElementName = att.Name;
- else elem.IsUnnamedAnyElement = true;
- elem.Namespace = (att.Namespace != null) ? att.Namespace : "";
+ if (att.Name != null && att.Name != string.Empty)
+ {
+ elem.ElementName = 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.");
+ }
list.Add (elem);
}
return list;
throw new ArgumentNullException ("type");
if (includedTypes == null) includedTypes = new ArrayList ();
- includedTypes.Add (type);
+ if (!includedTypes.Contains (type))
+ includedTypes.Add (type);
+ }
+
+ public void IncludeTypes (ICustomAttributeProvider provider)
+ {
+ object[] ats = provider.GetCustomAttributes (typeof(XmlIncludeAttribute), true);
+ foreach (XmlIncludeAttribute at in ats)
+ IncludeType (at.Type);
}
#endregion // Methods