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; } } }