eol-style:native
[mono.git] / mcs / class / System.XML / System.Xml.Serialization / XmlTypeMapping.cs
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 //
10
11 //
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.
30 //
31
32 using System.Xml;
33 using System;
34 using System.Collections;
35 using System.Globalization;
36 using System.Xml.Schema;
37
38 namespace System.Xml.Serialization
39 {
40         public class XmlTypeMapping : XmlMapping
41         {
42                 private string xmlType;
43                 private string xmlTypeNamespace;
44                 TypeData type;
45                 XmlTypeMapping baseMap;
46                 bool multiReferenceType = false;
47                 bool isSimpleType;
48                 string documentation;
49                 bool includeInSchema;
50                 bool isNullable = true;
51
52                 ArrayList _derivedTypes = new ArrayList();
53
54                 internal XmlTypeMapping(string elementName, string ns, TypeData typeData, string xmlType, string xmlTypeNamespace)
55                 : base (elementName, ns)
56                 {
57                         this.type = typeData;
58                         this.xmlType = xmlType;
59                         this.xmlTypeNamespace = xmlTypeNamespace;
60                 }
61
62 #if !NET_2_0
63                 public string ElementName
64                 {
65                         get { return _elementName; }
66                 }
67
68                 public string Namespace
69                 {
70                         get { return _namespace; }
71                 }
72 #endif
73
74                 public string TypeFullName
75                 {
76                         get { return type.FullTypeName; }
77                 }
78
79                 public string TypeName
80                 {
81                         get { return type.TypeName; }
82                 }
83
84                 internal TypeData TypeData
85                 {
86                         get { return type; }
87                 }
88
89                 internal string XmlType
90                 {
91                         get { return xmlType; }
92                 }
93
94                 internal string XmlTypeNamespace
95                 {
96                         get { return xmlTypeNamespace; }
97                 }
98
99                 internal ArrayList DerivedTypes
100                 {
101                         get { return _derivedTypes; }
102                         set { _derivedTypes = value; }
103                 }
104
105                 internal bool MultiReferenceType
106                 {
107                         get { return multiReferenceType; }
108                         set { multiReferenceType = value; }
109                 }
110
111                 internal XmlTypeMapping BaseMap
112                 {
113                         get { return baseMap; }
114                         set { baseMap = value; }
115                 }
116
117                 internal bool IsSimpleType
118                 {
119                         get { return isSimpleType; }
120                         set { isSimpleType = value; }
121                 }
122
123                 internal string Documentation
124                 {
125                         set { documentation = value; }
126                         get { return documentation; }
127                 }
128
129                 internal bool IncludeInSchema
130                 {
131                         get { return includeInSchema; }
132                         set { includeInSchema = value; }
133                 }
134                 
135                 internal bool IsNullable
136                 {
137                         get { return isNullable; }
138                         set { isNullable = value; }
139                 }
140
141                 internal XmlTypeMapping GetRealTypeMap (string objectFullTypeName)
142                 {
143                         if (TypeData.SchemaType == SchemaTypes.Enum)
144                                 return this;
145
146                         // Returns the map for a subtype of this map's type
147                         objectFullTypeName = objectFullTypeName.Replace ('+','.');
148                         if (TypeFullName == objectFullTypeName) return this;
149                         for (int n=0; n<_derivedTypes.Count; n++) {
150                                 XmlTypeMapping map = (XmlTypeMapping) _derivedTypes[n];
151                                 if (map.TypeFullName == objectFullTypeName) return map;
152                         }
153                         
154                         return null;
155                 }
156
157                 internal XmlTypeMapping GetRealElementMap (string name, string ens)
158                 {
159                         if (xmlType == name && xmlTypeNamespace == ens) return this;
160                         foreach (XmlTypeMapping map in _derivedTypes)
161                                 if (map.xmlType == name && map.xmlTypeNamespace == ens) return map;
162                         
163                         return null;
164                 }
165                 
166                 internal void UpdateRoot (XmlQualifiedName qname)
167                 {
168                         if (qname != null) {
169                                 this._elementName = qname.Name;
170                                 this._namespace = qname.Namespace;
171                         }
172                 }
173         }
174
175  
176         // Mapping info for XmlSerializable
177         internal class XmlSerializableMapping : XmlTypeMapping
178         {
179                 XmlSchema _schema;
180
181                 internal XmlSerializableMapping(string elementName, string ns, TypeData typeData, string xmlType, string xmlTypeNamespace)
182                         : base(elementName, ns, typeData, xmlType, xmlTypeNamespace)
183                 {
184                         IXmlSerializable serializable = (IXmlSerializable)Activator.CreateInstance(typeData.Type);
185                         _schema = serializable.GetSchema();
186                         if (_schema != null) 
187                         {
188                                 if (_schema.Id == null || _schema.Id.Length == 0) 
189                                         throw new InvalidOperationException("Schema Id is missing. The schema returned from " + typeData.Type.FullName + ".GetSchema() must have an Id.");
190                         }
191                 }
192
193                 internal XmlSchema Schema
194                 {
195                         get { return _schema; }
196                 }
197         }
198  
199
200         // Mapping info for classes and structs
201
202         internal class ClassMap: ObjectMap
203         {
204                 Hashtable _elements = new Hashtable ();
205                 ArrayList _elementMembers;
206                 Hashtable _attributeMembers;
207                 XmlTypeMapMemberAttribute[] _attributeMembersArray;
208                 XmlTypeMapElementInfo[] _elementsByIndex;
209                 ArrayList _flatLists;
210                 ArrayList _allMembers = new ArrayList ();
211                 ArrayList _membersWithDefault;
212                 ArrayList _listMembers;
213                 XmlTypeMapMemberAnyElement _defaultAnyElement;
214                 XmlTypeMapMemberAnyAttribute _defaultAnyAttribute;
215                 XmlTypeMapMemberNamespaces _namespaceDeclarations;
216                 XmlTypeMapMember _xmlTextCollector;
217                 XmlTypeMapMember _returnMember;
218                 bool _ignoreMemberNamespace;
219                 bool _canBeSimpleType = true;
220
221                 public void AddMember (XmlTypeMapMember member)
222                 {
223                         member.GlobalIndex = _allMembers.Count;
224                         _allMembers.Add (member);
225                         
226                         if (!(member.DefaultValue is System.DBNull) && member.DefaultValue != null) {
227                                 if (_membersWithDefault == null) _membersWithDefault = new ArrayList ();
228                                 _membersWithDefault.Add (member);
229                         }
230                         
231                         if (member.IsReturnValue)
232                                 _returnMember = member;
233                         
234                         if (member is XmlTypeMapMemberAttribute)
235                         {
236                                 XmlTypeMapMemberAttribute atm = (XmlTypeMapMemberAttribute)member;
237                                 if (_attributeMembers == null) _attributeMembers = new Hashtable();
238                                 string key = BuildKey (atm.AttributeName, atm.Namespace);
239                                 if (_attributeMembers.ContainsKey (key))
240                                         throw new InvalidOperationException ("The XML attribute named '" + atm.AttributeName + "' from namespace '" + atm.Namespace + "' is already present in the current scope. Use XML attributes to specify another XML name or namespace for the attribute.");
241                                 member.Index = _attributeMembers.Count;
242                                 _attributeMembers.Add (key, member);
243                                 return;
244                         }
245                         else if (member is XmlTypeMapMemberFlatList)
246                         {
247                                 RegisterFlatList ((XmlTypeMapMemberFlatList)member);
248                         }
249                         else if (member is XmlTypeMapMemberAnyElement)
250                         {
251                                 XmlTypeMapMemberAnyElement mem = (XmlTypeMapMemberAnyElement) member;
252                                 if (mem.IsDefaultAny) _defaultAnyElement = mem;
253                                 if (mem.TypeData.IsListType) RegisterFlatList (mem);
254                         }
255                         else if (member is XmlTypeMapMemberAnyAttribute)
256                         {
257                                 _defaultAnyAttribute = (XmlTypeMapMemberAnyAttribute) member;
258                                 return;
259                         }
260                         else if (member is XmlTypeMapMemberNamespaces)
261                         {
262                                 _namespaceDeclarations = (XmlTypeMapMemberNamespaces) member;
263                                 return;
264                         }
265
266                         if (member is XmlTypeMapMemberElement && ((XmlTypeMapMemberElement)member).IsXmlTextCollector)
267                         {
268                                 if (_xmlTextCollector != null) throw new InvalidOperationException ("XmlTextAttribute can only be applied once in a class");
269                                 _xmlTextCollector = member;
270                         }
271
272                         if (_elementMembers == null) {
273                                 _elementMembers = new ArrayList();
274                                 _elements = new Hashtable();
275                         }
276
277                         member.Index = _elementMembers.Count;
278                         _elementMembers.Add (member);
279
280                         ICollection elemsInfo = ((XmlTypeMapMemberElement)member).ElementInfo;
281                         foreach (XmlTypeMapElementInfo elem in elemsInfo)
282                         {
283                                 string key = BuildKey (elem.ElementName, elem.Namespace);
284                                 if (_elements.ContainsKey (key)) 
285                                         throw new InvalidOperationException ("The XML element named '" + elem.ElementName + "' from namespace '" + elem.Namespace + "' is already present in the current scope. Use XML attributes to specify another XML name or namespace for the element.");
286                                 _elements.Add (key, elem);
287                         }
288                         
289                         if (member.TypeData.IsListType && member.TypeData.Type != null && !member.TypeData.Type.IsArray) {
290                                 if (_listMembers == null) _listMembers = new ArrayList ();
291                                 _listMembers.Add (member);
292                         }
293                 }
294
295                 void RegisterFlatList (XmlTypeMapMemberExpandable member)
296                 {
297                         if (_flatLists == null) _flatLists = new ArrayList ();
298                         member.FlatArrayIndex = _flatLists.Count;
299                         _flatLists.Add (member);
300                 }
301
302                 public XmlTypeMapMemberAttribute GetAttribute (string name, string ns)
303                 {
304                         if (_attributeMembers == null) return null;
305                         return (XmlTypeMapMemberAttribute)_attributeMembers [BuildKey(name,ns)];
306                 }
307
308                 public XmlTypeMapElementInfo GetElement (string name, string ns)
309                 {
310                         if (_elements == null) return null;
311                         return (XmlTypeMapElementInfo)_elements [BuildKey(name,ns)];
312                 }
313                 
314                 public XmlTypeMapElementInfo GetElement (int index)
315                 {
316                         if (_elements == null) return null;
317                         
318                         if (_elementsByIndex == null)
319                         {
320                                 _elementsByIndex = new XmlTypeMapElementInfo [_elementMembers.Count];
321                                 foreach (XmlTypeMapMemberElement mem in _elementMembers)
322                                 {
323                                         if (mem.ElementInfo.Count != 1) 
324                                                 throw new InvalidOperationException ("Read by order only possible for encoded/bare format");
325                                                 
326                                         _elementsByIndex [mem.Index] = (XmlTypeMapElementInfo) mem.ElementInfo [0];
327                                 }
328                         }
329                         
330                         return _elementsByIndex [index];
331                 }
332                 
333                 private string BuildKey (string name, string ns)
334                 {
335                         if (_ignoreMemberNamespace) return name;
336                         else return name + " / " + ns;
337                 }
338                 
339                 public ICollection AllElementInfos
340                 {
341                         get { return _elements.Values; }
342                 }
343                 
344                 
345                 public bool IgnoreMemberNamespace
346                 {
347                         get { return _ignoreMemberNamespace; }
348                         set { _ignoreMemberNamespace = value; }
349                 }
350
351                 public XmlTypeMapMember FindMember (string name)
352                 {
353                         for (int n=0; n<_allMembers.Count; n++)
354                                 if (((XmlTypeMapMember)_allMembers[n]).Name == name) return (XmlTypeMapMember)_allMembers[n];
355                         return null;
356                 }
357
358                 public XmlTypeMapMemberAnyElement DefaultAnyElementMember
359                 {
360                         get { return _defaultAnyElement; }
361                 }
362
363                 public XmlTypeMapMemberAnyAttribute DefaultAnyAttributeMember
364                 {
365                         get { return _defaultAnyAttribute; }
366                 }
367
368                 public XmlTypeMapMemberNamespaces NamespaceDeclarations
369                 {
370                         get { return _namespaceDeclarations; }
371                 }
372
373                 public ICollection AttributeMembers
374                 {
375                         get 
376                         {
377                                 if (_attributeMembers == null) return null;
378                                 if (_attributeMembersArray != null) return _attributeMembersArray;
379                                 
380                                 _attributeMembersArray = new XmlTypeMapMemberAttribute[_attributeMembers.Count];
381                                 foreach (XmlTypeMapMemberAttribute mem in _attributeMembers.Values)
382                                         _attributeMembersArray [mem.Index] = mem;
383                                 return _attributeMembersArray;
384                         }
385                 }
386
387                 public ICollection ElementMembers
388                 {
389                         get { return _elementMembers; }
390                 }
391
392                 public ArrayList AllMembers
393                 {
394                         get { return _allMembers; }
395                 }
396
397                 public ArrayList FlatLists
398                 {
399                         get { return _flatLists; }
400                 }
401                 
402                 public ArrayList MembersWithDefault
403                 {
404                         get { return _membersWithDefault; }
405                 }
406                 
407                 public ArrayList ListMembers
408                 {
409                         get { return _listMembers; }
410                 }
411
412                 public XmlTypeMapMember XmlTextCollector
413                 {
414                         get { return _xmlTextCollector; }
415                 }
416                 
417                 public XmlTypeMapMember ReturnMember
418                 {
419                         get { return _returnMember; }
420                 }
421
422                 public XmlQualifiedName SimpleContentBaseType
423                 {
424                         get
425                         {
426                                 if (!_canBeSimpleType || _elementMembers == null || _elementMembers.Count != 1) return null;
427                                 XmlTypeMapMemberElement member = (XmlTypeMapMemberElement) _elementMembers[0];
428                                 if (member.ElementInfo.Count != 1) return null;
429                                 XmlTypeMapElementInfo einfo = (XmlTypeMapElementInfo) member.ElementInfo[0];
430                                 if (!einfo.IsTextElement) return null;
431                                 if (member.TypeData.SchemaType == SchemaTypes.Primitive || member.TypeData.SchemaType == SchemaTypes.Enum)
432                                         return new XmlQualifiedName (einfo.TypeData.XmlType, einfo.DataTypeNamespace);
433                                 return null;
434                         }
435                 }
436                 
437                 public void SetCanBeSimpleType (bool can)
438                 {
439                         _canBeSimpleType = can;
440                 }
441
442                 public bool HasSimpleContent
443                 {
444                         get
445                         {
446                                 return SimpleContentBaseType != null;
447                         }
448                 }
449
450         }
451
452         // Mapping info for arrays and lists
453
454         internal class ListMap: ObjectMap
455         {
456                 XmlTypeMapElementInfoList _itemInfo;
457                 bool _gotNestedMapping;
458                 XmlTypeMapping _nestedArrayMapping;
459                 string _choiceMember;
460
461                 public bool IsMultiArray
462                 {
463                         get
464                         {
465                                 return (NestedArrayMapping != null);
466                         }
467                 }
468
469                 public string ChoiceMember
470                 {
471                         get { return _choiceMember; }
472                         set { _choiceMember = value; }
473                 }
474
475                 public XmlTypeMapping NestedArrayMapping
476                 {
477                         get
478                         {
479                                 if (_gotNestedMapping) return _nestedArrayMapping;
480                                 _gotNestedMapping = true;
481
482                                 _nestedArrayMapping = ((XmlTypeMapElementInfo)_itemInfo[0]).MappedType;
483
484                                 if (_nestedArrayMapping == null) return null;
485                                 
486                                 if (_nestedArrayMapping.TypeData.SchemaType != SchemaTypes.Array) {
487                                         _nestedArrayMapping = null; return null;
488                                 }
489
490                                 foreach (XmlTypeMapElementInfo elem in _itemInfo)
491                                         if (elem.MappedType != _nestedArrayMapping) {
492                                                 _nestedArrayMapping = null;
493                                                 return null;
494                                         }
495
496                                 return _nestedArrayMapping;
497                         }
498                 }
499
500                 public XmlTypeMapElementInfoList ItemInfo
501                 {
502
503                         get { return _itemInfo; }
504                         set { _itemInfo = value; }
505                 }
506
507                 public XmlTypeMapElementInfo FindElement (object ob, int index, object memberValue)
508                 {
509                         if (_itemInfo.Count == 1) 
510                                 return (XmlTypeMapElementInfo) _itemInfo[0];
511                         else if (_choiceMember != null && index != -1)
512                         {
513                                 Array values = (Array) XmlTypeMapMember.GetValue (ob, _choiceMember);
514                                 if (values == null || index >= values.Length)
515                                         throw new InvalidOperationException ("Invalid or missing choice enum value in member '" + _choiceMember + "'.");
516                                 object val = values.GetValue (index);
517                                 foreach (XmlTypeMapElementInfo elem in _itemInfo)
518                                         if (elem.ChoiceValue != null && elem.ChoiceValue.Equals (val))
519                                                 return elem;
520                         }
521                         else
522                         {
523                                 if (memberValue == null) return null;
524                                 Type type = memberValue.GetType();
525                                 foreach (XmlTypeMapElementInfo elem in _itemInfo)
526                                         if (elem.TypeData.Type == type) return elem;
527                         }
528                         return null;
529                 }       
530
531                 public XmlTypeMapElementInfo FindElement (string elementName, string ns)
532                 {
533                         foreach (XmlTypeMapElementInfo elem in _itemInfo)
534                                 if (elem.ElementName == elementName && elem.Namespace == ns) return elem;
535                         return null;
536                 }
537                 
538                 public XmlTypeMapElementInfo FindTextElement ()
539                 {
540                         foreach (XmlTypeMapElementInfo elem in _itemInfo)
541                                 if (elem.IsTextElement) return elem;
542                         return null;
543                 }
544                 
545                 public string GetSchemaArrayName ()
546                 {
547                         XmlTypeMapElementInfo einfo = (XmlTypeMapElementInfo) _itemInfo[0];
548                         if (einfo.MappedType != null) return TypeTranslator.GetArrayName (einfo.MappedType.XmlType);
549                         else return TypeTranslator.GetArrayName (einfo.TypeData.XmlType);
550                 }
551
552                 public void GetArrayType (int itemCount, out string localName, out string ns)
553                 {
554                         string arrayDim;
555                         if (itemCount != -1) arrayDim = "[" + itemCount + "]";
556                         else arrayDim = "[]";
557
558                         XmlTypeMapElementInfo info = (XmlTypeMapElementInfo) _itemInfo[0];
559                         if (info.TypeData.SchemaType == SchemaTypes.Array)
560                         {
561                                 string nm;
562                                 ((ListMap)info.MappedType.ObjectMap).GetArrayType (-1, out nm, out ns);
563                                 localName = nm + arrayDim;
564                         }
565                         else 
566                         {
567                                 if (info.MappedType != null)
568                                 {
569                                         localName = info.MappedType.XmlType + arrayDim;
570                                         ns = info.MappedType.Namespace;
571                                 }
572                                 else 
573                                 {
574                                         localName = info.TypeData.XmlType + arrayDim;
575                                         ns = info.DataTypeNamespace;
576                                 }
577                         }
578                 }
579
580                 public override bool Equals (object other)
581                 {
582                         ListMap lmap = other as ListMap;
583                         if (lmap == null) return false;
584
585                         if (_itemInfo.Count != lmap._itemInfo.Count) return false;
586                         for (int n=0; n<_itemInfo.Count; n++)
587                                 if (!_itemInfo[n].Equals (lmap._itemInfo[n])) return false;
588                         return true;
589                 }
590
591                 public override int GetHashCode ()
592                 {
593                         return base.GetHashCode ();
594                 }
595         }
596
597         internal class EnumMap: ObjectMap
598         {
599                 readonly EnumMapMember[] _members;
600                 readonly bool _isFlags;
601                 readonly string[] _enumNames = null;
602                 readonly string[] _xmlNames = null;
603                 readonly long[] _values = null;
604
605                 public class EnumMapMember
606                 {
607                         readonly string _xmlName;
608                         readonly string _enumName;
609                         readonly long _value;
610                         string _documentation;
611
612                         public EnumMapMember (string xmlName, string enumName)
613                                 : this (xmlName, enumName, 0)
614                         {
615                         }
616
617                         public EnumMapMember (string xmlName, string enumName, long value)
618                         {
619                                 _xmlName = xmlName;
620                                 _enumName = enumName;
621                                 _value = value;
622                         }
623
624                         public string XmlName
625                         {
626                                 get { return _xmlName; }
627                         }
628
629                         public string EnumName
630                         {
631                                 get { return _enumName; }
632                         }
633
634                         public long Value
635                         {
636                                 get { return _value; }
637                         }
638
639                         public string Documentation
640                         {
641                                 get { return _documentation; }
642                                 set { _documentation = value; }
643                         }
644                 }
645
646                 public EnumMap (EnumMapMember[] members, bool isFlags)
647                 {
648                         _members = members;
649                         _isFlags = isFlags;
650
651                         _enumNames = new string[_members.Length];
652                         _xmlNames = new string[_members.Length];
653                         _values = new long[_members.Length];
654
655                         for (int i = 0; i < _members.Length; i++) {
656                                 EnumMapMember mem = _members[i];
657                                 _enumNames[i] = mem.EnumName;
658                                 _xmlNames[i] = mem.XmlName;
659                                 _values[i] = mem.Value;
660                         }
661                 }
662                 
663                 public bool IsFlags
664                 {
665                         get { return _isFlags; }
666                 }
667
668                 public EnumMapMember[] Members
669                 {
670                         get { return _members; }
671                 }
672
673                 public string[] EnumNames
674                 {
675                         get {
676                                 return _enumNames;
677                         }
678                 }
679
680                 public string[] XmlNames
681                 {
682                         get {
683                                 return _xmlNames;
684                         }
685                 }
686
687                 public long[] Values
688                 {
689                         get {
690                                 return _values;
691                         }
692                 }
693
694                 public string GetXmlName (string typeName, object enumValue)
695                 {
696                         if (enumValue is string) {
697                                 throw new InvalidCastException ();
698                         }
699
700                         long value = 0;
701
702                         try {
703                                 value = ((IConvertible) enumValue).ToInt64 (CultureInfo.CurrentCulture);
704                         } catch (FormatException) {
705                                 throw new InvalidCastException ();
706                         }
707
708                         for (int i = 0; i < Values.Length; i++) {
709                                 if (Values[i] == value)
710                                         return XmlNames[i];
711                         }
712
713                         if (IsFlags && value == 0)
714                                 return string.Empty;
715
716                         string xmlName = string.Empty;
717                         if (IsFlags) {
718 #if NET_2_0
719                                 xmlName = XmlCustomFormatter.FromEnum (value, XmlNames, Values, typeName);
720 #else
721                                 xmlName = XmlCustomFormatter.FromEnum (value, XmlNames, Values);
722 #endif
723                         }
724
725                         if (xmlName.Length == 0) {
726 #if NET_2_0
727                                 throw new InvalidOperationException (string.Format(CultureInfo.CurrentCulture,
728                                         "'{0}' is not a valid value for {1}.", value, typeName));
729 #else
730                                 return value.ToString (CultureInfo.InvariantCulture);
731 #endif
732                         }
733                         return xmlName;
734                 }
735
736                 public string GetEnumName (string typeName, string xmlName)
737                 {
738                         if (_isFlags) {
739                                 xmlName = xmlName.Trim ();
740                                 if (xmlName.Length == 0)
741                                         return "0";
742
743                                 System.Text.StringBuilder sb = new System.Text.StringBuilder ();
744                                 string[] enumNames = xmlName.Split (null);
745                                 foreach (string name in enumNames) {
746                                         if (name == string.Empty) continue;
747                                         string foundEnumValue = null;
748                                         for (int i = 0; i < XmlNames.Length; i++)
749                                                 if (XmlNames[i] == name) {
750                                                         foundEnumValue = EnumNames[i];
751                                                         break;
752                                                 }
753
754                                         if (foundEnumValue != null) {
755                                                 if (sb.Length > 0)
756                                                         sb.Append (',');
757                                                 sb.Append (foundEnumValue);
758                                         } else {
759                                                 throw new InvalidOperationException (string.Format (CultureInfo.CurrentCulture,
760                                                         "'{0}' is not a valid value for {1}.", name, typeName));
761                                         }
762                                 }
763                                 return sb.ToString ();
764                         }
765
766                         foreach (EnumMapMember mem in _members)
767                                 if (mem.XmlName == xmlName) return mem.EnumName;
768                                 
769                         return null;
770                 }
771         }
772 }