XmlCodeExporter.cs 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443
  1. //
  2. // System.Xml.Serialization.XmlCodeExporter
  3. //
  4. // Author:
  5. // Tim Coleman ([email protected])
  6. // Lluis Sanchez Gual ([email protected])
  7. //
  8. // Copyright (C) Tim Coleman, 2002
  9. //
  10. using System.CodeDom;
  11. using System.Collections;
  12. using System.Xml.Schema;
  13. namespace System.Xml.Serialization {
  14. public class XmlCodeExporter {
  15. #region Fields
  16. CodeNamespace codeNamespace;
  17. CodeCompileUnit codeCompileUnit;
  18. CodeAttributeDeclarationCollection includeMetadata;
  19. Hashtable exportedMaps = new Hashtable ();
  20. #endregion
  21. #region Constructors
  22. public XmlCodeExporter (CodeNamespace codeNamespace)
  23. {
  24. includeMetadata = new CodeAttributeDeclarationCollection ();
  25. this.codeNamespace = codeNamespace;
  26. }
  27. public XmlCodeExporter (CodeNamespace codeNamespace, CodeCompileUnit codeCompileUnit)
  28. : this (codeNamespace)
  29. {
  30. this.codeCompileUnit = codeCompileUnit;
  31. }
  32. #endregion // Constructors
  33. #region Properties
  34. public CodeAttributeDeclarationCollection IncludeMetadata {
  35. get { return includeMetadata; }
  36. }
  37. #endregion Properties
  38. #region Methods
  39. [MonoTODO]
  40. public void AddMappingMetadata (CodeAttributeDeclarationCollection metadata, XmlMemberMapping member, string ns)
  41. {
  42. throw new NotImplementedException ();
  43. }
  44. [MonoTODO]
  45. public void AddMappingMetadata (CodeAttributeDeclarationCollection metadata, XmlTypeMapping member, string ns)
  46. {
  47. throw new NotImplementedException ();
  48. }
  49. [MonoTODO]
  50. public void AddMappingMetadata (CodeAttributeDeclarationCollection metadata, XmlMemberMapping member, string ns, bool forceUseMemberName)
  51. {
  52. throw new NotImplementedException ();
  53. }
  54. public void ExportMembersMapping (XmlMembersMapping xmlMembersMapping)
  55. {
  56. CodeTypeDeclaration dummyClass = new CodeTypeDeclaration ();
  57. ExportMembersMapCode (dummyClass, (ClassMap)xmlMembersMapping.ObjectMap, xmlMembersMapping.Namespace, null);
  58. }
  59. public void ExportTypeMapping (XmlTypeMapping xmlTypeMapping)
  60. {
  61. ExportMapCode (xmlTypeMapping, true);
  62. }
  63. void ExportMapCode (XmlTypeMapping map, bool isRoot)
  64. {
  65. switch (map.TypeData.SchemaType)
  66. {
  67. case SchemaTypes.Enum:
  68. ExportEnumCode (map);
  69. break;
  70. case SchemaTypes.Array:
  71. ExportArrayCode (map);
  72. break;
  73. case SchemaTypes.Class:
  74. ExportClassCode (map, isRoot);
  75. break;
  76. case SchemaTypes.XmlSerializable:
  77. case SchemaTypes.XmlNode:
  78. case SchemaTypes.Primitive:
  79. // Ignore
  80. break;
  81. }
  82. }
  83. void ExportClassCode (XmlTypeMapping map, bool isRoot)
  84. {
  85. if (IsMapExported (map)) return;
  86. SetMapExported (map);
  87. CodeTypeDeclaration codeClass = new CodeTypeDeclaration (map.TypeData.TypeName);
  88. codeClass.Attributes = MemberAttributes.Public;
  89. CodeAttributeDeclaration att = new CodeAttributeDeclaration ("System.Xml.Serialization.XmlType");
  90. if (map.XmlType != map.TypeData.TypeName) att.Arguments.Add (GetArg (map.XmlType));
  91. if (map.XmlTypeNamespace != "") att.Arguments.Add (GetArg ("Namespace", map.XmlTypeNamespace));
  92. AddCustomAttribute (codeClass, att, false);
  93. if (isRoot) {
  94. CodeAttributeDeclaration ratt = new CodeAttributeDeclaration ("System.Xml.Serialization.XmlRoot");
  95. if (map.ElementName != map.TypeData.TypeName) ratt.Arguments.Add (GetArg (map.ElementName));
  96. if (map.Namespace != "") ratt.Arguments.Add (GetArg ("Namespace", map.Namespace));
  97. AddCustomAttribute (codeClass, ratt, false);
  98. }
  99. if (map.BaseMap != null)
  100. {
  101. CodeTypeReference ctr = new CodeTypeReference (map.BaseMap.TypeData.FullTypeName);
  102. codeClass.BaseTypes.Add (ctr);
  103. ExportMapCode (map.BaseMap, false);
  104. }
  105. foreach (XmlTypeMapping tm in map.DerivedTypes)
  106. {
  107. CodeAttributeDeclaration iatt = new CodeAttributeDeclaration ("System.Xml.Serialization.XmlInclude");
  108. iatt.Arguments.Add (new CodeAttributeArgument (new CodeTypeOfExpression(tm.TypeData.FullTypeName)));
  109. AddCustomAttribute (codeClass, iatt, true);
  110. ExportMapCode (tm, false);
  111. }
  112. AddCodeType (codeClass);
  113. ExportMembersMapCode (codeClass, (ClassMap)map.ObjectMap, map.Namespace, map.BaseMap);
  114. }
  115. void ExportMembersMapCode (CodeTypeDeclaration codeClass, ClassMap map, string defaultNamespace, XmlTypeMapping baseMap)
  116. {
  117. ICollection members = map.ElementMembers;
  118. if (members != null)
  119. {
  120. foreach (XmlTypeMapMemberElement member in members)
  121. {
  122. if (baseMap != null && DefinedInBaseMap (baseMap, member)) continue;
  123. Type memType = member.GetType();
  124. if (memType == typeof(XmlTypeMapMemberList))
  125. {
  126. AddArrayElementFieldMember (codeClass, (XmlTypeMapMemberList) member, defaultNamespace);
  127. }
  128. else if (memType == typeof(XmlTypeMapMemberFlatList))
  129. {
  130. AddElementFieldMember (codeClass, member, defaultNamespace);
  131. }
  132. else if (memType == typeof(XmlTypeMapMemberAnyElement))
  133. {
  134. AddAnyElementFieldMember (codeClass, member, defaultNamespace);
  135. }
  136. else if (memType == typeof(XmlTypeMapMemberElement))
  137. {
  138. AddElementFieldMember (codeClass, member, defaultNamespace);
  139. }
  140. else
  141. {
  142. throw new InvalidOperationException ("Member type " + memType + " not supported");
  143. }
  144. }
  145. }
  146. // Write attributes
  147. ICollection attributes = map.AttributeMembers;
  148. if (attributes != null)
  149. {
  150. foreach (XmlTypeMapMemberAttribute attr in attributes) {
  151. if (baseMap != null && DefinedInBaseMap (baseMap, attr)) continue;
  152. AddAttributeFieldMember (codeClass, attr, defaultNamespace);
  153. }
  154. }
  155. XmlTypeMapMember anyAttrMember = map.DefaultAnyAttributeMember;
  156. if (anyAttrMember != null)
  157. {
  158. CodeMemberField codeField = new CodeMemberField (anyAttrMember.TypeData.FullTypeName, anyAttrMember.Name);
  159. codeField.Comments.Add (new CodeCommentStatement ("<remarks/>", true));
  160. codeField.Attributes = MemberAttributes.Public;
  161. AddCustomAttribute (codeField, "System.Xml.Serialization.XmlAnyAttribute");
  162. codeClass.Members.Add (codeField);
  163. }
  164. }
  165. CodeMemberField CreateFieldMember (string type, string name, object defaultValue)
  166. {
  167. CodeMemberField codeField = new CodeMemberField (type, name);
  168. codeField.Attributes = MemberAttributes.Public;
  169. codeField.Comments.Add (new CodeCommentStatement ("<remarks/>", true));
  170. if (defaultValue != System.DBNull.Value)
  171. {
  172. AddCustomAttribute (codeField, "System.ComponentModel.DefaultValue", GetArg (defaultValue));
  173. codeField.InitExpression = new CodePrimitiveExpression (defaultValue);
  174. }
  175. return codeField;
  176. }
  177. void AddAttributeFieldMember (CodeTypeDeclaration codeClass, XmlTypeMapMemberAttribute attinfo, string defaultNamespace)
  178. {
  179. CodeMemberField codeField = CreateFieldMember (attinfo.TypeData.FullTypeName, attinfo.Name, attinfo.DefaultValue);
  180. codeClass.Members.Add (codeField);
  181. CodeAttributeDeclaration att = new CodeAttributeDeclaration ("System.Xml.Serialization.XmlAttribute");
  182. if (attinfo.Name != attinfo.AttributeName) att.Arguments.Add (GetArg (attinfo.AttributeName));
  183. if (attinfo.Namespace != defaultNamespace) att.Arguments.Add (GetArg ("Namespace", attinfo.Namespace));
  184. if (attinfo.Form != XmlSchemaForm.None) att.Arguments.Add (GetArg ("Form",attinfo.Form));
  185. AddCustomAttribute (codeField, att, true);
  186. if (attinfo.MappedType != null)
  187. ExportMapCode (attinfo.MappedType, false);
  188. }
  189. void AddElementFieldMember (CodeTypeDeclaration codeClass, XmlTypeMapMemberElement member, string defaultNamespace)
  190. {
  191. if (member.TypeData == null) Console.WriteLine ("NN:" + member.Name);
  192. CodeMemberField codeField = CreateFieldMember (member.TypeData.FullTypeName, member.Name, member.DefaultValue);
  193. codeClass.Members.Add (codeField);
  194. TypeData defaultType = member.TypeData;
  195. bool addAlwaysAttr = false;
  196. if (member is XmlTypeMapMemberFlatList)
  197. {
  198. defaultType = defaultType.ListItemTypeData;
  199. addAlwaysAttr = true;
  200. }
  201. foreach (XmlTypeMapElementInfo einfo in member.ElementInfo)
  202. {
  203. if (ExportExtraElementAttributes (codeField, einfo, defaultNamespace, defaultType))
  204. continue;
  205. CodeAttributeDeclaration att = new CodeAttributeDeclaration ("System.Xml.Serialization.XmlElement");
  206. if (einfo.ElementName != member.Name) att.Arguments.Add (GetArg (einfo.ElementName));
  207. if (einfo.TypeData.FullTypeName != defaultType.FullTypeName) att.Arguments.Add (GetTypeArg ("Type", einfo.TypeData.FullTypeName));
  208. if (einfo.Namespace != defaultNamespace) att.Arguments.Add (GetArg ("Namespace", einfo.Namespace));
  209. if (einfo.IsNullable) att.Arguments.Add (GetArg ("IsNullable", true));
  210. AddCustomAttribute (codeField, att, addAlwaysAttr);
  211. if (einfo.MappedType != null) ExportMapCode (einfo.MappedType, false);
  212. }
  213. if (member.ChoiceMember != null)
  214. AddCustomAttribute (codeField, "System.Xml.Serialization.XmlChoiceIdentifier", GetArg(member.ChoiceMember));
  215. }
  216. void AddAnyElementFieldMember (CodeTypeDeclaration codeClass, XmlTypeMapMemberElement member, string defaultNamespace)
  217. {
  218. CodeMemberField codeField = CreateFieldMember (member.TypeData.FullTypeName, member.Name, member.DefaultValue);
  219. codeClass.Members.Add (codeField);
  220. foreach (XmlTypeMapElementInfo einfo in member.ElementInfo)
  221. {
  222. ExportExtraElementAttributes (codeField, einfo, defaultNamespace, einfo.TypeData);
  223. }
  224. }
  225. bool DefinedInBaseMap (XmlTypeMapping map, XmlTypeMapMember member)
  226. {
  227. if (((ClassMap)map.ObjectMap).FindMember (member.Name) != null)
  228. return true;
  229. else if (map.BaseMap != null)
  230. return DefinedInBaseMap (map.BaseMap, member);
  231. else
  232. return false;
  233. }
  234. void AddArrayElementFieldMember (CodeTypeDeclaration codeClass, XmlTypeMapMemberList member, string defaultNamespace)
  235. {
  236. CodeMemberField codeField = new CodeMemberField (member.TypeData.FullTypeName, member.Name);
  237. codeField.Comments.Add (new CodeCommentStatement ("<remarks/>", true));
  238. codeField.Attributes = MemberAttributes.Public;
  239. codeClass.Members.Add (codeField);
  240. XmlTypeMapElementInfo einfo = (XmlTypeMapElementInfo) member.ElementInfo[0];
  241. CodeAttributeDeclaration att = new CodeAttributeDeclaration ("System.Xml.Serialization.XmlArray");
  242. if (einfo.ElementName != member.Name) att.Arguments.Add (GetArg ("ElementName", einfo.ElementName));
  243. if (einfo.Namespace != defaultNamespace) att.Arguments.Add (GetArg ("Namespace", einfo.Namespace));
  244. if (einfo.IsNullable) att.Arguments.Add (GetArg ("IsNullable", true));
  245. AddCustomAttribute (codeField, att, false);
  246. ListMap listMap = (ListMap) member.ListTypeMapping.ObjectMap;
  247. AddArrayItemAttributes (codeField, listMap, member.TypeData.ListItemTypeData, defaultNamespace, 0);
  248. }
  249. void AddArrayItemAttributes (CodeMemberField codeField, ListMap listMap, TypeData type, string defaultNamespace, int nestingLevel)
  250. {
  251. foreach (XmlTypeMapElementInfo ainfo in listMap.ItemInfo)
  252. {
  253. string defaultName;
  254. if (ainfo.MappedType != null) defaultName = ainfo.MappedType.ElementName;
  255. else defaultName = ainfo.TypeData.XmlType;
  256. bool needsType = (listMap.ItemInfo.Count > 1) ||
  257. (ainfo.TypeData.FullTypeName != type.FullTypeName && !listMap.IsMultiArray);
  258. CodeAttributeDeclaration att = new CodeAttributeDeclaration ("System.Xml.Serialization.XmlArrayItem");
  259. if (ainfo.ElementName != defaultName) att.Arguments.Add (GetArg ("ElementName", ainfo.ElementName));
  260. if (ainfo.Namespace != defaultNamespace && ainfo.Namespace != XmlSchema.Namespace) att.Arguments.Add (GetArg ("Namespace", ainfo.Namespace));
  261. if (needsType) att.Arguments.Add (GetTypeArg ("Type", ainfo.TypeData.FullTypeName));
  262. if (ainfo.IsNullable) att.Arguments.Add (GetArg ("IsNullable", true));
  263. if (att.Arguments.Count > 0 && nestingLevel > 0) att.Arguments.Add (GetArg ("NestingLevel", nestingLevel));
  264. AddCustomAttribute (codeField, att, false);
  265. if (ainfo.MappedType != null) ExportMapCode (ainfo.MappedType, false);
  266. }
  267. if (listMap.IsMultiArray)
  268. {
  269. XmlTypeMapping nmap = listMap.NestedArrayMapping;
  270. AddArrayItemAttributes (codeField, (ListMap) nmap.ObjectMap, nmap.TypeData.ListItemTypeData, defaultNamespace, nestingLevel + 1);
  271. }
  272. }
  273. void ExportArrayCode (XmlTypeMapping map)
  274. {
  275. ListMap listMap = (ListMap) map.ObjectMap;
  276. foreach (XmlTypeMapElementInfo ainfo in listMap.ItemInfo)
  277. {
  278. if (ainfo.MappedType != null) ExportMapCode (ainfo.MappedType, false);
  279. }
  280. }
  281. bool ExportExtraElementAttributes (CodeMemberField codeField, XmlTypeMapElementInfo einfo, string defaultNamespace, TypeData defaultType)
  282. {
  283. if (einfo.IsTextElement) {
  284. CodeAttributeDeclaration uatt = new CodeAttributeDeclaration ("System.Xml.Serialization.XmlText");
  285. if (einfo.TypeData.FullTypeName != defaultType.FullTypeName) uatt.Arguments.Add (GetTypeArg ("Type", einfo.TypeData.FullTypeName));
  286. AddCustomAttribute (codeField, uatt, true);
  287. return true;
  288. }
  289. else if (einfo.IsUnnamedAnyElement) {
  290. CodeAttributeDeclaration uatt = new CodeAttributeDeclaration ("System.Xml.Serialization.XmlAnyElement");
  291. if (!einfo.IsUnnamedAnyElement) uatt.Arguments.Add (GetArg ("Name", einfo.ElementName));
  292. if (einfo.Namespace != defaultNamespace) uatt.Arguments.Add (GetArg ("Namespace", einfo.Namespace));
  293. AddCustomAttribute (codeField, uatt, true);
  294. return true;
  295. }
  296. return false;
  297. }
  298. void ExportEnumCode (XmlTypeMapping map)
  299. {
  300. if (IsMapExported (map)) return;
  301. SetMapExported (map);
  302. CodeTypeDeclaration codeEnum = new CodeTypeDeclaration (map.TypeData.TypeName);
  303. codeEnum.Attributes = MemberAttributes.Public;
  304. codeEnum.IsEnum = true;
  305. AddCodeType (codeEnum);
  306. CodeAttributeDeclaration att = new CodeAttributeDeclaration ("System.Xml.Serialization.XmlTypeAttribute");
  307. if (map.ElementName != map.TypeData.TypeName) att.Arguments.Add (GetArg ("Name", map.ElementName));
  308. if (map.Namespace != "") att.Arguments.Add (GetArg ("Namespace", map.Namespace));
  309. AddCustomAttribute (codeEnum, att, false);
  310. EnumMap emap = (EnumMap) map.ObjectMap;
  311. foreach (EnumMap.EnumMapMember emem in emap.Members)
  312. {
  313. CodeMemberField codeField = new CodeMemberField ("", emem.EnumName);
  314. codeField.Comments.Add (new CodeCommentStatement ("<remarks/>", true));
  315. if (emem.EnumName != emem.XmlName)
  316. {
  317. CodeAttributeDeclaration xatt = new CodeAttributeDeclaration ("System.Xml.Serialization.XmlEnum");
  318. xatt.Arguments.Add (GetArg ("Name", emem.XmlName));
  319. AddCustomAttribute (codeField, xatt, true);
  320. }
  321. codeEnum.Members.Add (codeField);
  322. }
  323. }
  324. bool IsMapExported (XmlTypeMapping map)
  325. {
  326. if (exportedMaps.Contains (map)) return true;
  327. if (map.TypeData.Type == typeof(object)) return true;
  328. return false;
  329. }
  330. void SetMapExported (XmlTypeMapping map)
  331. {
  332. exportedMaps.Add (map,map);
  333. }
  334. void AddCustomAttribute (CodeTypeMember ctm, CodeAttributeDeclaration att, bool addIfNoParams)
  335. {
  336. if (att.Arguments.Count == 0 && !addIfNoParams) return;
  337. if (ctm.CustomAttributes == null) ctm.CustomAttributes = new CodeAttributeDeclarationCollection ();
  338. ctm.CustomAttributes.Add (att);
  339. }
  340. void AddCustomAttribute (CodeTypeMember ctm, string name, params CodeAttributeArgument[] args)
  341. {
  342. if (ctm.CustomAttributes == null) ctm.CustomAttributes = new CodeAttributeDeclarationCollection ();
  343. ctm.CustomAttributes.Add (new CodeAttributeDeclaration (name, args));
  344. }
  345. CodeAttributeArgument GetArg (string name, object value)
  346. {
  347. return new CodeAttributeArgument (name, new CodePrimitiveExpression(value));
  348. }
  349. CodeAttributeArgument GetArg (object value)
  350. {
  351. return new CodeAttributeArgument (new CodePrimitiveExpression(value));
  352. }
  353. CodeAttributeArgument GetTypeArg (string name, string typeName)
  354. {
  355. return new CodeAttributeArgument (name, new CodeTypeOfExpression(typeName));
  356. }
  357. void AddCodeType (CodeTypeDeclaration type)
  358. {
  359. type.Comments.Add (new CodeCommentStatement ("<remarks/>", true));
  360. codeNamespace.Types.Add (type);
  361. }
  362. #endregion // Methods
  363. }
  364. }