//----------------------------------------------------------------------- // // Copyright (c) 2009 Deltares. All rights reserved. // // B. Faassen // barry.faassen@deltares.nl // 9-2-2009 // Base class to convert between domain collections and xml (dto) collections //----------------------------------------------------------------------- using System.Collections.Generic; using System.Linq; using System.Xml.Linq; using Deltares.Standard.IO.DtoAssembler; namespace Deltares.Standard { /// /// Base class for a data transfer collection assembler /// /// The type of class to be assembled public abstract class DtoCollectionAssembler : IDtoCollectionAssembler where TDomainObject : new() { /// /// Holds a reference to the entity assembler /// private DtoAssembler entityAssembler; public DtoCollectionAssembler(DtoAssembler entityAssembler, string elementName) { this.entityAssembler = entityAssembler; this.ElementName = elementName; } #region IDtoCollectionAssembler Members /// /// Gets the entity assembler /// public IDtoAssembler EntityAssembler { get { return this.entityAssembler; } } /// /// Gets or sets the xml element name /// public string ElementName { get; private set; } /// /// /// /// /// public virtual IEnumerable CreateDomainObjectCollection(XElement dtoSequenceElement) { IEnumerable dto = from x in dtoSequenceElement.Descendants() where x.Name.LocalName == this.EntityAssembler.ElementName && x.Parent.Name.LocalName == this.ElementName select x; return dto.ToDomainObjectIterator(this.entityAssembler); } /// /// /// /// /// public virtual XElement CreateDataTransferObject(IEnumerable domainObjColl) { if (!this.ElementName.HasValidStringValue()) throw new DtoAssemblerException("There is no element name specified"); if (this.entityAssembler == null) { // TODO: need to support serialization based on reflection } // is there a schema attached to the assembler so we can // validate the collection? XDocument schema = this.entityAssembler.Schema; if (schema != null) { if (this.entityAssembler == null) { // TODO: need to support serialization based on reflection } else { // get the collection rules (min and max requirements) (if any) var collRules = from x in schema.Descendants() where x.Name.LocalName == "element" && x.Attribute("name").Value == this.entityAssembler.ElementName select new { MinOccurs = x.AttributeAs("minOccurs") == "unbounded" ? 0 : x.AttributeAs("minOccurs"), MaxOccurs = x.AttributeAs("maxOccurs") == "unbounded" ? -1 : x.AttributeAs("maxOccurs") }; if (collRules.Any()) { var rules = collRules.Single(); // validate the min and max values of the collection according to the xsd int count = domainObjColl.Count(); if (domainObjColl == null || (count == 0 && rules.MinOccurs > 0) || (count > 0 & rules.MaxOccurs >= 0 && count > rules.MaxOccurs)) { throw new CollectionRequirementsNotSatisfiedException(this.ElementName, this.EntityAssembler.ElementName, domainObjColl); } } } } else if (domainObjColl == null) { return null; // Use empty sequence instead? } return new XElement(this.ElementName, domainObjColl.ToDtoIterator(this.entityAssembler).ToArray()); } #endregion /// /// Creates a domain object collection from an xml document /// /// /// public IEnumerable CreateDomainObjectCollection(string xmlString) { XDocument doc = XDocument.Parse(xmlString); // assemble the collection return this.CreateDomainObjectCollection(doc); } /// /// Creates a domain object collection from an xml document /// /// /// public IEnumerable CreateDomainObjectCollection(XDocument doc) { IEnumerable dto = from x in doc.Descendants() where x.Name.LocalName == this.EntityAssembler.ElementName && x.Parent.Name.LocalName == this.ElementName select x; // assemble the collection return this.CreateDomainObjectCollection(dto); } /// /// /// /// /// public IEnumerable CreateDomainObjectCollection(IEnumerable dtoObjColl) { return dtoObjColl.ToDomainObjectIterator(this.entityAssembler); } /// /// /// /// /// public XElement CreateDataTransferObject(IEnumerable domainObjColl, XNamespace elementNamespace) { XElement el = this.CreateDataTransferObject(domainObjColl); var nel = new XElement(elementNamespace + this.ElementName); el.Name = nel.Name; return el; } } }