1 // Licensed to the .NET Foundation under one or more agreements. 2 // The .NET Foundation licenses this file to you under the MIT license. 3 // See the LICENSE file in the project root for more information. 4 5 using System.Collections.ObjectModel; 6 using System.Runtime.Serialization; 7 using System.Xml.Serialization; 8 using System.Collections.Generic; 9 using System.Xml; 10 using System.Xml.Schema; 11 using System.ServiceModel.Channels; 12 using System.Diagnostics; 13 using System.Diagnostics.CodeAnalysis; 14 using System.Runtime.CompilerServices; 15 16 namespace System.ServiceModel.Syndication 17 { CreateInlineCategoriesDelegate()18 internal delegate InlineCategoriesDocument CreateInlineCategoriesDelegate(); CreateReferencedCategoriesDelegate()19 internal delegate ReferencedCategoriesDocument CreateReferencedCategoriesDelegate(); 20 21 [XmlRoot(ElementName = App10Constants.Service, Namespace = App10Constants.Namespace)] 22 public class AtomPub10ServiceDocumentFormatter : ServiceDocumentFormatter, IXmlSerializable 23 { 24 private Type _documentType; 25 private int _maxExtensionSize; 26 private bool _preserveAttributeExtensions; 27 private bool _preserveElementExtensions; 28 AtomPub10ServiceDocumentFormatter()29 public AtomPub10ServiceDocumentFormatter() 30 : this(typeof(ServiceDocument)) 31 { 32 } 33 AtomPub10ServiceDocumentFormatter(Type documentTypeToCreate)34 public AtomPub10ServiceDocumentFormatter(Type documentTypeToCreate) 35 : base() 36 { 37 if (documentTypeToCreate == null) 38 { 39 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("documentTypeToCreate"); 40 } 41 if (!typeof(ServiceDocument).IsAssignableFrom(documentTypeToCreate)) 42 { 43 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument("documentTypeToCreate", 44 SR.Format(SR.InvalidObjectTypePassed, "documentTypeToCreate", "ServiceDocument")); 45 } 46 _maxExtensionSize = int.MaxValue; 47 _preserveAttributeExtensions = true; 48 _preserveElementExtensions = true; 49 _documentType = documentTypeToCreate; 50 } 51 AtomPub10ServiceDocumentFormatter(ServiceDocument documentToWrite)52 public AtomPub10ServiceDocumentFormatter(ServiceDocument documentToWrite) 53 : base(documentToWrite) 54 { 55 // No need to check that the parameter passed is valid - it is checked by the c'tor of the base class 56 _maxExtensionSize = int.MaxValue; 57 _preserveAttributeExtensions = true; 58 _preserveElementExtensions = true; 59 _documentType = documentToWrite.GetType(); 60 } 61 62 public override string Version 63 { 64 get { return App10Constants.Namespace; } 65 } 66 CanRead(XmlReader reader)67 public override bool CanRead(XmlReader reader) 68 { 69 if (reader == null) 70 { 71 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("reader"); 72 } 73 return reader.IsStartElement(App10Constants.Service, App10Constants.Namespace); 74 } 75 76 [SuppressMessage("Microsoft.Design", "CA1033:InterfaceMethodsShouldBeCallableByChildTypes", Justification = "The IXmlSerializable implementation is only for exposing under WCF DataContractSerializer. The funcionality is exposed to derived class through the ReadFrom\\WriteTo methods")] IXmlSerializable.GetSchema()77 XmlSchema IXmlSerializable.GetSchema() 78 { 79 return null; 80 } 81 82 [SuppressMessage("Microsoft.Design", "CA1033:InterfaceMethodsShouldBeCallableByChildTypes", Justification = "The IXmlSerializable implementation is only for exposing under WCF DataContractSerializer. The funcionality is exposed to derived class through the ReadFrom\\WriteTo methods")] IXmlSerializable.ReadXml(XmlReader reader)83 void IXmlSerializable.ReadXml(XmlReader reader) 84 { 85 if (reader == null) 86 { 87 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("reader"); 88 } 89 TraceServiceDocumentReadBegin(); 90 ReadDocument(reader); 91 TraceServiceDocumentReadEnd(); 92 } 93 94 [SuppressMessage("Microsoft.Design", "CA1033:InterfaceMethodsShouldBeCallableByChildTypes", Justification = "The IXmlSerializable implementation is only for exposing under WCF DataContractSerializer. The funcionality is exposed to derived class through the ReadFrom\\WriteTo methods")] IXmlSerializable.WriteXml(XmlWriter writer)95 void IXmlSerializable.WriteXml(XmlWriter writer) 96 { 97 if (writer == null) 98 { 99 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("writer"); 100 } 101 if (this.Document == null) 102 { 103 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.Format(SR.DocumentFormatterDoesNotHaveDocument))); 104 } 105 TraceServiceDocumentWriteBegin(); 106 WriteDocument(writer); 107 TraceServiceDocumentWriteEnd(); 108 } 109 ReadFrom(XmlReader reader)110 public override void ReadFrom(XmlReader reader) 111 { 112 if (reader == null) 113 { 114 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("reader"); 115 } 116 reader.MoveToContent(); 117 if (!CanRead(reader)) 118 { 119 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(SR.Format(SR.UnknownDocumentXml, reader.LocalName, reader.NamespaceURI))); 120 } 121 TraceServiceDocumentReadBegin(); 122 ReadDocument(reader); 123 TraceServiceDocumentReadEnd(); 124 } 125 WriteTo(XmlWriter writer)126 public override void WriteTo(XmlWriter writer) 127 { 128 if (writer == null) 129 { 130 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("writer"); 131 } 132 if (this.Document == null) 133 { 134 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.Format(SR.DocumentFormatterDoesNotHaveDocument))); 135 } 136 TraceServiceDocumentWriteBegin(); 137 writer.WriteStartElement(App10Constants.Prefix, App10Constants.Service, App10Constants.Namespace); 138 WriteDocument(writer); 139 writer.WriteEndElement(); 140 TraceServiceDocumentWriteEnd(); 141 } 142 ReadCategories(XmlReader reader, Uri baseUri, CreateInlineCategoriesDelegate inlineCategoriesFactory, CreateReferencedCategoriesDelegate referencedCategoriesFactory, string version, bool preserveElementExtensions, bool preserveAttributeExtensions, int maxExtensionSize)143 internal static CategoriesDocument ReadCategories(XmlReader reader, Uri baseUri, CreateInlineCategoriesDelegate inlineCategoriesFactory, CreateReferencedCategoriesDelegate referencedCategoriesFactory, string version, bool preserveElementExtensions, bool preserveAttributeExtensions, int maxExtensionSize) 144 { 145 string link = reader.GetAttribute(App10Constants.Href, string.Empty); 146 if (string.IsNullOrEmpty(link)) 147 { 148 InlineCategoriesDocument inlineCategories = inlineCategoriesFactory(); 149 ReadInlineCategories(reader, inlineCategories, baseUri, version, preserveElementExtensions, preserveAttributeExtensions, maxExtensionSize); 150 return inlineCategories; 151 } 152 else 153 { 154 ReferencedCategoriesDocument referencedCategories = referencedCategoriesFactory(); 155 ReadReferencedCategories(reader, referencedCategories, baseUri, new Uri(link, UriKind.RelativeOrAbsolute), version, preserveElementExtensions, preserveAttributeExtensions, maxExtensionSize); 156 return referencedCategories; 157 } 158 } 159 TraceServiceDocumentReadBegin()160 internal static void TraceServiceDocumentReadBegin() 161 { 162 } 163 TraceServiceDocumentReadEnd()164 internal static void TraceServiceDocumentReadEnd() 165 { 166 } 167 TraceServiceDocumentWriteBegin()168 internal static void TraceServiceDocumentWriteBegin() 169 { 170 } 171 TraceServiceDocumentWriteEnd()172 internal static void TraceServiceDocumentWriteEnd() 173 { 174 } 175 WriteCategoriesInnerXml(XmlWriter writer, CategoriesDocument categories, Uri baseUri, string version)176 internal static void WriteCategoriesInnerXml(XmlWriter writer, CategoriesDocument categories, Uri baseUri, string version) 177 { 178 Uri baseUriToWrite = FeedUtils.GetBaseUriToWrite(baseUri, categories.BaseUri); 179 if (baseUriToWrite != null) 180 { 181 WriteXmlBase(writer, baseUriToWrite); 182 } 183 if (!string.IsNullOrEmpty(categories.Language)) 184 { 185 WriteXmlLang(writer, categories.Language); 186 } 187 if (categories.IsInline) 188 { 189 WriteInlineCategoriesContent(writer, (InlineCategoriesDocument)categories, version); 190 } 191 else 192 { 193 WriteReferencedCategoriesContent(writer, (ReferencedCategoriesDocument)categories, version); 194 } 195 } 196 CreateDocumentInstance()197 protected override ServiceDocument CreateDocumentInstance() 198 { 199 if (_documentType == typeof(ServiceDocument)) 200 { 201 return new ServiceDocument(); 202 } 203 else 204 { 205 return (ServiceDocument)Activator.CreateInstance(_documentType); 206 } 207 } 208 ReadInlineCategories(XmlReader reader, InlineCategoriesDocument inlineCategories, Uri baseUri, string version, bool preserveElementExtensions, bool preserveAttributeExtensions, int maxExtensionSize)209 private static void ReadInlineCategories(XmlReader reader, InlineCategoriesDocument inlineCategories, Uri baseUri, string version, bool preserveElementExtensions, bool preserveAttributeExtensions, int maxExtensionSize) 210 { 211 inlineCategories.BaseUri = baseUri; 212 if (reader.HasAttributes) 213 { 214 while (reader.MoveToNextAttribute()) 215 { 216 if (reader.LocalName == "base" && reader.NamespaceURI == Atom10FeedFormatter.XmlNs) 217 { 218 inlineCategories.BaseUri = FeedUtils.CombineXmlBase(inlineCategories.BaseUri, reader.Value); 219 } 220 else if (reader.LocalName == "lang" && reader.NamespaceURI == Atom10FeedFormatter.XmlNs) 221 { 222 inlineCategories.Language = reader.Value; 223 } 224 else if (reader.LocalName == App10Constants.Fixed && reader.NamespaceURI == string.Empty) 225 { 226 inlineCategories.IsFixed = (reader.Value == "yes"); 227 } 228 else if (reader.LocalName == Atom10Constants.SchemeTag && reader.NamespaceURI == string.Empty) 229 { 230 inlineCategories.Scheme = reader.Value; 231 } 232 else 233 { 234 string ns = reader.NamespaceURI; 235 string name = reader.LocalName; 236 if (FeedUtils.IsXmlns(name, ns) || FeedUtils.IsXmlSchemaType(name, ns)) 237 { 238 continue; 239 } 240 string val = reader.Value; 241 if (!TryParseAttribute(name, ns, val, inlineCategories, version)) 242 { 243 if (preserveAttributeExtensions) 244 { 245 inlineCategories.AttributeExtensions.Add(new XmlQualifiedName(reader.LocalName, reader.NamespaceURI), reader.Value); 246 } 247 else 248 { 249 SyndicationFeedFormatter.TraceSyndicationElementIgnoredOnRead(reader); 250 } 251 } 252 } 253 } 254 } 255 SyndicationFeedFormatter.MoveToStartElement(reader); 256 bool isEmptyElement = reader.IsEmptyElement; 257 reader.ReadStartElement(); 258 if (!isEmptyElement) 259 { 260 XmlBuffer buffer = null; 261 XmlDictionaryWriter extWriter = null; 262 try 263 { 264 while (reader.IsStartElement()) 265 { 266 if (reader.IsStartElement(Atom10Constants.CategoryTag, Atom10Constants.Atom10Namespace)) 267 { 268 SyndicationCategory category = CreateCategory(inlineCategories); 269 Atom10FeedFormatter.ReadCategory(reader, category, version, preserveAttributeExtensions, preserveElementExtensions, maxExtensionSize); 270 if (category.Scheme == null) 271 { 272 category.Scheme = inlineCategories.Scheme; 273 } 274 inlineCategories.Categories.Add(category); 275 } 276 else if (!TryParseElement(reader, inlineCategories, version)) 277 { 278 if (preserveElementExtensions) 279 { 280 SyndicationFeedFormatter.CreateBufferIfRequiredAndWriteNode(ref buffer, ref extWriter, reader, maxExtensionSize); 281 } 282 else 283 { 284 SyndicationFeedFormatter.TraceSyndicationElementIgnoredOnRead(reader); 285 reader.Skip(); 286 } 287 } 288 } 289 LoadElementExtensions(buffer, extWriter, inlineCategories); 290 } 291 finally 292 { 293 if (extWriter != null) 294 { 295 extWriter.Close(); 296 } 297 } 298 reader.ReadEndElement(); 299 } 300 } 301 ReadReferencedCategories(XmlReader reader, ReferencedCategoriesDocument referencedCategories, Uri baseUri, Uri link, string version, bool preserveElementExtensions, bool preserveAttributeExtensions, int maxExtensionSize)302 private static void ReadReferencedCategories(XmlReader reader, ReferencedCategoriesDocument referencedCategories, Uri baseUri, Uri link, string version, bool preserveElementExtensions, bool preserveAttributeExtensions, int maxExtensionSize) 303 { 304 referencedCategories.BaseUri = baseUri; 305 referencedCategories.Link = link; 306 if (reader.HasAttributes) 307 { 308 while (reader.MoveToNextAttribute()) 309 { 310 if (reader.LocalName == "base" && reader.NamespaceURI == Atom10FeedFormatter.XmlNs) 311 { 312 referencedCategories.BaseUri = FeedUtils.CombineXmlBase(referencedCategories.BaseUri, reader.Value); 313 } 314 else if (reader.LocalName == "lang" && reader.NamespaceURI == Atom10FeedFormatter.XmlNs) 315 { 316 referencedCategories.Language = reader.Value; 317 } 318 else if (reader.LocalName == App10Constants.Href && reader.NamespaceURI == string.Empty) 319 { 320 continue; 321 } 322 else 323 { 324 string ns = reader.NamespaceURI; 325 string name = reader.LocalName; 326 if (FeedUtils.IsXmlns(name, ns) || FeedUtils.IsXmlSchemaType(name, ns)) 327 { 328 continue; 329 } 330 string val = reader.Value; 331 if (!TryParseAttribute(name, ns, val, referencedCategories, version)) 332 { 333 if (preserveAttributeExtensions) 334 { 335 referencedCategories.AttributeExtensions.Add(new XmlQualifiedName(reader.LocalName, reader.NamespaceURI), reader.Value); 336 } 337 else 338 { 339 SyndicationFeedFormatter.TraceSyndicationElementIgnoredOnRead(reader); 340 } 341 } 342 } 343 } 344 } 345 reader.MoveToElement(); 346 bool isEmptyElement = reader.IsEmptyElement; 347 reader.ReadStartElement(); 348 if (!isEmptyElement) 349 { 350 XmlBuffer buffer = null; 351 XmlDictionaryWriter extWriter = null; 352 try 353 { 354 while (reader.IsStartElement()) 355 { 356 if (!TryParseElement(reader, referencedCategories, version)) 357 { 358 if (preserveElementExtensions) 359 { 360 SyndicationFeedFormatter.CreateBufferIfRequiredAndWriteNode(ref buffer, ref extWriter, reader, maxExtensionSize); 361 } 362 else 363 { 364 SyndicationFeedFormatter.TraceSyndicationElementIgnoredOnRead(reader); 365 reader.Skip(); 366 } 367 } 368 } 369 LoadElementExtensions(buffer, extWriter, referencedCategories); 370 } 371 finally 372 { 373 if (extWriter != null) 374 { 375 extWriter.Close(); 376 } 377 } 378 reader.ReadEndElement(); 379 } 380 } 381 WriteCategories(XmlWriter writer, CategoriesDocument categories, Uri baseUri, string version)382 private static void WriteCategories(XmlWriter writer, CategoriesDocument categories, Uri baseUri, string version) 383 { 384 writer.WriteStartElement(App10Constants.Prefix, App10Constants.Categories, App10Constants.Namespace); 385 WriteCategoriesInnerXml(writer, categories, baseUri, version); 386 writer.WriteEndElement(); 387 } 388 WriteInlineCategoriesContent(XmlWriter writer, InlineCategoriesDocument categories, string version)389 private static void WriteInlineCategoriesContent(XmlWriter writer, InlineCategoriesDocument categories, string version) 390 { 391 if (!string.IsNullOrEmpty(categories.Scheme)) 392 { 393 writer.WriteAttributeString(Atom10Constants.SchemeTag, categories.Scheme); 394 } 395 // by default, categories are not fixed 396 if (categories.IsFixed) 397 { 398 writer.WriteAttributeString(App10Constants.Fixed, "yes"); 399 } 400 WriteAttributeExtensions(writer, categories, version); 401 for (int i = 0; i < categories.Categories.Count; ++i) 402 { 403 Atom10FeedFormatter.WriteCategory(writer, categories.Categories[i], version); 404 } 405 WriteElementExtensions(writer, categories, version); 406 } 407 WriteReferencedCategoriesContent(XmlWriter writer, ReferencedCategoriesDocument categories, string version)408 private static void WriteReferencedCategoriesContent(XmlWriter writer, ReferencedCategoriesDocument categories, string version) 409 { 410 if (categories.Link != null) 411 { 412 writer.WriteAttributeString(App10Constants.Href, FeedUtils.GetUriString(categories.Link)); 413 } 414 WriteAttributeExtensions(writer, categories, version); 415 WriteElementExtensions(writer, categories, version); 416 } 417 WriteXmlBase(XmlWriter writer, Uri baseUri)418 private static void WriteXmlBase(XmlWriter writer, Uri baseUri) 419 { 420 writer.WriteAttributeString("xml", "base", Atom10FeedFormatter.XmlNs, FeedUtils.GetUriString(baseUri)); 421 } 422 WriteXmlLang(XmlWriter writer, string lang)423 private static void WriteXmlLang(XmlWriter writer, string lang) 424 { 425 writer.WriteAttributeString("xml", "lang", Atom10FeedFormatter.XmlNs, lang); 426 } 427 ReadCollection(XmlReader reader, Workspace workspace)428 private ResourceCollectionInfo ReadCollection(XmlReader reader, Workspace workspace) 429 { 430 ResourceCollectionInfo result = CreateCollection(workspace); 431 result.BaseUri = workspace.BaseUri; 432 if (reader.HasAttributes) 433 { 434 while (reader.MoveToNextAttribute()) 435 { 436 if (reader.LocalName == "base" && reader.NamespaceURI == Atom10FeedFormatter.XmlNs) 437 { 438 result.BaseUri = FeedUtils.CombineXmlBase(result.BaseUri, reader.Value); 439 } 440 else if (reader.LocalName == App10Constants.Href && reader.NamespaceURI == string.Empty) 441 { 442 result.Link = new Uri(reader.Value, UriKind.RelativeOrAbsolute); 443 } 444 else 445 { 446 string ns = reader.NamespaceURI; 447 string name = reader.LocalName; 448 if (FeedUtils.IsXmlns(name, ns) || FeedUtils.IsXmlSchemaType(name, ns)) 449 { 450 continue; 451 } 452 string val = reader.Value; 453 if (!TryParseAttribute(name, ns, val, result, this.Version)) 454 { 455 if (_preserveAttributeExtensions) 456 { 457 result.AttributeExtensions.Add(new XmlQualifiedName(reader.LocalName, reader.NamespaceURI), reader.Value); 458 } 459 else 460 { 461 SyndicationFeedFormatter.TraceSyndicationElementIgnoredOnRead(reader); 462 } 463 } 464 } 465 } 466 } 467 468 XmlBuffer buffer = null; 469 XmlDictionaryWriter extWriter = null; 470 471 reader.ReadStartElement(); 472 try 473 { 474 while (reader.IsStartElement()) 475 { 476 if (reader.IsStartElement(Atom10Constants.TitleTag, Atom10Constants.Atom10Namespace)) 477 { 478 result.Title = Atom10FeedFormatter.ReadTextContentFrom(reader, "//app:service/app:workspace/app:collection/atom:title[@type]", _preserveAttributeExtensions); 479 } 480 else if (reader.IsStartElement(App10Constants.Categories, App10Constants.Namespace)) 481 { 482 result.Categories.Add(ReadCategories(reader, 483 result.BaseUri, 484 delegate () 485 { 486 return CreateInlineCategories(result); 487 }, 488 489 delegate () 490 { 491 return CreateReferencedCategories(result); 492 }, 493 this.Version, 494 _preserveElementExtensions, 495 _preserveAttributeExtensions, 496 _maxExtensionSize)); 497 } 498 else if (reader.IsStartElement(App10Constants.Accept, App10Constants.Namespace)) 499 { 500 result.Accepts.Add(reader.ReadElementString()); 501 } 502 else if (!TryParseElement(reader, result, this.Version)) 503 { 504 if (_preserveElementExtensions) 505 { 506 SyndicationFeedFormatter.CreateBufferIfRequiredAndWriteNode(ref buffer, ref extWriter, reader, _maxExtensionSize); 507 } 508 else 509 { 510 SyndicationFeedFormatter.TraceSyndicationElementIgnoredOnRead(reader); 511 reader.Skip(); 512 } 513 } 514 } 515 LoadElementExtensions(buffer, extWriter, result); 516 } 517 finally 518 { 519 if (extWriter != null) 520 { 521 extWriter.Close(); 522 } 523 } 524 reader.ReadEndElement(); 525 return result; 526 } 527 ReadDocument(XmlReader reader)528 private void ReadDocument(XmlReader reader) 529 { 530 ServiceDocument result = CreateDocumentInstance(); 531 try 532 { 533 SyndicationFeedFormatter.MoveToStartElement(reader); 534 bool elementIsEmpty = reader.IsEmptyElement; 535 if (reader.HasAttributes) 536 { 537 while (reader.MoveToNextAttribute()) 538 { 539 if (reader.LocalName == "lang" && reader.NamespaceURI == Atom10FeedFormatter.XmlNs) 540 { 541 result.Language = reader.Value; 542 } 543 else if (reader.LocalName == "base" && reader.NamespaceURI == Atom10FeedFormatter.XmlNs) 544 { 545 result.BaseUri = new Uri(reader.Value, UriKind.RelativeOrAbsolute); 546 } 547 else 548 { 549 string ns = reader.NamespaceURI; 550 string name = reader.LocalName; 551 if (FeedUtils.IsXmlns(name, ns) || FeedUtils.IsXmlSchemaType(name, ns)) 552 { 553 continue; 554 } 555 string val = reader.Value; 556 if (!TryParseAttribute(name, ns, val, result, this.Version)) 557 { 558 if (_preserveAttributeExtensions) 559 { 560 result.AttributeExtensions.Add(new XmlQualifiedName(reader.LocalName, reader.NamespaceURI), reader.Value); 561 } 562 else 563 { 564 SyndicationFeedFormatter.TraceSyndicationElementIgnoredOnRead(reader); 565 } 566 } 567 } 568 } 569 } 570 XmlBuffer buffer = null; 571 XmlDictionaryWriter extWriter = null; 572 573 reader.ReadStartElement(); 574 if (!elementIsEmpty) 575 { 576 try 577 { 578 while (reader.IsStartElement()) 579 { 580 if (reader.IsStartElement(App10Constants.Workspace, App10Constants.Namespace)) 581 { 582 result.Workspaces.Add(ReadWorkspace(reader, result)); 583 } 584 else if (!TryParseElement(reader, result, this.Version)) 585 { 586 if (_preserveElementExtensions) 587 { 588 SyndicationFeedFormatter.CreateBufferIfRequiredAndWriteNode(ref buffer, ref extWriter, reader, _maxExtensionSize); 589 } 590 else 591 { 592 SyndicationFeedFormatter.TraceSyndicationElementIgnoredOnRead(reader); 593 reader.Skip(); 594 } 595 } 596 } 597 LoadElementExtensions(buffer, extWriter, result); 598 } 599 finally 600 { 601 if (extWriter != null) 602 { 603 extWriter.Close(); 604 } 605 } 606 } 607 reader.ReadEndElement(); 608 } 609 catch (FormatException e) 610 { 611 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(FeedUtils.AddLineInfo(reader, SR.ErrorParsingDocument), e)); 612 } 613 catch (ArgumentException e) 614 { 615 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(FeedUtils.AddLineInfo(reader, SR.ErrorParsingDocument), e)); 616 } 617 SetDocument(result); 618 } 619 ReadWorkspace(XmlReader reader, ServiceDocument document)620 private Workspace ReadWorkspace(XmlReader reader, ServiceDocument document) 621 { 622 Workspace result = CreateWorkspace(document); 623 result.BaseUri = document.BaseUri; 624 if (reader.HasAttributes) 625 { 626 while (reader.MoveToNextAttribute()) 627 { 628 if (reader.LocalName == "base" && reader.NamespaceURI == Atom10FeedFormatter.XmlNs) 629 { 630 result.BaseUri = FeedUtils.CombineXmlBase(result.BaseUri, reader.Value); 631 } 632 else 633 { 634 string ns = reader.NamespaceURI; 635 string name = reader.LocalName; 636 if (FeedUtils.IsXmlns(name, ns) || FeedUtils.IsXmlSchemaType(name, ns)) 637 { 638 continue; 639 } 640 string val = reader.Value; 641 if (!TryParseAttribute(name, ns, val, result, this.Version)) 642 { 643 if (_preserveAttributeExtensions) 644 { 645 result.AttributeExtensions.Add(new XmlQualifiedName(reader.LocalName, reader.NamespaceURI), reader.Value); 646 } 647 else 648 { 649 SyndicationFeedFormatter.TraceSyndicationElementIgnoredOnRead(reader); 650 } 651 } 652 } 653 } 654 } 655 656 XmlBuffer buffer = null; 657 XmlDictionaryWriter extWriter = null; 658 659 reader.ReadStartElement(); 660 try 661 { 662 while (reader.IsStartElement()) 663 { 664 if (reader.IsStartElement(Atom10Constants.TitleTag, Atom10Constants.Atom10Namespace)) 665 { 666 result.Title = Atom10FeedFormatter.ReadTextContentFrom(reader, "//app:service/app:workspace/atom:title[@type]", _preserveAttributeExtensions); 667 } 668 else if (reader.IsStartElement(App10Constants.Collection, App10Constants.Namespace)) 669 { 670 result.Collections.Add(ReadCollection(reader, result)); 671 } 672 else if (!TryParseElement(reader, result, this.Version)) 673 { 674 if (_preserveElementExtensions) 675 { 676 SyndicationFeedFormatter.CreateBufferIfRequiredAndWriteNode(ref buffer, ref extWriter, reader, _maxExtensionSize); 677 } 678 else 679 { 680 SyndicationFeedFormatter.TraceSyndicationElementIgnoredOnRead(reader); 681 reader.Skip(); 682 } 683 } 684 } 685 LoadElementExtensions(buffer, extWriter, result); 686 } 687 finally 688 { 689 if (extWriter != null) 690 { 691 extWriter.Close(); 692 } 693 } 694 reader.ReadEndElement(); 695 return result; 696 } 697 WriteCollection(XmlWriter writer, ResourceCollectionInfo collection, Uri baseUri)698 private void WriteCollection(XmlWriter writer, ResourceCollectionInfo collection, Uri baseUri) 699 { 700 writer.WriteStartElement(App10Constants.Prefix, App10Constants.Collection, App10Constants.Namespace); 701 Uri baseUriToWrite = FeedUtils.GetBaseUriToWrite(baseUri, collection.BaseUri); 702 if (baseUriToWrite != null) 703 { 704 baseUri = collection.BaseUri; 705 WriteXmlBase(writer, baseUriToWrite); 706 } 707 if (collection.Link != null) 708 { 709 writer.WriteAttributeString(App10Constants.Href, FeedUtils.GetUriString(collection.Link)); 710 } 711 WriteAttributeExtensions(writer, collection, this.Version); 712 if (collection.Title != null) 713 { 714 collection.Title.WriteTo(writer, Atom10Constants.TitleTag, Atom10Constants.Atom10Namespace); 715 } 716 for (int i = 0; i < collection.Accepts.Count; ++i) 717 { 718 writer.WriteElementString(App10Constants.Prefix, App10Constants.Accept, App10Constants.Namespace, collection.Accepts[i]); 719 } 720 for (int i = 0; i < collection.Categories.Count; ++i) 721 { 722 WriteCategories(writer, collection.Categories[i], baseUri, this.Version); 723 } 724 WriteElementExtensions(writer, collection, this.Version); 725 writer.WriteEndElement(); 726 } 727 WriteDocument(XmlWriter writer)728 private void WriteDocument(XmlWriter writer) 729 { 730 // declare the atom10 namespace upfront for compactness 731 writer.WriteAttributeString(Atom10Constants.Atom10Prefix, Atom10FeedFormatter.XmlNsNs, Atom10Constants.Atom10Namespace); 732 if (!string.IsNullOrEmpty(this.Document.Language)) 733 { 734 WriteXmlLang(writer, this.Document.Language); 735 } 736 Uri baseUri = this.Document.BaseUri; 737 if (baseUri != null) 738 { 739 WriteXmlBase(writer, baseUri); 740 } 741 WriteAttributeExtensions(writer, this.Document, this.Version); 742 743 for (int i = 0; i < this.Document.Workspaces.Count; ++i) 744 { 745 WriteWorkspace(writer, this.Document.Workspaces[i], baseUri); 746 } 747 WriteElementExtensions(writer, this.Document, this.Version); 748 } 749 WriteWorkspace(XmlWriter writer, Workspace workspace, Uri baseUri)750 private void WriteWorkspace(XmlWriter writer, Workspace workspace, Uri baseUri) 751 { 752 writer.WriteStartElement(App10Constants.Prefix, App10Constants.Workspace, App10Constants.Namespace); 753 Uri baseUriToWrite = FeedUtils.GetBaseUriToWrite(baseUri, workspace.BaseUri); 754 if (baseUriToWrite != null) 755 { 756 baseUri = workspace.BaseUri; 757 WriteXmlBase(writer, baseUriToWrite); 758 } 759 WriteAttributeExtensions(writer, workspace, this.Version); 760 if (workspace.Title != null) 761 { 762 workspace.Title.WriteTo(writer, Atom10Constants.TitleTag, Atom10Constants.Atom10Namespace); 763 } 764 for (int i = 0; i < workspace.Collections.Count; ++i) 765 { 766 WriteCollection(writer, workspace.Collections[i], baseUri); 767 } 768 WriteElementExtensions(writer, workspace, this.Version); 769 writer.WriteEndElement(); 770 } 771 } 772 773 [XmlRoot(ElementName = App10Constants.Service, Namespace = App10Constants.Namespace)] 774 public class AtomPub10ServiceDocumentFormatter<TServiceDocument> : AtomPub10ServiceDocumentFormatter 775 where TServiceDocument : ServiceDocument, new() 776 { AtomPub10ServiceDocumentFormatter()777 public AtomPub10ServiceDocumentFormatter() : 778 base(typeof(TServiceDocument)) 779 { 780 } 781 AtomPub10ServiceDocumentFormatter(TServiceDocument documentToWrite)782 public AtomPub10ServiceDocumentFormatter(TServiceDocument documentToWrite) 783 : base(documentToWrite) 784 { 785 } 786 CreateDocumentInstance()787 protected override ServiceDocument CreateDocumentInstance() 788 { 789 return new TServiceDocument(); 790 } 791 } 792 } 793