**** Merged from MCS ****
[mono-project.git] / mcs / class / System.XML / System.Xml.Serialization / XmlTypeMapping.cs
blob0b64944f21dde7dc432566de173a202670cdf977
1 //
2 // XmlTypeMapping.cs:
3 //
4 // Author:
5 // John Donagher (john@webmeta.com)
6 // Lluis Sanchez Gual (lluis@ximian.com)
7 //
8 // (C) 2002 John Donagher
9 //
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
19 //
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
22 //
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32 using System.Xml;
33 using System;
34 using System.Collections;
35 using System.Globalization;
37 namespace System.Xml.Serialization
39 public class XmlTypeMapping : XmlMapping
41 private string xmlType;
42 private string xmlTypeNamespace;
43 TypeData type;
44 XmlTypeMapping baseMap;
45 bool multiReferenceType = false;
46 bool isSimpleType;
47 string documentation;
48 bool includeInSchema;
49 bool isNullable = true;
51 ArrayList _derivedTypes = new ArrayList();
53 internal XmlTypeMapping(string elementName, string ns, TypeData typeData, string xmlType, string xmlTypeNamespace)
54 : base (elementName, ns)
56 this.type = typeData;
57 this.xmlType = xmlType;
58 this.xmlTypeNamespace = xmlTypeNamespace;
61 #if !NET_2_0
62 public string ElementName
64 get { return _elementName; }
67 public string Namespace
69 get { return _namespace; }
71 #endif
73 public string TypeFullName
75 get { return type.FullTypeName; }
78 public string TypeName
80 get { return type.TypeName; }
83 internal TypeData TypeData
85 get { return type; }
88 internal string XmlType
90 get { return xmlType; }
93 internal string XmlTypeNamespace
95 get { return xmlTypeNamespace; }
98 internal ArrayList DerivedTypes
100 get { return _derivedTypes; }
101 set { _derivedTypes = value; }
104 internal bool MultiReferenceType
106 get { return multiReferenceType; }
107 set { multiReferenceType = value; }
110 internal XmlTypeMapping BaseMap
112 get { return baseMap; }
113 set { baseMap = value; }
116 internal bool IsSimpleType
118 get { return isSimpleType; }
119 set { isSimpleType = value; }
122 internal string Documentation
124 set { documentation = value; }
125 get { return documentation; }
128 internal bool IncludeInSchema
130 get { return includeInSchema; }
131 set { includeInSchema = value; }
134 internal bool IsNullable
136 get { return isNullable; }
137 set { isNullable = value; }
140 internal XmlTypeMapping GetRealTypeMap (string objectFullTypeName)
142 // Returns the map for a subtype of this map's type
144 objectFullTypeName = objectFullTypeName.Replace ('+','.');
145 if (TypeFullName == objectFullTypeName) return this;
146 for (int n=0; n<_derivedTypes.Count; n++) {
147 XmlTypeMapping map = (XmlTypeMapping) _derivedTypes[n];
148 if (map.TypeFullName == objectFullTypeName) return map;
151 return null;
154 internal XmlTypeMapping GetRealElementMap (string name, string ens)
156 if (xmlType == name && xmlTypeNamespace == ens) return this;
157 foreach (XmlTypeMapping map in _derivedTypes)
158 if (map.xmlType == name && map.xmlTypeNamespace == ens) return map;
160 return null;
163 internal void UpdateRoot (XmlQualifiedName qname)
165 if (qname != null) {
166 this._elementName = qname.Name;
167 this._namespace = qname.Namespace;
172 // Mapping info for classes and structs
174 internal class ClassMap: ObjectMap
176 Hashtable _elements = new Hashtable ();
177 ArrayList _elementMembers;
178 Hashtable _attributeMembers;
179 XmlTypeMapMemberAttribute[] _attributeMembersArray;
180 XmlTypeMapElementInfo[] _elementsByIndex;
181 ArrayList _flatLists;
182 ArrayList _allMembers = new ArrayList ();
183 ArrayList _membersWithDefault;
184 XmlTypeMapMemberAnyElement _defaultAnyElement;
185 XmlTypeMapMemberAnyAttribute _defaultAnyAttribute;
186 XmlTypeMapMemberNamespaces _namespaceDeclarations;
187 XmlTypeMapMember _xmlTextCollector;
188 XmlTypeMapMember _returnMember;
189 bool _ignoreMemberNamespace;
190 bool _canBeSimpleType = true;
192 public void AddMember (XmlTypeMapMember member)
194 _allMembers.Add (member);
196 if (!(member.DefaultValue is System.DBNull)) {
197 if (_membersWithDefault == null) _membersWithDefault = new ArrayList ();
198 _membersWithDefault.Add (member);
201 if (member.IsReturnValue)
202 _returnMember = member;
204 if (member is XmlTypeMapMemberAttribute)
206 XmlTypeMapMemberAttribute atm = (XmlTypeMapMemberAttribute)member;
207 if (_attributeMembers == null) _attributeMembers = new Hashtable();
208 string key = BuildKey (atm.AttributeName, atm.Namespace);
209 if (_attributeMembers.ContainsKey (key))
210 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.");
211 member.Index = _attributeMembers.Count;
212 _attributeMembers.Add (key, member);
213 return;
215 else if (member is XmlTypeMapMemberFlatList)
217 RegisterFlatList ((XmlTypeMapMemberFlatList)member);
219 else if (member is XmlTypeMapMemberAnyElement)
221 XmlTypeMapMemberAnyElement mem = (XmlTypeMapMemberAnyElement) member;
222 if (mem.IsDefaultAny) _defaultAnyElement = mem;
223 if (mem.TypeData.IsListType) RegisterFlatList (mem);
225 else if (member is XmlTypeMapMemberAnyAttribute)
227 _defaultAnyAttribute = (XmlTypeMapMemberAnyAttribute) member;
228 return;
230 else if (member is XmlTypeMapMemberNamespaces)
232 _namespaceDeclarations = (XmlTypeMapMemberNamespaces) member;
233 return;
236 if (member is XmlTypeMapMemberElement && ((XmlTypeMapMemberElement)member).IsXmlTextCollector)
238 if (_xmlTextCollector != null) throw new InvalidOperationException ("XmlTextAttribute can only be applied once in a class");
239 _xmlTextCollector = member;
242 if (_elementMembers == null) {
243 _elementMembers = new ArrayList();
244 _elements = new Hashtable();
247 member.Index = _elementMembers.Count;
248 _elementMembers.Add (member);
250 ICollection elemsInfo = ((XmlTypeMapMemberElement)member).ElementInfo;
251 foreach (XmlTypeMapElementInfo elem in elemsInfo)
253 string key = BuildKey (elem.ElementName, elem.Namespace);
254 if (_elements.ContainsKey (key))
255 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.");
256 _elements.Add (key, elem);
260 void RegisterFlatList (XmlTypeMapMemberExpandable member)
262 if (_flatLists == null) _flatLists = new ArrayList ();
263 member.FlatArrayIndex = _flatLists.Count;
264 _flatLists.Add (member);
267 public XmlTypeMapMemberAttribute GetAttribute (string name, string ns)
269 if (_attributeMembers == null) return null;
270 return (XmlTypeMapMemberAttribute)_attributeMembers [BuildKey(name,ns)];
273 public XmlTypeMapElementInfo GetElement (string name, string ns)
275 if (_elements == null) return null;
276 return (XmlTypeMapElementInfo)_elements [BuildKey(name,ns)];
279 public XmlTypeMapElementInfo GetElement (int index)
281 if (_elements == null) return null;
283 if (_elementsByIndex == null)
285 _elementsByIndex = new XmlTypeMapElementInfo [_elementMembers.Count];
286 foreach (XmlTypeMapMemberElement mem in _elementMembers)
288 if (mem.ElementInfo.Count != 1)
289 throw new InvalidOperationException ("Read by order only possible for encoded/bare format");
291 _elementsByIndex [mem.Index] = (XmlTypeMapElementInfo) mem.ElementInfo [0];
295 return _elementsByIndex [index];
298 private string BuildKey (string name, string ns)
300 if (_ignoreMemberNamespace) return name;
301 else return name + " / " + ns;
304 public ICollection AllElementInfos
306 get { return _elements.Values; }
310 public bool IgnoreMemberNamespace
312 get { return _ignoreMemberNamespace; }
313 set { _ignoreMemberNamespace = value; }
316 public XmlTypeMapMember FindMember (string name)
318 for (int n=0; n<_allMembers.Count; n++)
319 if (((XmlTypeMapMember)_allMembers[n]).Name == name) return (XmlTypeMapMember)_allMembers[n];
320 return null;
323 public XmlTypeMapMemberAnyElement DefaultAnyElementMember
325 get { return _defaultAnyElement; }
328 public XmlTypeMapMemberAnyAttribute DefaultAnyAttributeMember
330 get { return _defaultAnyAttribute; }
333 public XmlTypeMapMemberNamespaces NamespaceDeclarations
335 get { return _namespaceDeclarations; }
338 public ICollection AttributeMembers
340 get
342 if (_attributeMembers == null) return null;
343 if (_attributeMembersArray != null) return _attributeMembersArray;
345 _attributeMembersArray = new XmlTypeMapMemberAttribute[_attributeMembers.Count];
346 foreach (XmlTypeMapMemberAttribute mem in _attributeMembers.Values)
347 _attributeMembersArray [mem.Index] = mem;
348 return _attributeMembersArray;
352 public ICollection ElementMembers
354 get { return _elementMembers; }
357 public ArrayList AllMembers
359 get { return _allMembers; }
362 public ArrayList FlatLists
364 get { return _flatLists; }
367 public ArrayList MembersWithDefault
369 get { return _membersWithDefault; }
372 public XmlTypeMapMember XmlTextCollector
374 get { return _xmlTextCollector; }
377 public XmlTypeMapMember ReturnMember
379 get { return _returnMember; }
382 public XmlQualifiedName SimpleContentBaseType
386 if (!_canBeSimpleType || _elementMembers == null || _elementMembers.Count != 1) return null;
387 XmlTypeMapMemberElement member = (XmlTypeMapMemberElement) _elementMembers[0];
388 if (member.ElementInfo.Count != 1) return null;
389 XmlTypeMapElementInfo einfo = (XmlTypeMapElementInfo) member.ElementInfo[0];
390 if (!einfo.IsTextElement) return null;
391 if (member.TypeData.SchemaType == SchemaTypes.Primitive || member.TypeData.SchemaType == SchemaTypes.Enum)
392 return new XmlQualifiedName (einfo.TypeData.XmlType, einfo.DataTypeNamespace);
393 return null;
397 public void SetCanBeSimpleType (bool can)
399 _canBeSimpleType = can;
402 public bool HasSimpleContent
406 return SimpleContentBaseType != null;
412 // Mapping info for arrays and lists
414 internal class ListMap: ObjectMap
416 XmlTypeMapElementInfoList _itemInfo;
417 bool _gotNestedMapping;
418 XmlTypeMapping _nestedArrayMapping;
420 public bool IsMultiArray
424 return (NestedArrayMapping != null);
428 public XmlTypeMapping NestedArrayMapping
432 if (_gotNestedMapping) return _nestedArrayMapping;
433 _gotNestedMapping = true;
435 _nestedArrayMapping = ((XmlTypeMapElementInfo)_itemInfo[0]).MappedType;
437 if (_nestedArrayMapping == null) return null;
439 if (_nestedArrayMapping.TypeData.SchemaType != SchemaTypes.Array) {
440 _nestedArrayMapping = null; return null;
443 foreach (XmlTypeMapElementInfo elem in _itemInfo)
444 if (elem.MappedType != _nestedArrayMapping) {
445 _nestedArrayMapping = null;
446 return null;
449 return _nestedArrayMapping;
453 public XmlTypeMapElementInfoList ItemInfo
456 get { return _itemInfo; }
457 set { _itemInfo = value; }
460 public XmlTypeMapElementInfo FindElement (object memberValue)
462 if (_itemInfo.Count == 1)
463 return (XmlTypeMapElementInfo) _itemInfo[0];
464 else
466 if (memberValue == null) return null;
467 Type type = memberValue.GetType();
468 foreach (XmlTypeMapElementInfo elem in _itemInfo)
469 if (elem.TypeData.Type == type) return elem;
471 return null;
474 public XmlTypeMapElementInfo FindElement (string elementName, string ns)
476 foreach (XmlTypeMapElementInfo elem in _itemInfo)
477 if (elem.ElementName == elementName && elem.Namespace == ns) return elem;
478 return null;
481 public XmlTypeMapElementInfo FindTextElement ()
483 foreach (XmlTypeMapElementInfo elem in _itemInfo)
484 if (elem.IsTextElement) return elem;
485 return null;
488 public string GetSchemaArrayName ()
490 XmlTypeMapElementInfo einfo = (XmlTypeMapElementInfo) _itemInfo[0];
491 if (einfo.MappedType != null) return TypeTranslator.GetArrayName (einfo.MappedType.XmlType);
492 else return TypeTranslator.GetArrayName (einfo.TypeData.XmlType);
495 public void GetArrayType (int itemCount, out string localName, out string ns)
497 string arrayDim;
498 if (itemCount != -1) arrayDim = "[" + itemCount + "]";
499 else arrayDim = "[]";
501 XmlTypeMapElementInfo info = (XmlTypeMapElementInfo) _itemInfo[0];
502 if (info.TypeData.SchemaType == SchemaTypes.Array)
504 string nm;
505 ((ListMap)info.MappedType.ObjectMap).GetArrayType (-1, out nm, out ns);
506 localName = nm + arrayDim;
508 else
510 if (info.MappedType != null)
512 localName = info.MappedType.XmlType + arrayDim;
513 ns = info.MappedType.Namespace;
515 else
517 localName = info.TypeData.XmlType + arrayDim;
518 ns = info.DataTypeNamespace;
523 public override bool Equals (object other)
525 ListMap lmap = other as ListMap;
526 if (lmap == null) return false;
528 if (_itemInfo.Count != lmap._itemInfo.Count) return false;
529 for (int n=0; n<_itemInfo.Count; n++)
530 if (!_itemInfo[n].Equals (lmap._itemInfo[n])) return false;
531 return true;
534 public override int GetHashCode ()
536 return base.GetHashCode ();
540 internal class EnumMap: ObjectMap
542 EnumMapMember[] _members;
543 bool _isFlags;
545 public class EnumMapMember
547 string _xmlName;
548 string _enumName;
549 string _documentation;
551 public EnumMapMember (string xmlName, string enumName)
553 _xmlName = xmlName;
554 _enumName = enumName;
557 public string XmlName
559 get { return _xmlName; }
562 public string EnumName
564 get { return _enumName; }
567 public string Documentation
569 get { return _documentation; }
570 set { _documentation = value; }
574 public EnumMap (EnumMapMember[] members, bool isFlags)
576 _members = members;
577 _isFlags = isFlags;
580 public bool IsFlags
582 get { return _isFlags; }
585 public EnumMapMember[] Members
587 get { return _members; }
590 public string GetXmlName (object enumValue)
592 string enumName = enumValue.ToString();
594 if (_isFlags && enumName.IndexOf (',') != -1)
596 System.Text.StringBuilder sb = new System.Text.StringBuilder ();
597 string[] enumNames = enumValue.ToString().Split (',');
598 foreach (string name in enumNames)
600 string tname = name.Trim();
601 foreach (EnumMapMember mem in _members)
602 if (mem.EnumName == tname) {
603 sb.Append (mem.XmlName).Append (' ');
604 break;
607 sb.Remove (sb.Length-1, 1);
608 return sb.ToString ();
611 foreach (EnumMapMember mem in _members)
612 if (mem.EnumName == enumName) return mem.XmlName;
614 return Convert.ToInt64(enumValue).ToString(CultureInfo.InvariantCulture);
617 public string GetEnumName (string xmlName)
619 if (_isFlags && xmlName.Length == 0)
620 return "0";
622 if (_isFlags && xmlName.Trim().IndexOf (' ') != -1)
624 System.Text.StringBuilder sb = new System.Text.StringBuilder ();
625 string[] enumNames = xmlName.ToString().Split (' ');
626 foreach (string name in enumNames)
628 if (name == string.Empty) continue;
629 string foundEnumValue = null;
630 foreach (EnumMapMember mem in _members)
631 if (mem.XmlName == name) { foundEnumValue = mem.EnumName; break; }
633 if (foundEnumValue != null) sb.Append (foundEnumValue).Append (',');
634 else return null;
636 sb.Remove (sb.Length-1, 1);
637 return sb.ToString ();
640 foreach (EnumMapMember mem in _members)
641 if (mem.XmlName == xmlName) return mem.EnumName;
643 return null;