using System; using System.Collections.Generic; using System.Data; using System.IO; using System.Linq; using ExcelDataReader; using Newtonsoft.Json.Linq; using UnityEditor; using UnityEngine; namespace BlueWater.Editors { public class ExcelToJsonConverter : EditorWindow { private const string ExcelFolderPath = "Assets/Resources/Excel"; private const string JsonFolderPath = "Assets/Resources/Json"; public static Dictionary ToggleStates; private List _differences; private bool _showPopup; private string _selectedExcelFile; public static ExcelToJsonConverter Instance { get; private set; } private Vector2 _scrollPosition; [MenuItem("Tools/EXCEL TO JSON - BlueWater")] public static void ShowWindow() { Instance = GetWindow("EXCEL TO JSON"); } private void OnEnable() { ToggleStates = new Dictionary(); var excelFiles = Directory.GetFiles(ExcelFolderPath, "*.xlsx"); foreach (var excelFile in excelFiles) { ToggleStates[Path.GetFileNameWithoutExtension(excelFile)] = false; } } public void ProcessSelectedFiles() { List currentDifferences = new List(); bool differencesFound = false; foreach (var excelFile in ToggleStates.Keys) { if (ToggleStates[excelFile]) { string excelPath = Path.Combine(ExcelFolderPath, excelFile + ".xlsx"); string jsonPath = Path.Combine(JsonFolderPath, excelFile + ".json"); JArray newJsonArray = ConvertExcelToJsonArray(excelPath); if (File.Exists(jsonPath)) { JArray existingJsonArray = JArray.Parse(File.ReadAllText(jsonPath)); currentDifferences = CompareJsonObjects(newJsonArray, existingJsonArray); if (currentDifferences.Count > 0) { _selectedExcelFile = excelFile; _differences = currentDifferences; _showPopup = true; differencesFound = true; break; } } else { File.WriteAllText(jsonPath, newJsonArray.ToString()); } } } if (!differencesFound && !_showPopup) { EditorUtility.DisplayDialog("달라진점이 없음", "비교 대상인 새로운 엑셀 파일과 기존의 제이슨 파일에서 다른 점을 발견하지 못했습니다.", "확인"); } } private void OnGUI() { EditorGUILayout.LabelField("EXCEL TO JSON - Select & Compare", EditorStyles.boldLabel); _scrollPosition = EditorGUILayout.BeginScrollView(_scrollPosition); List keys = new List(ToggleStates.Keys); foreach (var excelFile in keys) { bool currentValue = ToggleStates[excelFile]; bool newValue = EditorGUILayout.ToggleLeft(excelFile, currentValue); if (currentValue != newValue) { ToggleStates[excelFile] = newValue; } } EditorGUILayout.EndScrollView(); if (GUILayout.Button("수정사항 체크")) { CheckModifiedToggles(); } GUILayout.Space(10); EditorGUILayout.BeginHorizontal(); if (GUILayout.Button("전체 해제")) { foreach (var excelFile in keys) { ToggleStates[excelFile] = false; } } if (GUILayout.Button("전체 선택")) { foreach (var excelFile in keys) { ToggleStates[excelFile] = true; } } EditorGUILayout.EndHorizontal(); GUILayout.Space(10); if (GUILayout.Button("선택된 파일들 비교 및 병합")) { ProcessSelectedFiles(); } if (_showPopup) { DifferencePopup window = DifferencePopup.ShowWindow(_differences, _selectedExcelFile, JsonFolderPath); window.OnClose += () => _showPopup = false; } } public void CheckModifiedToggles() { List keysToCheck = new List(ToggleStates.Keys); foreach (var excelFile in keysToCheck) { string excelPath = Path.Combine(ExcelFolderPath, excelFile + ".xlsx"); string jsonPath = Path.Combine(JsonFolderPath, excelFile + ".json"); if (File.Exists(jsonPath)) { JArray newJsonArray = ConvertExcelToJsonArray(excelPath); JArray existingJsonArray = JArray.Parse(File.ReadAllText(jsonPath)); List currentDifferences = CompareJsonObjects(newJsonArray, existingJsonArray); if (currentDifferences.Count > 0) { ToggleStates[excelFile] = true; } else { ToggleStates[excelFile] = false; } } } } public static JArray ConvertExcelToJsonArray(string excelPath) { FileStream stream = File.Open(excelPath, FileMode.Open, FileAccess.Read); IExcelDataReader excelReader = ExcelReaderFactory.CreateOpenXmlReader(stream); DataSet result = excelReader.AsDataSet(new ExcelDataSetConfiguration() { ConfigureDataTable = (tableReader) => new ExcelDataTableConfiguration() { UseHeaderRow = true } }); stream.Close(); DataTable table = result.Tables[0]; JArray jsonArray = new JArray(); foreach (DataRow row in table.Rows) { JObject obj = new JObject(); foreach (DataColumn column in table.Columns) { string cellValue = row[column].ToString(); if (float.TryParse(cellValue, out float floatResult)) { if (floatResult % 1 == 0) { obj[column.ColumnName] = Convert.ToInt32(floatResult); } else { obj[column.ColumnName] = floatResult; } } else if (IsString(cellValue)) { obj[column.ColumnName] = cellValue; } else { obj[column.ColumnName] = cellValue; } } jsonArray.Add(obj); } return jsonArray; } private static bool IsString(string value) { return value.Any(c => !char.IsDigit(c)); } private List CompareJsonObjects(JArray newObj, JArray existingObj) { List differences = new List(); int minLength = Mathf.Min(newObj.Count, existingObj.Count); int maxLength = Mathf.Max(newObj.Count, existingObj.Count); for (int i = 0; i < maxLength; i++) { if (i < minLength) { JObject newItem = newObj[i] as JObject; JObject existingItem = existingObj[i] as JObject; if (newItem != null && existingItem != null) { HashSet allPropertyNames = new HashSet(newItem.Properties().Select(p => p.Name)); allPropertyNames.UnionWith(existingItem.Properties().Select(p => p.Name)); foreach (string propertyName in allPropertyNames) { JToken newToken; JToken existingToken; if (newItem.TryGetValue(propertyName, out newToken) && existingItem.TryGetValue(propertyName, out existingToken)) { string newValueWithoutSpaces = newToken.ToString().Replace(" ", ""); string existingValueWithoutSpaces = existingToken.ToString().Replace(" ", ""); if (!newValueWithoutSpaces.Equals(existingValueWithoutSpaces)) { differences.Add(new DifferencePopup.Difference(propertyName, newToken.ToString(), existingToken.ToString(), i)); } } else if (!newItem.TryGetValue(propertyName, out newToken) && existingItem.TryGetValue(propertyName, out existingToken)) { differences.Add(new DifferencePopup.Difference(propertyName, "N/A", existingToken.ToString(), i)); } else if (newItem.TryGetValue(propertyName, out newToken) && !existingItem.TryGetValue(propertyName, out existingToken)) { differences.Add(new DifferencePopup.Difference(propertyName, newToken.ToString(), "N/A", i)); } } } else { Debug.LogError($"해당 인덱스에서 JSON 객체를 비교하지 못했습니다 {i}"); } } else { // 추가된 행에 대한 차이를 처리합니다. JObject newItem = i < newObj.Count ? newObj[i] as JObject : null; JObject existingItem = i < existingObj.Count ? existingObj[i] as JObject : null; JObject availableItem = newItem ?? existingItem; string newValue, existingValue; foreach (var property in availableItem.Properties()) { if (newItem != null && newItem.TryGetValue(property.Name, out JToken newToken)) { newValue = newToken.ToString(); } else { newValue = "N/A"; } if (existingItem != null && existingItem.TryGetValue(property.Name, out JToken existingToken)) { existingValue = existingToken.ToString(); } else { existingValue = "N/A"; } differences.Add(new DifferencePopup.Difference(property.Name, newValue, existingValue, i)); } } } return differences; } } }