using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using CncModels.Entity;
using System.Linq;
using log4net;
namespace CncCollector.Core
{
///
/// JSON 解析引擎:将原始 JSON 与品牌字段映射表结合,输出结构化字段字典。
///
public static class DataParser
{
/// 解析结果中的字段
public class ParsedField
{
/// 字段名(标准化后)
public string FieldName { get; set; }
/// 字段值
public object Value { get; set; }
/// 数据类型
public string DataType { get; set; }
}
private static readonly ILog Log = LogManager.GetLogger(typeof(DataParser));
///
/// 解析原始 JSON,并根据品牌映射提取字段。
/// 该实现尽量适配常见结构:JSON 为数组,元素包含一个 tags 数组,tags 中的元素拥有 id/value。
///
/// 品牌名称,用于定位字段映射(若为 null,尝试使用空映射)
/// 原始 JSON 字符串
/// 可选的品牌对象,包含映射信息
/// 解析后的字段字典,Key 为标准字段名
public static Dictionary Parse(string brandName, string json, Brand brand = null)
{
var result = new Dictionary();
if (string.IsNullOrWhiteSpace(json)) return result;
try
{
var root = JArray.Parse(json);
// 优先使用传入的 brand(若品牌包含字段映射)来定位 tags
var mappings = brand?.BrandFieldMappings?.ToList() ?? new List();
foreach (var item in root)
{
// 定位 tags 列表,默认字段路径为 "tags"
var tagsPath = brand?.TagsPath ?? "tags";
var tagsToken = item.SelectToken(tagsPath);
if (tagsToken == null) continue;
if (tagsToken is JArray tags)
{
foreach (var map in mappings)
{
var tag = tags.FirstOrDefault(t => string.Equals(t["id"]?.ToString(), map.FieldName, StringComparison.OrdinalIgnoreCase));
if (tag != null)
{
var raw = tag["value"]?.ToString();
var value = ConvertValue(raw, map.DataType);
var field = new ParsedField
{
FieldName = map.StandardField,
Value = value,
DataType = map.DataType
};
result[field.FieldName] = field;
}
}
}
// 解析到一个设备后就返回,简化实现
break;
}
}
catch (Exception ex)
{
Log.Error("DataParser 解析异常", ex);
}
return result;
}
private static object ConvertValue(string raw, string dataType)
{
if (string.IsNullOrWhiteSpace(raw)) return null;
if (string.Equals(dataType, "number", StringComparison.OrdinalIgnoreCase))
{
if (decimal.TryParse(raw, out var d)) return d;
}
// 去除形如 1219.00000 的尾缀
if (raw.EndsWith(".00000") && decimal.TryParse(raw.Replace(".00000", ""), out var d2))
{
return d2;
}
return raw;
}
}
}