diff --git a/Pf2eDataScrapper/SchemaBuilder/SchemaNode.cs b/Pf2eDataScrapper/SchemaBuilder/SchemaNode.cs index 6bfc4bc..cffa64b 100644 --- a/Pf2eDataScrapper/SchemaBuilder/SchemaNode.cs +++ b/Pf2eDataScrapper/SchemaBuilder/SchemaNode.cs @@ -1,41 +1,76 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Newtonsoft.Json.Linq; +using Newtonsoft.Json.Linq; using Pf2eDataScrapper.SchemaBuilder.Types; namespace Pf2eDataScrapper.SchemaBuilder { + /// + /// Элемент схемы данных. + /// internal class SchemaNode { + /// + /// Отображаемое имя элемента. + /// public string Name = ""; + /// + /// Путь к элементу. + /// public string Path = ""; + /// + /// Родительский элемент. + /// public SchemaNode? Parent = null; + /// + /// Указание, является ли элемент корневым. + /// public bool Root = false; + /// + /// Корневой элемент схемы данных. + /// public SchemaNode RootNode => Root ? this : Parent!.RootNode; + /// + /// Типы данных, использующиеся в элементе. + /// public List Types = []; + /// + /// Указание, может ли этот элемент отсутсвовать в структуре данных. + /// public bool IsNullable = false; + /// + /// Объект для определения типа поля в схеме данных. + /// public TypeResolver Resolver = new(); + /// + /// Количество значений, добавленных в тип. + /// public int Values { get; protected set; } = 0; + /// + /// Указание, является ли тип элемента простым. + /// public bool IsSimple => Types.Count == 1; + /// + /// Конструктор корневого элемента. + /// public SchemaNode() { this.Root = true; } + /// + /// Конструктор элемента схемы данных. + /// + /// Родительский элемент. + /// Имя элемента. public SchemaNode(SchemaNode parent, string name) { this.Parent = parent; @@ -44,6 +79,10 @@ namespace Pf2eDataScrapper.SchemaBuilder this.Resolver = parent.Resolver; } + /// + /// Добавление нового возможного значения. + /// + /// Добавляемое значение public void AddValue(JToken? value) { if (value is null || Resolver.TokenType(value) == JTokenType.Null) @@ -68,6 +107,10 @@ namespace Pf2eDataScrapper.SchemaBuilder Types.Add(newType); } + /// + /// Получение строкового представоения типа элемента. + /// + /// Строковое представоение типа элемента public string GetTypeName() { if (IsSimple) @@ -75,11 +118,15 @@ namespace Pf2eDataScrapper.SchemaBuilder return Types[0].GetTypeName(); } - List typeNames = Types.Select(t => t.GetTypeName()).ToList(); + var typeNames = Types.Select(t => t.GetTypeName()).ToList(); return string.Join("|", typeNames); } + /// + /// Полное строковое представление элемента. + /// + /// Строковое представление элемента. public override string ToString() { if (IsSimple) @@ -97,6 +144,9 @@ namespace Pf2eDataScrapper.SchemaBuilder return string.Join("\n" + AbstractSchemaType.Tab, result); } + /// + /// Подготовка элемента к красивому представлению. + /// public void Beautify() { foreach (var type in Types) diff --git a/Pf2eDataScrapper/SchemaBuilder/TypeResolver.cs b/Pf2eDataScrapper/SchemaBuilder/TypeResolver.cs index f334db0..d80266b 100644 --- a/Pf2eDataScrapper/SchemaBuilder/TypeResolver.cs +++ b/Pf2eDataScrapper/SchemaBuilder/TypeResolver.cs @@ -1,15 +1,19 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Newtonsoft.Json.Linq; +using Newtonsoft.Json.Linq; using Pf2eDataScrapper.SchemaBuilder.Types; namespace Pf2eDataScrapper.SchemaBuilder { + /// + /// Класс для определения типа поля в схеме данных. + /// internal class TypeResolver { + /// + /// Проверка соответствия пути. + /// + /// Элемент, путь которого проверяется. + /// Проверяемый путь. Допускается использование `*` в местах, где допускается любое значение. + /// `true`, если `node.Path` соответсвует указанному в `path` значению. public bool CheckPath(SchemaNode node, string path) { if (!path.Contains("*")) @@ -27,12 +31,23 @@ namespace Pf2eDataScrapper.SchemaBuilder return !pathParts.Where((t, i) => t != "*" && t != nodeParts[i]).Any(); } - + + /// + /// Проверка соответствия пути. + /// + /// Элемент, путь которого проверяется. + /// Проверяемые пути. Допускается использование `*` в местах, где допускается любое значение. + /// `true`, если `node.Path` соответсвует хотя бы одному указанному в `paths` значению. public bool CheckPath(SchemaNode node, ICollection paths) { return paths.Any(path => CheckPath(node, path)); } + /// + /// Получение типа значения. + /// + /// Значение. + /// Типа значения. public JTokenType TokenType(JToken? value) { if (value is null || value.Type is JTokenType.Null or JTokenType.Undefined or JTokenType.None) @@ -43,13 +58,23 @@ namespace Pf2eDataScrapper.SchemaBuilder return value.Type; } + /// + /// Определение типа поля. + /// + /// Поле схемы данных, для которого создаётся тип. + /// Добавляемое значение. + /// Новый тип для схемы данных + /// + /// Возникает, если у `value` значение идентично `null` + /// (такие значения должны обрабаотываться в `SchemaNode`). + /// public virtual AbstractSchemaType Resolve(SchemaNode node, JToken? value) { var type = TokenType(value); if (type == JTokenType.Null) { - throw new Exception("Value is null, cannot determine type"); + throw new ArgumentNullException(); } return type switch diff --git a/Pf2eDataScrapper/SchemaBuilder/Types/AbstractSchemaType.cs b/Pf2eDataScrapper/SchemaBuilder/Types/AbstractSchemaType.cs index 56669bd..0834703 100644 --- a/Pf2eDataScrapper/SchemaBuilder/Types/AbstractSchemaType.cs +++ b/Pf2eDataScrapper/SchemaBuilder/Types/AbstractSchemaType.cs @@ -1,37 +1,56 @@ -using System.ComponentModel.Design.Serialization; -using Newtonsoft.Json.Linq; +using Newtonsoft.Json.Linq; namespace Pf2eDataScrapper.SchemaBuilder.Types { + /// + /// Абстрактный тип представоления данных в схеме. + /// + /// Элемент, к которому добавляется тип. internal abstract class AbstractSchemaType(SchemaNode parent) { + /// + /// Элемент схемы данных, к которому относится тип. + /// public SchemaNode Parent = parent; + /// + /// Корневой элемент схемы данных. + /// public SchemaNode Root => Parent.RootNode; + /// + /// Объект для определения типа поля в схеме данных. + /// public TypeResolver Resolver => Root.Resolver; /// - /// Check if type is compatible with current type. + /// Проверка, что значение совместимо с текущим типом. /// - /// Value to be checked - /// True if value is compatible with current type + /// Проверяемое значение. + /// `true`, если значение совместимо с текущим типом. public abstract bool IsCompatibleValue(JToken value); /// - /// Add new possible value. + /// Добавление нового значения. /// - /// New value + /// Новое значение. public abstract void AddValue(JToken value); + /// + /// Подготовка типа к красивому представлению. + /// public abstract void Beautify(); /// - /// String representation of type. + /// Получение строкового представоения типа элемента. /// - /// + /// Строковое представоение типа элемента public abstract string GetTypeName(); + /// + /// Полное строковое представление элемента. + /// + /// Строковое представление элемента. public override string ToString() { return $"{GetTypeName()} {Parent.Path}"; @@ -39,20 +58,20 @@ namespace Pf2eDataScrapper.SchemaBuilder.Types /// - /// Tabulation characters. + /// Отступ для строкового представления. /// public const string Tab = " "; /// - /// Limit of elements in list or dictionary to be displayed. + /// Предел количество отображаемых элементов. /// - public const int ElementLimit = 20; + public const int ElementLimit = 10; /// - /// Indent text. + /// Увеличение отступа строки. /// - /// Text to be indented - /// Indented text + /// Изменяемая строка. + /// Строка с добавленными отступами. public static string Indent(string text) { return text.Replace("\n", "\n" + Tab); diff --git a/Pf2eDataScrapper/SchemaBuilder/Types/ArraySchemaType.cs b/Pf2eDataScrapper/SchemaBuilder/Types/ArraySchemaType.cs index 56063b4..896cc30 100644 --- a/Pf2eDataScrapper/SchemaBuilder/Types/ArraySchemaType.cs +++ b/Pf2eDataScrapper/SchemaBuilder/Types/ArraySchemaType.cs @@ -1,28 +1,42 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Transactions; -using Newtonsoft.Json.Linq; +using Newtonsoft.Json.Linq; namespace Pf2eDataScrapper.SchemaBuilder.Types { + /// + /// Тип представоления массива в схеме. + /// + /// Элемент, к которому добавляется тип. internal class ArraySchemaType(SchemaNode parent) : AbstractSchemaType(parent) { + /// + /// Минимальное количество элементов в массиве. + /// public int MinCount = int.MaxValue; + /// + /// Максимальное количество элементов в массиве. + /// public int MaxCount = int.MinValue; + /// + /// Схема элемента массива. + /// protected SchemaNode ElementSchema = new(parent, "[]"); - protected List Values = []; - + /// + /// Проверка, что значение совместимо с текущим типом. + /// + /// Проверяемое значение. + /// `true`, если значение совместимо с текущим типом. public override bool IsCompatibleValue(JToken value) { return Resolver.TokenType(value) == JTokenType.Array; } + /// + /// Добавление нового значения. + /// + /// Новое значение. public override void AddValue(JToken value) { if (value.Type != JTokenType.Array) @@ -41,16 +55,27 @@ namespace Pf2eDataScrapper.SchemaBuilder.Types } } + /// + /// Подготовка типа к красивому представлению. + /// public override void Beautify() { - + ElementSchema.Beautify(); } + /// + /// Получение строкового представоения типа элемента. + /// + /// Строковое представоение типа элемента public override string GetTypeName() { return $"array<{ElementSchema.GetTypeName()}>"; } + /// + /// Полное строковое представление элемента. + /// + /// Строковое представление элемента. public override string ToString() { return string.Join("\n" + Tab, [ diff --git a/Pf2eDataScrapper/SchemaBuilder/Types/DictionarySchemaType.cs b/Pf2eDataScrapper/SchemaBuilder/Types/DictionarySchemaType.cs index 9bead9c..4a49d73 100644 --- a/Pf2eDataScrapper/SchemaBuilder/Types/DictionarySchemaType.cs +++ b/Pf2eDataScrapper/SchemaBuilder/Types/DictionarySchemaType.cs @@ -1,23 +1,37 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Newtonsoft.Json.Linq; +using Newtonsoft.Json.Linq; namespace Pf2eDataScrapper.SchemaBuilder.Types { + /// + /// Тип представоления словаря в схеме. + /// + /// Элемент, к которому добавляется тип. internal class DictionarySchemaType(SchemaNode parent) : AbstractSchemaType(parent) { + /// + /// Схема ключей словаря. + /// public SchemaNode KeyNode = new(parent, "[key]"); + /// + /// Схема значений словаря. + /// public SchemaNode ItemNode = new(parent, "[value]"); + /// + /// Проверка, что значение совместимо с текущим типом. + /// + /// Проверяемое значение. + /// `true`, если значение совместимо с текущим типом. public override bool IsCompatibleValue(JToken value) { return Resolver.TokenType(value) == JTokenType.Object; } + /// + /// Добавление нового значения. + /// + /// Новое значение. public override void AddValue(JToken value) { var obj = (JObject)value; @@ -29,16 +43,28 @@ namespace Pf2eDataScrapper.SchemaBuilder.Types } } + /// + /// Подготовка типа к красивому представлению. + /// public override void Beautify() { - + KeyNode.Beautify(); + ItemNode.Beautify(); } + /// + /// Получение строкового представоения типа элемента. + /// + /// Строковое представоение типа элемента public override string GetTypeName() { return $"dict<{KeyNode.GetTypeName()}, {ItemNode.GetTypeName()}>"; } + /// + /// Полное строковое представление элемента. + /// + /// Строковое представление элемента. public override string ToString() { return string.Join("\n" + Tab, [ diff --git a/Pf2eDataScrapper/SchemaBuilder/Types/IgnoreSchemaType.cs b/Pf2eDataScrapper/SchemaBuilder/Types/IgnoreSchemaType.cs index 2d2ce19..d5d7605 100644 --- a/Pf2eDataScrapper/SchemaBuilder/Types/IgnoreSchemaType.cs +++ b/Pf2eDataScrapper/SchemaBuilder/Types/IgnoreSchemaType.cs @@ -1,24 +1,42 @@ using Newtonsoft.Json.Linq; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace Pf2eDataScrapper.SchemaBuilder.Types { + /// + /// Тип, указывающий, что данные игнорируются. + /// + /// Элемент, к которому добавляется тип. internal class IgnoreSchemaType(SchemaNode parent) : AbstractSchemaType(parent) { + /// + /// Проверка, что значение совместимо с текущим типом. + /// + /// Проверяемое значение. + /// `true`, если значение совместимо с текущим типом. public override bool IsCompatibleValue(JToken value) { return true; } + + /// + /// Добавление нового значения. + /// + /// Новое значение. public override void AddValue(JToken value) { } + + /// + /// Подготовка типа к красивому представлению. + /// public override void Beautify() { } + + /// + /// Получение строкового представоения типа элемента. + /// + /// Строковое представоение типа элемента public override string GetTypeName() { return "ignore"; diff --git a/Pf2eDataScrapper/SchemaBuilder/Types/ObjectSchemaType.cs b/Pf2eDataScrapper/SchemaBuilder/Types/ObjectSchemaType.cs index 9a299b5..b5324d2 100644 --- a/Pf2eDataScrapper/SchemaBuilder/Types/ObjectSchemaType.cs +++ b/Pf2eDataScrapper/SchemaBuilder/Types/ObjectSchemaType.cs @@ -1,21 +1,32 @@ using Newtonsoft.Json.Linq; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace Pf2eDataScrapper.SchemaBuilder.Types { + /// + /// Тип представоления объектов в схеме. + /// + /// Элемент, к которому добавляется тип. internal class ObjectSchemaType(SchemaNode parent) : AbstractSchemaType(parent) { + /// + /// Элемнты полей объекта. + /// public List Fields = []; + /// + /// Проверка, что значение совместимо с текущим типом. + /// + /// Проверяемое значение. + /// `true`, если значение совместимо с текущим типом. public override bool IsCompatibleValue(JToken value) { return Resolver.TokenType(value) == JTokenType.Object; } + /// + /// Добавление нового значения. + /// + /// Новое значение. public override void AddValue(JToken value) { var obj = (JObject)value; @@ -42,6 +53,9 @@ namespace Pf2eDataScrapper.SchemaBuilder.Types } } + /// + /// Подготовка типа к красивому представлению. + /// public override void Beautify() { Fields.Sort((a, b) => @@ -51,7 +65,7 @@ namespace Pf2eDataScrapper.SchemaBuilder.Types return 1; } - return a.Name.CompareTo(b.Name); + return string.Compare(a.Name, b.Name, StringComparison.Ordinal); }); foreach (var field in Fields) @@ -60,11 +74,19 @@ namespace Pf2eDataScrapper.SchemaBuilder.Types } } + /// + /// Получение строкового представоения типа элемента. + /// + /// Строковое представоение типа элемента public override string GetTypeName() { return "object"; } + /// + /// Полное строковое представление элемента. + /// + /// Строковое представление элемента. public override string ToString() { List rows = [base.ToString()]; diff --git a/Pf2eDataScrapper/SchemaBuilder/Types/StaticSchemaType.cs b/Pf2eDataScrapper/SchemaBuilder/Types/StaticSchemaType.cs index ab3d565..4ad0fe7 100644 --- a/Pf2eDataScrapper/SchemaBuilder/Types/StaticSchemaType.cs +++ b/Pf2eDataScrapper/SchemaBuilder/Types/StaticSchemaType.cs @@ -2,17 +2,37 @@ namespace Pf2eDataScrapper.SchemaBuilder.Types { + /// + /// Тип представоления простых значений в схеме. + /// + /// Элемент, к которому добавляется тип. + /// Тип значения. internal class StaticSchemaType(SchemaNode parent, JTokenType type) : AbstractSchemaType(parent) { + /// + /// Тип значения. + /// protected JTokenType Type = type; + /// + /// Набор возможных значений и их количества. + /// protected Dictionary Values = []; - + + /// + /// Проверка, что значение совместимо с текущим типом. + /// + /// Проверяемое значение. + /// `true`, если значение совместимо с текущим типом. public override bool IsCompatibleValue(JToken value) { return value.Type == Type; } + /// + /// Добавление нового значения. + /// + /// Новое значение. public override void AddValue(JToken value) { Values.TryAdd(value, 0); @@ -20,6 +40,9 @@ namespace Pf2eDataScrapper.SchemaBuilder.Types Values[value]++; } + /// + /// Подготовка типа к красивому представлению. + /// public override void Beautify() { if (Type == JTokenType.String) @@ -39,11 +62,19 @@ namespace Pf2eDataScrapper.SchemaBuilder.Types Values = Values.OrderByDescending(pair => pair.Value).ToDictionary(pair => pair.Key, pair => pair.Value); } + /// + /// Получение строкового представоения типа элемента. + /// + /// Строковое представоение типа элемента public override string GetTypeName() { return Type.ToString().ToLower(); } + /// + /// Полное строковое представление элемента. + /// + /// Строковое представление элемента. public override string ToString() { var result = base.ToString();