// Copyright (C) Stichting Deltares 2025. All rights reserved. // // This file is part of the application DAM - UI. // // DAM - UI is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . // // All names, logos, and references to "Deltares" are registered trademarks of // Stichting Deltares and remain full property of Stichting Deltares at all times. // All rights reserved. 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 readonly DtoAssembler entityAssembler; public DtoCollectionAssembler(DtoAssembler entityAssembler, string elementName) { this.entityAssembler = entityAssembler; ElementName = elementName; } /// /// Creates a domain object collection from an xml document /// /// /// public IEnumerable CreateDomainObjectCollection(string xmlString) { XDocument doc = XDocument.Parse(xmlString); // assemble the collection return 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 == EntityAssembler.ElementName && x.Parent.Name.LocalName == ElementName select x; // assemble the collection return CreateDomainObjectCollection(dto); } /// /// /// /// /// public IEnumerable CreateDomainObjectCollection(IEnumerable dtoObjColl) { return dtoObjColl.ToDomainObjectIterator(entityAssembler); } /// /// /// /// /// public XElement CreateDataTransferObject(IEnumerable domainObjColl, XNamespace elementNamespace) { XElement el = CreateDataTransferObject(domainObjColl); var nel = new XElement(elementNamespace + ElementName); el.Name = nel.Name; return el; } #region IDtoCollectionAssembler Members /// /// Gets the entity assembler /// public IDtoAssembler EntityAssembler { get { return entityAssembler; } } /// /// Gets or sets the xml element name /// public string ElementName { get; } /// /// /// /// /// public virtual IEnumerable CreateDomainObjectCollection(XElement dtoSequenceElement) { IEnumerable dto = from x in dtoSequenceElement.Descendants() where x.Name.LocalName == EntityAssembler.ElementName && x.Parent.Name.LocalName == ElementName select x; return dto.ToDomainObjectIterator(entityAssembler); } /// /// /// /// /// public virtual XElement CreateDataTransferObject(IEnumerable domainObjColl) { if (!ElementName.HasValidStringValue()) { throw new DtoAssemblerException("There is no element name specified"); } if (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 = entityAssembler.Schema; if (schema != null) { if (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 == 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(ElementName, EntityAssembler.ElementName, domainObjColl); } } } } else if (domainObjColl == null) { return null; // Use empty sequence instead? } return new XElement(ElementName, domainObjColl.ToDtoIterator(entityAssembler).ToArray()); } #endregion }