diff --git a/GBase/DataHandling/Exceptions/InvalidXmlFileException.cs b/GBase/DataHandling/Exceptions/InvalidXmlFileException.cs new file mode 100644 index 0000000..adfc8fc --- /dev/null +++ b/GBase/DataHandling/Exceptions/InvalidXmlFileException.cs @@ -0,0 +1,17 @@ +// Author: Gockner, Simon +// Created: 2020-11-09 +// Copyright(c) 2020 SimonG. All Rights Reserved. + +using System; + +namespace GBase.DataHandling.Exceptions +{ + public class InvalidXmlFileException : Exception + { + public InvalidXmlFileException(string message) + : base(message) + { + + } + } +} \ No newline at end of file diff --git a/GBase/DataHandling/XmlDataHandler.cs b/GBase/DataHandling/XmlDataHandler.cs index f666969..c168908 100644 --- a/GBase/DataHandling/XmlDataHandler.cs +++ b/GBase/DataHandling/XmlDataHandler.cs @@ -144,7 +144,7 @@ namespace GBase.DataHandling valueString = value.ToString(); await _cache.TryRemoveValue(propertyName, value); - await _xmlDataWriter.Remove(propertyName, valueString); + await _xmlDataWriter.Remove(TODO, propertyName, valueString, TODO); } /// diff --git a/GBase/DataHandling/XmlDataWriter.cs b/GBase/DataHandling/XmlDataWriter.cs index 40cc62a..5e3e54f 100644 --- a/GBase/DataHandling/XmlDataWriter.cs +++ b/GBase/DataHandling/XmlDataWriter.cs @@ -8,6 +8,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; using System.Xml.Linq; +using GBase.DataHandling.Exceptions; using GBase.Interfaces.DataHandling; using GBase.Interfaces.DataHandling.Xml; @@ -52,6 +53,7 @@ namespace GBase.DataHandling /// /// A to await /// + /// No root element is set public async Task Write(FileStream file, string propertyName, string value, bool overwrite, CancellationToken cancellationToken) { string typeName = typeof(T).FullName; @@ -59,43 +61,35 @@ namespace GBase.DataHandling throw new ArgumentNullException(nameof(typeName)); XDocument xmlDocument = await XDocument.LoadAsync(file, LoadOptions.None, cancellationToken); - file.Seek(0, SeekOrigin.Begin); //reset stream to it's beginning to be able to save it - XElement typeElement = _rootElement.Element(typeName); - if (typeElement != null) //type element already exists + XElement rootElement = xmlDocument.Root; + if (rootElement == null) + throw new InvalidXmlFileException("No root element is set."); + + XElement propertyElement = rootElement.Element(propertyName); + if (propertyElement != null) //property element already exists { - XElement propertyElement = typeElement.Element(propertyName); - if (propertyElement != null) //property element already exists + XElement valueElement = propertyElement.Element(XmlDataHandler.VALUE_ELEMENT_NAME); + if (valueElement != null && overwrite) //value element exists and overwrite is true { - XElement valueElement = propertyElement.Element(XmlDataHandler.VALUE_ELEMENT_NAME); - if (valueElement != null && overwrite) //value element exists and overwrite is true - { - valueElement.Value = value; //overwrite existing value - } - else if (!overwrite && propertyElement.Elements(XmlDataHandler.VALUE_ELEMENT_NAME).Any(v => v.Value.Equals(value))) //no overwrite and same value exists already - { - XElement sameValueElement = propertyElement.Elements(XmlDataHandler.VALUE_ELEMENT_NAME).First(v => v.Value.Equals(value)); - sameValueElement.Remove(); //remove the already existing value from its current position - propertyElement.AddFirst(sameValueElement); //add it as the first element again - } - else //no value element exists or overwrite is false - propertyElement.AddFirst(new XElement(XmlDataHandler.VALUE_ELEMENT_NAME) { Value = value }); //add a new value element + valueElement.Value = value; //overwrite existing value } - else //property element doesn't exist + else if (!overwrite && propertyElement.Elements(XmlDataHandler.VALUE_ELEMENT_NAME).Any(v => v.Value.Equals(value))) //no overwrite and same value exists already { - propertyElement = new XElement(propertyName, new XElement(XmlDataHandler.VALUE_ELEMENT_NAME) { Value = value }); //create the new property element with the value element - propertyElement.SetAttributeValue(XmlDataHandler.VALUE_TYPE_ATTRIBUTE_NAME, typeof(TProperty).FullName); //add the property type attribute - - typeElement.Add(propertyElement); //create new property element with the value element + XElement sameValueElement = propertyElement.Elements(XmlDataHandler.VALUE_ELEMENT_NAME).First(v => v.Value.Equals(value)); + sameValueElement.Remove(); //remove the already existing value from its current position + propertyElement.AddFirst(sameValueElement); //add it as the first element again } + else //no value element exists or overwrite is false + propertyElement.AddFirst(new XElement(XmlDataHandler.VALUE_ELEMENT_NAME) { Value = value }); //add a new value element } - else //type element doesn't exist + else //property element doesn't exist { - XElement propertyElement = new XElement(propertyName, new XElement(XmlDataHandler.VALUE_ELEMENT_NAME) { Value = value }); //create the new property element with the value element + propertyElement = new XElement(propertyName, new XElement(XmlDataHandler.VALUE_ELEMENT_NAME) { Value = value }); //create the new property element with the value element propertyElement.SetAttributeValue(XmlDataHandler.VALUE_TYPE_ATTRIBUTE_NAME, typeof(TProperty).FullName); //add the property type attribute - _rootElement.Add(new XElement(typeName, propertyElement)); //create a new type element with the new property element + rootElement.Add(propertyElement); //create new property element with the value element } //TODO: check if whole file is overwritten (probably) -> performance issues for large files? @@ -107,19 +101,27 @@ namespace GBase.DataHandling /// /// The of the property /// The of the property + /// /// The name of the property /// The value to set + /// /// A to await /// - public async Task Remove(string propertyName, string value) + /// No root element is set + public async Task Remove(FileStream file, string propertyName, string value, CancellationToken cancellationToken) { string typeName = typeof(T).FullName; if (typeName == null) throw new ArgumentNullException(nameof(typeName)); - _file.Seek(0, SeekOrigin.Begin); //reset stream to it's beginning to be able to save it + XDocument xmlDocument = await XDocument.LoadAsync(file, LoadOptions.None, cancellationToken); + file.Seek(0, SeekOrigin.Begin); //reset stream to it's beginning to be able to save it - XElement typeElement = _rootElement.Element(typeName); + XElement rootElement = xmlDocument.Root; + if (rootElement == null) + throw new InvalidXmlFileException("No root element is set."); + + XElement typeElement = rootElement.Element(typeName); XElement propertyElement = typeElement?.Element(propertyName); XElement valueElement = propertyElement?.Elements(XmlDataHandler.VALUE_ELEMENT_NAME).FirstOrDefault(e => e.Value.Equals(value)); if (valueElement == null) @@ -128,7 +130,7 @@ namespace GBase.DataHandling valueElement.Remove(); //TODO: check if whole file is overwritten (probably) -> performance issues for large files? - await _xmlDocument.SaveAsync(_file, SaveOptions.OmitDuplicateNamespaces, _cancellationToken); //save the document with the added elements + await xmlDocument.SaveAsync(file, SaveOptions.OmitDuplicateNamespaces, cancellationToken); //save the document with the added elements } } } \ No newline at end of file diff --git a/GBase/Interfaces/DataHandling/IDataWriter.cs b/GBase/Interfaces/DataHandling/IDataWriter.cs index cd65a26..c7a67c2 100644 --- a/GBase/Interfaces/DataHandling/IDataWriter.cs +++ b/GBase/Interfaces/DataHandling/IDataWriter.cs @@ -41,9 +41,11 @@ namespace GBase.Interfaces.DataHandling /// /// The of the property /// The of the property + /// /// The name of the property /// The value to set + /// /// A to await - Task Remove(string propertyName, string value); + Task Remove(FileStream file, string propertyName, string value, CancellationToken cancellationToken); } } \ No newline at end of file diff --git a/Test.GBase/DataHandling/XmlDataHandlerTest.cs b/Test.GBase/DataHandling/XmlDataHandlerTest.cs index cbf4b4f..548b2fe 100644 --- a/Test.GBase/DataHandling/XmlDataHandlerTest.cs +++ b/Test.GBase/DataHandling/XmlDataHandlerTest.cs @@ -213,7 +213,7 @@ namespace Test.GBase.DataHandling await xmlDataHandler.RemoveValue("property", "SomeString"); xmlDataHandlerCacheMock.Verify(c => c.TryRemoveValue("property", "SomeString"), Times.Once); - xmlDataWriterMock.Verify(w => w.Remove("property", "SomeString"), Times.Once); + xmlDataWriterMock.Verify(w => w.Remove(TODO, "property", "SomeString", TODO), Times.Once); } [Test] @@ -238,7 +238,7 @@ namespace Test.GBase.DataHandling await xmlDataHandler.RemoveValue>("property", stringList); xmlDataHandlerCacheMock.Verify(c => c.TryRemoveValue>("property", stringList), Times.Once); - xmlDataWriterMock.Verify(w => w.Remove>("property", $"{stringList[0]},{stringList[1]},{stringList[2]}"), Times.Once); + xmlDataWriterMock.Verify(w => w.Remove>(TODO, "property", $"{stringList[0]},{stringList[1]},{stringList[2]}", TODO), Times.Once); } [Test] @@ -262,7 +262,7 @@ namespace Test.GBase.DataHandling await xmlDataHandler.RemoveValue("property", null); xmlDataHandlerCacheMock.Verify(c => c.TryRemoveValue(It.IsAny(), It.IsAny()), Times.Never); - xmlDataWriterMock.Verify(w => w.Remove(It.IsAny(), It.IsAny()), Times.Never); + xmlDataWriterMock.Verify(w => w.Remove(TODO, It.IsAny(), It.IsAny(), TODO), Times.Never); } [Test]