You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
113 lines
4.5 KiB
113 lines
4.5 KiB
// Author: Gockner, Simon
|
|
// Created: 2020-02-12
|
|
// Copyright(c) 2020 SimonG. All Rights Reserved.
|
|
|
|
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using System.Xml.Linq;
|
|
using GBase.Helpers;
|
|
using GBase.Interfaces.DataHandling;
|
|
using GBase.Interfaces.DataHandling.Xml;
|
|
|
|
namespace GBase.DataHandling
|
|
{
|
|
/// <summary>
|
|
/// A <see cref="IDataReader"/> that reads from a xml file
|
|
/// </summary>
|
|
public class XmlDataReader : IXmlDataReader
|
|
{
|
|
private readonly FileStream _file;
|
|
private XDocument _xmlDocument;
|
|
private XElement _rootElement;
|
|
|
|
private bool _isInitialized;
|
|
private CancellationToken _cancellationToken;
|
|
|
|
/// <summary>
|
|
/// A <see cref="IDataReader"/> that reads from a xml file
|
|
/// </summary>
|
|
/// <param name="path">The path to the xml file</param>
|
|
public XmlDataReader(string path)
|
|
{
|
|
_file = File.Open(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Initialize the <see cref="XmlDataReader"/>
|
|
/// </summary>
|
|
/// <param name="cancellationToken">A <see cref="CancellationToken"/> to cancel the async operation</param>
|
|
/// <returns>Returns true if successful, false if not</returns>
|
|
/// <exception cref="Exception">No root element found</exception>
|
|
public async Task<bool> Init(CancellationToken cancellationToken)
|
|
{
|
|
if (_isInitialized)
|
|
return false;
|
|
|
|
_cancellationToken = cancellationToken;
|
|
_xmlDocument = await XDocument.LoadAsync(_file, LoadOptions.None, _cancellationToken);
|
|
|
|
_rootElement = _xmlDocument.Root;
|
|
if (_rootElement == null)
|
|
throw new Exception("No root element found.");
|
|
|
|
_isInitialized = true;
|
|
|
|
return true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Read the data of a property
|
|
/// </summary>
|
|
/// <typeparam name="T">The <see cref="Type"/></typeparam>
|
|
/// <typeparam name="TProperty">The <see cref="Type"/> of the property</typeparam>
|
|
/// <param name="propertyName">The name of the property</param>
|
|
/// <returns>The data of the given property, null if no data found</returns>
|
|
/// <exception cref="ArgumentNullException"><paramref name="propertyName"/></exception>
|
|
/// <exception cref="InvalidOperationException">Invalid <see cref="Type"/> found for the read object</exception>
|
|
public async Task<IEnumerable<TProperty>> Read<T, TProperty>(string propertyName)
|
|
//TODO: Read currently doesn't work for newly added items -> probably because file was loaded before new items were added; is probably not a problem -> cache
|
|
{
|
|
string typeName = typeof(T).FullName;
|
|
if (typeName == null)
|
|
throw new ArgumentNullException(nameof(typeName));
|
|
|
|
return await Task.Run(() =>
|
|
{
|
|
XElement typeElement = _rootElement.Element(typeName);
|
|
XElement propertyElement = typeElement?.Element(propertyName);
|
|
XAttribute propertyTypeAttribute = propertyElement?.Attribute(XmlDataHandler.VALUE_TYPE_ATTRIBUTE_NAME);
|
|
if (propertyTypeAttribute == null)
|
|
return null;
|
|
|
|
Type propertyType = Type.GetType(propertyTypeAttribute.Value);
|
|
if (propertyType != typeof(TProperty))
|
|
throw new InvalidOperationException("Invalid Type found for the read object.");
|
|
|
|
List<XElement> valueElements = propertyElement.Elements(XmlDataHandler.VALUE_ELEMENT_NAME).ToList();
|
|
if (!valueElements.Any())
|
|
return null;
|
|
|
|
IEnumerable<string> values = valueElements.Select(v => v.Value);
|
|
|
|
if (typeof(TProperty) != typeof(string) && typeof(TProperty).GetInterfaces().Contains(typeof(IEnumerable))) //read property is an IEnumerable
|
|
return values.Select(Enumerables.ConvertToGBaseEnumerable<TProperty>).ToList();
|
|
|
|
return values.Select(value => (TProperty)Convert.ChangeType(value, typeof(TProperty))).ToList();
|
|
}, _cancellationToken);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Dispose used resources asynchronously
|
|
/// </summary>
|
|
/// <returns>A <see cref="ValueTask"/> to await</returns>
|
|
public async ValueTask DisposeAsync()
|
|
{
|
|
await _file.DisposeAsync();
|
|
}
|
|
}
|
|
} |