* XmlAnyElementAttribute.cs, XmlArrayItemAttribute.cs: Added AllowMultiple flag.
[mono.git] / mcs / class / System.XML / System.Xml.Serialization / XmlTypeMapping.cs
1 //\r
2 // XmlTypeMapping.cs: \r
3 //\r
4 // Author:\r
5 //   John Donagher (john@webmeta.com)\r
6 //   Lluis Sanchez Gual (lluis@ximian.com)\r
7 //\r
8 // (C) 2002 John Donagher\r
9 //\r
10 \r
11 using System.Xml;\r
12 using System;\r
13 using System.Collections;\r
14 \r
15 namespace System.Xml.Serialization\r
16 {\r
17         public class XmlTypeMapping : XmlMapping\r
18         {\r
19                 private string elementName;\r
20                 private string ns;\r
21                 private string xmlType;\r
22                 TypeData type;\r
23                 bool multiReferenceType = false;\r
24 \r
25                 ArrayList _derivedTypes = new ArrayList();\r
26 \r
27                 internal XmlTypeMapping(string elementName, string ns, TypeData typeData, string xmlType)\r
28                 {\r
29                         this.elementName = elementName;\r
30                         this.ns = ns;\r
31                         this.type = typeData;\r
32                         this.xmlType = xmlType;\r
33                 }\r
34 \r
35                 public string ElementName\r
36                 {\r
37                         get { return elementName; }\r
38                 }\r
39 \r
40                 public string Namespace\r
41                 {\r
42                         get { return ns; }\r
43                 }\r
44 \r
45                 public string TypeFullName\r
46                 {\r
47                         get { return type.FullTypeName; }\r
48                 }\r
49 \r
50                 public string TypeName\r
51                 {\r
52                         get { return type.TypeName; }\r
53                 }\r
54 \r
55                 internal TypeData TypeData\r
56                 {\r
57                         get { return type; }\r
58                 }\r
59 \r
60                 internal string XmlType\r
61                 {\r
62                         get { return xmlType; }\r
63                 }\r
64 \r
65                 internal ArrayList DerivedTypes\r
66                 {\r
67                         get { return _derivedTypes; }\r
68                         set { _derivedTypes = value; }\r
69                 }\r
70 \r
71                 internal bool MultiReferenceType\r
72                 {\r
73                         get { return multiReferenceType; }\r
74                         set { multiReferenceType = value; }\r
75                 }\r
76 \r
77                 internal XmlTypeMapping GetRealTypeMap (string objectFullTypeName)\r
78                 {\r
79                         // Returns the map for a subtype of this map's type\r
80 \r
81                         if (TypeFullName == objectFullTypeName) return this;\r
82                         foreach (XmlTypeMapping map in _derivedTypes)\r
83                                 if (map.TypeFullName == objectFullTypeName) return map;\r
84 \r
85                         return null;\r
86                 }\r
87 \r
88                 internal XmlTypeMapping GetRealElementMap (string name, string ens)\r
89                 {\r
90                         if (xmlType == name && ns == ens) return this;\r
91                         foreach (XmlTypeMapping map in _derivedTypes)\r
92                                 if (map.xmlType == name && map.ns == ens) return map;\r
93                         return null;\r
94                 }\r
95         }\r
96 \r
97         // Mapping info for classes and structs\r
98 \r
99         internal class ClassMap: ObjectMap\r
100         {\r
101                 Hashtable _elements;\r
102                 ArrayList _elementMembers;\r
103                 Hashtable _attributeMembers;\r
104                 ArrayList _flatLists;\r
105                 XmlTypeMapMemberAnyElement _defaultAnyElement;\r
106                 XmlTypeMapMemberAnyAttribute _defaultAnyAttribute;\r
107                 XmlTypeMapMember _xmlTextCollector;\r
108 \r
109                 public void AddMember (XmlTypeMapMember member)\r
110                 {\r
111                         if (member is XmlTypeMapMemberAttribute)\r
112                         {\r
113                                 XmlTypeMapMemberAttribute atm = (XmlTypeMapMemberAttribute)member;\r
114                                 if (_attributeMembers == null) _attributeMembers = new Hashtable();\r
115                                 _attributeMembers.Add (atm.AttributeName + "/" + atm.Namespace, member);\r
116                                 return;\r
117                         }\r
118                         else if (member is XmlTypeMapMemberFlatList)\r
119                         {\r
120                                 RegisterFlatList ((XmlTypeMapMemberFlatList)member);\r
121                         }\r
122                         else if (member is XmlTypeMapMemberAnyElement)\r
123                         {\r
124                                 XmlTypeMapMemberAnyElement mem = (XmlTypeMapMemberAnyElement) member;\r
125                                 if (mem.IsDefaultAny) _defaultAnyElement = mem;\r
126                                 if (mem.TypeData.IsListType) RegisterFlatList (mem);\r
127                         }\r
128                         else if (member is XmlTypeMapMemberAnyAttribute)\r
129                         {\r
130                                 _defaultAnyAttribute = (XmlTypeMapMemberAnyAttribute) member;\r
131                                 return;\r
132                         }\r
133 \r
134                         if (member is XmlTypeMapMemberElement && ((XmlTypeMapMemberElement)member).IsXmlTextCollector)\r
135                         {\r
136                                 if (_xmlTextCollector != null) throw new InvalidOperationException ("XmlTextAttribute can only be applied once in a class");\r
137                                 _xmlTextCollector = member;\r
138                         }\r
139 \r
140                         if (_elementMembers == null) {\r
141                                 _elementMembers = new ArrayList();\r
142                                 _elements = new Hashtable();\r
143                         }\r
144 \r
145                         member.Index = _elementMembers.Count;\r
146                         _elementMembers.Add (member);\r
147 \r
148                         ICollection elemsInfo = ((XmlTypeMapMemberElement)member).ElementInfo;\r
149                         foreach (XmlTypeMapElementInfo elem in elemsInfo)\r
150                         {\r
151                                 string key = elem.ElementName+"/"+elem.Namespace;\r
152                                 if (_elements.ContainsKey (key)) \r
153                                         throw new InvalidOperationException ("The XML element named '" + elem.ElementName + "' from namespace '" + elem.Namespace + "' already present in the current scope. Use XML attributes to specify another XML name or namespace for the element.");\r
154                                 _elements.Add (key, elem);\r
155                         }\r
156                 }\r
157 \r
158                 void RegisterFlatList (XmlTypeMapMemberExpandable member)\r
159                 {\r
160                         if (_flatLists == null) _flatLists = new ArrayList ();\r
161                         member.FlatArrayIndex = _flatLists.Count;\r
162                         _flatLists.Add (member);\r
163                 }\r
164 \r
165                 public XmlTypeMapMemberAttribute GetAttribute (string name, string ns)\r
166                 {\r
167                         if (_attributeMembers == null) return null;\r
168                         return (XmlTypeMapMemberAttribute)_attributeMembers[name + "/" + ns];\r
169                 }\r
170 \r
171                 public XmlTypeMapElementInfo GetElement (string name, string ns)\r
172                 {\r
173                         if (_elements == null) return null;\r
174                         return (XmlTypeMapElementInfo)_elements[name + "/" + ns];\r
175                 }\r
176 \r
177                 public XmlTypeMapMemberAnyElement DefaultAnyElementMember\r
178                 {\r
179                         get { return _defaultAnyElement; }\r
180                 }\r
181 \r
182                 public XmlTypeMapMemberAnyAttribute DefaultAnyAttributeMember\r
183                 {\r
184                         get { return _defaultAnyAttribute; }\r
185                 }\r
186 \r
187                 public ICollection AttributeMembers\r
188                 {\r
189                         get { return (_attributeMembers != null) ? _attributeMembers.Values : null; }\r
190                 }\r
191 \r
192                 public ICollection ElementMembers\r
193                 {\r
194                         get { return _elementMembers; }\r
195                 }\r
196 \r
197                 public ICollection FlatLists\r
198                 {\r
199                         get { return _flatLists; }\r
200                 }\r
201 \r
202                 public XmlTypeMapMember XmlTextCollector\r
203                 {\r
204                         get { return _xmlTextCollector; }\r
205                 }\r
206         }\r
207 \r
208         // Mapping info for arrays and lists\r
209 \r
210         internal class ListMap: ObjectMap\r
211         {\r
212                 XmlTypeMapElementInfoList _itemInfo;\r
213 \r
214                 public XmlTypeMapElementInfoList ItemInfo\r
215                 {\r
216                         get { return _itemInfo; }\r
217                         set { _itemInfo = value; }\r
218                 }\r
219 \r
220                 public XmlTypeMapElementInfo FindElement (object memberValue)\r
221                 {\r
222                         if (_itemInfo.Count == 1) \r
223                                 return (XmlTypeMapElementInfo) _itemInfo[0];\r
224                         else\r
225                         {\r
226                                 if (memberValue == null) return null;\r
227                                 Type type = memberValue.GetType();\r
228                                 foreach (XmlTypeMapElementInfo elem in _itemInfo)\r
229                                         if (elem.TypeData.Type == type) return elem;\r
230                         }\r
231                         return null;\r
232                 }       \r
233 \r
234                 public XmlTypeMapElementInfo FindElement (string elementName, string ns)\r
235                 {\r
236                         foreach (XmlTypeMapElementInfo elem in _itemInfo)\r
237                                 if (elem.ElementName == elementName && elem.Namespace == ns) return elem;\r
238                         return null;\r
239                 }\r
240 \r
241                 public void GetArrayType (int itemCount, out string localName, out string ns)\r
242                 {\r
243                         string arrayDim;\r
244                         if (itemCount != -1) arrayDim = "[" + itemCount + "]";\r
245                         else arrayDim = "[]";\r
246 \r
247                         XmlTypeMapElementInfo info = (XmlTypeMapElementInfo) _itemInfo[0];\r
248                         if (info.TypeData.SchemaType == SchemaTypes.Array)\r
249                         {\r
250                                 string nm;\r
251                                 ((ListMap)info.MappedType.ObjectMap).GetArrayType (-1, out nm, out ns);\r
252                                 localName = nm + arrayDim;\r
253                         }\r
254                         else \r
255                         {\r
256                                 if (info.MappedType != null)\r
257                                 {\r
258                                         localName = info.MappedType.XmlType + arrayDim;\r
259                                         ns = info.MappedType.Namespace;\r
260                                 }\r
261                                 else \r
262                                 {\r
263                                         localName = info.DataType + arrayDim;\r
264                                         ns = info.DataTypeNamespace;\r
265                                 }\r
266                         }\r
267                 }\r
268 \r
269                 public override bool Equals (object other)\r
270                 {\r
271                         ListMap lmap = other as ListMap;\r
272                         if (lmap == null) return false;\r
273 \r
274                         if (_itemInfo.Count != lmap._itemInfo.Count) return false;\r
275                         for (int n=0; n<_itemInfo.Count; n++)\r
276                                 if (!_itemInfo[n].Equals (lmap._itemInfo[n])) return false;\r
277                         return true;\r
278                 }\r
279 \r
280                 public override int GetHashCode ()\r
281                 {\r
282                         return base.GetHashCode ();\r
283                 }\r
284         }\r
285 \r
286         internal class EnumMap: ObjectMap\r
287         {\r
288                 EnumMapMember[] _members;\r
289 \r
290                 public class EnumMapMember\r
291                 {\r
292                         string _xmlName;\r
293                         string _enumName;\r
294 \r
295                         public EnumMapMember (string xmlName, string enumName)\r
296                         {\r
297                                 _xmlName = xmlName;\r
298                                 _enumName = enumName;\r
299                         }\r
300 \r
301                         public string XmlName\r
302                         {\r
303                                 get { return _xmlName; }\r
304                         }\r
305 \r
306                         public string EnumName\r
307                         {\r
308                                 get { return _enumName; }\r
309                         }\r
310                 }\r
311 \r
312                 public EnumMap (EnumMapMember[] members)\r
313                 {\r
314                         _members = members;\r
315                 }\r
316 \r
317                 public EnumMapMember[] Members\r
318                 {\r
319                         get { return _members; }\r
320                 }\r
321 \r
322                 public string GetXmlName (object enumValue)\r
323                 {\r
324                         string enumName = enumValue.ToString();\r
325                         foreach (EnumMapMember mem in _members)\r
326                                 if (mem.EnumName == enumName) return mem.XmlName;\r
327                         \r
328                         return Convert.ToInt64(enumValue).ToString();\r
329                 }\r
330 \r
331                 public string GetEnumName (string xmlName)\r
332                 {\r
333                         foreach (EnumMapMember mem in _members)\r
334                                 if (mem.XmlName == xmlName) return mem.EnumName;\r
335                                 \r
336                         try {\r
337                                 Int64.Parse (xmlName);\r
338                                 return xmlName;\r
339                         }\r
340                         catch {\r
341                                 throw new InvalidOperationException ("Invalid enumeration value: " + xmlName);\r
342                         }\r
343                 }\r
344         }\r
345 }\r