Added collection classes. Will not do extra collection for subcomments rn.

This commit is contained in:
schnulller
2022-06-26 22:48:25 +02:00
parent 056ab77888
commit 0fa0ff6a88
22 changed files with 490 additions and 226 deletions

View File

@@ -0,0 +1,24 @@
namespace HaWeb.XMLParser;
using HaWeb.Models;
using System.Xml.Linq;
public interface IXMLCollection {
// Collections of Elements to be created a Hamann File Root
// Key: the key under which the element(s) will be filed
// xPath: (absolute, realtive if subelement) XPaths to the element(s)
// GenerateKey: How to extract an identifier for the single element in the collection
// GenerateDataFields: Generate a dict of data associated with each of the collected Elements input: XElement output: Dictonary<string>
// GroupingsGeneration: datafields by which dictorary-like groups should be held in memory input: List<CollectedItem> output: Dictonary<string, Lookup<string, CollectedItem[]>>
// SortingsGeneration: datafields by which a sorting should be held in memory input: List<CollectedItem> output: ordered List<CollectedItem>
// SubCollections to be created in this element
// Searchable: Will the element be indexed for full-text-search?
abstract string Key { get; }
abstract string[] xPath { get; }
abstract Func<XElement, string?> GenerateKey { get; }
abstract Func<XElement, IDictionary<string, string>?>? GenerateDataFields { get; }
abstract Func<IEnumerable<CollectedItem>, IDictionary<string, ILookup<string, CollectedItem>>?>? GroupingsGeneration { get; }
abstract Func<IEnumerable<CollectedItem>, IDictionary<string, IEnumerable<CollectedItem>>?>? SortingsGeneration { get; }
abstract IXMLCollection[]? SubCollections { get; }
abstract bool Searchable { get; }
}

View File

@@ -13,24 +13,6 @@ public interface IXMLRoot {
// XPaths to determine if container is present
public abstract string[] XPathContainer { get; }
// Collections of Elements to be created from this Root
// Key: the key under which the element(s) will be files
// xPath: the (absolute) XPath to the element(s)
// Searchable: Will the element be indexed for full-text-search?
// GenerateKey: How to extrect an identifier for the single element in the collection
// GenerateDataFields: Generate a dict of data associated with each of the collected Elements input: XElement output: Dictonary<string>
// GroupingsGeneration: datafields by which dictorary-like groups should be held in memory input: List<CollectedItem> output: Dictonary<string, Lookup<string, CollectedItem[]>>
// SortingsGeneration: datafields by which a sorting should be held in memory input: List<CollectedItem> output: ordered List<CollectedItem>
public abstract (
string Key,
string xPath,
Func<XElement, string?> GenerateKey,
Func<XElement, Dictionary<string, string[]>?>? GenerateDataFields,
Func<List<CollectedItem>, Dictionary<string, Lookup<string, CollectedItem>>?>? GroupingsGeneration,
Func<List<CollectedItem>, Dictionary<string, List<CollectedItem>>?>? SortingsGeneration,
bool Searchable
)[]? Collections { get; }
// Determines child objects to be collected
// (deprecated see collections above; only used internally)
public abstract Predicate<XElement> IsCollectedObject { get; }

View File

@@ -12,6 +12,7 @@ using HaXMLReader.Interfaces;
public class XMLService : IXMLService {
private Dictionary<string, FileList?>? _Used;
private Dictionary<string, IXMLRoot>? _Roots;
private Dictionary<string, IXMLCollection>? _Collections;
private Stack<Dictionary<string, FileList?>>? _InProduction;
@@ -20,15 +21,25 @@ public class XMLService : IXMLService {
public XMLService() {
// Getting all classes which implement IXMLRoot for possible document endpoints
var types = _GetAllTypesThatImplementInterface<IXMLRoot>().ToList();
types.ForEach( x => {
var roottypes = _GetAllTypesThatImplementInterface<IXMLRoot>().ToList();
roottypes.ForEach( x => {
if (this._Roots == null) this._Roots = new Dictionary<string, IXMLRoot>();
var instance = (IXMLRoot)Activator.CreateInstance(x)!;
if (instance != null) this._Roots.Add(instance.Prefix, instance);
});
var collectiontypes = _GetAllTypesThatImplementInterface<IXMLCollection>().ToList();
collectiontypes.ForEach( x => {
if (this._Collections == null) this._Collections = new Dictionary<string, IXMLCollection>();
var instance = (IXMLCollection)Activator.CreateInstance(x)!;
if (instance != null) this._Collections.Add(instance.Key, instance);
});
if (_Roots == null || !_Roots.Any())
throw new Exception("No classes for upload endpoints were found!");
if (_Collections == null || !_Collections.Any())
throw new Exception("No classes for object collection were found!");
}
public IXMLRoot? GetRoot(string name) {
@@ -66,33 +77,32 @@ public class XMLService : IXMLService {
int startingSize = 2909;
int startingSizeAllCollections = 23;
var ret = new ConcurrentDictionary<string, ItemsCollection>(concurrencyLevel, startingSizeAllCollections);
foreach (var root in _Roots) {
if (root.Value.Collections != null)
foreach (var coll in root.Value.Collections) {
var elem = document.XPathSelectElements(coll.xPath);
if (elem != null && elem.Any()) {
var items = new ConcurrentDictionary<string, CollectedItem>(concurrencyLevel, startingSize);
Parallel.ForEach(elem, (e) => {
var k = coll.GenerateKey(e);
if (k != null) {
var searchtext = coll.Searchable ?
StringHelpers.NormalizeWhiteSpace(e.ToString(), ' ', false) :
null;
var datafileds = coll.GenerateDataFields != null ?
coll.GenerateDataFields(e) :
null;
items[k] = new CollectedItem(k, e, root.Value, coll.Key, datafileds, searchtext);
}
});
if (items.Any()) {
if (!ret.ContainsKey(coll.Key))
ret[coll.Key] = new ItemsCollection(coll.Key, coll.Searchable, root.Value, coll.GroupingsGeneration, coll.SortingsGeneration);
foreach (var item in items)
ret[coll.Key].Items.Add(item.Key, item.Value);
if (_Collections != null)
foreach (var coll in _Collections) {
var elem = coll.Value.xPath.Aggregate(new List<XElement>(), (x, y) => { x.AddRange(document.XPathSelectElements(y).ToList()); return x; } );
if (elem != null && elem.Any()) {
var items = new ConcurrentDictionary<string, CollectedItem>(concurrencyLevel, startingSize);
Parallel.ForEach(elem, (e) => {
var k = coll.Value.GenerateKey(e);
if (k != null) {
var searchtext = coll.Value.Searchable ?
StringHelpers.NormalizeWhiteSpace(e.ToString(), ' ', false) :
null;
var datafileds = coll.Value.GenerateDataFields != null ?
coll.Value.GenerateDataFields(e) :
null;
items[k] = new CollectedItem(k, e, coll.Value, datafileds, searchtext);
}
});
if (items.Any()) {
if (!ret.ContainsKey(coll.Key))
ret[coll.Key] = new ItemsCollection(coll.Key, coll.Value);
foreach (var item in items)
ret[coll.Key].Items.Add(item.Key, item.Value);
}
}
}
}
if (ret.Any()) {
Parallel.ForEach(ret, (collection) => {