Merge pull request #3381 from krytarowski/netbsd-support-20
[mono.git] / mcs / class / System.XML / System.Xml.Serialization / XmlSerializationWriter.cs
1 //
2 // System.Xml.Serialization.XmlSerializationWriter.cs
3 //
4 // Author:
5 //   Tim Coleman (tim@timcoleman.com)
6 //   Lluis Sanchez Gual (lluis@ximian.com)
7 //
8 // Copyright (C) Tim Coleman, 2002
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;
33 using System.Collections;
34 using System.Collections.Generic;
35 using System.Globalization;
36 using System.Text;
37 using System.Xml;
38 using System.Xml.Schema;
39 using System.Runtime.Serialization;
40 using System.Reflection;
41
42 namespace System.Xml.Serialization 
43 {
44         public abstract class XmlSerializationWriter 
45                 : XmlSerializationGeneratedCode
46         {
47
48                 #region Fields
49
50                 ObjectIDGenerator idGenerator;
51                 int qnameCount;
52                 bool topLevelElement = false;
53
54                 ArrayList namespaces;
55                 XmlWriter writer;
56                 Queue referencedElements;
57                 Hashtable callbacks;
58                 Hashtable serializedObjects;
59                 const string xmlNamespace = "http://www.w3.org/2000/xmlns/";
60                 const string unexpectedTypeError = "The type {0} was not expected. Use the" +
61                         " XmlInclude or SoapInclude attribute to specify types that are not known statically.";
62
63                 #endregion // Fields
64
65                 #region Constructors
66
67                 protected XmlSerializationWriter ()
68                 {
69                         qnameCount = 0;
70                         serializedObjects = new Hashtable ();
71                 }
72                 
73                 internal void Initialize (XmlWriter writer, XmlSerializerNamespaces nss)
74                 {
75                         this.writer = writer;
76                         if (nss != null)
77                         {
78                                 namespaces = new ArrayList ();
79                                 foreach (XmlQualifiedName ns in nss.ToArray())
80                                         if (ns.Name != "" && ns.Namespace != "")
81                                                 namespaces.Add (ns);
82                         }       
83                 }
84
85                 #endregion // Constructors
86
87                 #region Properties
88
89                 protected ArrayList Namespaces {
90                         get { return namespaces; }
91                         set { namespaces = value; }
92                 }
93
94                 protected XmlWriter Writer {
95                         get { return writer; }
96                         set { writer = value; }
97                 }
98
99                 #endregion // Properties
100
101                 #region Methods
102                 
103                 protected void AddWriteCallback (Type type, string typeName, string typeNs, XmlSerializationWriteCallback callback)
104                 {
105                         WriteCallbackInfo info = new WriteCallbackInfo ();
106                         info.Type = type;
107                         info.TypeName = typeName;
108                         info.TypeNs = typeNs;
109                         info.Callback = callback;
110
111                         if (callbacks == null) callbacks = new Hashtable ();
112                         callbacks.Add (type, info);
113                 }
114                 
115                 protected Exception CreateChoiceIdentifierValueException (string value, string identifier, string name, string ns)
116                 {
117                         string message = string.Format ("Value '{0}' of the choice"
118                                 + " identifier '{1}' does not match element '{2}'"
119                                 + " from namespace '{3}'.", value, identifier,
120                                 name, ns);
121                         return new InvalidOperationException (message);
122                 }
123
124                 protected Exception CreateInvalidChoiceIdentifierValueException (string type, string identifier)
125                 {
126                         string message = string.Format ("Invalid or missing choice"
127                                 + " identifier '{0}' of type '{1}'.", identifier,
128                                 type);
129                         return new InvalidOperationException (message);
130                 }
131
132                 protected Exception CreateMismatchChoiceException (string value, string elementName, string enumValue)
133                 {
134                         string message = String.Format ("Value of {0} mismatches the type of {1}, you need to set it to {2}.", elementName, value, enumValue);
135                         return new InvalidOperationException (message);
136                 }
137
138                 protected Exception CreateUnknownAnyElementException (string name, string ns)
139                 {
140                         string message = String.Format ("The XML element named '{0}' from namespace '{1}' was not expected. The XML element name and namespace must match those provided via XmlAnyElementAttribute(s).", name, ns);
141                         return new InvalidOperationException (message);
142                 }
143
144                 protected Exception CreateUnknownTypeException (object o)
145                 {
146                         return CreateUnknownTypeException (o.GetType ());
147                 }
148
149                 protected Exception CreateUnknownTypeException (Type type)
150                 {
151                         string message = String.Format ("The type {0} may not be used in this context.", type);
152                         return new InvalidOperationException (message);
153                 }
154
155                 protected static byte[] FromByteArrayBase64 (byte[] value)
156                 {
157                         return value;
158                 }
159
160                 protected static string FromByteArrayHex (byte[] value)
161                 {
162                         return XmlCustomFormatter.FromByteArrayHex (value);
163                 }
164
165                 protected static string FromChar (char value)
166                 {
167                         return XmlCustomFormatter.FromChar (value);
168                 }
169
170                 protected static string FromDate (DateTime value)
171                 {
172                         return XmlCustomFormatter.FromDate (value);
173                 }
174
175                 protected static string FromDateTime (DateTime value)
176                 {
177                         return XmlCustomFormatter.FromDateTime (value);
178                 }
179
180                 protected static string FromEnum (long value, string[] values, long[] ids)
181                 {
182                         return XmlCustomFormatter.FromEnum (value, values, ids);
183                 }
184
185                 protected static string FromTime (DateTime value)
186                 {
187                         return XmlCustomFormatter.FromTime (value);
188                 }
189
190                 protected static string FromXmlName (string name)
191                 {
192                         return XmlCustomFormatter.FromXmlName (name);
193                 }
194
195                 protected static string FromXmlNCName (string ncName)
196                 {
197                         return XmlCustomFormatter.FromXmlNCName (ncName);
198                 }
199
200                 protected static string FromXmlNmToken (string nmToken)
201                 {
202                         return XmlCustomFormatter.FromXmlNmToken (nmToken);
203                 }
204
205                 protected static string FromXmlNmTokens (string nmTokens)
206                 {
207                         return XmlCustomFormatter.FromXmlNmTokens (nmTokens);
208                 }
209
210                 protected string FromXmlQualifiedName (XmlQualifiedName xmlQualifiedName)
211                 {
212                         if (xmlQualifiedName == null || xmlQualifiedName == XmlQualifiedName.Empty)
213                                 return null;
214                                 
215                         return GetQualifiedName (xmlQualifiedName.Name, xmlQualifiedName.Namespace);
216                 }
217
218                 private string GetId (object o, bool addToReferencesList)
219                 {
220                         if (idGenerator == null) idGenerator = new ObjectIDGenerator ();
221
222                         bool firstTime;
223                         long lid = idGenerator.GetId (o, out firstTime);
224                         return String.Format (CultureInfo.InvariantCulture, "id{0}", lid);
225                 }
226
227                 
228                 bool AlreadyQueued (object ob)
229                 {
230                         if (idGenerator == null) return false;
231
232                         bool firstTime;
233                         idGenerator.HasId (ob, out firstTime);
234                         return !firstTime;
235                 }
236
237                 private string GetNamespacePrefix (string ns)
238                 {
239                         string prefix = Writer.LookupPrefix (ns);
240                         if (prefix == null) 
241                         {
242                                 prefix = String.Format (CultureInfo.InvariantCulture, "q{0}", ++qnameCount);
243                                 WriteAttribute ("xmlns", prefix, null, ns);
244                         }
245                         return prefix;
246                 }
247
248                 private string GetQualifiedName (string name, string ns)
249                 {
250                         if (ns == String.Empty) return name;
251                         
252                         string prefix = GetNamespacePrefix (ns);
253                         if (prefix == String.Empty)
254                                 return name;
255                         else
256                                 return String.Format ("{0}:{1}", prefix, name);
257                 }
258
259                 protected abstract void InitCallbacks ();
260
261                 protected void TopLevelElement ()
262                 {
263                         topLevelElement = true;
264                 }
265
266                 protected void WriteAttribute (string localName, byte[] value)
267                 {
268                         WriteAttribute (localName, String.Empty, value);
269                 }
270
271                 protected void WriteAttribute (string localName, string value)
272                 {
273                         WriteAttribute (String.Empty, localName, String.Empty, value);
274                 }
275
276                 protected void WriteAttribute (string localName, string ns, byte[] value)
277                 {
278                         if (value == null)
279                                 return;
280
281                         Writer.WriteStartAttribute (localName, ns);
282                         WriteValue (value);
283                         Writer.WriteEndAttribute ();
284                 }
285
286                 protected void WriteAttribute (string localName, string ns, string value)
287                 {
288                         WriteAttribute (null, localName, ns, value);
289                 }
290
291                 protected void WriteAttribute (string prefix, string localName, string ns, string value)
292                 {
293                         if (value == null)
294                                 return;
295
296                         Writer.WriteAttributeString (prefix, localName, ns, value);
297                 }
298
299                 void WriteXmlNode (XmlNode node)
300                 {
301                         if (node is XmlDocument)
302                                 node = ((XmlDocument) node).DocumentElement;
303
304                         node.WriteTo (Writer);
305                 }
306
307                 protected void WriteElementEncoded (XmlNode node, string name, string ns, bool isNullable, bool any)
308                 {
309                         if (name != string.Empty)
310                         {
311                                 if (node == null)
312                                 {
313                                         if (isNullable)
314                                                 WriteNullTagEncoded (name, ns);
315                                 }
316                                 else if (any)
317                                         WriteXmlNode (node);
318                                 else
319                                 {
320                                         Writer.WriteStartElement (name, ns);
321                                         WriteXmlNode (node);
322                                         Writer.WriteEndElement ();
323                                 }
324                         }
325                         else
326                                 WriteXmlNode(node);
327                 }
328
329                 protected void WriteElementLiteral (XmlNode node, string name, string ns, bool isNullable, bool any)
330                 {
331                         if (name != string.Empty)
332                         {
333                                 if (node == null)
334                                 {
335                                         if (isNullable)
336                                                 WriteNullTagLiteral (name, ns);
337                                 }
338                                 else if (any)
339                                         WriteXmlNode (node);
340                                 else
341                                 {
342                                         Writer.WriteStartElement (name, ns);
343                                         WriteXmlNode (node);
344                                         Writer.WriteEndElement ();
345                                 }
346                         }
347                         else
348                                 WriteXmlNode (node);
349                 }
350
351                 protected void WriteElementQualifiedName (string localName, XmlQualifiedName value)
352                 {
353                         WriteElementQualifiedName (localName, String.Empty, value, null);
354                 }
355
356                 protected void WriteElementQualifiedName (string localName, string ns, XmlQualifiedName value)
357                 {
358                         WriteElementQualifiedName (localName, ns, value, null);
359                 }
360
361                 protected void WriteElementQualifiedName (string localName, XmlQualifiedName value, XmlQualifiedName xsiType)
362                 {
363                         WriteElementQualifiedName (localName, String.Empty, value, xsiType);
364                 }
365
366                 protected void WriteElementQualifiedName (string localName, string ns, XmlQualifiedName value, XmlQualifiedName xsiType)
367                 {
368                         localName = XmlCustomFormatter.FromXmlNCName (localName);
369                         WriteStartElement (localName, ns);
370                         if (xsiType != null) WriteXsiType (xsiType.Name, xsiType.Namespace);
371                         Writer.WriteString (FromXmlQualifiedName (value));
372                         WriteEndElement ();
373                 }
374
375                 protected void WriteElementString (string localName, string value)
376                 {
377                         WriteElementString (localName, String.Empty, value, null);
378                 }
379
380                 protected void WriteElementString (string localName, string ns, string value)
381                 {
382                         WriteElementString (localName, ns, value, null);
383                 }
384
385                 protected void WriteElementString (string localName, string value, XmlQualifiedName xsiType)
386                 {
387                         WriteElementString (localName, String.Empty, value, xsiType);
388                 }
389
390                 protected void WriteElementString (string localName, string ns, string value, XmlQualifiedName xsiType)
391                 {
392                         if (value == null) return;
393
394                         if (xsiType != null) {
395                                 localName = XmlCustomFormatter.FromXmlNCName (localName);
396                                 WriteStartElement (localName, ns);
397                                 WriteXsiType (xsiType.Name, xsiType.Namespace);
398                                 Writer.WriteString (value);
399                                 WriteEndElement ();
400                         } 
401                         else
402                                 Writer.WriteElementString (localName, ns, value);
403                 }
404
405                 protected void WriteElementStringRaw (string localName, byte[] value)
406                 {
407                         WriteElementStringRaw (localName, String.Empty, value, null);
408                 }
409
410                 protected void WriteElementStringRaw (string localName, string value)
411                 {
412                         WriteElementStringRaw (localName, String.Empty, value, null);
413                 }
414
415                 protected void WriteElementStringRaw (string localName, byte[] value, XmlQualifiedName xsiType)
416                 {
417                         WriteElementStringRaw (localName, String.Empty, value, xsiType);
418                 }
419
420                 protected void WriteElementStringRaw (string localName, string ns, byte[] value)
421                 {
422                         WriteElementStringRaw (localName, ns, value, null);
423                 }
424
425                 protected void WriteElementStringRaw (string localName, string ns, string value)
426                 {
427                         WriteElementStringRaw (localName, ns, value, null);
428                 }
429
430                 protected void WriteElementStringRaw (string localName, string value, XmlQualifiedName xsiType)
431                 {
432                         WriteElementStringRaw (localName, String.Empty, value, null);
433                 }
434
435                 protected void WriteElementStringRaw (string localName, string ns, byte[] value, XmlQualifiedName xsiType)
436                 {
437                         if (value == null)
438                                 return;
439
440                         WriteStartElement (localName, ns);
441
442                         if (xsiType != null)
443                                 WriteXsiType (xsiType.Name, xsiType.Namespace);
444
445                         if (value.Length > 0) 
446                                 Writer.WriteBase64(value,0,value.Length);
447                         WriteEndElement ();
448                 }
449
450                 protected void WriteElementStringRaw (string localName, string ns, string value, XmlQualifiedName xsiType)
451                 {
452                         localName = XmlCustomFormatter.FromXmlNCName (localName);
453                         WriteStartElement (localName, ns);
454
455                         if (xsiType != null)
456                                 WriteXsiType (xsiType.Name, xsiType.Namespace);
457
458                         Writer.WriteRaw (value);
459                         WriteEndElement ();
460                 }
461
462                 protected void WriteEmptyTag (string name)
463                 {
464                         WriteEmptyTag (name, String.Empty);
465                 }
466
467                 protected void WriteEmptyTag (string name, string ns)
468                 {
469                         name = XmlCustomFormatter.FromXmlName (name);
470                         WriteStartElement (name, ns);
471                         WriteEndElement ();
472                 }
473
474                 protected void WriteEndElement ()
475                 {
476                         WriteEndElement (null);
477                 }
478
479                 protected void WriteEndElement (object o)
480                 {
481                         if (o != null)
482                                 serializedObjects.Remove (o);
483                                 
484                         Writer.WriteEndElement ();
485                 }
486
487                 protected void WriteId (object o)
488                 {
489                         WriteAttribute ("id", GetId (o, true));
490                 }
491
492                 protected void WriteNamespaceDeclarations (XmlSerializerNamespaces xmlns)
493                 {
494                         if (xmlns == null)
495                                 return;
496                         foreach (DictionaryEntry qn in xmlns.Namespaces) {
497                                 if ((string) qn.Value != String.Empty && Writer.LookupPrefix ((string) qn.Value) != (string) qn.Key)
498                                         WriteAttribute ("xmlns", (string) qn.Key, xmlNamespace, (string) qn.Value);
499                         }
500                 }
501
502                 protected void WriteNullableQualifiedNameEncoded (string name, string ns, XmlQualifiedName value, XmlQualifiedName xsiType)
503                 {
504                         if (value != null)
505                                 WriteElementQualifiedName (name, ns, value, xsiType);
506                         else
507                                 WriteNullTagEncoded (name, ns);
508                 }
509
510                 protected void WriteNullableQualifiedNameLiteral (string name, string ns, XmlQualifiedName value)
511                 {
512                         if (value != null)
513                                 WriteElementQualifiedName (name, ns, value);
514                         else
515                                 WriteNullTagLiteral (name, ns);
516                 }
517
518                 protected void WriteNullableStringEncoded (string name, string ns, string value, XmlQualifiedName xsiType)
519                 {
520                         if (value != null)
521                                 WriteElementString (name, ns, value, xsiType);
522                         else
523                                 WriteNullTagEncoded (name, ns);
524                 }
525
526                 protected void WriteNullableStringEncodedRaw (string name, string ns, byte[] value, XmlQualifiedName xsiType)
527                 {
528                         if (value == null)
529                                 WriteNullTagEncoded (name, ns);
530                         else
531                                 WriteElementStringRaw (name, ns, value, xsiType);
532                 }
533
534                 protected void WriteNullableStringEncodedRaw (string name, string ns, string value, XmlQualifiedName xsiType)
535                 {
536                         if (value == null)
537                                 WriteNullTagEncoded (name, ns);
538                         else
539                                 WriteElementStringRaw (name, ns, value, xsiType);
540                 }
541
542                 protected void WriteNullableStringLiteral (string name, string ns, string value)
543                 {
544                         if (value != null)
545                                 WriteElementString (name, ns, value, null);
546                         else
547                                 WriteNullTagLiteral (name, ns);
548                 }
549
550                 protected void WriteNullableStringLiteralRaw (string name, string ns, byte[] value)
551                 {
552                         if (value == null)
553                                 WriteNullTagLiteral (name, ns);
554                         else
555                                 WriteElementStringRaw (name, ns, value);
556                 }
557
558                 protected void WriteNullableStringLiteralRaw (string name, string ns, string value)
559                 {
560                         if (value == null)
561                                 WriteNullTagLiteral (name, ns);
562                         else
563                                 WriteElementStringRaw (name, ns, value);
564                 }
565
566                 protected void WriteNullTagEncoded (string name)
567                 {
568                         WriteNullTagEncoded (name, String.Empty);
569                 }
570
571                 protected void WriteNullTagEncoded (string name, string ns)
572                 {
573                         Writer.WriteStartElement (name, ns);
574                         Writer.WriteAttributeString ("nil", XmlSchema.InstanceNamespace, "true");
575                         Writer.WriteEndElement ();
576                 }
577
578                 protected void WriteNullTagLiteral (string name)
579                 {
580                         WriteNullTagLiteral (name, String.Empty);
581                 }
582
583                 protected void WriteNullTagLiteral (string name, string ns)
584                 {
585                         WriteStartElement (name, ns);
586                         Writer.WriteAttributeString ("nil", XmlSchema.InstanceNamespace, "true");
587                         WriteEndElement ();
588                 }
589
590                 protected void WritePotentiallyReferencingElement (string n, string ns, object o)
591                 {
592                         WritePotentiallyReferencingElement (n, ns, o, null, false, false);
593                 }
594
595                 protected void WritePotentiallyReferencingElement (string n, string ns, object o, Type ambientType)
596                 {
597                         WritePotentiallyReferencingElement (n, ns, o, ambientType, false, false);
598                 }
599
600                 protected void WritePotentiallyReferencingElement (string n, string ns, object o, Type ambientType, bool suppressReference)
601                 {
602                         WritePotentiallyReferencingElement (n, ns, o, ambientType, suppressReference, false);
603                 }
604
605                 protected void WritePotentiallyReferencingElement (string n, string ns, object o, Type ambientType, bool suppressReference, bool isNullable)
606                 {
607                         if (o == null) 
608                         {
609                                 if (isNullable) WriteNullTagEncoded (n, ns);
610                                 return;
611                         }
612
613                         var t = o.GetType ();
614
615                         WriteStartElement (n, ns, true);
616
617                         CheckReferenceQueue ();
618
619                         if (callbacks != null && callbacks.ContainsKey (o.GetType ()))
620                         {
621                                 WriteCallbackInfo info = (WriteCallbackInfo) callbacks[t];
622                                 if (t.IsEnum) {
623                                         info.Callback (o);
624                                 }
625                                 else if (suppressReference) {
626                                         Writer.WriteAttributeString ("id", GetId (o, false));
627                                         if (ambientType != t) WriteXsiType(info.TypeName, info.TypeNs);
628                                         info.Callback (o);
629                                 }
630                                 else {
631                                         if (!AlreadyQueued (o)) referencedElements.Enqueue (o);
632                                         Writer.WriteAttributeString ("href", "#" + GetId (o, true));
633                                 }
634                         }
635                         else
636                         {
637                                 // Must be a primitive type or array of primitives
638                                 TypeData td = TypeTranslator.GetTypeData (t, null, true);
639                                 if (td.SchemaType == SchemaTypes.Primitive) {
640                                         if (t != ambientType)
641                                                 WriteXsiType (td.XmlType, XmlSchema.Namespace);
642                                         Writer.WriteString (XmlCustomFormatter.ToXmlString (td, o));
643                                 } else if (IsPrimitiveArray (td)) {
644                                         if (!AlreadyQueued (o)) referencedElements.Enqueue (o);
645                                         Writer.WriteAttributeString ("href", "#" + GetId (o, true));
646                                 } else {
647                                         throw new InvalidOperationException ("Invalid type: " + t.FullName);
648                                 }
649                         }
650
651                         WriteEndElement ();
652                 }
653
654                 protected void WriteReferencedElements ()
655                 {
656                         if (referencedElements == null) return;
657                         if (callbacks == null) return;
658
659                         while (referencedElements.Count > 0)
660                         {
661                                 object o = referencedElements.Dequeue ();
662                                 TypeData td = TypeTranslator.GetTypeData (o.GetType ());
663                                 WriteCallbackInfo info = (WriteCallbackInfo) callbacks[o.GetType()];
664                                 
665                                 if (info != null) {
666                                         WriteStartElement (info.TypeName, info.TypeNs, true);
667                                         Writer.WriteAttributeString ("id", GetId (o, false));
668
669                                         if (td.SchemaType != SchemaTypes.Array) // Array use its own "arrayType" attribute
670                                                 WriteXsiType(info.TypeName, info.TypeNs);
671
672                                         info.Callback (o);
673                                         WriteEndElement ();
674                                 } else if (IsPrimitiveArray (td)) {
675                                         WriteArray (o, td);
676                                 }
677                         }
678                 }
679                 
680                 bool IsPrimitiveArray (TypeData td)
681                 {
682                         if (td.SchemaType == SchemaTypes.Array) {
683                                 if (td.ListItemTypeData.SchemaType == SchemaTypes.Primitive || td.ListItemType == typeof(object))
684                                         return true;
685                                 return IsPrimitiveArray (td.ListItemTypeData);
686                         } else
687                                 return false;
688                 }
689
690                 void WriteArray (object o, TypeData td)
691                 {
692                         TypeData itemTypeData = td;
693                         string xmlType;
694                         int nDims = -1;
695
696                         do {
697                                 itemTypeData = itemTypeData.ListItemTypeData;
698                                 xmlType = itemTypeData.XmlType;
699                                 nDims++;
700                         }
701                         while (itemTypeData.SchemaType == SchemaTypes.Array );
702
703                         while (nDims-- > 0)
704                                 xmlType += "[]";
705
706                         WriteStartElement("Array", XmlSerializer.EncodingNamespace, true);
707                         Writer.WriteAttributeString("id", GetId(o, false));
708                         if (td.SchemaType == SchemaTypes.Array) {
709                                 Array a = (Array)o;
710                                 int len = a.Length;
711                                 Writer.WriteAttributeString("arrayType", XmlSerializer.EncodingNamespace, GetQualifiedName(xmlType, XmlSchema.Namespace) + "[" + len.ToString() + "]");
712                                 for (int i = 0; i < len; i++) {
713                                         WritePotentiallyReferencingElement("Item", "", a.GetValue(i), td.ListItemType, false, true);
714                                 }
715                         }
716                         WriteEndElement();
717                 }
718
719
720                 protected void WriteReferencingElement (string n, string ns, object o)
721                 {
722                         WriteReferencingElement (n, ns, o, false);
723                 }
724
725                 protected void WriteReferencingElement (string n, string ns, object o, bool isNullable)
726                 {
727                         if (o == null) 
728                         {
729                                 if (isNullable) WriteNullTagEncoded (n, ns);
730                                 return;
731                         }
732                         else
733                         {
734                                 CheckReferenceQueue ();
735                                 if (!AlreadyQueued (o)) referencedElements.Enqueue (o);
736
737                                 Writer.WriteStartElement (n, ns);
738                                 Writer.WriteAttributeString ("href", "#" + GetId (o, true));
739                                 Writer.WriteEndElement ();
740                         }
741                 }
742
743                 void CheckReferenceQueue ()
744                 {
745                         if (referencedElements == null)  
746                         {
747                                 referencedElements = new Queue ();
748                                 InitCallbacks ();
749                         }
750                 }
751
752                 [MonoTODO]
753                 protected void WriteRpcResult (string name, string ns)
754                 {
755                         throw new NotImplementedException ();
756                 }
757
758                 protected void WriteSerializable (IXmlSerializable serializable, string name, string ns, bool isNullable)
759                 {
760                         WriteSerializable (serializable, name, ns, isNullable, true);
761                 }
762
763                 protected
764                 void WriteSerializable (IXmlSerializable serializable, string name, string ns, bool isNullable, bool wrapped)
765                 {
766                         if (serializable == null)
767                         {
768                                 if (isNullable && wrapped) WriteNullTagLiteral (name, ns);
769                                 return;
770                         }
771                         else
772                         {
773                                 if (wrapped)
774                                         Writer.WriteStartElement (name, ns);
775                                 serializable.WriteXml (Writer);
776                                 if (wrapped)
777                                         Writer.WriteEndElement ();
778                         }
779                 }
780
781                 protected void WriteStartDocument ()
782                 {
783                         if (Writer.WriteState == WriteState.Start)
784                                 Writer.WriteStartDocument ();
785                 }
786
787                 protected void WriteStartElement (string name)
788                 {
789                         WriteStartElement (name, String.Empty, null, false);
790                 }
791
792                 protected void WriteStartElement (string name, string ns)
793                 {
794                         WriteStartElement (name, ns, null, false);
795                 }
796
797                 protected void WriteStartElement (string name, string ns, bool writePrefixed)
798                 {
799                         WriteStartElement (name, ns, null, writePrefixed);
800                 }
801
802                 protected void WriteStartElement (string name, string ns, object o)
803                 {
804                         WriteStartElement (name, ns, o, false);
805                 }
806
807                 protected void WriteStartElement (string name, string ns, object o, bool writePrefixed)
808                 {
809                         WriteStartElement (name, ns, o, writePrefixed, namespaces);
810                 }
811
812                 protected void WriteStartElement (string name, string ns, Object o, bool writePrefixed, XmlSerializerNamespaces xmlns)
813                 {
814                         WriteStartElement (name, ns, o, writePrefixed, xmlns != null ? xmlns.ToArray () : null);
815                 }
816
817                 void WriteStartElement (string name, string ns, object o, bool writePrefixed, ICollection namespaces)
818                 {
819                         if (o != null)
820                         {
821                                 if (serializedObjects.Contains (o))
822                                         throw new InvalidOperationException ("A circular reference was detected while serializing an object of type " + o.GetType().Name);
823                                 else
824                                         serializedObjects [o] = o;
825                         }
826                         
827                         string prefix = null;
828                         
829                         if (topLevelElement && ns != null && ns.Length != 0)
830                         {
831                                 if (namespaces != null)
832                                         foreach (XmlQualifiedName qn in namespaces)
833                                                 if (qn.Namespace == ns) {
834                                                         prefix = qn.Name;
835                                                         writePrefixed = true;
836                                                         break;
837                                                 }
838                         }
839
840                         if (writePrefixed && ns != string.Empty)
841                         {
842                                 name = XmlCustomFormatter.FromXmlName (name);
843                                 
844                                 if (prefix == null)
845                                         prefix = Writer.LookupPrefix (ns);
846                                 if (prefix == null || prefix.Length == 0)
847                                         prefix = "q" + (++qnameCount);
848                                 Writer.WriteStartElement (prefix, name, ns);
849                         } else
850                                 Writer.WriteStartElement (name, ns);
851
852                         if (topLevelElement) 
853                         {
854                                 if (namespaces != null) {
855                                         foreach (XmlQualifiedName qn in namespaces)
856                                         {
857                                                 string currentPrefix = Writer.LookupPrefix (qn.Namespace);
858                                                 if (currentPrefix != null && currentPrefix.Length != 0) continue;
859                                                 
860                                                 WriteAttribute ("xmlns",qn.Name,xmlNamespace,qn.Namespace);
861                                         }
862                                 }
863                                 topLevelElement = false;
864                         }
865                 }
866
867                 protected void WriteTypedPrimitive (string name, string ns, object o, bool xsiType)
868                 {
869                         string value;
870                         TypeData td = TypeTranslator.GetTypeData (o.GetType (), null, true);
871                         if (td.SchemaType != SchemaTypes.Primitive)
872                                 throw new InvalidOperationException (String.Format ("The type of the argument object '{0}' is not primitive.", td.FullTypeName));
873
874                         if (name == null) {
875                                 ns = td.IsXsdType ? XmlSchema.Namespace : XmlSerializer.WsdlTypesNamespace;
876                                 name = td.XmlType;
877                         }
878                         else
879                                 name = XmlCustomFormatter.FromXmlName (name);
880                         Writer.WriteStartElement (name, ns);
881
882                         if (o is XmlQualifiedName)
883                                 value = FromXmlQualifiedName ((XmlQualifiedName) o);
884                         else
885                                 value = XmlCustomFormatter.ToXmlString (td, o);
886
887                         if (xsiType)
888                         {
889                                 if (td.SchemaType != SchemaTypes.Primitive)
890                                         throw new InvalidOperationException (string.Format (unexpectedTypeError, o.GetType().FullName));
891                                 WriteXsiType (td.XmlType, td.IsXsdType ? XmlSchema.Namespace : XmlSerializer.WsdlTypesNamespace);
892                         }
893
894                         WriteValue (value);
895
896                         Writer.WriteEndElement ();
897                 }
898
899                 protected void WriteValue (byte[] value)
900                 {
901                         Writer.WriteBase64 (value, 0, value.Length);
902                 }
903
904                 protected void WriteValue (string value)
905                 {
906                         if (value != null)
907                                 Writer.WriteString (value);
908                 }
909
910                 protected void WriteXmlAttribute (XmlNode node)
911                 {
912                         WriteXmlAttribute (node, null);
913                 }
914
915                 protected void WriteXmlAttribute (XmlNode node, object container)
916                 {
917                         XmlAttribute attr = node as XmlAttribute;
918                         if (attr == null)
919                                 throw new InvalidOperationException ("The node must be either type XmlAttribute or a derived type.");
920                         
921                         if (attr.NamespaceURI == XmlSerializer.WsdlNamespace)
922                         {
923                                 // The wsdl arrayType attribute needs special handling
924                                 if (attr.LocalName == "arrayType") {
925                                         string ns, type, dimensions;
926                                         TypeTranslator.ParseArrayType (attr.Value, out type, out ns, out dimensions);
927                                         string value = GetQualifiedName (type + dimensions, ns);
928                                         WriteAttribute (attr.Prefix, attr.LocalName, attr.NamespaceURI, value);
929                                         return;
930                                 }
931                         }
932                         
933                         WriteAttribute (attr.Prefix, attr.LocalName, attr.NamespaceURI, attr.Value);
934                 }
935
936                 protected void WriteXsiType (string name, string ns)
937                 {
938                         if (ns != null && ns != string.Empty)
939                                 WriteAttribute ("type", XmlSchema.InstanceNamespace, GetQualifiedName (name, ns));
940                         else
941                                 WriteAttribute ("type", XmlSchema.InstanceNamespace, name);
942                 }
943                 
944
945                 protected Exception CreateInvalidAnyTypeException (object o)
946                 {
947                         if (o == null)
948                                 return new InvalidOperationException ("null is invalid as anyType in XmlSerializer");
949                         else
950                                 return CreateInvalidAnyTypeException (o.GetType ());
951                 }
952                 
953                 protected Exception CreateInvalidAnyTypeException (Type type)
954                 {
955                         return new InvalidOperationException (String.Format ("An object of type '{0}' is invalid as anyType in XmlSerializer", type));
956                 }
957
958                 protected Exception CreateInvalidEnumValueException (object value, string typeName)
959                 {
960                         return new InvalidOperationException (string.Format(CultureInfo.CurrentCulture,
961                                 "'{0}' is not a valid value for {1}.", value, typeName));
962                 }
963
964                 protected static string FromEnum (long value, string[] values, long[] ids, string typeName)
965                 {
966                         return XmlCustomFormatter.FromEnum (value, values, ids, typeName);
967                 }
968
969                 [MonoTODO]
970                 protected string FromXmlQualifiedName (XmlQualifiedName xmlQualifiedName, bool ignoreEmpty)
971                 {
972                         throw new NotImplementedException ();
973                 }
974                 
975                 [MonoTODO]
976                 protected static Assembly ResolveDynamicAssembly (string assemblyFullName)
977                 {
978                         throw new NotImplementedException ();
979                 }
980                 
981                 [MonoTODO]
982                 protected bool EscapeName
983                 {
984                         get { throw new NotImplementedException(); }
985                         set { throw new NotImplementedException(); }
986                 }
987
988                 #endregion
989
990                 class WriteCallbackInfo
991                 {
992                         public Type Type;
993                         public string TypeName;
994                         public string TypeNs;
995                         public XmlSerializationWriteCallback Callback;
996                 }
997         }
998 }