[LoongArch64] Part-5:add loongarch support in some files for LoongArch64. (#21769)
[mono-project.git] / mcs / class / System.XML / System.Xml.Serialization / XmlSerializationWriterInterpreter.cs
blobcf7985349eb7d4a215d53e4a70fdedf5c7c5db65
1 //
2 // XmlSerializationWriterInterpreter.cs:
3 //
4 // Author:
5 // Lluis Sanchez Gual (lluis@ximian.com)
6 //
7 // (C) 2002, 2003 Ximian, Inc. http://www.ximian.com
8 //
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
18 //
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
21 //
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 using System;
32 using System.Text;
33 using System.Collections;
34 using System.Reflection;
35 using System.Xml.Schema;
37 namespace System.Xml.Serialization
39 internal class XmlSerializationWriterInterpreter: XmlSerializationWriter
41 XmlMapping _typeMap;
42 SerializationFormat _format;
43 const string xmlNamespace = "http://www.w3.org/2000/xmlns/";
45 public XmlSerializationWriterInterpreter (XmlMapping typeMap)
47 _typeMap = typeMap;
48 _format = typeMap.Format;
51 protected override void InitCallbacks ()
53 ArrayList maps = _typeMap.RelatedMaps;
54 if (maps != null)
56 foreach (XmlTypeMapping map in maps) {
57 CallbackInfo info = new CallbackInfo (this, map);
58 if (map.TypeData.SchemaType == SchemaTypes.Enum) AddWriteCallback(map.TypeData.Type, map.XmlType, map.Namespace, new XmlSerializationWriteCallback (info.WriteEnum));
59 else AddWriteCallback(map.TypeData.Type, map.XmlType, map.Namespace, new XmlSerializationWriteCallback (info.WriteObject));
64 public void WriteRoot (object ob)
66 WriteStartDocument ();
68 if (_typeMap is XmlTypeMapping)
70 XmlTypeMapping mp = (XmlTypeMapping) _typeMap;
71 if (mp.TypeData.SchemaType == SchemaTypes.Class || mp.TypeData.SchemaType == SchemaTypes.Array)
72 TopLevelElement ();
74 if (_format == SerializationFormat.Literal)
75 WriteObject (mp, ob, mp.ElementName, mp.Namespace, true, false, true);
76 else
77 WritePotentiallyReferencingElement (mp.ElementName, mp.Namespace, ob, mp.TypeData.Type, true, false);
79 else if (ob is object[])
80 WriteMessage ((XmlMembersMapping)_typeMap, (object[]) ob);
81 else
82 throw CreateUnknownTypeException (ob);
84 WriteReferencedElements ();
87 protected XmlTypeMapping GetTypeMap (Type type)
89 ArrayList maps = _typeMap.RelatedMaps;
90 if (maps != null)
92 foreach (XmlTypeMapping map in maps)
93 if (map.TypeData.Type == type) return map;
95 throw new InvalidOperationException ("Type " + type + " not mapped");
98 protected virtual void WriteObject (XmlTypeMapping typeMap, object ob, string element, string namesp, bool isNullable, bool needType, bool writeWrappingElem)
100 if (ob == null)
102 if (isNullable)
104 if (_format == SerializationFormat.Literal) WriteNullTagLiteral(element, namesp);
105 else WriteNullTagEncoded (element, namesp);
107 return;
110 if (ob is XmlNode)
112 if (_format == SerializationFormat.Literal) WriteElementLiteral((XmlNode)ob, "", "", true, typeMap.IsAny);
113 else WriteElementEncoded((XmlNode)ob, "", "", true, typeMap.IsAny);
114 return;
117 if (typeMap.TypeData.SchemaType == SchemaTypes.XmlSerializable)
119 WriteSerializable ((IXmlSerializable)ob, element, namesp, isNullable, !typeMap.IsAny);
120 return;
123 var obExpectedType = typeMap.TypeData.Type;
124 if (!ob.GetType().IsAssignableFrom (obExpectedType))
125 ob = ImplicitConvert (ob, obExpectedType);
127 XmlTypeMapping map = typeMap.GetRealTypeMap (ob.GetType());
129 if (map == null)
131 // bug #81539
132 if (ob.GetType ().IsArray && typeof (XmlNode).IsAssignableFrom (ob.GetType ().GetElementType ())) {
133 Writer.WriteStartElement (element, namesp);
134 foreach (XmlNode node in (IEnumerable) ob)
135 node.WriteTo (Writer);
136 Writer.WriteEndElement ();
138 else
139 WriteTypedPrimitive (element, namesp, ob, true);
140 return;
143 if (writeWrappingElem)
145 if (map != typeMap || _format == SerializationFormat.Encoded) needType = true;
146 WriteStartElement (element, namesp, ob);
149 if (needType)
150 WriteXsiType(map.XmlType, map.XmlTypeNamespace);
152 switch (map.TypeData.SchemaType)
154 case SchemaTypes.Class: WriteObjectElement (map, ob, element, namesp); break;
155 case SchemaTypes.Array: WriteListElement (map, ob, element, namesp); break;
156 case SchemaTypes.Primitive: WritePrimitiveElement (map, ob, element, namesp); break;
157 case SchemaTypes.Enum: WriteEnumElement (map, ob, element, namesp); break;
160 if (writeWrappingElem)
161 WriteEndElement (ob);
164 protected virtual void WriteMessage (XmlMembersMapping membersMap, object[] parameters)
166 if (membersMap.HasWrapperElement) {
167 TopLevelElement ();
168 WriteStartElement(membersMap.ElementName, membersMap.Namespace, (_format == SerializationFormat.Encoded));
170 if (Writer.LookupPrefix (XmlSchema.Namespace) == null)
171 WriteAttribute ("xmlns","xsd",XmlSchema.Namespace,XmlSchema.Namespace);
173 if (Writer.LookupPrefix (XmlSchema.InstanceNamespace) == null)
174 WriteAttribute ("xmlns","xsi",XmlSchema.InstanceNamespace,XmlSchema.InstanceNamespace);
177 WriteMembers ((ClassMap)membersMap.ObjectMap, parameters, true);
179 if (membersMap.HasWrapperElement)
180 WriteEndElement();
183 protected virtual void WriteObjectElement (XmlTypeMapping typeMap, object ob, string element, string namesp)
185 ClassMap map = (ClassMap)typeMap.ObjectMap;
186 if (map.NamespaceDeclarations != null)
187 WriteNamespaceDeclarations ((XmlSerializerNamespaces) map.NamespaceDeclarations.GetValue (ob));
189 WriteObjectElementAttributes (typeMap, ob);
190 WriteObjectElementElements (typeMap, ob);
193 protected virtual void WriteObjectElementAttributes (XmlTypeMapping typeMap, object ob)
195 ClassMap map = (ClassMap)typeMap.ObjectMap;
196 WriteAttributeMembers (map, ob, false);
199 protected virtual void WriteObjectElementElements (XmlTypeMapping typeMap, object ob)
201 ClassMap map = (ClassMap)typeMap.ObjectMap;
202 WriteElementMembers (map, ob, false);
205 void WriteMembers (ClassMap map, object ob, bool isValueList)
207 WriteAttributeMembers (map, ob, isValueList);
208 WriteElementMembers (map, ob, isValueList);
211 void WriteAttributeMembers (ClassMap map, object ob, bool isValueList)
213 // Write attributes
215 XmlTypeMapMember anyAttrMember = map.DefaultAnyAttributeMember;
216 if (anyAttrMember != null && MemberHasValue (anyAttrMember, ob, isValueList))
218 ICollection extraAtts = (ICollection) GetMemberValue (anyAttrMember, ob, isValueList);
219 if (extraAtts != null)
221 foreach (XmlAttribute attr in extraAtts)
222 if (attr.NamespaceURI != xmlNamespace)
223 WriteXmlAttribute (attr, ob);
227 ICollection attributes = map.AttributeMembers;
228 if (attributes != null)
230 foreach (XmlTypeMapMemberAttribute attr in attributes) {
231 if (MemberHasValue (attr, ob, isValueList))
232 WriteAttribute (attr.AttributeName, attr.Namespace, GetStringValue (attr.MappedType, attr.TypeData, GetMemberValue (attr, ob, isValueList)));
237 void WriteElementMembers (ClassMap map, object ob, bool isValueList)
239 ICollection members = map.ElementMembers;
240 if (members != null)
242 foreach (XmlTypeMapMemberElement member in members)
244 if (!MemberHasValue (member, ob, isValueList)) continue;
245 object memberValue = GetMemberValue (member, ob, isValueList);
246 Type memType = member.GetType();
248 if (memType == typeof(XmlTypeMapMemberList))
250 WriteMemberElement ((XmlTypeMapElementInfo) member.ElementInfo[0], memberValue);
252 else if (memType == typeof(XmlTypeMapMemberFlatList))
254 if (memberValue != null)
255 WriteListContent (ob, member.TypeData, ((XmlTypeMapMemberFlatList)member).ListMap, memberValue, null);
257 else if (memType == typeof(XmlTypeMapMemberAnyElement))
259 if (memberValue != null)
260 WriteAnyElementContent ((XmlTypeMapMemberAnyElement)member, memberValue);
262 else if (memType == typeof(XmlTypeMapMemberAnyAttribute))
264 // Ignore
266 else if (memType == typeof(XmlTypeMapMemberElement))
268 XmlTypeMapElementInfo elem = member.FindElement (ob, memberValue);
269 WriteMemberElement (elem, memberValue);
271 else
272 throw new InvalidOperationException ("Unknown member type");
277 object GetMemberValue (XmlTypeMapMember member, object ob, bool isValueList)
279 if (isValueList) return ((object[])ob)[member.GlobalIndex];
280 else return member.GetValue (ob);
283 bool MemberHasValue (XmlTypeMapMember member, object ob, bool isValueList)
285 if (isValueList) {
286 if (member.IsOptionalValueType && !member.GetValueSpecified (ob))
287 return false;
288 return member.GlobalIndex < ((object[])ob).Length;
290 else if (member.DefaultValue != System.DBNull.Value) {
291 object val = GetMemberValue (member, ob, isValueList);
292 if (val == null && member.DefaultValue == null) return false;
293 if (val != null && val.GetType().IsEnum)
295 if (val.Equals (member.DefaultValue)) return false;
296 Type t = Enum.GetUnderlyingType(val.GetType());
297 val = Convert.ChangeType (val, t, null);
299 if (val != null && val.Equals (member.DefaultValue)) return false;
301 else if (member.IsOptionalValueType)
302 return member.GetValueSpecified (ob);
304 return true;
307 void WriteMemberElement (XmlTypeMapElementInfo elem, object memberValue)
309 switch (elem.TypeData.SchemaType)
311 case SchemaTypes.XmlNode:
312 string elemName = elem.WrappedElement ? elem.ElementName : "";
313 if (_format == SerializationFormat.Literal) WriteElementLiteral(((XmlNode)memberValue), elemName, elem.Namespace, elem.IsNullable, false);
314 else WriteElementEncoded(((XmlNode)memberValue), elemName, elem.Namespace, elem.IsNullable, false);
315 break;
317 case SchemaTypes.Enum:
318 case SchemaTypes.Primitive:
319 if (_format == SerializationFormat.Literal)
320 WritePrimitiveValueLiteral (memberValue, elem.ElementName, elem.Namespace, elem.MappedType, elem.TypeData, elem.WrappedElement, elem.IsNullable);
321 else
322 WritePrimitiveValueEncoded (memberValue, elem.ElementName, elem.Namespace, new XmlQualifiedName (elem.DataTypeName, elem.DataTypeNamespace), elem.MappedType, elem.TypeData, elem.WrappedElement, elem.IsNullable);
323 break;
325 case SchemaTypes.Array:
326 if (memberValue == null) {
327 if (!elem.IsNullable) return;
328 if (_format == SerializationFormat.Literal) WriteNullTagLiteral (elem.ElementName, elem.Namespace);
329 else WriteNullTagEncoded (elem.ElementName, elem.Namespace);
331 else if (elem.MappedType.MultiReferenceType)
332 WriteReferencingElement (elem.ElementName, elem.Namespace, memberValue, elem.IsNullable);
333 else {
334 WriteStartElement(elem.ElementName, elem.Namespace, memberValue);
335 WriteListContent (null, elem.TypeData, (ListMap) elem.MappedType.ObjectMap, memberValue, null);
336 WriteEndElement (memberValue);
338 break;
340 case SchemaTypes.Class:
341 if (elem.MappedType.MultiReferenceType) {
342 if (elem.MappedType.TypeData.Type == typeof(object))
343 WritePotentiallyReferencingElement (elem.ElementName, elem.Namespace, memberValue, null, false, elem.IsNullable);
344 else
345 WriteReferencingElement (elem.ElementName, elem.Namespace, memberValue, elem.IsNullable);
347 else WriteObject (elem.MappedType, memberValue, elem.ElementName, elem.Namespace, elem.IsNullable, false, true);
348 break;
350 case SchemaTypes.XmlSerializable:
351 // bug #419973
352 if (!elem.MappedType.TypeData.Type.IsInstanceOfType (memberValue))
353 memberValue = ImplicitConvert (memberValue, elem.MappedType.TypeData.Type);
354 WriteSerializable ((IXmlSerializable) memberValue, elem.ElementName, elem.Namespace, elem.IsNullable);
355 break;
357 default:
358 throw new NotSupportedException ("Invalid value type");
362 internal static object ImplicitConvert (object obj, Type type)
364 if (obj == null)
365 return null;
367 for (Type t = obj.GetType (); t != typeof (object); t = t.BaseType) {
368 MethodInfo mi = t.GetMethod ("op_Implicit", new Type [] {t});
369 if (mi != null && mi.ReturnType == type)
370 return mi.Invoke (null, new object [] {obj});
372 mi = type.GetMethod ("op_Implicit", new Type [] {t});
373 if (mi != null && mi.ReturnType == type)
374 return mi.Invoke (null, new object [] {obj});
376 return obj;
379 void WritePrimitiveValueLiteral (object memberValue, string name, string ns, XmlTypeMapping mappedType, TypeData typeData, bool wrapped, bool isNullable)
381 if (!wrapped) {
382 WriteValue (GetStringValue (mappedType, typeData, memberValue));
384 else if (isNullable) {
385 if (typeData.Type == typeof(XmlQualifiedName)) WriteNullableQualifiedNameLiteral (name, ns, (XmlQualifiedName)memberValue);
386 else WriteNullableStringLiteral (name, ns, GetStringValue (mappedType, typeData, memberValue));
388 else {
389 if (typeData.Type == typeof(XmlQualifiedName)) WriteElementQualifiedName (name, ns, (XmlQualifiedName)memberValue);
390 else WriteElementString (name, ns, GetStringValue (mappedType, typeData, memberValue));
394 void WritePrimitiveValueEncoded (object memberValue, string name, string ns, XmlQualifiedName xsiType, XmlTypeMapping mappedType, TypeData typeData, bool wrapped, bool isNullable)
396 if (!wrapped) {
397 WriteValue (GetStringValue (mappedType, typeData, memberValue));
399 else if (isNullable) {
400 if (typeData.Type == typeof(XmlQualifiedName)) WriteNullableQualifiedNameEncoded (name, ns, (XmlQualifiedName)memberValue, xsiType);
401 else WriteNullableStringEncoded (name, ns, GetStringValue (mappedType, typeData, memberValue), xsiType);
403 else {
404 if (typeData.Type == typeof(XmlQualifiedName)) WriteElementQualifiedName (name, ns, (XmlQualifiedName)memberValue, xsiType);
405 else WriteElementString (name, ns, GetStringValue (mappedType, typeData, memberValue), xsiType);
409 protected virtual void WriteListElement (XmlTypeMapping typeMap, object ob, string element, string namesp)
411 if (_format == SerializationFormat.Encoded)
413 string n, ns;
414 int itemCount = GetListCount (typeMap.TypeData, ob);
415 ((ListMap) typeMap.ObjectMap).GetArrayType (itemCount, out n, out ns);
416 string arrayType = (ns != string.Empty) ? FromXmlQualifiedName (new XmlQualifiedName(n,ns)) : n;
417 WriteAttribute ("arrayType", XmlSerializer.EncodingNamespace, arrayType);
419 WriteListContent (null, typeMap.TypeData, (ListMap) typeMap.ObjectMap, ob, null);
422 void WriteListContent (object container, TypeData listType, ListMap map, object ob, StringBuilder targetString)
424 if (listType.Type.IsArray)
426 Array array = (Array)ob;
427 for (int n=0; n<array.Length; n++)
429 object item = array.GetValue (n);
430 XmlTypeMapElementInfo info = map.FindElement (container, n, item);
431 if (info != null && targetString == null) WriteMemberElement (info, item);
432 else if (info != null && targetString != null) targetString.Append (GetStringValue (info.MappedType, info.TypeData, item)).Append (" ");
433 else if (item != null) throw CreateUnknownTypeException (item);
436 else if (ob is ICollection)
438 int count = (int) ob.GetType().GetProperty ("Count").GetValue(ob,null);
439 PropertyInfo itemProp = TypeData.GetIndexerProperty (listType.Type);
440 object[] index = new object[1];
441 for (int n=0; n<count; n++)
443 index[0] = n;
444 object item = itemProp.GetValue (ob, index);
445 XmlTypeMapElementInfo info = map.FindElement (container, n, item);
446 if (info != null && targetString == null) WriteMemberElement (info, item);
447 else if (info != null && targetString != null) targetString.Append (GetStringValue (info.MappedType, info.TypeData, item)).Append (" ");
448 else if (item != null) throw CreateUnknownTypeException (item);
451 else if (ob is IEnumerable)
453 IEnumerable e = (IEnumerable)ob;
454 foreach (object item in e)
456 XmlTypeMapElementInfo info = map.FindElement (container, -1, item);
457 if (info != null && targetString == null) WriteMemberElement (info, item);
458 else if (info != null && targetString != null) targetString.Append (GetStringValue (info.MappedType, info.TypeData, item)).Append (" ");
459 else if (item != null) throw CreateUnknownTypeException (item);
462 else
463 throw new Exception ("Unsupported collection type");
466 int GetListCount (TypeData listType, object ob)
468 if (listType.Type.IsArray)
469 return ((Array)ob).Length;
470 else
471 return (int) listType.Type.GetProperty ("Count").GetValue(ob,null);
474 void WriteAnyElementContent (XmlTypeMapMemberAnyElement member, object memberValue)
477 // XmlAnyElement can be of XmlElement or XmlNode type
479 if (member.TypeData.Type == typeof (XmlElement) || member.TypeData.Type == typeof(XmlNode)) {
480 memberValue = new object[] { memberValue };
483 Array elems = (Array) memberValue;
484 foreach (var elem_ in elems)
486 XmlNode elem = elem_ as XmlNode;
487 if (elem == null)
488 throw new InvalidOperationException (String.Format ("XmlAnyElementAttribute can only be applied to members of type XmlElement, XmlElement[] or XmlNode[]. The target object is {0}", elem_ != null ? elem_.GetType () : null));
489 if (elem is XmlElement)
491 if (member.IsElementDefined (elem.Name, elem.NamespaceURI))
493 if (_format == SerializationFormat.Literal) WriteElementLiteral (elem, "", "", false, true);
494 else WriteElementEncoded (elem, "", "", false, true);
496 else
497 throw CreateUnknownAnyElementException (elem.Name, elem.NamespaceURI);
499 else
500 elem.WriteTo (Writer);
504 protected virtual void WritePrimitiveElement (XmlTypeMapping typeMap, object ob, string element, string namesp)
506 Writer.WriteString (GetStringValue (typeMap, typeMap.TypeData, ob));
509 protected virtual void WriteEnumElement (XmlTypeMapping typeMap, object ob, string element, string namesp)
511 Writer.WriteString (GetEnumXmlValue (typeMap, ob));
514 string GetStringValue (XmlTypeMapping typeMap, TypeData type, object value)
516 if (type.SchemaType == SchemaTypes.Array) {
517 if (value == null) return null;
518 StringBuilder sb = new StringBuilder ();
519 WriteListContent (null, typeMap.TypeData, (ListMap)typeMap.ObjectMap, value, sb);
520 return sb.ToString ().Trim ();
522 else if (type.SchemaType == SchemaTypes.Enum)
523 return GetEnumXmlValue (typeMap, value);
524 else if (type.Type == typeof (XmlQualifiedName))
525 return FromXmlQualifiedName ((XmlQualifiedName)value);
526 else if (value == null)
527 return null;
528 else
529 return XmlCustomFormatter.ToXmlString (type, value);
532 string GetEnumXmlValue (XmlTypeMapping typeMap, object ob)
534 if (ob == null)
535 return null;
536 EnumMap map = (EnumMap)typeMap.ObjectMap;
537 return map.GetXmlName (typeMap.TypeFullName, ob);
540 class CallbackInfo
542 XmlSerializationWriterInterpreter _swi;
543 XmlTypeMapping _typeMap;
545 public CallbackInfo (XmlSerializationWriterInterpreter swi, XmlTypeMapping typeMap)
547 _swi = swi;
548 _typeMap = typeMap;
551 internal void WriteObject (object ob)
553 _swi.WriteObject (_typeMap, ob, _typeMap.ElementName, _typeMap.Namespace, false, false, false);
556 internal void WriteEnum (object ob)
558 _swi.WriteObject (_typeMap, ob, _typeMap.ElementName, _typeMap.Namespace, false, true, false);