XmlCodeExporter.cs 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450
  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. AddCodeType (codeClass, map.Documentation);
  89. codeClass.Attributes = MemberAttributes.Public;
  90. CodeAttributeDeclaration att = new CodeAttributeDeclaration ("System.Xml.Serialization.XmlType");
  91. if (map.XmlType != map.TypeData.TypeName) att.Arguments.Add (GetArg (map.XmlType));
  92. if (map.XmlTypeNamespace != "") att.Arguments.Add (GetArg ("Namespace", map.XmlTypeNamespace));
  93. AddCustomAttribute (codeClass, att, false);
  94. if (map.ElementName != map.XmlType || map.Namespace != map.XmlTypeNamespace) {
  95. CodeAttributeDeclaration ratt = new CodeAttributeDeclaration ("System.Xml.Serialization.XmlRoot");
  96. ratt.Arguments.Add (GetArg (map.ElementName));
  97. ratt.Arguments.Add (GetArg ("Namespace", map.Namespace));
  98. AddCustomAttribute (codeClass, ratt, false);
  99. }
  100. ExportMembersMapCode (codeClass, (ClassMap)map.ObjectMap, map.Namespace, map.BaseMap);
  101. if (map.BaseMap != null)
  102. {
  103. CodeTypeReference ctr = new CodeTypeReference (map.BaseMap.TypeData.FullTypeName);
  104. codeClass.BaseTypes.Add (ctr);
  105. ExportMapCode (map.BaseMap, false);
  106. }
  107. foreach (XmlTypeMapping tm in map.DerivedTypes)
  108. {
  109. CodeAttributeDeclaration iatt = new CodeAttributeDeclaration ("System.Xml.Serialization.XmlInclude");
  110. iatt.Arguments.Add (new CodeAttributeArgument (new CodeTypeOfExpression(tm.TypeData.FullTypeName)));
  111. AddCustomAttribute (codeClass, iatt, true);
  112. ExportMapCode (tm, false);
  113. }
  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. AddComments (codeField, anyAttrMember.Documentation);
  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, string comments)
  166. {
  167. CodeMemberField codeField = new CodeMemberField (type, name);
  168. codeField.Attributes = MemberAttributes.Public;
  169. AddComments (codeField, comments);
  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, attinfo.Documentation);
  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. if (!TypeTranslator.IsDefaultPrimitiveTpeData(attinfo.TypeData)) att.Arguments.Add (GetArg ("DataType",attinfo.TypeData.XmlType));
  186. AddCustomAttribute (codeField, att, true);
  187. if (attinfo.MappedType != null)
  188. ExportMapCode (attinfo.MappedType, false);
  189. }
  190. void AddElementFieldMember (CodeTypeDeclaration codeClass, XmlTypeMapMemberElement member, string defaultNamespace)
  191. {
  192. CodeMemberField codeField = CreateFieldMember (member.TypeData.FullTypeName, member.Name, member.DefaultValue, member.Documentation);
  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. if (!TypeTranslator.IsDefaultPrimitiveTpeData(einfo.TypeData)) att.Arguments.Add (GetArg ("DataType",einfo.TypeData.XmlType));
  211. AddCustomAttribute (codeField, att, addAlwaysAttr);
  212. if (einfo.MappedType != null) ExportMapCode (einfo.MappedType, false);
  213. }
  214. if (member.ChoiceMember != null)
  215. AddCustomAttribute (codeField, "System.Xml.Serialization.XmlChoiceIdentifier", GetArg(member.ChoiceMember));
  216. }
  217. void AddAnyElementFieldMember (CodeTypeDeclaration codeClass, XmlTypeMapMemberElement member, string defaultNamespace)
  218. {
  219. CodeMemberField codeField = CreateFieldMember (member.TypeData.FullTypeName, member.Name, member.DefaultValue, member.Documentation);
  220. codeClass.Members.Add (codeField);
  221. foreach (XmlTypeMapElementInfo einfo in member.ElementInfo)
  222. {
  223. ExportExtraElementAttributes (codeField, einfo, defaultNamespace, einfo.TypeData);
  224. }
  225. }
  226. bool DefinedInBaseMap (XmlTypeMapping map, XmlTypeMapMember member)
  227. {
  228. if (((ClassMap)map.ObjectMap).FindMember (member.Name) != null)
  229. return true;
  230. else if (map.BaseMap != null)
  231. return DefinedInBaseMap (map.BaseMap, member);
  232. else
  233. return false;
  234. }
  235. void AddArrayElementFieldMember (CodeTypeDeclaration codeClass, XmlTypeMapMemberList member, string defaultNamespace)
  236. {
  237. CodeMemberField codeField = new CodeMemberField (member.TypeData.FullTypeName, member.Name);
  238. AddComments (codeField, member.Documentation);
  239. codeField.Attributes = MemberAttributes.Public;
  240. codeClass.Members.Add (codeField);
  241. XmlTypeMapElementInfo einfo = (XmlTypeMapElementInfo) member.ElementInfo[0];
  242. CodeAttributeDeclaration att = new CodeAttributeDeclaration ("System.Xml.Serialization.XmlArray");
  243. if (einfo.ElementName != member.Name) att.Arguments.Add (GetArg ("ElementName", einfo.ElementName));
  244. if (einfo.Namespace != defaultNamespace) att.Arguments.Add (GetArg ("Namespace", einfo.Namespace));
  245. if (einfo.IsNullable) att.Arguments.Add (GetArg ("IsNullable", true));
  246. AddCustomAttribute (codeField, att, false);
  247. ListMap listMap = (ListMap) member.ListTypeMapping.ObjectMap;
  248. AddArrayItemAttributes (codeField, listMap, member.TypeData.ListItemTypeData, defaultNamespace, 0);
  249. }
  250. void AddArrayItemAttributes (CodeMemberField codeField, ListMap listMap, TypeData type, string defaultNamespace, int nestingLevel)
  251. {
  252. foreach (XmlTypeMapElementInfo ainfo in listMap.ItemInfo)
  253. {
  254. string defaultName;
  255. if (ainfo.MappedType != null) defaultName = ainfo.MappedType.ElementName;
  256. else defaultName = ainfo.TypeData.XmlType;
  257. bool needsType = (listMap.ItemInfo.Count > 1) ||
  258. (ainfo.TypeData.FullTypeName != type.FullTypeName && !listMap.IsMultiArray);
  259. CodeAttributeDeclaration att = new CodeAttributeDeclaration ("System.Xml.Serialization.XmlArrayItem");
  260. if (ainfo.ElementName != defaultName) att.Arguments.Add (GetArg ("ElementName", ainfo.ElementName));
  261. if (ainfo.Namespace != defaultNamespace && ainfo.Namespace != XmlSchema.Namespace) att.Arguments.Add (GetArg ("Namespace", ainfo.Namespace));
  262. if (needsType) att.Arguments.Add (GetTypeArg ("Type", ainfo.TypeData.FullTypeName));
  263. if (ainfo.IsNullable) att.Arguments.Add (GetArg ("IsNullable", true));
  264. if (att.Arguments.Count > 0 && nestingLevel > 0) att.Arguments.Add (GetArg ("NestingLevel", nestingLevel));
  265. AddCustomAttribute (codeField, att, false);
  266. if (ainfo.MappedType != null) ExportMapCode (ainfo.MappedType, false);
  267. }
  268. if (listMap.IsMultiArray)
  269. {
  270. XmlTypeMapping nmap = listMap.NestedArrayMapping;
  271. AddArrayItemAttributes (codeField, (ListMap) nmap.ObjectMap, nmap.TypeData.ListItemTypeData, defaultNamespace, nestingLevel + 1);
  272. }
  273. }
  274. void ExportArrayCode (XmlTypeMapping map)
  275. {
  276. ListMap listMap = (ListMap) map.ObjectMap;
  277. foreach (XmlTypeMapElementInfo ainfo in listMap.ItemInfo)
  278. {
  279. if (ainfo.MappedType != null) ExportMapCode (ainfo.MappedType, false);
  280. }
  281. }
  282. bool ExportExtraElementAttributes (CodeMemberField codeField, XmlTypeMapElementInfo einfo, string defaultNamespace, TypeData defaultType)
  283. {
  284. if (einfo.IsTextElement) {
  285. CodeAttributeDeclaration uatt = new CodeAttributeDeclaration ("System.Xml.Serialization.XmlText");
  286. if (einfo.TypeData.FullTypeName != defaultType.FullTypeName) uatt.Arguments.Add (GetTypeArg ("Type", einfo.TypeData.FullTypeName));
  287. AddCustomAttribute (codeField, uatt, true);
  288. return true;
  289. }
  290. else if (einfo.IsUnnamedAnyElement) {
  291. CodeAttributeDeclaration uatt = new CodeAttributeDeclaration ("System.Xml.Serialization.XmlAnyElement");
  292. if (!einfo.IsUnnamedAnyElement) uatt.Arguments.Add (GetArg ("Name", einfo.ElementName));
  293. if (einfo.Namespace != defaultNamespace) uatt.Arguments.Add (GetArg ("Namespace", einfo.Namespace));
  294. AddCustomAttribute (codeField, uatt, true);
  295. return true;
  296. }
  297. return false;
  298. }
  299. void ExportEnumCode (XmlTypeMapping map)
  300. {
  301. if (IsMapExported (map)) return;
  302. SetMapExported (map);
  303. CodeTypeDeclaration codeEnum = new CodeTypeDeclaration (map.TypeData.TypeName);
  304. codeEnum.Attributes = MemberAttributes.Public;
  305. codeEnum.IsEnum = true;
  306. AddCodeType (codeEnum, map.Documentation);
  307. CodeAttributeDeclaration att = new CodeAttributeDeclaration ("System.Xml.Serialization.XmlTypeAttribute");
  308. if (map.ElementName != map.TypeData.TypeName) att.Arguments.Add (GetArg ("Name", map.ElementName));
  309. if (map.Namespace != "") att.Arguments.Add (GetArg ("Namespace", map.Namespace));
  310. AddCustomAttribute (codeEnum, att, false);
  311. EnumMap emap = (EnumMap) map.ObjectMap;
  312. foreach (EnumMap.EnumMapMember emem in emap.Members)
  313. {
  314. CodeMemberField codeField = new CodeMemberField ("", emem.EnumName);
  315. AddComments (codeField, emem.Documentation);
  316. if (emem.EnumName != emem.XmlName)
  317. {
  318. CodeAttributeDeclaration xatt = new CodeAttributeDeclaration ("System.Xml.Serialization.XmlEnum");
  319. xatt.Arguments.Add (GetArg ("Name", emem.XmlName));
  320. AddCustomAttribute (codeField, xatt, true);
  321. }
  322. codeEnum.Members.Add (codeField);
  323. }
  324. }
  325. bool IsMapExported (XmlTypeMapping map)
  326. {
  327. if (exportedMaps.Contains (map)) return true;
  328. if (map.TypeData.Type == typeof(object)) return true;
  329. return false;
  330. }
  331. void SetMapExported (XmlTypeMapping map)
  332. {
  333. exportedMaps.Add (map,map);
  334. }
  335. void AddCustomAttribute (CodeTypeMember ctm, CodeAttributeDeclaration att, bool addIfNoParams)
  336. {
  337. if (att.Arguments.Count == 0 && !addIfNoParams) return;
  338. if (ctm.CustomAttributes == null) ctm.CustomAttributes = new CodeAttributeDeclarationCollection ();
  339. ctm.CustomAttributes.Add (att);
  340. }
  341. void AddCustomAttribute (CodeTypeMember ctm, string name, params CodeAttributeArgument[] args)
  342. {
  343. if (ctm.CustomAttributes == null) ctm.CustomAttributes = new CodeAttributeDeclarationCollection ();
  344. ctm.CustomAttributes.Add (new CodeAttributeDeclaration (name, args));
  345. }
  346. CodeAttributeArgument GetArg (string name, object value)
  347. {
  348. return new CodeAttributeArgument (name, new CodePrimitiveExpression(value));
  349. }
  350. CodeAttributeArgument GetArg (object value)
  351. {
  352. return new CodeAttributeArgument (new CodePrimitiveExpression(value));
  353. }
  354. CodeAttributeArgument GetTypeArg (string name, string typeName)
  355. {
  356. return new CodeAttributeArgument (name, new CodeTypeOfExpression(typeName));
  357. }
  358. void AddComments (CodeTypeMember member, string comments)
  359. {
  360. if (comments == null || comments == "") member.Comments.Add (new CodeCommentStatement ("<remarks/>", true));
  361. else member.Comments.Add (new CodeCommentStatement ("<remarks>\n" + comments + "\n</remarks>", true));
  362. }
  363. void AddCodeType (CodeTypeDeclaration type, string comments)
  364. {
  365. AddComments (type, comments);
  366. codeNamespace.Types.Add (type);
  367. }
  368. #endregion // Methods
  369. }
  370. }