using System.Diagnostics.CodeAnalysis; using NewJson = XFEExtension.NetCore.XFETransform.Json; namespace XFEExtension.NetCore.XFETransform.JsonConverter; /// /// 旧版可查询 JSON 节点兼容包装器。新代码应使用 。 /// [Obsolete("请使用 XFEJsonNode。QueryableJsonNode 将在下一个主版本中删除。")] public class QueryableJsonNode : INodeBase, IQueryableJsonNode { private readonly NewJson.XFEJsonNode? _lazyNode; private JsonNode? _originalNode; private int _layer; private string _propertyName = string.Empty; /// /// 使用旧版节点创建兼容包装器。 /// public QueryableJsonNode(JsonNode jsonNode) { _originalNode = jsonNode ?? throw new ArgumentNullException(nameof(jsonNode)); _layer = jsonNode.Layer; _propertyName = jsonNode.PropertyName; } internal QueryableJsonNode(NewJson.XFEJsonNode node, int layer = -1, string propertyName = "") { _lazyNode = node; _layer = layer; _propertyName = propertyName; } /// /// 空节点。 /// public static readonly QueryableJsonNode Empty = new(new JsonNode()); /// /// 按属性路径查询当前节点,或执行旧版 package 指令。 /// public QueryableJsonNode? this[params string[] nodeProperties] { get { ArgumentNullException.ThrowIfNull(nodeProperties); if (nodeProperties.Length == 0) throw new ArgumentException("至少需要一个属性名称或打包指令。", nameof(nodeProperties)); if (_lazyNode is null) return OriginalNode is JsonComplexPropertyNode complex ? JsonNodeConverter.AnalyzePropertyArray(nodeProperties, complex) : throw new InvalidOperationException("该节点为简单节点,无法继续查找。"); if (nodeProperties[0].StartsWith("package:", StringComparison.OrdinalIgnoreCase)) return Package(nodeProperties[0][8..], nodeProperties[1..]); var current = _lazyNode; var layer = _layer; string propertyName = _propertyName; foreach (var name in nodeProperties) { current = current[name]; if (current is null) return null; layer++; propertyName = name; } return new(current, layer, propertyName); } } /// /// 原始旧版节点。访问此属性会显式物化当前惰性子树。 /// public JsonNode OriginalNode => _originalNode ??= JsonNodeConverter.Materialize(_lazyNode!, _propertyName, _layer); /// /// 节点字符串值;对象和数组返回空字符串。 /// public string Value => _lazyNode is null ? OriginalNode is IValueNode valueNode ? valueNode.Value : string.Empty : JsonNodeConverter.GetCompatibilityValue(_lazyNode); internal object? InnerValue { get; set; } /// /// 标量数组的字符串列表。 /// public List List => GetList(); /// /// 旧版值类型。 /// public ValueType ValueType => _lazyNode is null ? OriginalNode is IValueNode valueNode ? valueNode.ValueType : ValueType.None : JsonNodeConverter.GetCompatibilityValueType(_lazyNode); /// /// 获取或设置兼容层级。 /// public int Layer { get => _layer; set { _layer = value; if (_originalNode is not null) _originalNode.Layer = value; } } /// /// 获取或设置兼容属性名称。 /// public string PropertyName { get => _propertyName; set { _propertyName = value; if (_originalNode is not null) _originalNode.PropertyName = value; } } /// /// 返回兼容字符串值。 /// public override string ToString() => Value; /// /// 获取当前标量值。 /// public object? GetValue() => _lazyNode is not null ? ValueType switch { ValueType.None or ValueType.Null => null, ValueType.Text => _lazyNode.GetString(), ValueType.Boolean => _lazyNode.GetBoolean(), ValueType.Int => _lazyNode.GetInt32(), ValueType.Long => _lazyNode.GetInt64(), ValueType.Float => _lazyNode.GetSingle(), _ => null } : OriginalNode is IValueNode valueNode ? GetValueByValueType(valueNode.Value, valueNode.ValueType) : null; /// /// 按旧版值类型转换字符串。 /// public static object? GetValueByValueType(string value, ValueType valueType) => valueType switch { ValueType.None or ValueType.Null => null, ValueType.Text => value, ValueType.Char => char.Parse(value), ValueType.Boolean => bool.Parse(value), ValueType.Int => int.Parse(value, System.Globalization.CultureInfo.InvariantCulture), ValueType.Long => long.Parse(value, System.Globalization.CultureInfo.InvariantCulture), ValueType.Float => float.Parse(value, System.Globalization.CultureInfo.InvariantCulture), _ => throw new NotSupportedException($"不支持旧版值类型 {valueType}。") }; /// /// 将当前节点转换为指定类型。 /// public T GetValue() => _lazyNode is not null ? _lazyNode.Deserialize()! : (T)GetValue()!; /// /// 获取标量数组的字符串列表。 /// public List GetList() => _lazyNode is not null ? [.. _lazyNode.EnumerateArray().Select(JsonNodeConverter.GetCompatibilityValue)] : OriginalNode is JsonComplexPropertyNode complex ? [.. complex.DescendingNodes.Select(node => node is IValueNode valueNode ? valueNode.Value : null!)] : throw new InvalidOperationException("当前节点不是数组。"); /// /// 获取指定类型的数组值。 /// public List GetList() => _lazyNode is not null ? [.. _lazyNode.EnumerateArray().Select(node => node.Deserialize()!)] : OriginalNode is JsonComplexPropertyNode complex ? [.. complex.DescendingNodes.Select(node => node is IValueNode valueNode ? (T)GetValueByValueType(valueNode.Value, valueNode.ValueType)! : default!)] : throw new InvalidOperationException("当前节点不是数组。"); /// /// 获取旧版数组对象投影结果。 /// [Obsolete("请使用 XFEJsonNode.ProjectArray。")] public List> PackageInListObject() => InnerValue as List> ?? throw new InvalidOperationException("当前节点不包含 package:list 结果。"); /// /// 获取旧版对象投影结果。 /// [Obsolete("请使用 XFEJsonNode.SelectProperties。")] public Dictionary PackageObject() => InnerValue as Dictionary ?? throw new InvalidOperationException("当前节点不包含 package:object 结果。"); /// /// 获取直接子节点。 /// public IEnumerable GetChildNodes() { if (_lazyNode is not null) { return _lazyNode.Kind switch { NewJson.XFEJsonValueKind.Array => _lazyNode.EnumerateArray().Select((node, index) => new QueryableJsonNode(node, _layer + 1, index.ToString())), NewJson.XFEJsonValueKind.Object => _lazyNode.EnumerateObject().Select(property => new QueryableJsonNode(property.Value, _layer + 1, property.Name)), _ => throw new InvalidOperationException("无法枚举标量节点的子节点。") }; } return OriginalNode is JsonComplexPropertyNode complex ? complex.DescendingNodes.Select(node => new QueryableJsonNode(node)) : throw new InvalidOperationException("无法枚举标量节点的子节点。"); } /// /// 隐式将 JSON 字符串转换为惰性兼容节点。 /// [return: NotNullIfNotNull(nameof(jsonString))] public static implicit operator QueryableJsonNode?(string? jsonString) => jsonString is null ? null : new(NewJson.XFEJson.Parse(jsonString)); /// /// 链式查询属性。 /// public static QueryableJsonNode? operator >(QueryableJsonNode? node, string propertyName) => node?[propertyName]; /// /// 链式查询属性。 /// public static QueryableJsonNode? operator <(QueryableJsonNode? node, string propertyName) => node?[propertyName]; /// /// 隐式读取兼容字符串值。 /// [return: NotNullIfNotNull(nameof(node))] public static implicit operator string?(QueryableJsonNode? node) => node?.ToString(); private QueryableJsonNode? Package(string packageType, string[] propertyNames) { if (_lazyNode is null) return null; if (packageType.Equals("object", StringComparison.OrdinalIgnoreCase)) { var result = new Dictionary(StringComparer.Ordinal); foreach (var pair in _lazyNode.SelectProperties(propertyNames)) { if (pair.Value is null || pair.Value.Kind is NewJson.XFEJsonValueKind.Object or NewJson.XFEJsonValueKind.Array) continue; result[pair.Key] = new(JsonNodeConverter.GetCompatibilityValue(pair.Value), JsonNodeConverter.GetCompatibilityValueType(pair.Value)); } return new QueryableJsonNode(_lazyNode, _layer, _propertyName) { InnerValue = result }; } if (packageType.Equals("list", StringComparison.OrdinalIgnoreCase)) { var result = new List>(); foreach (var projection in _lazyNode.ProjectArray(propertyNames)) { var item = new Dictionary(StringComparer.Ordinal); foreach (var pair in projection) { if (pair.Value is null || pair.Value.Kind is NewJson.XFEJsonValueKind.Object or NewJson.XFEJsonValueKind.Array) continue; item[pair.Key] = new(JsonNodeConverter.GetCompatibilityValue(pair.Value), JsonNodeConverter.GetCompatibilityValueType(pair.Value)); } result.Add(item); } return new QueryableJsonNode(_lazyNode, _layer, _propertyName) { InnerValue = result }; } return null; } }