namespace HaWeb.XMLTests; using HaWeb.Models; using System.Linq; using System.Xml; using System.Xml.Linq; using System.Xml.XPath; public class XMLTester { private Dictionary? _Ruleset; private Dictionary? _CollectionRuleset; private List? _Documents; private Dictionary>? _IDs; private Dictionary>? _CollectionIDs; private Dictionary?> _XPathEvaluated; public XMLTester (IXMLTestService testService, Dictionary? filelists) { _Ruleset = testService.Ruleset; _CollectionRuleset = testService.CollectionRuleset; if (filelists != null) { foreach (var fl in filelists) { if (fl.Value != null) { if (_Documents == null) _Documents = new List(); var docs = fl.Value.GetFileList(); if (docs != null) _Documents.AddRange(docs); } } } _XPathEvaluated = new Dictionary?>(); } public void Test() { if (_Ruleset == null) return; _IDs = new Dictionary>(); foreach (var rule in _Ruleset) { buildIDs(rule.Value); checkRequiredAttributes(rule.Value); checkReferences(rule.Value); } if (_CollectionRuleset == null) return; _CollectionIDs = new Dictionary>(); foreach (var collectionrule in _CollectionRuleset) { buildIDs(collectionrule.Value); checkReferences(collectionrule.Value); } } private void checkReferences(INodeRule rule) { if (rule.References == null || !rule.References.Any()) return; var elements = GetEvaluateXPath(rule.XPath); if (elements != null && elements.Any()) { foreach (var e in elements) { foreach (var r in rule.References) { var hasattr = checkAttribute(e.Item1, r.LinkAttribute, e.Item2, false); var keyname = r.RemoteElement.XPath + "-" + r.RemoteAttribute; if (_IDs != null && _IDs.ContainsKey(keyname) && hasattr) { var val = e.Item1.Attribute(r.LinkAttribute)!.Value; if (!_IDs[keyname].Contains(val)) { e.Item2.File.Log(generateLogMessage(e.Item1) + "Verlinktes Element " + val + " nicht gefunden."); } } } } } } private void checkReferences(ICollectionRule rule) { if (rule.Backlinks == null || !rule.Backlinks.Any() || !_CollectionIDs.ContainsKey(rule.Name)) return; foreach (var bl in rule.Backlinks) { var elemens = GetEvaluateXPath(bl); if (elemens != null && elemens.Any()) { foreach(var r in rule.GenerateBacklinkString(elemens)) { if (!r.Item4 && !_CollectionIDs[rule.Name].Contains(r.Item1)) { r.Item3.File.Log(generateLogMessage(r.Item2) + "Verlinktes Element " + r.Item1 + " nicht gefunden."); } if (r.Item4) { var coll = _CollectionIDs[rule.Name]; var items = r.Item1.Split('-'); var searchterm = items[0]; var found = coll.Where(x => x.StartsWith(searchterm)); if (items[0] == "NA" || found == null || !found.Any()) { r.Item3.File.Log(generateLogMessage(r.Item2) + "Verlinktes Element " + r.Item1 + " nicht gefunden."); } else { for (var i = 1; i < items.Length; i++) { if (items[i] == "NA") break; else { searchterm = searchterm + "-" + items[i]; found = found.Where(x => x.StartsWith(searchterm)); if (found == null || !found.Any()) r.Item3.File.Log(generateLogMessage(r.Item2) + "Verlinktes Element " + r.Item1 + " nicht gefunden."); } } } } } } } } private void checkRequiredAttributes(INodeRule rule) { if (rule.Attributes == null) return; var elements = GetEvaluateXPath(rule.XPath); if (elements != null && elements.Any()) { foreach (var e in elements) { foreach (var attr in rule.Attributes) { checkAttribute(e.Item1, attr, e.Item2); } } } } private void buildIDs(INodeRule rule) { if (!String.IsNullOrWhiteSpace(rule.uniquenessAttribute)) { checkUniqueness(rule.XPath, rule.uniquenessAttribute); } if (rule.References != null && rule.References.Any()) { foreach (var reference in rule.References) { checkUniqueness(reference.RemoteElement, reference.RemoteAttribute); } } } private void buildIDs(ICollectionRule rule) { if (rule.Bases != null && rule.Bases.Any()) { var hs = new HashSet(); foreach (var b in rule.Bases) { var elemens = GetEvaluateXPath(b); if (elemens != null && elemens.Any()) { foreach (var r in rule.GenerateIdentificationStrings(elemens)) { if (!hs.Add(r.Item1)) { r.Item3.File.Log(generateLogMessage(r.Item2) + "Brief-Seite-Zeile " + r.Item1 + " mehrdeutig."); } } } } _CollectionIDs!.TryAdd(rule.Name, hs); } } private void checkUniqueness(HamannXPath xpathelement, string attribute) { if (_Documents == null || _IDs == null || _IDs.ContainsKey(xpathelement.XPath + "-" + attribute)) return; var hs = new HashSet(); var elements = GetEvaluateXPath(xpathelement); if (elements != null) foreach (var e in elements) { if (checkAttribute(e.Item1, attribute, e.Item2)) { if (!hs.Add(e.Item1.Attribute(attribute)!.Value)) { e.Item2.File.Log(generateLogMessage(e.Item1) + "Attributwert " + e.Item1.Attribute(attribute)!.Value + " doppelt."); } } } _IDs.TryAdd(xpathelement.XPath + "-" + attribute, hs); } private bool checkAttribute(XElement element, string attributename, XMLRootDocument doc, bool log = true) { if (!element.HasAttributes || element.Attribute(attributename) == null) { if (log) doc.File.Log(generateLogMessage(element) + "Attribut " + attributename + " fehlt."); return false; } return true; } private string generateLogMessage(XElement element) { return "Zeile " + ((IXmlLineInfo)element).LineNumber.ToString() + ", Element " + element.Name + ": "; } // Cache for XPATH evaluation private List<(XElement, XMLRootDocument)>? GetEvaluateXPath(HamannXPath xpath) { if (_Documents == null || xpath == null) return null; if (_XPathEvaluated.ContainsKey(xpath.XPath)) return _XPathEvaluated[xpath.XPath]; if (!_XPathEvaluated.ContainsKey(xpath.XPath)) _XPathEvaluated.Add(xpath.XPath, null); foreach (var d in _Documents) { if (xpath.Documents != null && !xpath.Documents.Contains(d.Prefix)) continue; var elements = d.Element.XPathSelectElements("." + xpath.XPath).ToList(); if (elements != null && elements.Any()) { if (_XPathEvaluated[xpath.XPath] == null) _XPathEvaluated[xpath.XPath] = new List<(XElement, XMLRootDocument)>(); foreach (var res in elements) { _XPathEvaluated[xpath.XPath]!.Add((res, d)); } } } return _XPathEvaluated[xpath.XPath]; } }