@ -10,6 +10,7 @@ using System.Linq;
using System.Threading ;
using System.Threading.Tasks ;
using System.Xml.Linq ;
using GBase.DataHandling.Exceptions ;
using GBase.Helpers ;
using GBase.Interfaces.DataHandling ;
using GBase.Interfaces.DataHandling.Xml ;
@ -21,65 +22,34 @@ namespace GBase.DataHandling
/// </summary>
public class XmlDataReader : IXmlDataReader
{
private readonly FileStream _f ile ;
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 )
{
_f ile = 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 ( _f ile , 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="file"></param>
/// <param name="propertyName">The name of the property</param>
/// <param name="cancellationToken"></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 )
public async Task < IEnumerable < TProperty > > Read < T , TProperty > ( FileStream file , string propertyName , CancellationToken cancellationToken )
//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 ) ) ;
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
return await Task . Run ( ( ) = >
{
XElement typeElement = _ rootElement . Element ( typeName ) ;
XElement propertyElement = typeElement ? . Element ( propertyName ) ;
XElement rootElement = xmlDocument . Root ;
if ( rootElement = = null )
throw new InvalidXmlFileException ( "No root element is set." ) ;
XElement propertyElement = rootElement . Element ( propertyName ) ;
XAttribute propertyTypeAttribute = propertyElement ? . Attribute ( XmlDataHandler . VALUE_TYPE_ATTRIBUTE_NAME ) ;
if ( propertyTypeAttribute = = null )
return null ;
@ -98,16 +68,7 @@ namespace GBase.DataHandling
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 _f ile . DisposeAsync ( ) ;
} , cancellationToken ) ;
}
}
}