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 XmlSerializationWriter()67 protected XmlSerializationWriter () 68 { 69 qnameCount = 0; 70 serializedObjects = new Hashtable (); 71 } 72 Initialize(XmlWriter writer, XmlSerializerNamespaces nss)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 AddWriteCallback(Type type, string typeName, string typeNs, XmlSerializationWriteCallback callback)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 CreateChoiceIdentifierValueException(string value, string identifier, string name, string ns)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 CreateInvalidChoiceIdentifierValueException(string type, string identifier)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 CreateMismatchChoiceException(string value, string elementName, string enumValue)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 CreateUnknownAnyElementException(string name, string ns)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 CreateUnknownTypeException(object o)144 protected Exception CreateUnknownTypeException (object o) 145 { 146 return CreateUnknownTypeException (o.GetType ()); 147 } 148 CreateUnknownTypeException(Type type)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 FromByteArrayBase64(byte[] value)155 protected static byte[] FromByteArrayBase64 (byte[] value) 156 { 157 return value; 158 } 159 FromByteArrayHex(byte[] value)160 protected static string FromByteArrayHex (byte[] value) 161 { 162 return XmlCustomFormatter.FromByteArrayHex (value); 163 } 164 FromChar(char value)165 protected static string FromChar (char value) 166 { 167 return XmlCustomFormatter.FromChar (value); 168 } 169 FromDate(DateTime value)170 protected static string FromDate (DateTime value) 171 { 172 return XmlCustomFormatter.FromDate (value); 173 } 174 FromDateTime(DateTime value)175 protected static string FromDateTime (DateTime value) 176 { 177 return XmlCustomFormatter.FromDateTime (value); 178 } 179 FromEnum(long value, string[] values, long[] ids)180 protected static string FromEnum (long value, string[] values, long[] ids) 181 { 182 return XmlCustomFormatter.FromEnum (value, values, ids); 183 } 184 FromTime(DateTime value)185 protected static string FromTime (DateTime value) 186 { 187 return XmlCustomFormatter.FromTime (value); 188 } 189 FromXmlName(string name)190 protected static string FromXmlName (string name) 191 { 192 return XmlCustomFormatter.FromXmlName (name); 193 } 194 FromXmlNCName(string ncName)195 protected static string FromXmlNCName (string ncName) 196 { 197 return XmlCustomFormatter.FromXmlNCName (ncName); 198 } 199 FromXmlNmToken(string nmToken)200 protected static string FromXmlNmToken (string nmToken) 201 { 202 return XmlCustomFormatter.FromXmlNmToken (nmToken); 203 } 204 FromXmlNmTokens(string nmTokens)205 protected static string FromXmlNmTokens (string nmTokens) 206 { 207 return XmlCustomFormatter.FromXmlNmTokens (nmTokens); 208 } 209 FromXmlQualifiedName(XmlQualifiedName xmlQualifiedName)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 GetId(object o, bool addToReferencesList)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 AlreadyQueued(object ob)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 GetNamespacePrefix(string ns)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 GetQualifiedName(string name, string ns)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 InitCallbacks()259 protected abstract void InitCallbacks (); 260 TopLevelElement()261 protected void TopLevelElement () 262 { 263 topLevelElement = true; 264 } 265 WriteAttribute(string localName, byte[] value)266 protected void WriteAttribute (string localName, byte[] value) 267 { 268 WriteAttribute (localName, String.Empty, value); 269 } 270 WriteAttribute(string localName, string value)271 protected void WriteAttribute (string localName, string value) 272 { 273 WriteAttribute (String.Empty, localName, String.Empty, value); 274 } 275 WriteAttribute(string localName, string ns, byte[] value)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 WriteAttribute(string localName, string ns, string value)286 protected void WriteAttribute (string localName, string ns, string value) 287 { 288 WriteAttribute (null, localName, ns, value); 289 } 290 WriteAttribute(string prefix, string localName, string ns, string value)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 WriteXmlNode(XmlNode node)299 void WriteXmlNode (XmlNode node) 300 { 301 if (node is XmlDocument) 302 node = ((XmlDocument) node).DocumentElement; 303 304 node.WriteTo (Writer); 305 } 306 WriteElementEncoded(XmlNode node, string name, string ns, bool isNullable, bool any)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 WriteElementLiteral(XmlNode node, string name, string ns, bool isNullable, bool any)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 WriteElementQualifiedName(string localName, XmlQualifiedName value)351 protected void WriteElementQualifiedName (string localName, XmlQualifiedName value) 352 { 353 WriteElementQualifiedName (localName, String.Empty, value, null); 354 } 355 WriteElementQualifiedName(string localName, string ns, XmlQualifiedName value)356 protected void WriteElementQualifiedName (string localName, string ns, XmlQualifiedName value) 357 { 358 WriteElementQualifiedName (localName, ns, value, null); 359 } 360 WriteElementQualifiedName(string localName, XmlQualifiedName value, XmlQualifiedName xsiType)361 protected void WriteElementQualifiedName (string localName, XmlQualifiedName value, XmlQualifiedName xsiType) 362 { 363 WriteElementQualifiedName (localName, String.Empty, value, xsiType); 364 } 365 WriteElementQualifiedName(string localName, string ns, XmlQualifiedName value, XmlQualifiedName xsiType)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 WriteElementString(string localName, string value)375 protected void WriteElementString (string localName, string value) 376 { 377 WriteElementString (localName, String.Empty, value, null); 378 } 379 WriteElementString(string localName, string ns, string value)380 protected void WriteElementString (string localName, string ns, string value) 381 { 382 WriteElementString (localName, ns, value, null); 383 } 384 WriteElementString(string localName, string value, XmlQualifiedName xsiType)385 protected void WriteElementString (string localName, string value, XmlQualifiedName xsiType) 386 { 387 WriteElementString (localName, String.Empty, value, xsiType); 388 } 389 WriteElementString(string localName, string ns, string value, XmlQualifiedName xsiType)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 WriteElementStringRaw(string localName, byte[] value)405 protected void WriteElementStringRaw (string localName, byte[] value) 406 { 407 WriteElementStringRaw (localName, String.Empty, value, null); 408 } 409 WriteElementStringRaw(string localName, string value)410 protected void WriteElementStringRaw (string localName, string value) 411 { 412 WriteElementStringRaw (localName, String.Empty, value, null); 413 } 414 WriteElementStringRaw(string localName, byte[] value, XmlQualifiedName xsiType)415 protected void WriteElementStringRaw (string localName, byte[] value, XmlQualifiedName xsiType) 416 { 417 WriteElementStringRaw (localName, String.Empty, value, xsiType); 418 } 419 WriteElementStringRaw(string localName, string ns, byte[] value)420 protected void WriteElementStringRaw (string localName, string ns, byte[] value) 421 { 422 WriteElementStringRaw (localName, ns, value, null); 423 } 424 WriteElementStringRaw(string localName, string ns, string value)425 protected void WriteElementStringRaw (string localName, string ns, string value) 426 { 427 WriteElementStringRaw (localName, ns, value, null); 428 } 429 WriteElementStringRaw(string localName, string value, XmlQualifiedName xsiType)430 protected void WriteElementStringRaw (string localName, string value, XmlQualifiedName xsiType) 431 { 432 WriteElementStringRaw (localName, String.Empty, value, null); 433 } 434 WriteElementStringRaw(string localName, string ns, byte[] value, XmlQualifiedName xsiType)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 WriteElementStringRaw(string localName, string ns, string value, XmlQualifiedName xsiType)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 WriteEmptyTag(string name)462 protected void WriteEmptyTag (string name) 463 { 464 WriteEmptyTag (name, String.Empty); 465 } 466 WriteEmptyTag(string name, string ns)467 protected void WriteEmptyTag (string name, string ns) 468 { 469 name = XmlCustomFormatter.FromXmlName (name); 470 WriteStartElement (name, ns); 471 WriteEndElement (); 472 } 473 WriteEndElement()474 protected void WriteEndElement () 475 { 476 WriteEndElement (null); 477 } 478 WriteEndElement(object o)479 protected void WriteEndElement (object o) 480 { 481 if (o != null) 482 serializedObjects.Remove (o); 483 484 Writer.WriteEndElement (); 485 } 486 WriteId(object o)487 protected void WriteId (object o) 488 { 489 WriteAttribute ("id", GetId (o, true)); 490 } 491 WriteNamespaceDeclarations(XmlSerializerNamespaces xmlns)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 WriteNullableQualifiedNameEncoded(string name, string ns, XmlQualifiedName value, XmlQualifiedName xsiType)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 WriteNullableQualifiedNameLiteral(string name, string ns, XmlQualifiedName value)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 WriteNullableStringEncoded(string name, string ns, string value, XmlQualifiedName xsiType)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 WriteNullableStringEncodedRaw(string name, string ns, byte[] value, XmlQualifiedName xsiType)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 WriteNullableStringEncodedRaw(string name, string ns, string value, XmlQualifiedName xsiType)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 WriteNullableStringLiteral(string name, string ns, string value)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 WriteNullableStringLiteralRaw(string name, string ns, byte[] value)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 WriteNullableStringLiteralRaw(string name, string ns, string value)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 WriteNullTagEncoded(string name)566 protected void WriteNullTagEncoded (string name) 567 { 568 WriteNullTagEncoded (name, String.Empty); 569 } 570 WriteNullTagEncoded(string name, string ns)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 WriteNullTagLiteral(string name)578 protected void WriteNullTagLiteral (string name) 579 { 580 WriteNullTagLiteral (name, String.Empty); 581 } 582 WriteNullTagLiteral(string name, string ns)583 protected void WriteNullTagLiteral (string name, string ns) 584 { 585 WriteStartElement (name, ns); 586 Writer.WriteAttributeString ("nil", XmlSchema.InstanceNamespace, "true"); 587 WriteEndElement (); 588 } 589 WritePotentiallyReferencingElement(string n, string ns, object o)590 protected void WritePotentiallyReferencingElement (string n, string ns, object o) 591 { 592 WritePotentiallyReferencingElement (n, ns, o, null, false, false); 593 } 594 WritePotentiallyReferencingElement(string n, string ns, object o, Type ambientType)595 protected void WritePotentiallyReferencingElement (string n, string ns, object o, Type ambientType) 596 { 597 WritePotentiallyReferencingElement (n, ns, o, ambientType, false, false); 598 } 599 WritePotentiallyReferencingElement(string n, string ns, object o, Type ambientType, bool suppressReference)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 WritePotentiallyReferencingElement(string n, string ns, object o, Type ambientType, bool suppressReference, bool isNullable)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 WriteReferencedElements()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 IsPrimitiveArray(TypeData td)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 WriteArray(object o, TypeData td)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 WriteReferencingElement(string n, string ns, object o)720 protected void WriteReferencingElement (string n, string ns, object o) 721 { 722 WriteReferencingElement (n, ns, o, false); 723 } 724 WriteReferencingElement(string n, string ns, object o, bool isNullable)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 CheckReferenceQueue()743 void CheckReferenceQueue () 744 { 745 if (referencedElements == null) 746 { 747 referencedElements = new Queue (); 748 InitCallbacks (); 749 } 750 } 751 752 [MonoTODO] WriteRpcResult(string name, string ns)753 protected void WriteRpcResult (string name, string ns) 754 { 755 throw new NotImplementedException (); 756 } 757 WriteSerializable(IXmlSerializable serializable, string name, string ns, bool isNullable)758 protected void WriteSerializable (IXmlSerializable serializable, string name, string ns, bool isNullable) 759 { 760 WriteSerializable (serializable, name, ns, isNullable, true); 761 } 762 763 protected WriteSerializable(IXmlSerializable serializable, string name, string ns, bool isNullable, bool wrapped)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 WriteStartDocument()781 protected void WriteStartDocument () 782 { 783 if (Writer.WriteState == WriteState.Start) 784 Writer.WriteStartDocument (); 785 } 786 WriteStartElement(string name)787 protected void WriteStartElement (string name) 788 { 789 WriteStartElement (name, String.Empty, null, false); 790 } 791 WriteStartElement(string name, string ns)792 protected void WriteStartElement (string name, string ns) 793 { 794 WriteStartElement (name, ns, null, false); 795 } 796 WriteStartElement(string name, string ns, bool writePrefixed)797 protected void WriteStartElement (string name, string ns, bool writePrefixed) 798 { 799 WriteStartElement (name, ns, null, writePrefixed); 800 } 801 WriteStartElement(string name, string ns, object o)802 protected void WriteStartElement (string name, string ns, object o) 803 { 804 WriteStartElement (name, ns, o, false); 805 } 806 WriteStartElement(string name, string ns, object o, bool writePrefixed)807 protected void WriteStartElement (string name, string ns, object o, bool writePrefixed) 808 { 809 WriteStartElement (name, ns, o, writePrefixed, namespaces); 810 } 811 WriteStartElement(string name, string ns, Object o, bool writePrefixed, XmlSerializerNamespaces xmlns)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 WriteStartElement(string name, string ns, object o, bool writePrefixed, ICollection namespaces)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 WriteTypedPrimitive(string name, string ns, object o, bool xsiType)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 WriteValue(byte[] value)899 protected void WriteValue (byte[] value) 900 { 901 Writer.WriteBase64 (value, 0, value.Length); 902 } 903 WriteValue(string value)904 protected void WriteValue (string value) 905 { 906 if (value != null) 907 Writer.WriteString (value); 908 } 909 WriteXmlAttribute(XmlNode node)910 protected void WriteXmlAttribute (XmlNode node) 911 { 912 WriteXmlAttribute (node, null); 913 } 914 WriteXmlAttribute(XmlNode node, object container)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 WriteXsiType(string name, string ns)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 CreateInvalidAnyTypeException(object o)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 CreateInvalidAnyTypeException(Type type)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 CreateInvalidEnumValueException(object value, string typeName)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 FromEnum(long value, string[] values, long[] ids, string typeName)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] FromXmlQualifiedName(XmlQualifiedName xmlQualifiedName, bool ignoreEmpty)970 protected string FromXmlQualifiedName (XmlQualifiedName xmlQualifiedName, bool ignoreEmpty) 971 { 972 throw new NotImplementedException (); 973 } 974 975 [MonoTODO] ResolveDynamicAssembly(string assemblyFullName)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 } 999