PageRenderTime 51ms CodeModel.GetById 11ms RepoModel.GetById 0ms app.codeStats 1ms

/mcs/class/System.XML/System.Xml.Serialization/XmlReflectionImporter.cs

https://bitbucket.org/danipen/mono
C# | 1176 lines | 916 code | 176 blank | 84 comment | 387 complexity | 9b65d9033b05253160fdcb1ebba631ca MD5 | raw file
Possible License(s): Unlicense, Apache-2.0, LGPL-2.0, MPL-2.0-no-copyleft-exception, CC-BY-SA-3.0, GPL-2.0
  1. //
  2. // System.Xml.Serialization.XmlReflectionImporter
  3. //
  4. // Author:
  5. // Tim Coleman (tim@timcoleman.com)
  6. // Erik LeBel (eriklebel@yahoo.ca)
  7. // Lluis Sanchez Gual (lluis@ximian.com)
  8. //
  9. // Copyright (C) Tim Coleman, 2002
  10. // (C) 2003 Erik LeBel
  11. //
  12. //
  13. // Permission is hereby granted, free of charge, to any person obtaining
  14. // a copy of this software and associated documentation files (the
  15. // "Software"), to deal in the Software without restriction, including
  16. // without limitation the rights to use, copy, modify, merge, publish,
  17. // distribute, sublicense, and/or sell copies of the Software, and to
  18. // permit persons to whom the Software is furnished to do so, subject to
  19. // the following conditions:
  20. //
  21. // The above copyright notice and this permission notice shall be
  22. // included in all copies or substantial portions of the Software.
  23. //
  24. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  25. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  26. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  27. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  28. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  29. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  30. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  31. //
  32. using System.Collections;
  33. using System.Collections.Generic;
  34. using System.Globalization;
  35. using System.Reflection;
  36. using System.Xml.Schema;
  37. namespace System.Xml.Serialization {
  38. public class XmlReflectionImporter {
  39. string initialDefaultNamespace;
  40. XmlAttributeOverrides attributeOverrides;
  41. ArrayList includedTypes;
  42. ReflectionHelper helper = new ReflectionHelper();
  43. int arrayChoiceCount = 1;
  44. ArrayList relatedMaps = new ArrayList ();
  45. bool allowPrivateTypes = false;
  46. static readonly string errSimple = "Cannot serialize object of type '{0}'. Base " +
  47. "type '{1}' has simpleContent and can be only extended by adding XmlAttribute " +
  48. "elements. Please consider changing XmlText member of the base class to string array";
  49. static readonly string errSimple2 = "Cannot serialize object of type '{0}'. " +
  50. "Consider changing type of XmlText member '{1}' from '{2}' to string or string array";
  51. #region Constructors
  52. public XmlReflectionImporter ()
  53. : this (null, null)
  54. {
  55. }
  56. public XmlReflectionImporter (string defaultNamespace)
  57. : this (null, defaultNamespace)
  58. {
  59. }
  60. public XmlReflectionImporter (XmlAttributeOverrides attributeOverrides)
  61. : this (attributeOverrides, null)
  62. {
  63. }
  64. public XmlReflectionImporter (XmlAttributeOverrides attributeOverrides, string defaultNamespace)
  65. {
  66. if (defaultNamespace == null)
  67. this.initialDefaultNamespace = String.Empty;
  68. else
  69. this.initialDefaultNamespace = defaultNamespace;
  70. if (attributeOverrides == null)
  71. this.attributeOverrides = new XmlAttributeOverrides();
  72. else
  73. this.attributeOverrides = attributeOverrides;
  74. }
  75. /* void Reset ()
  76. {
  77. helper = new ReflectionHelper();
  78. arrayChoiceCount = 1;
  79. }
  80. */
  81. internal bool AllowPrivateTypes
  82. {
  83. get { return allowPrivateTypes; }
  84. set { allowPrivateTypes = value; }
  85. }
  86. #endregion // Constructors
  87. #region Methods
  88. public XmlMembersMapping ImportMembersMapping (string elementName,
  89. string ns,
  90. XmlReflectionMember [] members,
  91. bool hasWrapperElement)
  92. {
  93. return ImportMembersMapping (elementName, ns, members, hasWrapperElement, true);
  94. }
  95. #if NET_2_0
  96. [MonoTODO]
  97. public
  98. #endif
  99. XmlMembersMapping ImportMembersMapping (string elementName,
  100. string ns,
  101. XmlReflectionMember[] members,
  102. bool hasWrapperElement,
  103. bool rpc)
  104. {
  105. return ImportMembersMapping (elementName, ns, members, hasWrapperElement, rpc, true);
  106. }
  107. #if NET_2_0
  108. [MonoTODO]
  109. public
  110. #endif
  111. XmlMembersMapping ImportMembersMapping (string elementName,
  112. string ns,
  113. XmlReflectionMember[] members,
  114. bool hasWrapperElement,
  115. bool rpc,
  116. bool openModel)
  117. {
  118. return ImportMembersMapping (elementName, ns, members, hasWrapperElement, rpc, openModel, XmlMappingAccess.Read | XmlMappingAccess.Write);
  119. }
  120. #if NET_2_0
  121. [MonoTODO] // FIXME: handle writeAccessors, validate, and mapping access
  122. public
  123. #endif
  124. XmlMembersMapping ImportMembersMapping (string elementName,
  125. string ns,
  126. XmlReflectionMember[] members,
  127. bool hasWrapperElement,
  128. bool rpc,
  129. bool openModel,
  130. XmlMappingAccess access)
  131. {
  132. // Reset (); Disabled. See ChangeLog
  133. ArrayList mapping = new ArrayList ();
  134. for (int n=0; n<members.Length; n++)
  135. {
  136. XmlTypeMapMember mapMem = CreateMapMember (null, members[n], ns);
  137. mapMem.GlobalIndex = n;
  138. mapMem.CheckOptionalValueType (members);
  139. mapping.Add (new XmlMemberMapping (members[n].MemberName, ns, mapMem, false));
  140. }
  141. elementName = XmlConvert.EncodeLocalName (elementName);
  142. XmlMembersMapping mps = new XmlMembersMapping (elementName, ns, hasWrapperElement, false, (XmlMemberMapping[])mapping.ToArray (typeof(XmlMemberMapping)));
  143. mps.RelatedMaps = relatedMaps;
  144. mps.Format = SerializationFormat.Literal;
  145. Type[] extraTypes = includedTypes != null ? (Type[])includedTypes.ToArray(typeof(Type)) : null;
  146. #if !NET_2_1
  147. mps.Source = new MembersSerializationSource (elementName, hasWrapperElement, members, false, true, ns, extraTypes);
  148. if (allowPrivateTypes) mps.Source.CanBeGenerated = false;
  149. #endif
  150. return mps;
  151. }
  152. public XmlTypeMapping ImportTypeMapping (Type type)
  153. {
  154. return ImportTypeMapping (type, null, null);
  155. }
  156. public XmlTypeMapping ImportTypeMapping (Type type, string defaultNamespace)
  157. {
  158. return ImportTypeMapping (type, null, defaultNamespace);
  159. }
  160. public XmlTypeMapping ImportTypeMapping (Type type, XmlRootAttribute root)
  161. {
  162. return ImportTypeMapping (type, root, null);
  163. }
  164. public XmlTypeMapping ImportTypeMapping (Type type, XmlRootAttribute root, string defaultNamespace)
  165. {
  166. if (type == null)
  167. throw new ArgumentNullException ("type");
  168. if (type == typeof (void))
  169. throw new NotSupportedException ("The type " + type.FullName + " may not be serialized.");
  170. return ImportTypeMapping (TypeTranslator.GetTypeData (type), root,
  171. defaultNamespace);
  172. }
  173. internal XmlTypeMapping ImportTypeMapping (TypeData typeData, string defaultNamespace)
  174. {
  175. return ImportTypeMapping (typeData, (XmlRootAttribute) null,
  176. defaultNamespace);
  177. }
  178. private XmlTypeMapping ImportTypeMapping (TypeData typeData, XmlRootAttribute root, string defaultNamespace)
  179. {
  180. if (typeData == null)
  181. throw new ArgumentNullException ("typeData");
  182. if (typeData.Type == null)
  183. throw new ArgumentException ("Specified TypeData instance does not have Type set.");
  184. if (defaultNamespace == null) defaultNamespace = initialDefaultNamespace;
  185. if (defaultNamespace == null) defaultNamespace = string.Empty;
  186. try {
  187. XmlTypeMapping map;
  188. switch (typeData.SchemaType) {
  189. case SchemaTypes.Class: map = ImportClassMapping (typeData, root, defaultNamespace); break;
  190. case SchemaTypes.Array: map = ImportListMapping (typeData, root, defaultNamespace, null, 0); break;
  191. case SchemaTypes.XmlNode: map = ImportXmlNodeMapping (typeData, root, defaultNamespace); break;
  192. case SchemaTypes.Primitive: map = ImportPrimitiveMapping (typeData, root, defaultNamespace); break;
  193. case SchemaTypes.Enum: map = ImportEnumMapping (typeData, root, defaultNamespace); break;
  194. case SchemaTypes.XmlSerializable: map = ImportXmlSerializableMapping (typeData, root, defaultNamespace); break;
  195. default: throw new NotSupportedException ("Type " + typeData.Type.FullName + " not supported for XML stialization");
  196. }
  197. #if NET_2_0
  198. // bug #372780
  199. map.SetKey (typeData.Type.ToString ());
  200. #endif
  201. map.RelatedMaps = relatedMaps;
  202. map.Format = SerializationFormat.Literal;
  203. Type[] extraTypes = includedTypes != null ? (Type[]) includedTypes.ToArray (typeof (Type)) : null;
  204. #if !NET_2_1
  205. map.Source = new XmlTypeSerializationSource (typeData.Type, root, attributeOverrides, defaultNamespace, extraTypes);
  206. if (allowPrivateTypes) map.Source.CanBeGenerated = false;
  207. #endif
  208. return map;
  209. } catch (InvalidOperationException ex) {
  210. throw new InvalidOperationException (string.Format (CultureInfo.InvariantCulture,
  211. "There was an error reflecting type '{0}'.", typeData.Type.FullName), ex);
  212. }
  213. }
  214. XmlTypeMapping CreateTypeMapping (TypeData typeData, XmlRootAttribute root, string defaultXmlType, string defaultNamespace)
  215. {
  216. bool hasTypeNamespace = !string.IsNullOrEmpty (defaultNamespace);
  217. string rootNamespace = null;
  218. string typeNamespace = null;
  219. string elementName;
  220. bool includeInSchema = true;
  221. XmlAttributes atts = null;
  222. bool nullable = CanBeNull (typeData);
  223. if (defaultXmlType == null) defaultXmlType = typeData.XmlType;
  224. if (!typeData.IsListType)
  225. {
  226. if (attributeOverrides != null)
  227. atts = attributeOverrides[typeData.Type];
  228. if (atts != null && typeData.SchemaType == SchemaTypes.Primitive)
  229. throw new InvalidOperationException ("XmlRoot and XmlType attributes may not be specified for the type " + typeData.FullTypeName);
  230. }
  231. if (atts == null)
  232. atts = new XmlAttributes (typeData.Type);
  233. if (atts.XmlRoot != null && root == null)
  234. root = atts.XmlRoot;
  235. if (atts.XmlType != null)
  236. {
  237. if (atts.XmlType.Namespace != null) {
  238. typeNamespace = atts.XmlType.Namespace;
  239. hasTypeNamespace = true;
  240. }
  241. if (atts.XmlType.TypeName != null && atts.XmlType.TypeName != string.Empty)
  242. defaultXmlType = XmlConvert.EncodeLocalName (atts.XmlType.TypeName);
  243. includeInSchema = atts.XmlType.IncludeInSchema;
  244. }
  245. elementName = defaultXmlType;
  246. if (root != null)
  247. {
  248. if (root.ElementName.Length != 0)
  249. elementName = XmlConvert.EncodeLocalName(root.ElementName);
  250. if (root.Namespace != null) {
  251. rootNamespace = root.Namespace;
  252. hasTypeNamespace = true;
  253. }
  254. nullable = root.IsNullable;
  255. }
  256. rootNamespace = rootNamespace ?? defaultNamespace ?? string.Empty;
  257. typeNamespace = typeNamespace ?? rootNamespace;
  258. XmlTypeMapping map;
  259. switch (typeData.SchemaType) {
  260. case SchemaTypes.XmlSerializable:
  261. map = new XmlSerializableMapping (root, elementName, rootNamespace, typeData, defaultXmlType, typeNamespace);
  262. break;
  263. case SchemaTypes.Primitive:
  264. if (!typeData.IsXsdType)
  265. map = new XmlTypeMapping (elementName, rootNamespace,
  266. typeData, defaultXmlType, XmlSerializer.WsdlTypesNamespace);
  267. else
  268. map = new XmlTypeMapping (elementName, rootNamespace,
  269. typeData, defaultXmlType, typeNamespace);
  270. break;
  271. default:
  272. map = new XmlTypeMapping (elementName, rootNamespace, typeData, defaultXmlType, hasTypeNamespace ? typeNamespace : null);
  273. break;
  274. }
  275. map.IncludeInSchema = includeInSchema;
  276. map.IsNullable = nullable;
  277. relatedMaps.Add (map);
  278. return map;
  279. }
  280. XmlTypeMapping ImportClassMapping (Type type, XmlRootAttribute root, string defaultNamespace)
  281. {
  282. TypeData typeData = TypeTranslator.GetTypeData (type);
  283. return ImportClassMapping (typeData, root, defaultNamespace);
  284. }
  285. XmlTypeMapping ImportClassMapping (TypeData typeData, XmlRootAttribute root, string defaultNamespace)
  286. {
  287. Type type = typeData.Type;
  288. XmlTypeMapping map = helper.GetRegisteredClrType (type, GetTypeNamespace (typeData, root, defaultNamespace));
  289. if (map != null) return map;
  290. if (!allowPrivateTypes)
  291. ReflectionHelper.CheckSerializableType (type, false);
  292. map = CreateTypeMapping (typeData, root, null, defaultNamespace);
  293. helper.RegisterClrType (map, type, map.XmlTypeNamespace);
  294. helper.RegisterSchemaType (map, map.XmlType, map.XmlTypeNamespace);
  295. // Import members
  296. ClassMap classMap = new ClassMap ();
  297. map.ObjectMap = classMap;
  298. var members = GetReflectionMembers (type);
  299. bool? isOrderExplicit = null;
  300. foreach (XmlReflectionMember rmember in members)
  301. {
  302. int? order = rmember.XmlAttributes.Order;
  303. if (isOrderExplicit == null)
  304. {
  305. if (order != null)
  306. isOrderExplicit = (int) order >= 0;
  307. }
  308. else if (order != null && isOrderExplicit != ((int) order >= 0))
  309. 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.");
  310. }
  311. if (isOrderExplicit == true)
  312. members.Sort ((m1, m2) => (int) m1.XmlAttributes.SortableOrder - (int) m2.XmlAttributes.SortableOrder);
  313. foreach (XmlReflectionMember rmember in members)
  314. {
  315. string ns = map.XmlTypeNamespace;
  316. if (rmember.XmlAttributes.XmlIgnore) continue;
  317. if (rmember.DeclaringType != null && rmember.DeclaringType != type) {
  318. XmlTypeMapping bmap = ImportClassMapping (rmember.DeclaringType, root, defaultNamespace);
  319. if (bmap.HasXmlTypeNamespace)
  320. ns = bmap.XmlTypeNamespace;
  321. }
  322. try {
  323. XmlTypeMapMember mem = CreateMapMember (type, rmember, ns);
  324. mem.CheckOptionalValueType (type);
  325. classMap.AddMember (mem);
  326. } catch (Exception ex) {
  327. throw new InvalidOperationException (string.Format (
  328. CultureInfo.InvariantCulture, "There was an error" +
  329. " reflecting field '{0}'.", rmember.MemberName), ex);
  330. }
  331. }
  332. // Import extra classes
  333. if (type == typeof (object) && includedTypes != null)
  334. {
  335. foreach (Type intype in includedTypes)
  336. map.DerivedTypes.Add (ImportTypeMapping (intype, defaultNamespace));
  337. }
  338. // Register inheritance relations
  339. if (type.BaseType != null)
  340. {
  341. XmlTypeMapping bmap = ImportClassMapping (type.BaseType, root, defaultNamespace);
  342. ClassMap cbmap = bmap.ObjectMap as ClassMap;
  343. if (type.BaseType != typeof (object)) {
  344. map.BaseMap = bmap;
  345. if (!cbmap.HasSimpleContent)
  346. classMap.SetCanBeSimpleType (false);
  347. }
  348. // At this point, derived classes of this map must be already registered
  349. RegisterDerivedMap (bmap, map);
  350. if (cbmap.HasSimpleContent && classMap.ElementMembers != null && classMap.ElementMembers.Count != 1)
  351. throw new InvalidOperationException (String.Format (errSimple, map.TypeData.TypeName, map.BaseMap.TypeData.TypeName));
  352. }
  353. ImportIncludedTypes (type, defaultNamespace);
  354. if (classMap.XmlTextCollector != null && !classMap.HasSimpleContent)
  355. {
  356. XmlTypeMapMember mem = classMap.XmlTextCollector;
  357. if (mem.TypeData.Type != typeof(string) &&
  358. mem.TypeData.Type != typeof(string[]) &&
  359. mem.TypeData.Type != typeof(XmlNode[]) &&
  360. mem.TypeData.Type != typeof(object[]))
  361. throw new InvalidOperationException (String.Format (errSimple2, map.TypeData.TypeName, mem.Name, mem.TypeData.TypeName));
  362. }
  363. return map;
  364. }
  365. void RegisterDerivedMap (XmlTypeMapping map, XmlTypeMapping derivedMap)
  366. {
  367. map.DerivedTypes.Add (derivedMap);
  368. map.DerivedTypes.AddRange (derivedMap.DerivedTypes);
  369. if (map.BaseMap != null)
  370. RegisterDerivedMap (map.BaseMap, derivedMap);
  371. else {
  372. XmlTypeMapping obmap = ImportTypeMapping (typeof(object));
  373. if (obmap != map)
  374. obmap.DerivedTypes.Add (derivedMap);
  375. }
  376. }
  377. string GetTypeNamespace (TypeData typeData, XmlRootAttribute root, string defaultNamespace)
  378. {
  379. string typeNamespace = null;
  380. XmlAttributes atts = null;
  381. if (!typeData.IsListType)
  382. {
  383. if (attributeOverrides != null)
  384. atts = attributeOverrides[typeData.Type];
  385. }
  386. if (atts == null)
  387. atts = new XmlAttributes (typeData.Type);
  388. if (atts.XmlType != null)
  389. {
  390. if (atts.XmlType.Namespace != null && atts.XmlType.Namespace.Length != 0 && typeData.SchemaType != SchemaTypes.Enum)
  391. typeNamespace = atts.XmlType.Namespace;
  392. }
  393. if (typeNamespace != null && typeNamespace.Length != 0) return typeNamespace;
  394. if (atts.XmlRoot != null && root == null)
  395. root = atts.XmlRoot;
  396. if (root != null)
  397. {
  398. if (root.Namespace != null && root.Namespace.Length != 0)
  399. return root.Namespace;
  400. }
  401. if (defaultNamespace == null) return "";
  402. else return defaultNamespace;
  403. }
  404. XmlTypeMapping ImportListMapping (Type type, XmlRootAttribute root, string defaultNamespace, XmlAttributes atts, int nestingLevel)
  405. {
  406. TypeData typeData = TypeTranslator.GetTypeData (type);
  407. return ImportListMapping (typeData, root, defaultNamespace, atts, nestingLevel);
  408. }
  409. XmlTypeMapping ImportListMapping (TypeData typeData, XmlRootAttribute root, string defaultNamespace, XmlAttributes atts, int nestingLevel)
  410. {
  411. Type type = typeData.Type;
  412. ListMap obmap = new ListMap ();
  413. if (!allowPrivateTypes)
  414. ReflectionHelper.CheckSerializableType (type, true);
  415. if (atts == null) atts = new XmlAttributes();
  416. Type itemType = typeData.ListItemType;
  417. // warning: byte[][] should not be considered multiarray
  418. bool isMultiArray = (type.IsArray && (TypeTranslator.GetTypeData(itemType).SchemaType == SchemaTypes.Array) && itemType.IsArray);
  419. XmlTypeMapElementInfoList list = new XmlTypeMapElementInfoList();
  420. foreach (XmlArrayItemAttribute att in atts.XmlArrayItems)
  421. {
  422. if (att.Namespace != null && att.Form == XmlSchemaForm.Unqualified)
  423. throw new InvalidOperationException ("XmlArrayItemAttribute.Form must not be Unqualified when it has an explicit Namespace value.");
  424. if (att.NestingLevel != nestingLevel) continue;
  425. Type elemType = (att.Type != null) ? att.Type : itemType;
  426. XmlTypeMapElementInfo elem = new XmlTypeMapElementInfo (null, TypeTranslator.GetTypeData(elemType, att.DataType));
  427. elem.Namespace = att.Namespace != null ? att.Namespace : defaultNamespace;
  428. if (elem.Namespace == null) elem.Namespace = "";
  429. elem.Form = att.Form;
  430. if (att.Form == XmlSchemaForm.Unqualified)
  431. elem.Namespace = string.Empty;
  432. elem.IsNullable = att.IsNullable && CanBeNull (elem.TypeData);
  433. elem.NestingLevel = att.NestingLevel;
  434. if (isMultiArray) {
  435. elem.MappedType = ImportListMapping (elemType, null, elem.Namespace, atts, nestingLevel + 1);
  436. } else if (elem.TypeData.IsComplexType) {
  437. elem.MappedType = ImportTypeMapping (elemType, null, elem.Namespace);
  438. }
  439. if (att.ElementName.Length != 0) {
  440. elem.ElementName = XmlConvert.EncodeLocalName (att.ElementName);
  441. } else if (elem.MappedType != null) {
  442. elem.ElementName = elem.MappedType.ElementName;
  443. } else {
  444. elem.ElementName = TypeTranslator.GetTypeData (elemType).XmlType;
  445. }
  446. list.Add (elem);
  447. }
  448. if (list.Count == 0)
  449. {
  450. XmlTypeMapElementInfo elem = new XmlTypeMapElementInfo (null, TypeTranslator.GetTypeData (itemType));
  451. if (isMultiArray)
  452. elem.MappedType = ImportListMapping (itemType, null, defaultNamespace, atts, nestingLevel + 1);
  453. else if (elem.TypeData.IsComplexType)
  454. elem.MappedType = ImportTypeMapping (itemType, null, defaultNamespace);
  455. if (elem.MappedType != null) {
  456. elem.ElementName = elem.MappedType.XmlType;
  457. } else {
  458. elem.ElementName = TypeTranslator.GetTypeData (itemType).XmlType;
  459. }
  460. elem.Namespace = (defaultNamespace != null) ? defaultNamespace : "";
  461. elem.IsNullable = CanBeNull (elem.TypeData);
  462. list.Add (elem);
  463. }
  464. obmap.ItemInfo = list;
  465. // If there can be different element names (types) in the array, then its name cannot
  466. // be "ArrayOfXXX" it must be something like ArrayOfChoiceNNN
  467. string baseName;
  468. if (list.Count > 1) {
  469. baseName = "ArrayOfChoice" + (arrayChoiceCount++);
  470. } else {
  471. XmlTypeMapElementInfo elem = ((XmlTypeMapElementInfo) list[0]);
  472. if (elem.MappedType != null) {
  473. baseName = TypeTranslator.GetArrayName (elem.MappedType.XmlType);
  474. } else {
  475. baseName = TypeTranslator.GetArrayName (elem.ElementName);
  476. }
  477. }
  478. // Avoid name colisions
  479. int nameCount = 1;
  480. string name = baseName;
  481. do {
  482. XmlTypeMapping foundMap = helper.GetRegisteredSchemaType (name, defaultNamespace);
  483. if (foundMap == null) nameCount = -1;
  484. else if (obmap.Equals (foundMap.ObjectMap) && typeData.Type == foundMap.TypeData.Type) return foundMap;
  485. else name = baseName + (nameCount++);
  486. }
  487. while (nameCount != -1);
  488. XmlTypeMapping map = CreateTypeMapping (typeData, root, name, defaultNamespace);
  489. map.ObjectMap = obmap;
  490. // Register any of the including types as a derived class of object
  491. XmlIncludeAttribute[] includes = (XmlIncludeAttribute[])type.GetCustomAttributes (typeof (XmlIncludeAttribute), false);
  492. XmlTypeMapping objectMapping = ImportTypeMapping (typeof(object));
  493. for (int i = 0; i < includes.Length; i++)
  494. {
  495. Type includedType = includes[i].Type;
  496. objectMapping.DerivedTypes.Add(ImportTypeMapping (includedType, null, defaultNamespace));
  497. }
  498. // Register this map as a derived class of object
  499. helper.RegisterSchemaType (map, name, defaultNamespace);
  500. ImportTypeMapping (typeof(object)).DerivedTypes.Add (map);
  501. return map;
  502. }
  503. XmlTypeMapping ImportXmlNodeMapping (TypeData typeData, XmlRootAttribute root, string defaultNamespace)
  504. {
  505. Type type = typeData.Type;
  506. XmlTypeMapping map = helper.GetRegisteredClrType (type, GetTypeNamespace (typeData, root, defaultNamespace));
  507. if (map != null) return map;
  508. map = CreateTypeMapping (typeData, root, null, defaultNamespace);
  509. helper.RegisterClrType (map, type, map.XmlTypeNamespace);
  510. if (type.BaseType != null)
  511. {
  512. XmlTypeMapping bmap = ImportTypeMapping (type.BaseType, root, defaultNamespace);
  513. if (type.BaseType != typeof (object))
  514. map.BaseMap = bmap;
  515. RegisterDerivedMap (bmap, map);
  516. }
  517. return map;
  518. }
  519. XmlTypeMapping ImportPrimitiveMapping (TypeData typeData, XmlRootAttribute root, string defaultNamespace)
  520. {
  521. Type type = typeData.Type;
  522. XmlTypeMapping map = helper.GetRegisteredClrType (type, GetTypeNamespace (typeData, root, defaultNamespace));
  523. if (map != null) return map;
  524. map = CreateTypeMapping (typeData, root, null, defaultNamespace);
  525. helper.RegisterClrType (map, type, map.XmlTypeNamespace);
  526. return map;
  527. }
  528. XmlTypeMapping ImportEnumMapping (TypeData typeData, XmlRootAttribute root, string defaultNamespace)
  529. {
  530. Type type = typeData.Type;
  531. XmlTypeMapping map = helper.GetRegisteredClrType (type, GetTypeNamespace (typeData, root, defaultNamespace));
  532. if (map != null) return map;
  533. if (!allowPrivateTypes)
  534. ReflectionHelper.CheckSerializableType (type, false);
  535. map = CreateTypeMapping (typeData, root, null, defaultNamespace);
  536. map.IsNullable = false;
  537. helper.RegisterClrType (map, type, map.XmlTypeNamespace);
  538. ArrayList members = new ArrayList();
  539. string [] names = Enum.GetNames (type);
  540. foreach (string name in names) {
  541. FieldInfo field = type.GetField (name);
  542. string xmlName = null;
  543. if (field.IsDefined(typeof(XmlIgnoreAttribute), false))
  544. continue;
  545. object[] atts = field.GetCustomAttributes (typeof(XmlEnumAttribute), false);
  546. if (atts.Length > 0) xmlName = ((XmlEnumAttribute)atts[0]).Name;
  547. if (xmlName == null) xmlName = name;
  548. long value = ((IConvertible) field.GetValue (null)).ToInt64 (CultureInfo.InvariantCulture);
  549. members.Add (new EnumMap.EnumMapMember (xmlName, name, value));
  550. }
  551. bool isFlags = type.IsDefined (typeof (FlagsAttribute), false);
  552. map.ObjectMap = new EnumMap ((EnumMap.EnumMapMember[])members.ToArray (typeof(EnumMap.EnumMapMember)), isFlags);
  553. ImportTypeMapping (typeof(object)).DerivedTypes.Add (map);
  554. return map;
  555. }
  556. XmlTypeMapping ImportXmlSerializableMapping (TypeData typeData, XmlRootAttribute root, string defaultNamespace)
  557. {
  558. Type type = typeData.Type;
  559. XmlTypeMapping map = helper.GetRegisteredClrType (type, GetTypeNamespace (typeData, root, defaultNamespace));
  560. if (map != null) return map;
  561. if (!allowPrivateTypes)
  562. ReflectionHelper.CheckSerializableType (type, false);
  563. map = CreateTypeMapping (typeData, root, null, defaultNamespace);
  564. helper.RegisterClrType (map, type, map.XmlTypeNamespace);
  565. return map;
  566. }
  567. void ImportIncludedTypes (Type type, string defaultNamespace)
  568. {
  569. XmlIncludeAttribute[] includes = (XmlIncludeAttribute[])type.GetCustomAttributes (typeof (XmlIncludeAttribute), false);
  570. for (int n=0; n<includes.Length; n++)
  571. {
  572. Type includedType = includes[n].Type;
  573. ImportTypeMapping (includedType, null, defaultNamespace);
  574. }
  575. }
  576. List<XmlReflectionMember> GetReflectionMembers (Type type)
  577. {
  578. // First we want to find the inheritance hierarchy in reverse order.
  579. Type currentType = type;
  580. ArrayList typeList = new ArrayList();
  581. typeList.Add(currentType);
  582. while (currentType != typeof(object))
  583. {
  584. currentType = currentType.BaseType; // Read the base type.
  585. typeList.Insert(0, currentType); // Insert at 0 to reverse the order.
  586. }
  587. // Read all Fields via reflection.
  588. ArrayList fieldList = new ArrayList();
  589. FieldInfo[] tfields = type.GetFields (BindingFlags.Instance | BindingFlags.Public);
  590. #if TARGET_JVM
  591. // This statement ensures fields are ordered starting from the base type.
  592. for (int ti=0; ti<typeList.Count; ti++) {
  593. for (int i=0; i<tfields.Length; i++) {
  594. FieldInfo field = tfields[i];
  595. if (field.DeclaringType == typeList[ti])
  596. fieldList.Add (field);
  597. }
  598. }
  599. #else
  600. currentType = null;
  601. int currentIndex = 0;
  602. foreach (FieldInfo field in tfields)
  603. {
  604. // This statement ensures fields are ordered starting from the base type.
  605. if (currentType != field.DeclaringType)
  606. {
  607. currentType = field.DeclaringType;
  608. currentIndex=0;
  609. }
  610. fieldList.Insert(currentIndex++, field);
  611. }
  612. #endif
  613. // Read all Properties via reflection.
  614. ArrayList propList = new ArrayList();
  615. PropertyInfo[] tprops = type.GetProperties (BindingFlags.Instance | BindingFlags.Public);
  616. #if TARGET_JVM
  617. // This statement ensures properties are ordered starting from the base type.
  618. for (int ti=0; ti<typeList.Count; ti++) {
  619. for (int i=0; i<tprops.Length; i++) {
  620. PropertyInfo prop = tprops[i];
  621. if (!prop.CanRead) continue;
  622. if (prop.GetIndexParameters().Length > 0) continue;
  623. if (prop.DeclaringType == typeList[ti])
  624. propList.Add (prop);
  625. }
  626. }
  627. #else
  628. currentType = null;
  629. currentIndex = 0;
  630. foreach (PropertyInfo prop in tprops)
  631. {
  632. // This statement ensures properties are ordered starting from the base type.
  633. if (currentType != prop.DeclaringType)
  634. {
  635. currentType = prop.DeclaringType;
  636. currentIndex = 0;
  637. }
  638. if (!prop.CanRead) continue;
  639. if (prop.GetIndexParameters().Length > 0) continue;
  640. propList.Insert(currentIndex++, prop);
  641. }
  642. #endif
  643. var members = new List<XmlReflectionMember>();
  644. int fieldIndex=0;
  645. int propIndex=0;
  646. // We now step through the type hierarchy from the base (object) through
  647. // to the supplied class, as each step outputting all Fields, and then
  648. // all Properties. This is the exact same ordering as .NET 1.0/1.1.
  649. foreach (Type t in typeList)
  650. {
  651. // Add any fields matching the current DeclaringType.
  652. while (fieldIndex < fieldList.Count)
  653. {
  654. FieldInfo field = (FieldInfo)fieldList[fieldIndex];
  655. if (field.DeclaringType==t)
  656. {
  657. fieldIndex++;
  658. XmlAttributes atts = attributeOverrides[type, field.Name];
  659. if (atts == null) atts = new XmlAttributes (field);
  660. if (atts.XmlIgnore) continue;
  661. XmlReflectionMember member = new XmlReflectionMember(field.Name, field.FieldType, atts);
  662. member.DeclaringType = field.DeclaringType;
  663. members.Add(member);
  664. }
  665. else break;
  666. }
  667. // Add any properties matching the current DeclaringType.
  668. while (propIndex < propList.Count)
  669. {
  670. PropertyInfo prop = (PropertyInfo)propList[propIndex];
  671. if (prop.DeclaringType==t)
  672. {
  673. propIndex++;
  674. XmlAttributes atts = attributeOverrides[type, prop.Name];
  675. if (atts == null) atts = new XmlAttributes (prop);
  676. if (atts.XmlIgnore) continue;
  677. if (!prop.CanWrite) {
  678. if (prop.PropertyType.IsGenericType && TypeData.GetGenericListItemType (prop.PropertyType) == null) continue; // check this before calling GetTypeData() which raises error for missing Add(). See bug #704813.
  679. if (TypeTranslator.GetTypeData (prop.PropertyType).SchemaType != SchemaTypes.Array || prop.PropertyType.IsArray) continue;
  680. }
  681. XmlReflectionMember member = new XmlReflectionMember(prop.Name, prop.PropertyType, atts);
  682. member.DeclaringType = prop.DeclaringType;
  683. members.Add(member);
  684. }
  685. else break;
  686. }
  687. }
  688. return members;
  689. }
  690. private XmlTypeMapMember CreateMapMember (Type declaringType, XmlReflectionMember rmember, string defaultNamespace)
  691. {
  692. XmlTypeMapMember mapMember;
  693. XmlAttributes atts = rmember.XmlAttributes;
  694. TypeData typeData = TypeTranslator.GetTypeData (rmember.MemberType);
  695. if (atts.XmlArray != null) {
  696. if (atts.XmlArray.Namespace != null && atts.XmlArray.Form == XmlSchemaForm.Unqualified)
  697. throw new InvalidOperationException ("XmlArrayAttribute.Form must not be Unqualified when it has an explicit Namespace value.");
  698. if (typeData.SchemaType != SchemaTypes.Array &&
  699. !(typeData.SchemaType == SchemaTypes.Primitive && typeData.Type == typeof (byte [])))
  700. throw new InvalidOperationException ("XmlArrayAttribute can be applied to members of array or collection type.");
  701. }
  702. if (atts.XmlAnyAttribute != null)
  703. {
  704. if ( (rmember.MemberType.FullName == "System.Xml.XmlAttribute[]") ||
  705. (rmember.MemberType.FullName == "System.Xml.XmlNode[]") )
  706. {
  707. mapMember = new XmlTypeMapMemberAnyAttribute();
  708. }
  709. else
  710. throw new InvalidOperationException ("XmlAnyAttributeAttribute can only be applied to members of type XmlAttribute[] or XmlNode[]");
  711. }
  712. else
  713. if (atts.XmlAnyElements != null && atts.XmlAnyElements.Count > 0)
  714. {
  715. // no XmlNode type check is done here (seealso: bug #553032).
  716. XmlTypeMapMemberAnyElement member = new XmlTypeMapMemberAnyElement();
  717. member.ElementInfo = ImportAnyElementInfo (defaultNamespace, rmember, member, atts);
  718. mapMember = member;
  719. }
  720. else if (atts.Xmlns)
  721. {
  722. XmlTypeMapMemberNamespaces mapNamespaces = new XmlTypeMapMemberNamespaces ();
  723. mapMember = mapNamespaces;
  724. }
  725. else if (atts.XmlAttribute != null)
  726. {
  727. // An attribute
  728. if (atts.XmlElements != null && atts.XmlElements.Count > 0)
  729. throw new Exception ("XmlAttributeAttribute and XmlElementAttribute cannot be applied to the same member");
  730. XmlTypeMapMemberAttribute mapAttribute = new XmlTypeMapMemberAttribute ();
  731. if (atts.XmlAttribute.AttributeName.Length == 0)
  732. mapAttribute.AttributeName = rmember.MemberName;
  733. else
  734. mapAttribute.AttributeName = atts.XmlAttribute.AttributeName;
  735. mapAttribute.AttributeName = XmlConvert.EncodeLocalName (mapAttribute.AttributeName);
  736. if (typeData.IsComplexType)
  737. mapAttribute.MappedType = ImportTypeMapping (typeData.Type, null, defaultNamespace);
  738. if (atts.XmlAttribute.Namespace != null && atts.XmlAttribute.Namespace != defaultNamespace)
  739. {
  740. if (atts.XmlAttribute.Form == XmlSchemaForm.Unqualified)
  741. throw new InvalidOperationException ("The Form property may not be 'Unqualified' when an explicit Namespace property is present");
  742. mapAttribute.Form = XmlSchemaForm.Qualified;
  743. mapAttribute.Namespace = atts.XmlAttribute.Namespace;
  744. }
  745. else
  746. {
  747. mapAttribute.Form = atts.XmlAttribute.Form;
  748. if (atts.XmlAttribute.Form == XmlSchemaForm.Qualified)
  749. mapAttribute.Namespace = defaultNamespace;
  750. else
  751. mapAttribute.Namespace = "";
  752. }
  753. typeData = TypeTranslator.GetTypeData(rmember.MemberType, atts.XmlAttribute.DataType);
  754. mapMember = mapAttribute;
  755. }
  756. else if (typeData.SchemaType == SchemaTypes.Array)
  757. {
  758. // If the member has a single XmlElementAttribute and the type is the type of the member,
  759. // then it is not a flat list
  760. if (atts.XmlElements.Count > 1 ||
  761. (atts.XmlElements.Count == 1 && atts.XmlElements[0].Type != typeData.Type) ||
  762. (atts.XmlText != null))
  763. {
  764. // A flat list
  765. // check that it does not have XmlArrayAttribute
  766. if (atts.XmlArray != null)
  767. throw new InvalidOperationException ("XmlArrayAttribute cannot be used with members which also attributed with XmlElementAttribute or XmlTextAttribute.");
  768. XmlTypeMapMemberFlatList member = new XmlTypeMapMemberFlatList ();
  769. member.ListMap = new ListMap ();
  770. member.ListMap.ItemInfo = ImportElementInfo (declaringType, XmlConvert.EncodeLocalName (rmember.MemberName), defaultNamespace, typeData.ListItemType, member, atts);
  771. member.ElementInfo = member.ListMap.ItemInfo;
  772. member.ListMap.ChoiceMember = member.ChoiceMember;
  773. mapMember = member;
  774. }
  775. else
  776. {
  777. // A list
  778. XmlTypeMapMemberList member = new XmlTypeMapMemberList ();
  779. // Creates an ElementInfo that identifies the array instance.
  780. member.ElementInfo = new XmlTypeMapElementInfoList();
  781. XmlTypeMapElementInfo elem = new XmlTypeMapElementInfo (member, typeData);
  782. elem.ElementName = XmlConvert.EncodeLocalName((atts.XmlArray != null && atts.XmlArray.ElementName.Length != 0) ? atts.XmlArray.ElementName : rmember.MemberName);
  783. // note that it could be changed below (when Form is Unqualified)
  784. elem.Namespace = (atts.XmlArray != null && atts.XmlArray.Namespace != null) ? atts.XmlArray.Namespace : defaultNamespace;
  785. elem.MappedType = ImportListMapping (rmember.MemberType, null, elem.Namespace, atts, 0);
  786. elem.IsNullable = (atts.XmlArray != null) ? atts.XmlArray.IsNullable : false;
  787. elem.Form = (atts.XmlArray != null) ? atts.XmlArray.Form : XmlSchemaForm.Qualified;
  788. elem.ExplicitOrder = (atts.XmlArray != null) ? atts.XmlArray.Order : -1;
  789. // This is a bit tricky, but is done
  790. // after filling descendant members, so
  791. // that array items could be serialized
  792. // with proper namespace.
  793. if (atts.XmlArray != null && atts.XmlArray.Form == XmlSchemaForm.Unqualified)
  794. elem.Namespace = String.Empty;
  795. member.ElementInfo.Add (elem);
  796. mapMember = member;
  797. }
  798. }
  799. else
  800. {
  801. // An element
  802. XmlTypeMapMemberElement member = new XmlTypeMapMemberElement ();
  803. member.ElementInfo = ImportElementInfo (declaringType, XmlConvert.EncodeLocalName(rmember.MemberName), defaultNamespace, rmember.MemberType, member, atts);
  804. mapMember = member;
  805. }
  806. mapMember.DefaultValue = GetDefaultValue (typeData, atts.XmlDefaultValue);
  807. mapMember.TypeData = typeData;
  808. mapMember.Name = rmember.MemberName;
  809. mapMember.IsReturnValue = rmember.IsReturnValue;
  810. return mapMember;
  811. }
  812. XmlTypeMapElementInfoList ImportElementInfo (Type cls, string defaultName, string defaultNamespace, Type defaultType, XmlTypeMapMemberElement member, XmlAttributes atts)
  813. {
  814. EnumMap choiceEnumMap = null;
  815. Type choiceEnumType = null;
  816. XmlTypeMapElementInfoList list = new XmlTypeMapElementInfoList();
  817. ImportTextElementInfo (list, defaultType, member, atts, defaultNamespace);
  818. if (atts.XmlChoiceIdentifier != null) {
  819. if (cls == null)
  820. throw new InvalidOperationException ("XmlChoiceIdentifierAttribute not supported in this context.");
  821. member.ChoiceMember = atts.XmlChoiceIdentifier.MemberName;
  822. MemberInfo[] mems = cls.GetMember (member.ChoiceMember, BindingFlags.Instance|BindingFlags.Public);
  823. if (mems.Length == 0)
  824. throw new InvalidOperationException ("Choice member '" + member.ChoiceMember + "' not found in class '" + cls);
  825. if (mems[0] is PropertyInfo) {
  826. PropertyInfo pi = (PropertyInfo)mems[0];
  827. if (!pi.CanWrite || !pi.CanRead)
  828. throw new InvalidOperationException ("Choice property '" + member.ChoiceMember + "' must be read/write.");
  829. choiceEnumType = pi.PropertyType;
  830. }
  831. else choiceEnumType = ((FieldInfo)mems[0]).FieldType;
  832. member.ChoiceTypeData = TypeTranslator.GetTypeData (choiceEnumType);
  833. if (choiceEnumType.IsArray)
  834. choiceEnumType = choiceEnumType.GetElementType ();
  835. choiceEnumMap = ImportTypeMapping (choiceEnumType).ObjectMap as EnumMap;
  836. if (choiceEnumMap == null)
  837. throw new InvalidOperationException ("The member '" + mems[0].Name + "' is not a valid target for XmlChoiceIdentifierAttribute.");
  838. }
  839. if (atts.XmlElements.Count == 0 && list.Count == 0)
  840. {
  841. XmlTypeMapElementInfo elem = new XmlTypeMapElementInfo (member, TypeTranslator.GetTypeData(defaultType));
  842. elem.ElementName = defaultName;
  843. elem.Namespace = defaultNamespace;
  844. if (elem.TypeData.IsComplexType)
  845. elem.MappedType = ImportTypeMapping (defaultType, null, defaultNamespace);
  846. list.Add (elem);
  847. }
  848. bool multiType = (atts.XmlElements.Count > 1);
  849. foreach (XmlElementAttribute att in atts.XmlElements)
  850. {
  851. Type elemType = (att.Type != null) ? att.Type : defaultType;
  852. XmlTypeMapElementInfo elem = new XmlTypeMapElementInfo (member, TypeTranslator.GetTypeData(elemType, att.DataType));
  853. elem.Form = att.Form;
  854. if (elem.Form != XmlSchemaForm.Unqualified)
  855. elem.Namespace = (att.Namespace != null) ? att.Namespace : defaultNamespace;
  856. // elem may already be nullable, and IsNullable property in XmlElement is false by default
  857. if (att.IsNullable && !elem.IsNullable)
  858. elem.IsNullable = att.IsNullable;
  859. elem.ExplicitOrder = att.Order;
  860. if (elem.IsNullable && !elem.TypeData.IsNullable)
  861. throw new InvalidOperationException ("IsNullable may not be 'true' for value type " + elem.TypeData.FullTypeName + " in member '" + defaultName + "'");
  862. if (elem.TypeData.IsComplexType)
  863. {
  864. if (att.DataType.Length != 0) throw new InvalidOperationException (
  865. string.Format(CultureInfo.InvariantCulture, "'{0}' is "
  866. + "an invalid value for '{1}.{2}' of type '{3}'. "
  867. + "The property may only be specified for primitive types.",
  868. att.DataType, cls.FullName, defaultName,
  869. elem.TypeData.FullTypeName));
  870. elem.MappedType = ImportTypeMapping (elemType, null, elem.Namespace);
  871. }
  872. if (att.ElementName.Length != 0) {
  873. elem.ElementName = XmlConvert.EncodeLocalName(att.ElementName);
  874. } else if (multiType) {
  875. if (elem.MappedType != null) {
  876. elem.ElementName = elem.MappedType.ElementName;
  877. } else {
  878. elem.ElementName = TypeTranslator.GetTypeData (elemType).XmlType;
  879. }
  880. } else {
  881. elem.ElementName = defaultName;
  882. }
  883. if (choiceEnumMap != null) {
  884. string cname = choiceEnumMap.GetEnumName (choiceEnumType.FullName, elem.ElementName);
  885. if (cname == null)
  886. throw new InvalidOperationException (string.Format (
  887. CultureInfo.InvariantCulture, "Type {0} is missing"
  888. + " enumeration value '{1}' for element '{1} from"
  889. + " namespace '{2}'.", choiceEnumType, elem.ElementName,
  890. elem.Namespace));
  891. elem.ChoiceValue = Enum.Parse (choiceEnumType, cname, false);
  892. }
  893. list.Add (elem);
  894. }
  895. return list;
  896. }
  897. XmlTypeMapElementInfoList ImportAnyElementInfo (string defaultNamespace, XmlReflectionMember rmember, XmlTypeMapMemberElement member, XmlAttributes atts)
  898. {
  899. XmlTypeMapElementInfoList list = new XmlTypeMapElementInfoList();
  900. ImportTextElementInfo (list, rmember.MemberType, member, atts, defaultNamespace);
  901. foreach (XmlAnyElementAttribute att in atts.XmlAnyElements)
  902. {
  903. XmlTypeMapElementInfo elem = new XmlTypeMapElementInfo (member, TypeTranslator.GetTypeData(typeof(XmlElement)));
  904. if (att.Name.Length != 0)
  905. {
  906. elem.ElementName = XmlConvert.EncodeLocalName(att.Name);
  907. elem.Namespace = (att.Namespace != null) ? att.Namespace : "";
  908. }
  909. else
  910. {
  911. elem.IsUnnamedAnyElement = true;
  912. elem.Namespace = defaultNamespace;
  913. if (att.Namespace != null)
  914. 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.");
  915. }
  916. elem.ExplicitOrder = att.Order;
  917. list.Add (elem);
  918. }
  919. return list;
  920. }
  921. void ImportTextElementInfo (XmlTypeMapElementInfoList list, Type defaultType, XmlTypeMapMemberElement member, XmlAttributes atts, string defaultNamespace)
  922. {
  923. if (atts.XmlText != null)
  924. {
  925. member.IsXmlTextCollector = true;
  926. if (atts.XmlText.Type != null) {
  927. TypeData td = TypeTranslator.GetTypeData (defaultType);
  928. if ((td.SchemaType == SchemaTypes.Primitive || td.SchemaType == SchemaTypes.Enum) && atts.XmlText.Type != defaultType) {
  929. throw new InvalidOperationException ("The type for XmlText may not be specified for primitive types.");
  930. }
  931. defaultType = atts.XmlText.Type;
  932. }
  933. if (defaultType == typeof(XmlNode)) defaultType = typeof(XmlText); // Nodes must be text nodes
  934. XmlTypeMapElementInfo elem = new XmlTypeMapElementInfo (member, TypeTranslator.GetTypeData(defaultType, atts.XmlText.DataType));
  935. if (elem.TypeData.SchemaType != SchemaTypes.Primitive &&
  936. elem.TypeData.SchemaType != SchemaTypes.Enum &&
  937. elem.TypeData.SchemaType != SchemaTypes.XmlNode &&
  938. !(elem.TypeData.SchemaType == SchemaTypes.Array && elem.TypeData.ListItemTypeData.SchemaType == SchemaTypes.XmlNode)
  939. )
  940. throw new InvalidOperationException ("XmlText cannot be used to encode complex types");
  941. if (elem.TypeData.IsComplexType)
  942. elem.MappedType = ImportTypeMapping (defaultType, null, defaultNamespace);
  943. elem.IsTextElement = true;
  944. elem.WrappedElement = false;
  945. list.Add (elem);
  946. }
  947. }
  948. bool CanBeNull (TypeData type)
  949. {
  950. #if !NET_2_0 // idiotic compatibility
  951. if (type.Type == typeof (XmlQualifiedName))
  952. return false;
  953. #endif
  954. return !type.Type.IsValueType || type.IsNullable;
  955. }
  956. public void IncludeType (Type type)
  957. {
  958. if (type == null)
  959. throw new ArgumentNullException ("type");
  960. if (includedTypes == null) includedTypes = new ArrayList ();
  961. if (!includedTypes.Contains (type))
  962. includedTypes.Add (type);
  963. if (relatedMaps.Count > 0) {
  964. foreach (XmlTypeMapping map in (ArrayList) relatedMaps.Clone ()) {
  965. if (map.TypeData.Type == typeof(object))
  966. map.DerivedTypes.Add (ImportTypeMapping (type));
  967. }
  968. }
  969. }
  970. public void IncludeTypes (ICustomAttributeProvider provider)
  971. {
  972. object[] ats = provider.GetCustomAttributes (typeof(XmlIncludeAttribute), true);
  973. foreach (XmlIncludeAttribute at in ats)
  974. IncludeType (at.Type);
  975. }
  976. private object GetDefaultValue (TypeData typeData, object defaultValue)
  977. {
  978. if (defaultValue == DBNull.Value || typeData.SchemaType != SchemaTypes.Enum)
  979. return defaultValue;
  980. // get string representation of enum value
  981. string namedValue = Enum.Format (typeData.Type, defaultValue, "g");
  982. // get decimal representation of enum value
  983. string decimalValue = Enum.Format (typeData.Type, defaultValue, "d");
  984. // if decimal representation matches string representation, then
  985. // the value is not defined in the enum type (as the "g" format
  986. // will return the decimal equivalent of the value if the value
  987. // is not equal to a combination of named enumerated constants
  988. if (namedValue == decimalValue) {
  989. string msg = string.Format (CultureInfo.InvariantCulture,
  990. "Value '{0}' cannot be converted to {1}.", defaultValue,
  991. defaultValue.GetType ().FullName);
  992. throw new InvalidOperationException (msg);
  993. }
  994. // XmlSerializer expects integral enum value
  995. //return namedValue.Replace (',', ' ');
  996. return defaultValue;
  997. }
  998. #endregion // Methods
  999. }
  1000. }