XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

XFEExtension

【DLL】XFE各类拓展是一个C#的DLL库,旨在优化C#代码中常用语句的使用,并提供更简洁的访问方式,同时提供Xunit测试框架,快速搭建服务器/客户端,免费ChatGPTAPI接口,免费通讯服务器,XFE下载器,新增格式等

公开
关注 0 Fork 0 Star 0
UTF-8
using NewJson = XFEExtension.NetCore.XFETransform.Json;

namespace XFEExtension.NetCore.XFETransform.JsonConverter;

/// <summary>
/// 旧版 JSON 节点树转换器。新代码应使用 <see cref="NewJson.XFEJson"/> 和
/// <see cref="NewJson.XFEJsonNode"/> 的惰性 API。
/// </summary>
/// <param name="jsonString">JSON 文本。</param>
[Obsolete("JsonNodeConverter 会显式物化完整兼容树。请使用 XFEJson.Parse 获取惰性 XFEJsonNode。")]
public class JsonNodeConverter(string jsonString)
{
    /// <summary>
    /// 原始 JSON 字符串。
    /// </summary>
    public string JsonString { get; set; } = jsonString;

    /// <summary>
    /// 将 JSON 显式物化为旧版节点树。
    /// </summary>
    public JsonNode ConvertToJsonNode()
    {
        ArgumentNullException.ThrowIfNull(JsonString);
        var root = NewJson.XFEJson.Parse(JsonString);
        root.Validate();
        return Materialize(root, string.Empty, -1);
    }

    internal static QueryableJsonNode? AnalyzePropertyArray(string[] nodeProperties, JsonComplexPropertyNode jsonComplexPropertyNode)
    {
        ArgumentNullException.ThrowIfNull(nodeProperties);
        if (nodeProperties.Length == 0)
            throw new ArgumentException("至少需要一个属性名称或打包指令。", nameof(nodeProperties));

        if (nodeProperties[0].StartsWith("package:", StringComparison.OrdinalIgnoreCase))
        {
            return nodeProperties[0][8..].ToLowerInvariant() switch
            {
                "list" => NodeOperator.PackageInList(nodeProperties[1..], jsonComplexPropertyNode),
                "object" => NodeOperator.PackageToList(nodeProperties[1..], jsonComplexPropertyNode),
                _ => null
            };
        }

        JsonNode current = jsonComplexPropertyNode;
        foreach (var propertyName in nodeProperties)
        {
            if (current is not JsonComplexPropertyNode complex)
                throw new InvalidOperationException("该节点为简单节点,无法继续查找。");
            current = complex.DescendingNodes.Find(node => node.PropertyName == propertyName)!;
            if (current is null)
                return null;
        }
        return new(current);
    }

    internal static JsonNode Materialize(NewJson.XFEJsonNode node, string propertyName, int layer)
    {
        switch (node.Kind)
        {
            case NewJson.XFEJsonValueKind.Object:
                {
                    var result = new JsonComplexPropertyNode
                    {
                        IsList = false,
                        Layer = layer,
                        PropertyName = propertyName
                    };
                    foreach (var property in node.EnumerateObject())
                        result.DescendingNodes.Add(Materialize(property.Value, property.Name, layer + 1));
                    return result;
                }
            case NewJson.XFEJsonValueKind.Array:
                {
                    var result = new JsonComplexPropertyNode
                    {
                        IsList = true,
                        Layer = layer,
                        PropertyName = propertyName
                    };
                    foreach (var element in node.EnumerateArray())
                        result.DescendingNodes.Add(Materialize(element, string.Empty, layer + 1));
                    return result;
                }
            default:
                return new JsonPropertyNode
                {
                    Layer = layer,
                    PropertyName = propertyName,
                    Value = GetCompatibilityValue(node),
                    ValueType = GetCompatibilityValueType(node)
                };
        }
    }

    internal static string GetCompatibilityValue(NewJson.XFEJsonNode node) => node.Kind switch
    {
        NewJson.XFEJsonValueKind.String => node.GetString() ?? string.Empty,
        NewJson.XFEJsonValueKind.Null => string.Empty,
        _ => node.GetRawText()
    };

    internal static ValueType GetCompatibilityValueType(NewJson.XFEJsonNode node)
    {
        return node.Kind switch
        {
            NewJson.XFEJsonValueKind.String => ValueType.Text,
            NewJson.XFEJsonValueKind.True or NewJson.XFEJsonValueKind.False => ValueType.Boolean,
            NewJson.XFEJsonValueKind.Null => ValueType.Null,
            NewJson.XFEJsonValueKind.Number => JudgeNumberType(node.GetRawText()),
            _ => ValueType.None
        };
    }

    private static ValueType JudgeNumberType(string rawText)
    {
        if (rawText.ContainsAny('.', 'e', 'E'))
            return ValueType.Float;
        if (int.TryParse(rawText, System.Globalization.NumberStyles.AllowLeadingSign,
                System.Globalization.CultureInfo.InvariantCulture, out _))
            return ValueType.Int;
        return long.TryParse(rawText, System.Globalization.NumberStyles.AllowLeadingSign,
            System.Globalization.CultureInfo.InvariantCulture, out _) ? ValueType.Long : ValueType.Float;
    }
}