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
22 private string xmlTypeNamespace;
\r
24 XmlTypeMapping baseMap;
\r
25 bool multiReferenceType = false;
\r
27 string documentation;
\r
28 bool includeInSchema;
\r
30 ArrayList _derivedTypes = new ArrayList();
\r
32 internal XmlTypeMapping(string elementName, string ns, TypeData typeData, string xmlType, string xmlTypeNamespace)
\r
34 this.elementName = elementName;
\r
36 this.type = typeData;
\r
37 this.xmlType = xmlType;
\r
38 this.xmlTypeNamespace = xmlTypeNamespace;
\r
41 public string ElementName
\r
43 get { return elementName; }
\r
46 public string Namespace
\r
51 public string TypeFullName
\r
53 get { return type.FullTypeName; }
\r
56 public string TypeName
\r
58 get { return type.TypeName; }
\r
61 internal TypeData TypeData
\r
63 get { return type; }
\r
66 internal string XmlType
\r
68 get { return xmlType; }
\r
71 internal string XmlTypeNamespace
\r
73 get { return xmlTypeNamespace; }
\r
76 internal ArrayList DerivedTypes
\r
78 get { return _derivedTypes; }
\r
79 set { _derivedTypes = value; }
\r
82 internal bool MultiReferenceType
\r
84 get { return multiReferenceType; }
\r
85 set { multiReferenceType = value; }
\r
88 internal XmlTypeMapping BaseMap
\r
90 get { return baseMap; }
\r
91 set { baseMap = value; }
\r
94 internal bool IsSimpleType
\r
96 get { return isSimpleType; }
\r
97 set { isSimpleType = value; }
\r
100 internal string Documentation
\r
102 set { documentation = value; }
\r
103 get { return documentation; }
\r
106 internal bool IncludeInSchema
\r
108 get { return includeInSchema; }
\r
109 set { includeInSchema = value; }
\r
112 internal XmlTypeMapping GetRealTypeMap (string objectFullTypeName)
\r
114 // Returns the map for a subtype of this map's type
\r
116 if (TypeFullName == objectFullTypeName) return this;
\r
117 foreach (XmlTypeMapping map in _derivedTypes)
\r
118 if (map.TypeFullName == objectFullTypeName) return map;
\r
123 internal XmlTypeMapping GetRealElementMap (string name, string ens)
\r
125 if (xmlType == name && xmlTypeNamespace == ens) return this;
\r
126 foreach (XmlTypeMapping map in _derivedTypes)
\r
127 if (map.xmlType == name && map.xmlTypeNamespace == ens) return map;
\r
133 // Mapping info for classes and structs
\r
135 internal class ClassMap: ObjectMap
\r
137 Hashtable _elements = new Hashtable ();
\r
138 ArrayList _elementMembers;
\r
139 Hashtable _attributeMembers;
\r
140 XmlTypeMapElementInfo[] _elementsByIndex;
\r
141 ArrayList _flatLists;
\r
142 ArrayList _allMembers = new ArrayList ();
\r
143 XmlTypeMapMemberAnyElement _defaultAnyElement;
\r
144 XmlTypeMapMemberAnyAttribute _defaultAnyAttribute;
\r
145 XmlTypeMapMemberNamespaces _namespaceDeclarations;
\r
146 XmlTypeMapMember _xmlTextCollector;
\r
147 bool _ignoreMemberNamespace;
\r
148 bool _canBeSimpleType = true;
\r
150 public void AddMember (XmlTypeMapMember member)
\r
152 _allMembers.Add (member);
\r
153 if (member is XmlTypeMapMemberAttribute)
\r
155 XmlTypeMapMemberAttribute atm = (XmlTypeMapMemberAttribute)member;
\r
156 if (_attributeMembers == null) _attributeMembers = new Hashtable();
\r
157 string key = BuildKey (atm.AttributeName, atm.Namespace);
\r
158 if (_attributeMembers.ContainsKey (key))
\r
159 throw new InvalidOperationException ("The XML attribute named '" + atm.AttributeName + "' from namespace '" + atm.Namespace + "' already present in the current scope. Use XML attributes to specify another XML name or namespace for the attribute.");
\r
160 _attributeMembers.Add (key, member);
\r
163 else if (member is XmlTypeMapMemberFlatList)
\r
165 RegisterFlatList ((XmlTypeMapMemberFlatList)member);
\r
167 else if (member is XmlTypeMapMemberAnyElement)
\r
169 XmlTypeMapMemberAnyElement mem = (XmlTypeMapMemberAnyElement) member;
\r
170 if (mem.IsDefaultAny) _defaultAnyElement = mem;
\r
171 if (mem.TypeData.IsListType) RegisterFlatList (mem);
\r
173 else if (member is XmlTypeMapMemberAnyAttribute)
\r
175 _defaultAnyAttribute = (XmlTypeMapMemberAnyAttribute) member;
\r
178 else if (member is XmlTypeMapMemberNamespaces)
\r
180 _namespaceDeclarations = (XmlTypeMapMemberNamespaces) member;
\r
184 if (member is XmlTypeMapMemberElement && ((XmlTypeMapMemberElement)member).IsXmlTextCollector)
\r
186 if (_xmlTextCollector != null) throw new InvalidOperationException ("XmlTextAttribute can only be applied once in a class");
\r
187 _xmlTextCollector = member;
\r
190 if (_elementMembers == null) {
\r
191 _elementMembers = new ArrayList();
\r
192 _elements = new Hashtable();
\r
195 member.Index = _elementMembers.Count;
\r
196 _elementMembers.Add (member);
\r
198 ICollection elemsInfo = ((XmlTypeMapMemberElement)member).ElementInfo;
\r
199 foreach (XmlTypeMapElementInfo elem in elemsInfo)
\r
201 string key = BuildKey (elem.ElementName, elem.Namespace);
\r
202 if (_elements.ContainsKey (key))
\r
203 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
204 _elements.Add (key, elem);
\r
208 void RegisterFlatList (XmlTypeMapMemberExpandable member)
\r
210 if (_flatLists == null) _flatLists = new ArrayList ();
\r
211 member.FlatArrayIndex = _flatLists.Count;
\r
212 _flatLists.Add (member);
\r
215 public XmlTypeMapMemberAttribute GetAttribute (string name, string ns)
\r
217 if (_attributeMembers == null) return null;
\r
218 return (XmlTypeMapMemberAttribute)_attributeMembers [BuildKey(name,ns)];
\r
221 public XmlTypeMapElementInfo GetElement (string name, string ns)
\r
223 if (_elements == null) return null;
\r
224 return (XmlTypeMapElementInfo)_elements [BuildKey(name,ns)];
\r
227 public XmlTypeMapElementInfo GetElement (int index)
\r
229 if (_elements == null) return null;
\r
231 if (_elementsByIndex == null)
\r
233 _elementsByIndex = new XmlTypeMapElementInfo [_elementMembers.Count];
\r
234 foreach (XmlTypeMapMemberElement mem in _elementMembers)
\r
236 if (mem.ElementInfo.Count != 1)
\r
237 throw new InvalidOperationException ("Read by order only possible for encoded/bare format");
\r
239 _elementsByIndex [mem.Index] = (XmlTypeMapElementInfo) mem.ElementInfo [0];
\r
243 return _elementsByIndex [index];
\r
246 private string BuildKey (string name, string ns)
\r
248 if (_ignoreMemberNamespace) return name;
\r
249 else return name + " / " + ns;
\r
252 public ICollection AllElementInfos
\r
254 get { return _elements.Values; }
\r
258 public bool IgnoreMemberNamespace
\r
260 get { return _ignoreMemberNamespace; }
\r
261 set { _ignoreMemberNamespace = value; }
\r
264 public XmlTypeMapMember FindMember (string name)
\r
266 for (int n=0; n<_allMembers.Count; n++)
\r
267 if (((XmlTypeMapMember)_allMembers[n]).Name == name) return (XmlTypeMapMember)_allMembers[n];
\r
271 public XmlTypeMapMemberAnyElement DefaultAnyElementMember
\r
273 get { return _defaultAnyElement; }
\r
276 public XmlTypeMapMemberAnyAttribute DefaultAnyAttributeMember
\r
278 get { return _defaultAnyAttribute; }
\r
281 public XmlTypeMapMemberNamespaces NamespaceDeclarations
\r
283 get { return _namespaceDeclarations; }
\r
286 public ICollection AttributeMembers
\r
288 get { return (_attributeMembers != null) ? _attributeMembers.Values : null; }
\r
291 public ICollection ElementMembers
\r
293 get { return _elementMembers; }
\r
296 public ArrayList AllMembers
\r
298 get { return _allMembers; }
\r
301 public ArrayList FlatLists
\r
303 get { return _flatLists; }
\r
306 public XmlTypeMapMember XmlTextCollector
\r
308 get { return _xmlTextCollector; }
\r
311 public XmlQualifiedName SimpleContentBaseType
\r
315 if (!_canBeSimpleType || _elementMembers == null || _elementMembers.Count != 1) return null;
\r
316 XmlTypeMapMemberElement member = (XmlTypeMapMemberElement) _elementMembers[0];
\r
317 if (member.ElementInfo.Count != 1) return null;
\r
318 XmlTypeMapElementInfo einfo = (XmlTypeMapElementInfo) member.ElementInfo[0];
\r
319 if (!einfo.IsTextElement) return null;
\r
320 if (member.TypeData.SchemaType == SchemaTypes.Primitive || member.TypeData.SchemaType == SchemaTypes.Enum)
\r
321 return new XmlQualifiedName (einfo.TypeData.XmlType, einfo.DataTypeNamespace);
\r
326 public void SetCanBeSimpleType (bool can)
\r
328 _canBeSimpleType = can;
\r
331 public bool HasSimpleContent
\r
335 return SimpleContentBaseType != null;
\r
341 // Mapping info for arrays and lists
\r
343 internal class ListMap: ObjectMap
\r
345 XmlTypeMapElementInfoList _itemInfo;
\r
346 bool _gotNestedMapping;
\r
347 XmlTypeMapping _nestedArrayMapping;
\r
349 public bool IsMultiArray
\r
353 return (NestedArrayMapping != null);
\r
357 public XmlTypeMapping NestedArrayMapping
\r
361 if (_gotNestedMapping) return _nestedArrayMapping;
\r
362 _gotNestedMapping = true;
\r
364 _nestedArrayMapping = ((XmlTypeMapElementInfo)_itemInfo[0]).MappedType;
\r
366 if (_nestedArrayMapping == null) return null;
\r
368 if (_nestedArrayMapping.TypeData.SchemaType != SchemaTypes.Array) {
\r
369 _nestedArrayMapping = null; return null;
\r
372 foreach (XmlTypeMapElementInfo elem in _itemInfo)
\r
373 if (elem.MappedType != _nestedArrayMapping) {
\r
374 _nestedArrayMapping = null;
\r
378 return _nestedArrayMapping;
\r
382 public XmlTypeMapElementInfoList ItemInfo
\r
385 get { return _itemInfo; }
\r
386 set { _itemInfo = value; }
\r
389 public XmlTypeMapElementInfo FindElement (object memberValue)
\r
391 if (_itemInfo.Count == 1)
\r
392 return (XmlTypeMapElementInfo) _itemInfo[0];
\r
395 if (memberValue == null) return null;
\r
396 Type type = memberValue.GetType();
\r
397 foreach (XmlTypeMapElementInfo elem in _itemInfo)
\r
398 if (elem.TypeData.Type == type) return elem;
\r
403 public XmlTypeMapElementInfo FindElement (string elementName, string ns)
\r
405 foreach (XmlTypeMapElementInfo elem in _itemInfo)
\r
406 if (elem.ElementName == elementName && elem.Namespace == ns) return elem;
\r
410 public XmlTypeMapElementInfo FindTextElement ()
\r
412 foreach (XmlTypeMapElementInfo elem in _itemInfo)
\r
413 if (elem.IsTextElement) return elem;
\r
417 public string GetSchemaArrayName ()
\r
419 XmlTypeMapElementInfo einfo = (XmlTypeMapElementInfo) _itemInfo[0];
\r
420 if (einfo.MappedType != null) return TypeTranslator.GetArrayName (einfo.MappedType.XmlType);
\r
421 else return TypeTranslator.GetArrayName (einfo.TypeData.XmlType);
\r
424 public void GetArrayType (int itemCount, out string localName, out string ns)
\r
427 if (itemCount != -1) arrayDim = "[" + itemCount + "]";
\r
428 else arrayDim = "[]";
\r
430 XmlTypeMapElementInfo info = (XmlTypeMapElementInfo) _itemInfo[0];
\r
431 if (info.TypeData.SchemaType == SchemaTypes.Array)
\r
434 ((ListMap)info.MappedType.ObjectMap).GetArrayType (-1, out nm, out ns);
\r
435 localName = nm + arrayDim;
\r
439 if (info.MappedType != null)
\r
441 localName = info.MappedType.XmlType + arrayDim;
\r
442 ns = info.MappedType.Namespace;
\r
446 localName = info.TypeData.XmlType + arrayDim;
\r
447 ns = info.DataTypeNamespace;
\r
452 public override bool Equals (object other)
\r
454 ListMap lmap = other as ListMap;
\r
455 if (lmap == null) return false;
\r
457 if (_itemInfo.Count != lmap._itemInfo.Count) return false;
\r
458 for (int n=0; n<_itemInfo.Count; n++)
\r
459 if (!_itemInfo[n].Equals (lmap._itemInfo[n])) return false;
\r
463 public override int GetHashCode ()
\r
465 return base.GetHashCode ();
\r
469 internal class EnumMap: ObjectMap
\r
471 EnumMapMember[] _members;
\r
474 public class EnumMapMember
\r
478 string _documentation;
\r
480 public EnumMapMember (string xmlName, string enumName)
\r
482 _xmlName = xmlName;
\r
483 _enumName = enumName;
\r
486 public string XmlName
\r
488 get { return _xmlName; }
\r
491 public string EnumName
\r
493 get { return _enumName; }
\r
496 public string Documentation
\r
498 get { return _documentation; }
\r
499 set { _documentation = value; }
\r
503 public EnumMap (EnumMapMember[] members, bool isFlags)
\r
505 _members = members;
\r
506 _isFlags = isFlags;
\r
509 public bool IsFlags
\r
511 get { return _isFlags; }
\r
514 public EnumMapMember[] Members
\r
516 get { return _members; }
\r
519 public string GetXmlName (object enumValue)
\r
521 string enumName = enumValue.ToString();
\r
523 if (_isFlags && enumName.IndexOf (',') != -1)
\r
525 System.Text.StringBuilder sb = new System.Text.StringBuilder ();
\r
526 string[] enumNames = enumValue.ToString().Split (',');
\r
527 foreach (string name in enumNames)
\r
529 string tname = name.Trim();
\r
530 foreach (EnumMapMember mem in _members)
\r
531 if (mem.EnumName == tname) {
\r
532 sb.Append (mem.XmlName).Append (' ');
\r
536 sb.Remove (sb.Length-1, 1);
\r
537 return sb.ToString ();
\r
540 foreach (EnumMapMember mem in _members)
\r
541 if (mem.EnumName == enumName) return mem.XmlName;
\r
543 return Convert.ToInt64(enumValue).ToString();
\r
546 public string GetEnumName (string xmlName)
\r
548 if (_isFlags && xmlName.Trim().IndexOf (' ') != -1)
\r
550 System.Text.StringBuilder sb = new System.Text.StringBuilder ();
\r
551 string[] enumNames = xmlName.ToString().Split (' ');
\r
552 foreach (string name in enumNames)
\r
554 if (name == string.Empty) continue;
\r
555 string foundEnumValue = null;
\r
556 foreach (EnumMapMember mem in _members)
\r
557 if (mem.XmlName == name) { foundEnumValue = mem.EnumName; break; }
\r
559 if (foundEnumValue != null) sb.Append (foundEnumValue).Append (',');
\r
560 else throw new InvalidOperationException ("Invalid enum value '" + name + "'");
\r
562 sb.Remove (sb.Length-1, 1);
\r
563 return sb.ToString ();
\r
566 foreach (EnumMapMember mem in _members)
\r
567 if (mem.XmlName == xmlName) return mem.EnumName;
\r