2 // XmlTypeMapping.cs:
\r
5 // John Donagher (john@webmeta.com)
\r
6 // Lluis Sanchez Gual (lluis@ximian.com)
\r
8 // (C) 2002 John Donagher
\r
13 using System.Collections;
\r
15 namespace System.Xml.Serialization
\r
17 public class XmlTypeMapping : XmlMapping
\r
19 private string elementName;
\r
21 private string xmlType;
\r
23 XmlTypeMapping baseMap;
\r
24 bool multiReferenceType = false;
\r
26 ArrayList _derivedTypes = new ArrayList();
\r
28 internal XmlTypeMapping(string elementName, string ns, TypeData typeData, string xmlType)
\r
30 this.elementName = elementName;
\r
32 this.type = typeData;
\r
33 this.xmlType = xmlType;
\r
36 public string ElementName
\r
38 get { return elementName; }
\r
41 public string Namespace
\r
46 public string TypeFullName
\r
48 get { return type.FullTypeName; }
\r
51 public string TypeName
\r
53 get { return type.TypeName; }
\r
56 internal TypeData TypeData
\r
58 get { return type; }
\r
61 internal string XmlType
\r
63 get { return xmlType; }
\r
66 internal ArrayList DerivedTypes
\r
68 get { return _derivedTypes; }
\r
69 set { _derivedTypes = value; }
\r
72 internal bool MultiReferenceType
\r
74 get { return multiReferenceType; }
\r
75 set { multiReferenceType = value; }
\r
78 internal XmlTypeMapping BaseMap
\r
80 get { return baseMap; }
\r
81 set { baseMap = value; }
\r
84 internal XmlTypeMapping GetRealTypeMap (string objectFullTypeName)
\r
86 // Returns the map for a subtype of this map's type
\r
88 if (TypeFullName == objectFullTypeName) return this;
\r
89 foreach (XmlTypeMapping map in _derivedTypes)
\r
90 if (map.TypeFullName == objectFullTypeName) return map;
\r
95 internal XmlTypeMapping GetRealElementMap (string name, string ens)
\r
97 if (xmlType == name && ns == ens) return this;
\r
98 foreach (XmlTypeMapping map in _derivedTypes)
\r
99 if (map.xmlType == name && map.ns == ens) return map;
\r
104 // Mapping info for classes and structs
\r
106 internal class ClassMap: ObjectMap
\r
108 Hashtable _elements;
\r
109 ArrayList _elementMembers;
\r
110 Hashtable _attributeMembers;
\r
111 ArrayList _flatLists;
\r
112 ArrayList _allMembers = new ArrayList ();
\r
113 XmlTypeMapMemberAnyElement _defaultAnyElement;
\r
114 XmlTypeMapMemberAnyAttribute _defaultAnyAttribute;
\r
115 XmlTypeMapMemberNamespaces _namespaceDeclarations;
\r
116 XmlTypeMapMember _xmlTextCollector;
\r
118 public void AddMember (XmlTypeMapMember member)
\r
120 _allMembers.Add (member);
\r
121 if (member is XmlTypeMapMemberAttribute)
\r
123 XmlTypeMapMemberAttribute atm = (XmlTypeMapMemberAttribute)member;
\r
124 if (_attributeMembers == null) _attributeMembers = new Hashtable();
\r
125 _attributeMembers.Add (atm.AttributeName + "/" + atm.Namespace, member);
\r
128 else if (member is XmlTypeMapMemberFlatList)
\r
130 RegisterFlatList ((XmlTypeMapMemberFlatList)member);
\r
132 else if (member is XmlTypeMapMemberAnyElement)
\r
134 XmlTypeMapMemberAnyElement mem = (XmlTypeMapMemberAnyElement) member;
\r
135 if (mem.IsDefaultAny) _defaultAnyElement = mem;
\r
136 if (mem.TypeData.IsListType) RegisterFlatList (mem);
\r
138 else if (member is XmlTypeMapMemberAnyAttribute)
\r
140 _defaultAnyAttribute = (XmlTypeMapMemberAnyAttribute) member;
\r
143 else if (member is XmlTypeMapMemberNamespaces)
\r
145 _namespaceDeclarations = (XmlTypeMapMemberNamespaces) member;
\r
149 if (member is XmlTypeMapMemberElement && ((XmlTypeMapMemberElement)member).IsXmlTextCollector)
\r
151 if (_xmlTextCollector != null) throw new InvalidOperationException ("XmlTextAttribute can only be applied once in a class");
\r
152 _xmlTextCollector = member;
\r
155 if (_elementMembers == null) {
\r
156 _elementMembers = new ArrayList();
\r
157 _elements = new Hashtable();
\r
160 member.Index = _elementMembers.Count;
\r
161 _elementMembers.Add (member);
\r
163 ICollection elemsInfo = ((XmlTypeMapMemberElement)member).ElementInfo;
\r
164 foreach (XmlTypeMapElementInfo elem in elemsInfo)
\r
166 string key = elem.ElementName+"/"+elem.Namespace;
\r
167 if (_elements.ContainsKey (key))
\r
168 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
169 _elements.Add (key, elem);
\r
173 void RegisterFlatList (XmlTypeMapMemberExpandable member)
\r
175 if (_flatLists == null) _flatLists = new ArrayList ();
\r
176 member.FlatArrayIndex = _flatLists.Count;
\r
177 _flatLists.Add (member);
\r
180 public XmlTypeMapMemberAttribute GetAttribute (string name, string ns)
\r
182 if (_attributeMembers == null) return null;
\r
183 return (XmlTypeMapMemberAttribute)_attributeMembers[name + "/" + ns];
\r
186 public XmlTypeMapElementInfo GetElement (string name, string ns)
\r
188 if (_elements == null) return null;
\r
189 return (XmlTypeMapElementInfo)_elements[name + "/" + ns];
\r
192 public XmlTypeMapMember FindMember (string name)
\r
194 for (int n=0; n<_allMembers.Count; n++)
\r
195 if (((XmlTypeMapMember)_allMembers[n]).Name == name) return (XmlTypeMapMember)_allMembers[n];
\r
199 public XmlTypeMapMemberAnyElement DefaultAnyElementMember
\r
201 get { return _defaultAnyElement; }
\r
204 public XmlTypeMapMemberAnyAttribute DefaultAnyAttributeMember
\r
206 get { return _defaultAnyAttribute; }
\r
209 public XmlTypeMapMemberNamespaces NamespaceDeclarations
\r
211 get { return _namespaceDeclarations; }
\r
214 public ICollection AttributeMembers
\r
216 get { return (_attributeMembers != null) ? _attributeMembers.Values : null; }
\r
219 public ICollection ElementMembers
\r
221 get { return _elementMembers; }
\r
224 public ICollection FlatLists
\r
226 get { return _flatLists; }
\r
229 public XmlTypeMapMember XmlTextCollector
\r
231 get { return _xmlTextCollector; }
\r
235 // Mapping info for arrays and lists
\r
237 internal class ListMap: ObjectMap
\r
239 XmlTypeMapElementInfoList _itemInfo;
\r
241 public XmlTypeMapElementInfoList ItemInfo
\r
243 get { return _itemInfo; }
\r
244 set { _itemInfo = value; }
\r
247 public XmlTypeMapElementInfo FindElement (object memberValue)
\r
249 if (_itemInfo.Count == 1)
\r
250 return (XmlTypeMapElementInfo) _itemInfo[0];
\r
253 if (memberValue == null) return null;
\r
254 Type type = memberValue.GetType();
\r
255 foreach (XmlTypeMapElementInfo elem in _itemInfo)
\r
256 if (elem.TypeData.Type == type) return elem;
\r
261 public XmlTypeMapElementInfo FindElement (string elementName, string ns)
\r
263 foreach (XmlTypeMapElementInfo elem in _itemInfo)
\r
264 if (elem.ElementName == elementName && elem.Namespace == ns) return elem;
\r
268 public void GetArrayType (int itemCount, out string localName, out string ns)
\r
271 if (itemCount != -1) arrayDim = "[" + itemCount + "]";
\r
272 else arrayDim = "[]";
\r
274 XmlTypeMapElementInfo info = (XmlTypeMapElementInfo) _itemInfo[0];
\r
275 if (info.TypeData.SchemaType == SchemaTypes.Array)
\r
278 ((ListMap)info.MappedType.ObjectMap).GetArrayType (-1, out nm, out ns);
\r
279 localName = nm + arrayDim;
\r
283 if (info.MappedType != null)
\r
285 localName = info.MappedType.XmlType + arrayDim;
\r
286 ns = info.MappedType.Namespace;
\r
290 localName = info.TypeData.XmlType + arrayDim;
\r
291 ns = info.DataTypeNamespace;
\r
296 public override bool Equals (object other)
\r
298 ListMap lmap = other as ListMap;
\r
299 if (lmap == null) return false;
\r
301 if (_itemInfo.Count != lmap._itemInfo.Count) return false;
\r
302 for (int n=0; n<_itemInfo.Count; n++)
\r
303 if (!_itemInfo[n].Equals (lmap._itemInfo[n])) return false;
\r
307 public override int GetHashCode ()
\r
309 return base.GetHashCode ();
\r
313 internal class EnumMap: ObjectMap
\r
315 EnumMapMember[] _members;
\r
318 public class EnumMapMember
\r
323 public EnumMapMember (string xmlName, string enumName)
\r
325 _xmlName = xmlName;
\r
326 _enumName = enumName;
\r
329 public string XmlName
\r
331 get { return _xmlName; }
\r
334 public string EnumName
\r
336 get { return _enumName; }
\r
340 public EnumMap (EnumMapMember[] members, bool isFlags)
\r
342 _members = members;
\r
343 _isFlags = isFlags;
\r
346 public EnumMapMember[] Members
\r
348 get { return _members; }
\r
351 public string GetXmlName (object enumValue)
\r
353 string enumName = enumValue.ToString();
\r
355 if (_isFlags && enumName.IndexOf (',') != -1)
\r
357 System.Text.StringBuilder sb = new System.Text.StringBuilder ();
\r
358 string[] enumNames = enumValue.ToString().Split (',');
\r
359 foreach (string name in enumNames)
\r
361 foreach (EnumMapMember mem in _members)
\r
362 if (mem.EnumName == name.Trim()) {
\r
363 sb.Append (mem.XmlName).Append (' ');
\r
367 sb.Remove (sb.Length-1, 1);
\r
368 return sb.ToString ();
\r
371 foreach (EnumMapMember mem in _members)
\r
372 if (mem.EnumName == enumName) return mem.XmlName;
\r
374 return Convert.ToInt64(enumValue).ToString();
\r
377 public string GetEnumName (string xmlName)
\r
379 if (_isFlags && xmlName.Trim().IndexOf (' ') != -1)
\r
381 System.Text.StringBuilder sb = new System.Text.StringBuilder ();
\r
382 string[] enumNames = xmlName.ToString().Split (' ');
\r
383 foreach (string name in enumNames)
\r
385 if (name == string.Empty) continue;
\r
386 string foundEnumValue = null;
\r
387 foreach (EnumMapMember mem in _members)
\r
388 if (mem.XmlName == name) { foundEnumValue = mem.EnumName; break; }
\r
390 if (foundEnumValue != null) sb.Append (foundEnumValue).Append (',');
\r
391 else throw new InvalidOperationException ("Invalid enum value '" + name + "'");
\r
393 sb.Remove (sb.Length-1, 1);
\r
394 return sb.ToString ();
\r
397 foreach (EnumMapMember mem in _members)
\r
398 if (mem.XmlName == xmlName) return mem.EnumName;
\r
401 Int64.Parse (xmlName);
\r
405 throw new InvalidOperationException ("Invalid enumeration value: " + xmlName);
\r