2006-02-21 Atsushi Enomoto <atsushi@ximian.com>
[mono.git] / mcs / class / System.XML / System.Xml.Serialization / XmlCodeExporter.cs
1 // \r
2 // System.Xml.Serialization.XmlCodeExporter \r
3 //\r
4 // Author:\r
5 //   Tim Coleman (tim@timcoleman.com)\r
6 //   Lluis Sanchez Gual (lluis@ximian.com)\r
7 //\r
8 // Copyright (C) Tim Coleman, 2002\r
9 //\r
10 \r
11 //\r
12 // Permission is hereby granted, free of charge, to any person obtaining\r
13 // a copy of this software and associated documentation files (the\r
14 // "Software"), to deal in the Software without restriction, including\r
15 // without limitation the rights to use, copy, modify, merge, publish,\r
16 // distribute, sublicense, and/or sell copies of the Software, and to\r
17 // permit persons to whom the Software is furnished to do so, subject to\r
18 // the following conditions:\r
19 // \r
20 // The above copyright notice and this permission notice shall be\r
21 // included in all copies or substantial portions of the Software.\r
22 // \r
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\r
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\r
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\r
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
30 //\r
31 \r
32 using System.CodeDom;\r
33 using System.Collections;\r
34 using System.Xml.Schema;\r
35 using System.CodeDom.Compiler;\r
36 \r
37 namespace System.Xml.Serialization \r
38 {\r
39 \r
40         public class XmlCodeExporter \r
41 #if NET_2_0\r
42                 : CodeExporter\r
43 #endif\r
44         {\r
45                 #region Fields\r
46 \r
47 #if NET_2_0\r
48                 CodeGenerationOptions options;\r
49 #else\r
50                 XmlMapCodeGenerator codeGenerator;\r
51 #endif\r
52 \r
53                 #endregion\r
54 \r
55                 #region Constructors\r
56 \r
57                 public XmlCodeExporter (CodeNamespace codeNamespace): this (codeNamespace, null)\r
58                 {\r
59                 }\r
60 \r
61                 public XmlCodeExporter (CodeNamespace codeNamespace, CodeCompileUnit codeCompileUnit)\r
62                 {\r
63                         codeGenerator = new XmlMapCodeGenerator (codeNamespace, codeCompileUnit);\r
64                 }\r
65 \r
66 #if NET_2_0\r
67 \r
68                 public XmlCodeExporter (CodeNamespace codeNamespace, \r
69                                                                 CodeCompileUnit codeCompileUnit, \r
70                                                                 CodeGenerationOptions options)\r
71                 : this (codeNamespace, codeCompileUnit, null, options, null)\r
72                 {\r
73                 }\r
74                 \r
75                 public XmlCodeExporter (CodeNamespace codeNamespace, \r
76                                                                 CodeCompileUnit codeCompileUnit, \r
77                                                                 CodeGenerationOptions options, \r
78                                                                 Hashtable mappings)\r
79                 : this (codeNamespace, codeCompileUnit, null, options, mappings)\r
80                 {\r
81                         \r
82                 }\r
83                 \r
84                 [MonoTODO ("mappings?")]\r
85                 public XmlCodeExporter (CodeNamespace codeNamespace, \r
86                                                                 CodeCompileUnit codeCompileUnit, \r
87                                                                 ICodeGenerator codeGen, \r
88                                                                 CodeGenerationOptions options, \r
89                                                                 Hashtable mappings)\r
90                 {\r
91                         codeGenerator = new XmlMapCodeGenerator (codeNamespace, codeCompileUnit, codeGen, options, mappings);\r
92                 }\r
93                 \r
94 #endif\r
95 \r
96                 #endregion // Constructors\r
97 \r
98                 #region Properties\r
99 \r
100 #if !NET_2_0\r
101                 public CodeAttributeDeclarationCollection IncludeMetadata {\r
102                         get { return codeGenerator.IncludeMetadata; }\r
103                 }\r
104 #endif\r
105 \r
106                 #endregion Properties\r
107 \r
108                 #region Methods\r
109 \r
110                 public void AddMappingMetadata (CodeAttributeDeclarationCollection metadata, XmlMemberMapping member, string ns)\r
111                 {\r
112                         AddMappingMetadata (metadata, member, ns, false);\r
113                 }\r
114 \r
115                 public void AddMappingMetadata (CodeAttributeDeclarationCollection metadata, XmlTypeMapping member, string ns)\r
116                 {\r
117                         if ( (member.TypeData.SchemaType == SchemaTypes.Primitive ||\r
118                               member.TypeData.SchemaType == SchemaTypes.Array) \r
119                                 && member.Namespace != XmlSchema.Namespace)\r
120                         {\r
121                                 CodeAttributeDeclaration ratt = new CodeAttributeDeclaration ("System.Xml.Serialization.XmlRoot");\r
122                                 ratt.Arguments.Add (MapCodeGenerator.GetArg (member.ElementName));\r
123                                 ratt.Arguments.Add (MapCodeGenerator.GetArg ("Namespace", member.Namespace));\r
124                                 ratt.Arguments.Add (MapCodeGenerator.GetArg ("IsNullable", member.IsNullable));\r
125                                 metadata.Add (ratt);\r
126                         }\r
127                 }\r
128 \r
129                 public void AddMappingMetadata (CodeAttributeDeclarationCollection metadata, XmlMemberMapping member, string ns, bool forceUseMemberName)\r
130                 {\r
131                         CodeAttributeDeclaration att;\r
132                         TypeData memType = member.TypeMapMember.TypeData;\r
133                         \r
134                         if (member.Any)\r
135                         {\r
136                                 XmlTypeMapElementInfoList list = (XmlTypeMapElementInfoList)((XmlTypeMapMemberElement)member.TypeMapMember).ElementInfo;\r
137                                 foreach (XmlTypeMapElementInfo info in list)\r
138                                 {\r
139                                         if (info.IsTextElement)\r
140                                                 metadata.Add (new CodeAttributeDeclaration ("System.Xml.Serialization.XmlText"));\r
141                                         else {\r
142                                                 att = new CodeAttributeDeclaration ("System.Xml.Serialization.XmlAnyElement");\r
143                                                 if (!info.IsUnnamedAnyElement) {\r
144                                                         att.Arguments.Add (MapCodeGenerator.GetArg ("Name", info.ElementName));\r
145                                                         if (info.Namespace != ns) att.Arguments.Add (MapCodeGenerator.GetArg ("Namespace", member.Namespace));\r
146                                                 }\r
147                                                 metadata.Add (att);\r
148                                         }\r
149                                 }\r
150                         }\r
151                         else if (member.TypeMapMember is XmlTypeMapMemberList)\r
152                         {\r
153                                 // Array parameter\r
154                                 XmlTypeMapMemberList list = member.TypeMapMember as XmlTypeMapMemberList;\r
155                                 ListMap listMap = (ListMap) list.ListTypeMapping.ObjectMap;\r
156                                 \r
157                                 codeGenerator.AddArrayAttributes (metadata, list, ns, forceUseMemberName);\r
158                                 codeGenerator.AddArrayItemAttributes (metadata, listMap, memType.ListItemTypeData, list.Namespace, 0);\r
159                         }\r
160                         else if (member.TypeMapMember is XmlTypeMapMemberElement) {\r
161                                 codeGenerator.AddElementMemberAttributes ((XmlTypeMapMemberElement) member.TypeMapMember, ns, metadata, forceUseMemberName);\r
162                         }\r
163                         else if (member.TypeMapMember is XmlTypeMapMemberAttribute) {\r
164                                 codeGenerator.AddAttributeMemberAttributes ((XmlTypeMapMemberAttribute) member.TypeMapMember, ns, metadata, forceUseMemberName);\r
165                         }\r
166                         else\r
167                                 throw new NotSupportedException ("Schema type not supported");\r
168                 }\r
169 \r
170                 public void ExportMembersMapping (XmlMembersMapping xmlMembersMapping)\r
171                 {\r
172                         codeGenerator.ExportMembersMapping (xmlMembersMapping);\r
173                 }\r
174 \r
175                 public void ExportTypeMapping (XmlTypeMapping xmlTypeMapping)\r
176                 {\r
177                         codeGenerator.ExportTypeMapping (xmlTypeMapping);\r
178                 }\r
179 \r
180                 #endregion // Methods\r
181         }\r
182         \r
183         class XmlMapCodeGenerator : MapCodeGenerator\r
184         {\r
185                 public XmlMapCodeGenerator (CodeNamespace codeNamespace, CodeCompileUnit codeCompileUnit)\r
186                 : base (codeNamespace, codeCompileUnit)\r
187                 {\r
188                 }\r
189 \r
190                 public XmlMapCodeGenerator (CodeNamespace codeNamespace, CodeCompileUnit codeCompileUnit, ICodeGenerator codeGen, CodeGenerationOptions options, Hashtable mappings)\r
191                 : base (codeNamespace, codeCompileUnit, codeGen, options, mappings)\r
192                 {\r
193                 }\r
194                 \r
195                 protected override void GenerateClass (XmlTypeMapping map, CodeTypeDeclaration codeClass)\r
196                 {\r
197                         CodeAttributeDeclaration att = new CodeAttributeDeclaration ("System.Xml.Serialization.XmlType");\r
198                         if (map.XmlType != map.TypeData.TypeName) att.Arguments.Add (GetArg (map.XmlType));\r
199                         if (map.XmlTypeNamespace != "") att.Arguments.Add (GetArg ("Namespace", map.XmlTypeNamespace));\r
200                         if (!map.IncludeInSchema) att.Arguments.Add (GetArg ("IncludeInSchema", false));\r
201                         AddCustomAttribute (codeClass, att, false);\r
202 \r
203                         CodeAttributeDeclaration ratt = new CodeAttributeDeclaration ("System.Xml.Serialization.XmlRoot");\r
204                         if (map.ElementName != map.XmlType) ratt.Arguments.Add (GetArg (map.ElementName));\r
205                         if (map.Namespace != "") ratt.Arguments.Add (GetArg ("Namespace", map.Namespace));\r
206                         AddCustomAttribute (codeClass, ratt, false);\r
207                 }\r
208                 \r
209                 protected override void GenerateClassInclude (CodeAttributeDeclarationCollection attributes, XmlTypeMapping map)\r
210                 {\r
211                         CodeAttributeDeclaration iatt = new CodeAttributeDeclaration ("System.Xml.Serialization.XmlInclude");\r
212                         iatt.Arguments.Add (new CodeAttributeArgument (new CodeTypeOfExpression(map.TypeData.FullTypeName)));\r
213                         attributes.Add (iatt);\r
214                 }\r
215                 \r
216                 protected override void GenerateAnyAttribute (CodeTypeMember codeField)\r
217                 {\r
218                         AddCustomAttribute (codeField, "System.Xml.Serialization.XmlAnyAttribute");\r
219                 }\r
220                 \r
221                 protected override void GenerateAttributeMember (CodeAttributeDeclarationCollection attributes, XmlTypeMapMemberAttribute attinfo, string defaultNamespace, bool forceUseMemberName)\r
222                 {\r
223                         CodeAttributeDeclaration att = new CodeAttributeDeclaration ("System.Xml.Serialization.XmlAttribute");\r
224                         if (forceUseMemberName || attinfo.Name != attinfo.AttributeName) att.Arguments.Add (GetArg (attinfo.AttributeName));\r
225                         if (attinfo.Namespace != defaultNamespace) att.Arguments.Add (GetArg ("Namespace", attinfo.Namespace));\r
226                         if (attinfo.Form != XmlSchemaForm.None) att.Arguments.Add (GetEnumArg ("Form","System.Xml.Schema.XmlSchemaForm",attinfo.Form.ToString()));\r
227                         if (!TypeTranslator.IsDefaultPrimitiveTpeData(attinfo.TypeData)) att.Arguments.Add (GetArg ("DataType",attinfo.TypeData.XmlType));\r
228                         attributes.Add (att);\r
229                         \r
230                         if (attinfo.Ignore)\r
231                                 attributes.Add (new CodeAttributeDeclaration ("System.Xml.Serialization.XmlIgnoreAttribute"));\r
232                 }\r
233                 \r
234                 protected override void GenerateElementInfoMember (CodeAttributeDeclarationCollection attributes, XmlTypeMapMemberElement member, XmlTypeMapElementInfo einfo, TypeData defaultType, string defaultNamespace, bool addAlwaysAttr, bool forceUseMemberName)\r
235                 {\r
236                         CodeAttributeDeclaration att = new CodeAttributeDeclaration ("System.Xml.Serialization.XmlElement");\r
237                         if (forceUseMemberName || einfo.ElementName != member.Name) att.Arguments.Add (GetArg (einfo.ElementName));\r
238                         if (einfo.TypeData.FullTypeName != defaultType.FullTypeName) att.Arguments.Add (GetTypeArg ("Type", einfo.TypeData.FullTypeName));\r
239                         if (einfo.Namespace != defaultNamespace) att.Arguments.Add (GetArg ("Namespace", einfo.Namespace));\r
240                         if (einfo.Form == XmlSchemaForm.Unqualified) att.Arguments.Add (GetEnumArg ("Form", "System.Xml.Schema.XmlSchemaForm", einfo.Form.ToString()));\r
241                         if (einfo.IsNullable) att.Arguments.Add (GetArg ("IsNullable", true));\r
242                         if (!TypeTranslator.IsDefaultPrimitiveTpeData(einfo.TypeData)) att.Arguments.Add (GetArg ("DataType",einfo.TypeData.XmlType));\r
243                         if (addAlwaysAttr || att.Arguments.Count > 0) attributes.Add (att);\r
244                 }\r
245                 \r
246                 protected override void GenerateElementMember (CodeAttributeDeclarationCollection attributes, XmlTypeMapMemberElement member)\r
247                 {\r
248                         if (member.ChoiceMember != null) {\r
249                                 CodeAttributeDeclaration att = new CodeAttributeDeclaration ("System.Xml.Serialization.XmlChoiceIdentifier");\r
250                                 att.Arguments.Add (GetArg(member.ChoiceMember));\r
251                                 attributes.Add (att);\r
252                         }\r
253 \r
254                         if (member.Ignore)\r
255                                 attributes.Add (new CodeAttributeDeclaration ("System.Xml.Serialization.XmlIgnoreAttribute"));\r
256                 }\r
257                 \r
258                 protected override void GenerateArrayElement (CodeAttributeDeclarationCollection attributes, XmlTypeMapMemberElement member, string defaultNamespace, bool forceUseMemberName)\r
259                 {\r
260                         XmlTypeMapElementInfo einfo = (XmlTypeMapElementInfo) member.ElementInfo[0];\r
261                         CodeAttributeDeclaration att = new CodeAttributeDeclaration ("System.Xml.Serialization.XmlArray");\r
262                         if (forceUseMemberName || (einfo.ElementName != member.Name)) att.Arguments.Add (GetArg ("ElementName", einfo.ElementName));\r
263                         if (einfo.Namespace != defaultNamespace) att.Arguments.Add (GetArg ("Namespace", einfo.Namespace));\r
264                         if (einfo.Form == XmlSchemaForm.Unqualified) att.Arguments.Add (MapCodeGenerator.GetEnumArg ("Form", "System.Xml.Schema.XmlSchemaForm", einfo.Form.ToString()));\r
265                         if (einfo.IsNullable) att.Arguments.Add (GetArg ("IsNullable", true));\r
266                         if (att.Arguments.Count > 0) attributes.Add (att);\r
267                 }\r
268                 \r
269                 protected override void GenerateArrayItemAttributes (CodeAttributeDeclarationCollection attributes, ListMap listMap, TypeData type, XmlTypeMapElementInfo ainfo, string defaultName, string defaultNamespace, int nestingLevel)\r
270                 {\r
271                         bool needsType = (listMap.ItemInfo.Count > 1) ||\r
272                                                          (ainfo.TypeData.FullTypeName != type.FullTypeName && !listMap.IsMultiArray);\r
273 \r
274                         CodeAttributeDeclaration att = new CodeAttributeDeclaration ("System.Xml.Serialization.XmlArrayItem");\r
275                         if (ainfo.ElementName != defaultName) att.Arguments.Add (GetArg ("ElementName", ainfo.ElementName));\r
276                         if (ainfo.Namespace != defaultNamespace && ainfo.Namespace != XmlSchema.Namespace) att.Arguments.Add (GetArg ("Namespace", ainfo.Namespace));\r
277                         if (needsType) att.Arguments.Add (GetTypeArg ("Type", ainfo.TypeData.FullTypeName));\r
278                         if (!ainfo.IsNullable) att.Arguments.Add (GetArg ("IsNullable", false));\r
279                         if (ainfo.Form == XmlSchemaForm.Unqualified) att.Arguments.Add (MapCodeGenerator.GetEnumArg ("Form", "System.Xml.Schema.XmlSchemaForm", ainfo.Form.ToString()));\r
280                         if (att.Arguments.Count > 0 && nestingLevel > 0) att.Arguments.Add (GetArg ("NestingLevel", nestingLevel));\r
281                         \r
282                         if (att.Arguments.Count > 0) attributes.Add (att);\r
283                 }\r
284 \r
285                 protected override void GenerateTextElementAttribute (CodeAttributeDeclarationCollection attributes, XmlTypeMapElementInfo einfo, TypeData defaultType)\r
286                 {\r
287                         CodeAttributeDeclaration uatt = new CodeAttributeDeclaration ("System.Xml.Serialization.XmlText");\r
288                         if (einfo.TypeData.FullTypeName != defaultType.FullTypeName) uatt.Arguments.Add (GetTypeArg ("Type", einfo.TypeData.FullTypeName));\r
289                         attributes.Add (uatt);\r
290                 }\r
291                 \r
292                 protected override void GenerateUnnamedAnyElementAttribute (CodeAttributeDeclarationCollection attributes, XmlTypeMapElementInfo einfo, string defaultNamespace)\r
293                 {\r
294                         CodeAttributeDeclaration uatt = new CodeAttributeDeclaration ("System.Xml.Serialization.XmlAnyElement");\r
295                         if (!einfo.IsUnnamedAnyElement) uatt.Arguments.Add (GetArg ("Name", einfo.ElementName));\r
296                         if (einfo.Namespace != defaultNamespace) uatt.Arguments.Add (GetArg ("Namespace", einfo.Namespace));\r
297                         attributes.Add (uatt);\r
298                 }\r
299                 \r
300                 protected override void GenerateEnum (XmlTypeMapping map, CodeTypeDeclaration codeEnum)\r
301                 {\r
302                         CodeAttributeDeclaration att = new CodeAttributeDeclaration ("System.Xml.Serialization.XmlTypeAttribute");\r
303                         if (map.XmlType != map.TypeData.TypeName) att.Arguments.Add (GetArg ("TypeName", map.XmlType));\r
304                         if (map.XmlTypeNamespace != "") att.Arguments.Add (GetArg ("Namespace", map.XmlTypeNamespace));\r
305                         AddCustomAttribute (codeEnum, att, false);\r
306                 }               \r
307                 \r
308                 protected override void GenerateEnumItem (CodeMemberField codeField, EnumMap.EnumMapMember emem)\r
309                 {\r
310                         if (emem.EnumName != emem.XmlName)\r
311                         {\r
312                                 CodeAttributeDeclaration xatt = new CodeAttributeDeclaration ("System.Xml.Serialization.XmlEnum");\r
313                                 xatt.Arguments.Add (GetArg ("Name", emem.XmlName));\r
314 \r
315                                 AddCustomAttribute (codeField, xatt, true);\r
316                         }\r
317                 }\r
318                 \r
319                 protected override void GenerateSpecifierMember (CodeTypeMember codeField)\r
320                 {\r
321                         AddCustomAttribute (codeField, "System.Xml.Serialization.XmlIgnore");\r
322                 }\r
323 \r
324         }\r
325 }\r