5 // John Donagher (john@webmeta.com)
6 // Lluis Sanchez Gual (lluis@ximian.com)
8 // (C) 2002 John Donagher
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:
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
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.
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
;
44 XmlTypeMapping baseMap
;
45 bool multiReferenceType
= false;
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
)
57 this.xmlType
= xmlType
;
58 this.xmlTypeNamespace
= xmlTypeNamespace
;
62 public string ElementName
64 get { return _elementName; }
67 public string Namespace
69 get { return _namespace; }
73 public string TypeFullName
75 get { return type.FullTypeName; }
78 public string TypeName
80 get { return type.TypeName; }
83 internal TypeData TypeData
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
;
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
;
163 internal void UpdateRoot (XmlQualifiedName qname
)
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
);
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
;
230 else if (member
is XmlTypeMapMemberNamespaces
)
232 _namespaceDeclarations
= (XmlTypeMapMemberNamespaces
) member
;
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
];
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
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
);
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;
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];
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
;
474 public XmlTypeMapElementInfo
FindElement (string elementName
, string ns
)
476 foreach (XmlTypeMapElementInfo elem
in _itemInfo
)
477 if (elem
.ElementName
== elementName
&& elem
.Namespace
== ns
) return elem
;
481 public XmlTypeMapElementInfo
FindTextElement ()
483 foreach (XmlTypeMapElementInfo elem
in _itemInfo
)
484 if (elem
.IsTextElement
) return elem
;
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
)
498 if (itemCount
!= -1) arrayDim
= "[" + itemCount
+ "]";
499 else arrayDim
= "[]";
501 XmlTypeMapElementInfo info
= (XmlTypeMapElementInfo
) _itemInfo
[0];
502 if (info
.TypeData
.SchemaType
== SchemaTypes
.Array
)
505 ((ListMap
)info
.MappedType
.ObjectMap
).GetArrayType (-1, out nm
, out ns
);
506 localName
= nm
+ arrayDim
;
510 if (info
.MappedType
!= null)
512 localName
= info
.MappedType
.XmlType
+ arrayDim
;
513 ns
= info
.MappedType
.Namespace
;
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;
534 public override int GetHashCode ()
536 return base.GetHashCode ();
540 internal class EnumMap
: ObjectMap
542 EnumMapMember
[] _members
;
545 public class EnumMapMember
549 string _documentation
;
551 public EnumMapMember (string xmlName
, string enumName
)
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
)
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 (' ');
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)
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 (',');
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
;