2 // System.Xml.Serialization.XmlReflectionImporter
5 // Tim Coleman (tim@timcoleman.com)
6 // Erik LeBel (eriklebel@yahoo.ca)
7 // Lluis Sanchez Gual (lluis@ximian.com)
9 // Copyright (C) Tim Coleman, 2002
10 // (C) 2003 Erik LeBel
14 // Permission is hereby granted, free of charge, to any person obtaining
15 // a copy of this software and associated documentation files (the
16 // "Software"), to deal in the Software without restriction, including
17 // without limitation the rights to use, copy, modify, merge, publish,
18 // distribute, sublicense, and/or sell copies of the Software, and to
19 // permit persons to whom the Software is furnished to do so, subject to
20 // the following conditions:
22 // The above copyright notice and this permission notice shall be
23 // included in all copies or substantial portions of the Software.
25 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
29 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
30 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
31 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
34 using System.Reflection;
35 using System.Collections;
36 using System.Xml.Schema;
38 namespace System.Xml.Serialization {
39 public class XmlReflectionImporter {
41 string initialDefaultNamespace;
42 XmlAttributeOverrides attributeOverrides;
43 ArrayList includedTypes;
44 ReflectionHelper helper = new ReflectionHelper();
45 int arrayChoiceCount = 1;
46 ArrayList relatedMaps = new ArrayList ();
47 bool allowPrivateTypes = false;
49 static readonly string errSimple = "Cannot serialize object of type '{0}'. Base " +
50 "type '{1}' has simpleContent and can be only extended by adding XmlAttribute " +
51 "elements. Please consider changing XmlText member of the base class to string array";
53 static readonly string errSimple2 = "Cannot serialize object of type '{0}'. " +
54 "Consider changing type of XmlText member '{1}' from '{2}' to string or string array";
58 public XmlReflectionImporter ()
63 public XmlReflectionImporter (string defaultNamespace)
64 : this (null, defaultNamespace)
68 public XmlReflectionImporter (XmlAttributeOverrides attributeOverrides)
69 : this (attributeOverrides, null)
73 public XmlReflectionImporter (XmlAttributeOverrides attributeOverrides, string defaultNamespace)
75 if (defaultNamespace == null)
76 this.initialDefaultNamespace = String.Empty;
78 this.initialDefaultNamespace = defaultNamespace;
80 if (attributeOverrides == null)
81 this.attributeOverrides = new XmlAttributeOverrides();
83 this.attributeOverrides = attributeOverrides;
88 helper = new ReflectionHelper();
92 internal bool AllowPrivateTypes
94 get { return allowPrivateTypes; }
95 set { allowPrivateTypes = value; }
98 #endregion // Constructors
102 public XmlMembersMapping ImportMembersMapping (string elementName,
104 XmlReflectionMember [] members,
105 bool hasWrapperElement)
107 // Reset (); Disabled. See ChangeLog
109 XmlMemberMapping[] mapping = new XmlMemberMapping[members.Length];
110 for (int n=0; n<members.Length; n++)
112 XmlTypeMapMember mapMem = CreateMapMember (members[n], ns);
113 mapping[n] = new XmlMemberMapping (members[n].MemberName, ns, mapMem, false);
115 XmlMembersMapping mps = new XmlMembersMapping (elementName, ns, hasWrapperElement, false, mapping);
116 mps.RelatedMaps = relatedMaps;
117 mps.Format = SerializationFormat.Literal;
118 Type[] extraTypes = includedTypes != null ? (Type[])includedTypes.ToArray(typeof(Type)) : null;
119 mps.Source = new MembersSerializationSource (elementName, hasWrapperElement, members, false, true, ns, extraTypes);
120 if (allowPrivateTypes) mps.Source.CanBeGenerated = false;
126 public XmlMembersMapping ImportMembersMapping (string elementName,
128 XmlReflectionMember[] members,
129 bool hasWrapperElement,
132 throw new NotImplementedException ();
136 public XmlMembersMapping ImportMembersMapping (string elementName,
138 XmlReflectionMember[] members,
139 bool hasWrapperElement,
143 throw new NotImplementedException ();
147 public XmlTypeMapping ImportTypeMapping (Type type)
149 return ImportTypeMapping (type, null, null);
152 public XmlTypeMapping ImportTypeMapping (Type type, string defaultNamespace)
154 return ImportTypeMapping (type, null, defaultNamespace);
157 public XmlTypeMapping ImportTypeMapping (Type type, XmlRootAttribute group)
159 return ImportTypeMapping (type, group, null);
162 public XmlTypeMapping ImportTypeMapping (Type type, XmlRootAttribute root, string defaultNamespace)
165 throw new ArgumentNullException ("type");
167 if (type == typeof (void))
168 throw new InvalidOperationException ("Type " + type.Name + " may not be serialized.");
170 if (defaultNamespace == null) defaultNamespace = initialDefaultNamespace;
171 if (defaultNamespace == null) defaultNamespace = string.Empty;
175 switch (TypeTranslator.GetTypeData(type).SchemaType)
177 case SchemaTypes.Class: map = ImportClassMapping (type, root, defaultNamespace); break;
178 case SchemaTypes.Array: map = ImportListMapping (type, root, defaultNamespace, null, 0); break;
179 case SchemaTypes.XmlNode: map = ImportXmlNodeMapping (type, root, defaultNamespace); break;
180 case SchemaTypes.Primitive: map = ImportPrimitiveMapping (type, root, defaultNamespace); break;
181 case SchemaTypes.Enum: map = ImportEnumMapping (type, root, defaultNamespace); break;
182 case SchemaTypes.XmlSerializable: map = ImportXmlSerializableMapping (type, root, defaultNamespace); break;
183 default: throw new NotSupportedException ("Type " + type.FullName + " not supported for XML stialization");
186 map.RelatedMaps = relatedMaps;
187 map.Format = SerializationFormat.Literal;
188 Type[] extraTypes = includedTypes != null ? (Type[])includedTypes.ToArray(typeof(Type)) : null;
189 map.Source = new XmlTypeSerializationSource (type, root, attributeOverrides, defaultNamespace, extraTypes);
190 if (allowPrivateTypes) map.Source.CanBeGenerated = false;
194 XmlTypeMapping CreateTypeMapping (TypeData typeData, XmlRootAttribute root, string defaultXmlType, string defaultNamespace)
196 string rootNamespace = defaultNamespace;
197 string typeNamespace = null;
199 bool includeInSchema = true;
200 XmlAttributes atts = null;
201 bool nullable = true;
203 if (defaultXmlType == null) defaultXmlType = typeData.XmlType;
205 if (!typeData.IsListType)
207 if (attributeOverrides != null)
208 atts = attributeOverrides[typeData.Type];
210 if (atts != null && typeData.SchemaType == SchemaTypes.Primitive)
211 throw new InvalidOperationException ("XmlRoot and XmlType attributes may not be specified for the type " + typeData.FullTypeName);
215 atts = new XmlAttributes (typeData.Type);
217 if (atts.XmlRoot != null && root == null)
220 if (atts.XmlType != null)
222 if (atts.XmlType.Namespace != null && atts.XmlType.Namespace != string.Empty && typeData.SchemaType != SchemaTypes.Enum)
223 typeNamespace = atts.XmlType.Namespace;
225 if (atts.XmlType.TypeName != null && atts.XmlType.TypeName != string.Empty)
226 defaultXmlType = atts.XmlType.TypeName;
228 includeInSchema = atts.XmlType.IncludeInSchema;
231 elementName = defaultXmlType;
235 if (root.ElementName != null && root.ElementName != String.Empty)
236 elementName = root.ElementName;
237 if (root.Namespace != null && root.Namespace != String.Empty)
238 rootNamespace = root.Namespace;
239 nullable = root.IsNullable;
242 if (rootNamespace == null) rootNamespace = "";
243 if (typeNamespace == null || typeNamespace.Length == 0) typeNamespace = rootNamespace;
245 XmlTypeMapping map = new XmlTypeMapping (elementName, rootNamespace, typeData, defaultXmlType, typeNamespace);
246 map.IncludeInSchema = includeInSchema;
247 map.IsNullable = nullable;
248 relatedMaps.Add (map);
253 XmlTypeMapping ImportClassMapping (Type type, XmlRootAttribute root, string defaultNamespace)
255 TypeData typeData = TypeTranslator.GetTypeData (type);
256 XmlTypeMapping map = helper.GetRegisteredClrType (type, GetTypeNamespace (typeData, root, defaultNamespace));
257 if (map != null) return map;
259 if (!allowPrivateTypes)
260 ReflectionHelper.CheckSerializableType (type, false);
262 map = CreateTypeMapping (typeData, root, null, defaultNamespace);
263 helper.RegisterClrType (map, type, map.XmlTypeNamespace);
264 helper.RegisterSchemaType (map, map.XmlType, map.XmlTypeNamespace);
268 ClassMap classMap = new ClassMap ();
269 map.ObjectMap = classMap;
273 ICollection members = GetReflectionMembers (type);
274 foreach (XmlReflectionMember rmember in members)
276 string ns = map.XmlTypeNamespace;
277 if (rmember.XmlAttributes.XmlIgnore) continue;
278 if (rmember.DeclaringType != null && rmember.DeclaringType != type) {
279 XmlTypeMapping bmap = ImportClassMapping (rmember.DeclaringType, root, defaultNamespace);
280 ns = bmap.XmlTypeNamespace;
283 XmlTypeMapMember mem = CreateMapMember (rmember, ns);
284 mem.CheckOptionalValueType (type);
285 classMap.AddMember (mem);
288 // catch (Exception ex) {
289 // throw helper.CreateError (map, ex.Message);
292 // Import extra classes
294 if (type == typeof (object) && includedTypes != null)
296 foreach (Type intype in includedTypes)
297 map.DerivedTypes.Add (ImportTypeMapping (intype, defaultNamespace));
300 // Register inheritance relations
302 if (type.BaseType != null)
304 XmlTypeMapping bmap = ImportClassMapping (type.BaseType, root, defaultNamespace);
305 ClassMap cbmap = bmap.ObjectMap as ClassMap;
307 if (type.BaseType != typeof (object)) {
309 if (!cbmap.HasSimpleContent)
310 classMap.SetCanBeSimpleType (false);
313 // At this point, derived classes of this map must be already registered
315 RegisterDerivedMap (bmap, map);
317 if (cbmap.HasSimpleContent && classMap.ElementMembers != null && classMap.ElementMembers.Count != 1)
318 throw new InvalidOperationException (String.Format (errSimple, map.TypeData.TypeName, map.BaseMap.TypeData.TypeName));
321 ImportIncludedTypes (type, defaultNamespace);
323 if (classMap.XmlTextCollector != null && !classMap.HasSimpleContent)
325 XmlTypeMapMember mem = classMap.XmlTextCollector;
326 if (mem.TypeData.Type != typeof(string) &&
327 mem.TypeData.Type != typeof(string[]) &&
328 mem.TypeData.Type != typeof(object[]) &&
329 mem.TypeData.Type != typeof(XmlNode[]))
331 throw new InvalidOperationException (String.Format (errSimple2, map.TypeData.TypeName, mem.Name, mem.TypeData.TypeName));
337 void RegisterDerivedMap (XmlTypeMapping map, XmlTypeMapping derivedMap)
339 map.DerivedTypes.Add (derivedMap);
340 map.DerivedTypes.AddRange (derivedMap.DerivedTypes);
342 if (map.BaseMap != null)
343 RegisterDerivedMap (map.BaseMap, derivedMap);
345 XmlTypeMapping obmap = ImportTypeMapping (typeof(object));
347 obmap.DerivedTypes.Add (derivedMap);
351 string GetTypeNamespace (TypeData typeData, XmlRootAttribute root, string defaultNamespace)
353 string typeNamespace = null;
355 XmlAttributes atts = null;
356 if (!typeData.IsListType)
358 if (attributeOverrides != null)
359 atts = attributeOverrides[typeData.Type];
363 atts = new XmlAttributes (typeData.Type);
365 if (atts.XmlType != null)
367 if (atts.XmlType.Namespace != null && atts.XmlType.Namespace.Length != 0 && typeData.SchemaType != SchemaTypes.Enum)
368 typeNamespace = atts.XmlType.Namespace;
371 if (typeNamespace != null && typeNamespace.Length != 0) return typeNamespace;
373 if (atts.XmlRoot != null && root == null)
378 if (root.Namespace != null && root.Namespace.Length != 0)
379 return root.Namespace;
382 if (defaultNamespace == null) return "";
383 else return defaultNamespace;
386 XmlTypeMapping ImportListMapping (Type type, XmlRootAttribute root, string defaultNamespace, XmlAttributes atts, int nestingLevel)
388 TypeData typeData = TypeTranslator.GetTypeData (type);
389 ListMap obmap = new ListMap ();
391 if (!allowPrivateTypes)
392 ReflectionHelper.CheckSerializableType (type, true);
394 if (atts == null) atts = new XmlAttributes();
395 Type itemType = typeData.ListItemType;
397 // warning: byte[][] should not be considered multiarray
398 bool isMultiArray = (type.IsArray && (TypeTranslator.GetTypeData(itemType).SchemaType == SchemaTypes.Array) && itemType.IsArray);
400 XmlTypeMapElementInfoList list = new XmlTypeMapElementInfoList();
402 foreach (XmlArrayItemAttribute att in atts.XmlArrayItems)
404 if (att.NestingLevel != nestingLevel) continue;
405 Type elemType = (att.Type != null) ? att.Type : itemType;
406 XmlTypeMapElementInfo elem = new XmlTypeMapElementInfo (null, TypeTranslator.GetTypeData(elemType, att.DataType));
407 elem.Namespace = att.Namespace != null ? att.Namespace : defaultNamespace;
408 if (elem.Namespace == null) elem.Namespace = "";
409 elem.Form = att.Form;
410 elem.IsNullable = att.IsNullable && CanBeNull (elem.TypeData);
411 elem.NestingLevel = att.NestingLevel;
414 elem.MappedType = ImportListMapping (elemType, null, elem.Namespace, atts, nestingLevel + 1);
415 else if (elem.TypeData.IsComplexType)
416 elem.MappedType = ImportTypeMapping (elemType, null, elem.Namespace);
418 if (att.ElementName != null) elem.ElementName = att.ElementName;
419 else if (elem.MappedType != null) elem.ElementName = elem.MappedType.ElementName;
420 else elem.ElementName = TypeTranslator.GetTypeData(elemType).XmlType;
427 XmlTypeMapElementInfo elem = new XmlTypeMapElementInfo (null, TypeTranslator.GetTypeData (itemType));
429 elem.MappedType = ImportListMapping (itemType, null, defaultNamespace, atts, nestingLevel + 1);
430 else if (elem.TypeData.IsComplexType)
431 elem.MappedType = ImportTypeMapping (itemType, null, defaultNamespace);
433 if (elem.MappedType != null) elem.ElementName = elem.MappedType.XmlType;
434 else elem.ElementName = TypeTranslator.GetTypeData(itemType).XmlType ;
436 elem.Namespace = (defaultNamespace != null) ? defaultNamespace : "";
437 elem.IsNullable = CanBeNull (elem.TypeData);
441 obmap.ItemInfo = list;
443 // If there can be different element names (types) in the array, then its name cannot
444 // be "ArrayOfXXX" it must be something like ArrayOfChoiceNNN
448 baseName = "ArrayOfChoice" + (arrayChoiceCount++);
451 XmlTypeMapElementInfo elem = ((XmlTypeMapElementInfo)list[0]);
452 if (elem.MappedType != null) baseName = TypeTranslator.GetArrayName (elem.MappedType.XmlType);
453 else baseName = TypeTranslator.GetArrayName (elem.ElementName);
456 // Avoid name colisions
459 string name = baseName;
462 XmlTypeMapping foundMap = helper.GetRegisteredSchemaType (name, defaultNamespace);
463 if (foundMap == null) nameCount = -1;
464 else if (obmap.Equals (foundMap.ObjectMap) && typeData.Type == foundMap.TypeData.Type) return foundMap;
465 else name = baseName + (nameCount++);
467 while (nameCount != -1);
469 XmlTypeMapping map = CreateTypeMapping (typeData, root, name, defaultNamespace);
470 map.ObjectMap = obmap;
472 // Register any of the including types as a derived class of object
473 XmlIncludeAttribute[] includes = (XmlIncludeAttribute[])type.GetCustomAttributes (typeof (XmlIncludeAttribute), false);
475 XmlTypeMapping objectMapping = ImportTypeMapping (typeof(object));
476 for (int i = 0; i < includes.Length; i++)
478 Type includedType = includes[i].Type;
479 objectMapping.DerivedTypes.Add(ImportTypeMapping (includedType, null, defaultNamespace));
482 // Register this map as a derived class of object
484 helper.RegisterSchemaType (map, name, defaultNamespace);
485 ImportTypeMapping (typeof(object)).DerivedTypes.Add (map);
490 XmlTypeMapping ImportXmlNodeMapping (Type type, XmlRootAttribute root, string defaultNamespace)
492 XmlTypeMapping map = helper.GetRegisteredClrType (type, GetTypeNamespace (TypeTranslator.GetTypeData (type), root, defaultNamespace));
493 if (map != null) return map;
495 // Registers the maps for XmlNode and XmlElement
497 XmlTypeMapping nodeMap = CreateTypeMapping (TypeTranslator.GetTypeData (typeof(XmlNode)), root, null, defaultNamespace);
498 helper.RegisterClrType (nodeMap, typeof(XmlNode), nodeMap.XmlTypeNamespace);
500 XmlTypeMapping elemMap = CreateTypeMapping (TypeTranslator.GetTypeData (typeof(XmlElement)), root, null, defaultNamespace);
501 helper.RegisterClrType (elemMap, typeof(XmlElement), elemMap.XmlTypeNamespace);
503 XmlTypeMapping textMap = CreateTypeMapping (TypeTranslator.GetTypeData (typeof(XmlText)), root, null, defaultNamespace);
504 helper.RegisterClrType (textMap, typeof(XmlText), textMap.XmlTypeNamespace);
506 XmlTypeMapping docMap = CreateTypeMapping (TypeTranslator.GetTypeData (typeof(XmlDocument)), root, null, defaultNamespace);
507 helper.RegisterClrType (docMap, typeof(XmlDocument), textMap.XmlTypeNamespace);
509 XmlTypeMapping obmap = ImportTypeMapping (typeof(object));
510 obmap.DerivedTypes.Add (nodeMap);
511 obmap.DerivedTypes.Add (elemMap);
512 obmap.DerivedTypes.Add (textMap);
513 obmap.DerivedTypes.Add (docMap);
514 nodeMap.DerivedTypes.Add (elemMap);
515 nodeMap.DerivedTypes.Add (textMap);
516 nodeMap.DerivedTypes.Add (docMap);
518 map = helper.GetRegisteredClrType (type, GetTypeNamespace (TypeTranslator.GetTypeData (type), root, defaultNamespace));
519 if (map == null) throw new InvalidOperationException ("Objects of type '" + type + "' can't be serialized");
523 XmlTypeMapping ImportPrimitiveMapping (Type type, XmlRootAttribute root, string defaultNamespace)
525 TypeData typeData = TypeTranslator.GetTypeData (type);
526 XmlTypeMapping map = helper.GetRegisteredClrType (type, GetTypeNamespace (typeData, root, defaultNamespace));
527 if (map != null) return map;
528 map = CreateTypeMapping (typeData, root, null, defaultNamespace);
529 helper.RegisterClrType (map, type, map.XmlTypeNamespace);
533 XmlTypeMapping ImportEnumMapping (Type type, XmlRootAttribute root, string defaultNamespace)
535 TypeData typeData = TypeTranslator.GetTypeData (type);
536 XmlTypeMapping map = helper.GetRegisteredClrType (type, GetTypeNamespace (typeData, root, defaultNamespace));
537 if (map != null) return map;
539 if (!allowPrivateTypes)
540 ReflectionHelper.CheckSerializableType (type, false);
542 map = CreateTypeMapping (typeData, root, null, defaultNamespace);
543 helper.RegisterClrType (map, type, map.XmlTypeNamespace);
545 string [] names = Enum.GetNames (type);
546 ArrayList members = new ArrayList();
547 foreach (string name in names)
549 MemberInfo[] mem = type.GetMember (name);
550 string xmlName = null;
551 object[] atts = mem[0].GetCustomAttributes (typeof(XmlIgnoreAttribute), false);
552 if (atts.Length > 0) continue;
553 atts = mem[0].GetCustomAttributes (typeof(XmlEnumAttribute), false);
554 if (atts.Length > 0) xmlName = ((XmlEnumAttribute)atts[0]).Name;
555 if (xmlName == null) xmlName = name;
556 members.Add (new EnumMap.EnumMapMember (xmlName, name));
559 bool isFlags = type.GetCustomAttributes (typeof(FlagsAttribute),false).Length > 0;
560 map.ObjectMap = new EnumMap ((EnumMap.EnumMapMember[])members.ToArray (typeof(EnumMap.EnumMapMember)), isFlags);
561 ImportTypeMapping (typeof(object)).DerivedTypes.Add (map);
565 XmlTypeMapping ImportXmlSerializableMapping (Type type, XmlRootAttribute root, string defaultNamespace)
567 TypeData typeData = TypeTranslator.GetTypeData (type);
568 XmlTypeMapping map = helper.GetRegisteredClrType (type, GetTypeNamespace (typeData, root, defaultNamespace));
569 if (map != null) return map;
571 if (!allowPrivateTypes)
572 ReflectionHelper.CheckSerializableType (type, false);
574 map = CreateTypeMapping (typeData, root, null, defaultNamespace);
575 helper.RegisterClrType (map, type, map.XmlTypeNamespace);
579 void ImportIncludedTypes (Type type, string defaultNamespace)
581 XmlIncludeAttribute[] includes = (XmlIncludeAttribute[])type.GetCustomAttributes (typeof (XmlIncludeAttribute), false);
582 for (int n=0; n<includes.Length; n++)
584 Type includedType = includes[n].Type;
585 ImportTypeMapping (includedType, null, defaultNamespace);
589 ICollection GetReflectionMembers (Type type)
591 // First we want to find the inheritance hierarchy in reverse order.
592 Type currentType = type;
593 ArrayList typeList = new ArrayList();
594 typeList.Add(currentType);
595 while (currentType != typeof(object))
597 currentType = currentType.BaseType; // Read the base type.
598 typeList.Insert(0, currentType); // Insert at 0 to reverse the order.
601 // Read all Fields via reflection.
602 ArrayList fieldList = new ArrayList();
603 FieldInfo[] tfields = type.GetFields (BindingFlags.Instance | BindingFlags.Public);
605 int currentIndex = 0;
606 foreach (FieldInfo field in tfields)
608 // This statement ensures fields are ordered starting from the base type.
609 if (currentType != field.DeclaringType)
611 currentType = field.DeclaringType;
614 fieldList.Insert(currentIndex++, field);
617 // Read all Properties via reflection.
618 ArrayList propList = new ArrayList();
619 PropertyInfo[] tprops = type.GetProperties (BindingFlags.Instance | BindingFlags.Public);
622 foreach (PropertyInfo prop in tprops)
624 // This statement ensures properties are ordered starting from the base type.
625 if (currentType != prop.DeclaringType)
627 currentType = prop.DeclaringType;
630 if (!prop.CanRead) continue;
631 if (!prop.CanWrite && TypeTranslator.GetTypeData (prop.PropertyType).SchemaType != SchemaTypes.Array) continue;
632 if (prop.GetIndexParameters().Length > 0) continue;
633 propList.Insert(currentIndex++, prop);
636 ArrayList members = new ArrayList();
639 // We now step through the type hierarchy from the base (object) through
640 // to the supplied class, as each step outputting all Fields, and then
641 // all Properties. This is the exact same ordering as .NET 1.0/1.1.
642 foreach (Type t in typeList)
644 // Add any fields matching the current DeclaringType.
645 while (fieldIndex < fieldList.Count)
647 FieldInfo field = (FieldInfo)fieldList[fieldIndex];
648 if (field.DeclaringType==t)
651 XmlAttributes atts = attributeOverrides[type, field.Name];
652 if (atts == null) atts = new XmlAttributes (field);
653 if (atts.XmlIgnore) continue;
654 XmlReflectionMember member = new XmlReflectionMember(field.Name, field.FieldType, atts);
655 member.DeclaringType = field.DeclaringType;
661 // Add any properties matching the current DeclaringType.
662 while (propIndex < propList.Count)
664 PropertyInfo prop = (PropertyInfo)propList[propIndex];
665 if (prop.DeclaringType==t)
668 XmlAttributes atts = attributeOverrides[type, prop.Name];
669 if (atts == null) atts = new XmlAttributes (prop);
670 if (atts.XmlIgnore) continue;
671 XmlReflectionMember member = new XmlReflectionMember(prop.Name, prop.PropertyType, atts);
672 member.DeclaringType = prop.DeclaringType;
681 private XmlTypeMapMember CreateMapMember (XmlReflectionMember rmember, string defaultNamespace)
683 XmlTypeMapMember mapMember;
684 XmlAttributes atts = rmember.XmlAttributes;
685 TypeData typeData = TypeTranslator.GetTypeData (rmember.MemberType);
687 if (atts.XmlAnyAttribute != null)
689 if ( (rmember.MemberType.FullName == "System.Xml.XmlAttribute[]") ||
690 (rmember.MemberType.FullName == "System.Xml.XmlNode[]") )
692 mapMember = new XmlTypeMapMemberAnyAttribute();
695 throw new InvalidOperationException ("XmlAnyAttributeAttribute can only be applied to members of type XmlAttribute[] or XmlNode[]");
697 else if (atts.XmlAnyElements != null && atts.XmlAnyElements.Count > 0)
699 if ( (rmember.MemberType.FullName == "System.Xml.XmlElement[]") ||
700 (rmember.MemberType.FullName == "System.Xml.XmlNode[]") ||
701 (rmember.MemberType.FullName == "System.Xml.XmlElement"))
703 XmlTypeMapMemberAnyElement member = new XmlTypeMapMemberAnyElement();
704 member.ElementInfo = ImportAnyElementInfo (defaultNamespace, rmember, member, atts);
708 throw new InvalidOperationException ("XmlAnyElementAttribute can only be applied to members of type XmlElement, XmlElement[] or XmlNode[]");
712 XmlTypeMapMemberNamespaces mapNamespaces = new XmlTypeMapMemberNamespaces ();
713 mapMember = mapNamespaces;
715 else if (atts.XmlAttribute != null)
719 if (atts.XmlElements != null && atts.XmlElements.Count > 0)
720 throw new Exception ("XmlAttributeAttribute and XmlElementAttribute cannot be applied to the same member");
722 XmlTypeMapMemberAttribute mapAttribute = new XmlTypeMapMemberAttribute ();
723 if (atts.XmlAttribute.AttributeName == null)
724 mapAttribute.AttributeName = rmember.MemberName;
726 mapAttribute.AttributeName = atts.XmlAttribute.AttributeName;
728 if (typeData.IsComplexType)
729 mapAttribute.MappedType = ImportTypeMapping (typeData.Type, null, mapAttribute.Namespace);
731 if (atts.XmlAttribute.Namespace != null && atts.XmlAttribute.Namespace != defaultNamespace)
733 if (atts.XmlAttribute.Form == XmlSchemaForm.Unqualified)
734 throw new InvalidOperationException ("The Form property may not be 'Unqualified' when an explicit Namespace property is present");
735 mapAttribute.Form = XmlSchemaForm.Qualified;
736 mapAttribute.Namespace = atts.XmlAttribute.Namespace;
740 mapAttribute.Form = atts.XmlAttribute.Form;
741 if (atts.XmlAttribute.Form == XmlSchemaForm.Qualified)
742 mapAttribute.Namespace = defaultNamespace;
744 mapAttribute.Namespace = "";
747 typeData = TypeTranslator.GetTypeData(rmember.MemberType, atts.XmlAttribute.DataType);
748 mapMember = mapAttribute;
750 else if (typeData.SchemaType == SchemaTypes.Array)
752 // If the member has a single XmlElementAttribute and the type is the type of the member,
753 // then it is not a flat list
755 if (atts.XmlElements.Count > 1 ||
756 (atts.XmlElements.Count == 1 && atts.XmlElements[0].Type != typeData.Type) ||
757 (atts.XmlText != null))
761 // TODO: check that it does not have XmlArrayAttribute
762 XmlTypeMapMemberFlatList member = new XmlTypeMapMemberFlatList ();
763 member.ListMap = new ListMap ();
764 member.ListMap.ItemInfo = ImportElementInfo (rmember.MemberName, defaultNamespace, typeData.ListItemType, member, atts);
765 member.ElementInfo = member.ListMap.ItemInfo;
772 XmlTypeMapMemberList member = new XmlTypeMapMemberList ();
774 // Creates an ElementInfo that identifies the array instance.
775 member.ElementInfo = new XmlTypeMapElementInfoList();
776 XmlTypeMapElementInfo elem = new XmlTypeMapElementInfo (member, typeData);
777 elem.ElementName = (atts.XmlArray != null && atts.XmlArray.ElementName != null) ? atts.XmlArray.ElementName : rmember.MemberName;
778 elem.Namespace = (atts.XmlArray != null && atts.XmlArray.Namespace != null) ? atts.XmlArray.Namespace : defaultNamespace;
779 elem.MappedType = ImportListMapping (rmember.MemberType, null, elem.Namespace, atts, 0);
780 elem.IsNullable = (atts.XmlArray != null) ? atts.XmlArray.IsNullable : false;
781 elem.Form = (atts.XmlArray != null) ? atts.XmlArray.Form : XmlSchemaForm.Qualified;
783 member.ElementInfo.Add (elem);
791 XmlTypeMapMemberElement member = new XmlTypeMapMemberElement ();
792 member.ElementInfo = ImportElementInfo (rmember.MemberName, defaultNamespace, rmember.MemberType, member, atts);
796 mapMember.DefaultValue = atts.XmlDefaultValue;
797 mapMember.TypeData = typeData;
798 mapMember.Name = rmember.MemberName;
799 mapMember.IsReturnValue = rmember.IsReturnValue;
803 XmlTypeMapElementInfoList ImportElementInfo (string defaultName, string defaultNamespace, Type defaultType, XmlTypeMapMemberElement member, XmlAttributes atts)
805 XmlTypeMapElementInfoList list = new XmlTypeMapElementInfoList();
807 ImportTextElementInfo (list, defaultType, member, atts);
809 if (atts.XmlElements.Count == 0 && list.Count == 0)
811 XmlTypeMapElementInfo elem = new XmlTypeMapElementInfo (member, TypeTranslator.GetTypeData(defaultType));
812 elem.ElementName = defaultName;
813 elem.Namespace = defaultNamespace;
814 if (elem.TypeData.IsComplexType)
815 elem.MappedType = ImportTypeMapping (defaultType, null, defaultNamespace);
819 bool multiType = (atts.XmlElements.Count > 1);
820 foreach (XmlElementAttribute att in atts.XmlElements)
822 Type elemType = (att.Type != null) ? att.Type : defaultType;
823 XmlTypeMapElementInfo elem = new XmlTypeMapElementInfo (member, TypeTranslator.GetTypeData(elemType, att.DataType));
824 elem.ElementName = (att.ElementName != null) ? att.ElementName : defaultName;
825 elem.Namespace = (att.Namespace != null) ? att.Namespace : defaultNamespace;
826 elem.Form = att.Form;
827 elem.IsNullable = att.IsNullable;
829 if (elem.IsNullable && elem.TypeData.IsValueType)
830 throw new InvalidOperationException ("IsNullable may not be 'true' for value type " + elem.TypeData.FullTypeName + " in member '" + defaultName + "'");
832 if (elem.TypeData.IsComplexType)
834 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.");
835 elem.MappedType = ImportTypeMapping (elemType, null, elem.Namespace);
838 if (att.ElementName != null)
839 elem.ElementName = att.ElementName;
840 else if (multiType) {
841 if (elem.MappedType != null) elem.ElementName = elem.MappedType.ElementName;
842 else elem.ElementName = TypeTranslator.GetTypeData(elemType).XmlType;
845 elem.ElementName = defaultName;
852 XmlTypeMapElementInfoList ImportAnyElementInfo (string defaultNamespace, XmlReflectionMember rmember, XmlTypeMapMemberElement member, XmlAttributes atts)
854 XmlTypeMapElementInfoList list = new XmlTypeMapElementInfoList();
856 ImportTextElementInfo (list, rmember.MemberType, member, atts);
858 foreach (XmlAnyElementAttribute att in atts.XmlAnyElements)
860 XmlTypeMapElementInfo elem = new XmlTypeMapElementInfo (member, TypeTranslator.GetTypeData(typeof(XmlElement)));
861 if (att.Name != null && att.Name != string.Empty)
863 elem.ElementName = att.Name;
864 elem.Namespace = (att.Namespace != null) ? att.Namespace : "";
868 elem.IsUnnamedAnyElement = true;
869 elem.Namespace = defaultNamespace;
870 if (att.Namespace != null)
871 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.");
878 void ImportTextElementInfo (XmlTypeMapElementInfoList list, Type defaultType, XmlTypeMapMemberElement member, XmlAttributes atts)
880 if (atts.XmlText != null)
882 member.IsXmlTextCollector = true;
883 if (atts.XmlText.Type != null) defaultType = atts.XmlText.Type;
884 if (defaultType == typeof(XmlNode)) defaultType = typeof(XmlText); // Nodes must be text nodes
886 XmlTypeMapElementInfo elem = new XmlTypeMapElementInfo (member, TypeTranslator.GetTypeData(defaultType, atts.XmlText.DataType));
888 if (elem.TypeData.SchemaType != SchemaTypes.Primitive &&
889 elem.TypeData.SchemaType != SchemaTypes.Enum &&
890 elem.TypeData.SchemaType != SchemaTypes.XmlNode &&
891 !(elem.TypeData.SchemaType == SchemaTypes.Array && elem.TypeData.ListItemTypeData.SchemaType == SchemaTypes.XmlNode)
893 throw new InvalidOperationException ("XmlText cannot be used to encode complex types");
895 elem.IsTextElement = true;
896 elem.WrappedElement = false;
901 bool CanBeNull (TypeData type)
903 return (type.SchemaType != SchemaTypes.Primitive || type.Type == typeof (string));
906 public void IncludeType (Type type)
909 throw new ArgumentNullException ("type");
911 if (includedTypes == null) includedTypes = new ArrayList ();
912 if (!includedTypes.Contains (type))
913 includedTypes.Add (type);
916 public void IncludeTypes (ICustomAttributeProvider provider)
918 object[] ats = provider.GetCustomAttributes (typeof(XmlIncludeAttribute), true);
919 foreach (XmlIncludeAttribute at in ats)
920 IncludeType (at.Type);
923 #endregion // Methods