ExportExcel 정리, height정렬 attRef 분리
This commit is contained in:
0
Models/AppSettings.cs
Normal file
0
Models/AppSettings.cs
Normal file
397
Models/DwgDataExtractor.cs
Normal file
397
Models/DwgDataExtractor.cs
Normal file
@@ -0,0 +1,397 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using Teigha.DatabaseServices;
|
||||
using Teigha.Runtime;
|
||||
|
||||
namespace DwgExtractorManual.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// DWG 파일에서 텍스트 엔티티를 추출하는 클래스
|
||||
/// </summary>
|
||||
internal class DwgDataExtractor
|
||||
{
|
||||
private readonly FieldMapper fieldMapper;
|
||||
|
||||
public DwgDataExtractor(FieldMapper fieldMapper)
|
||||
{
|
||||
this.fieldMapper = fieldMapper ?? throw new ArgumentNullException(nameof(fieldMapper));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// DWG 파일에서 데이터를 추출하여 ExcelRowData 리스트로 반환
|
||||
/// </summary>
|
||||
public DwgExtractionResult ExtractFromDwgFile(string filePath, IProgress<double>? progress = null, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var result = new DwgExtractionResult();
|
||||
|
||||
if (!File.Exists(filePath))
|
||||
{
|
||||
Debug.WriteLine($"? 파일이 존재하지 않습니다: {filePath}");
|
||||
return result;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
progress?.Report(0);
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
using (var database = new Database(false, true))
|
||||
{
|
||||
database.ReadDwgFile(filePath, FileOpenMode.OpenForReadAndWriteNoShare, false, null);
|
||||
progress?.Report(10);
|
||||
|
||||
using (var tran = database.TransactionManager.StartTransaction())
|
||||
{
|
||||
var bt = tran.GetObject(database.BlockTableId, OpenMode.ForRead) as BlockTable;
|
||||
using (var btr = tran.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForRead) as BlockTableRecord)
|
||||
{
|
||||
int totalEntities = btr.Cast<ObjectId>().Count();
|
||||
int processedCount = 0;
|
||||
var fileName = Path.GetFileNameWithoutExtension(database.Filename);
|
||||
|
||||
if (string.IsNullOrEmpty(fileName))
|
||||
{
|
||||
fileName = "Unknown_File";
|
||||
}
|
||||
|
||||
foreach (ObjectId entId in btr)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
using (var ent = tran.GetObject(entId, OpenMode.ForRead) as Entity)
|
||||
{
|
||||
string layerName = GetLayerName(ent.LayerId, tran, database);
|
||||
|
||||
ProcessEntity(ent, tran, database, layerName, fileName, result);
|
||||
}
|
||||
|
||||
processedCount++;
|
||||
double currentProgress = 10.0 + (double)processedCount / totalEntities * 80.0;
|
||||
progress?.Report(Math.Min(currentProgress, 90.0));
|
||||
}
|
||||
}
|
||||
|
||||
tran.Commit();
|
||||
}
|
||||
}
|
||||
|
||||
progress?.Report(100);
|
||||
return result;
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
Debug.WriteLine("? 작업이 취소되었습니다.");
|
||||
progress?.Report(0);
|
||||
return result;
|
||||
}
|
||||
catch (Teigha.Runtime.Exception ex)
|
||||
{
|
||||
progress?.Report(0);
|
||||
Debug.WriteLine($"? DWG 파일 처리 중 Teigha 오류 발생: {ex.Message}");
|
||||
return result;
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
progress?.Report(0);
|
||||
Debug.WriteLine($"? 일반 오류 발생: {ex.Message}");
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// DWG 파일에서 텍스트 엔티티들을 추출하여 Height 정보와 함께 반환합니다.
|
||||
/// </summary>
|
||||
public List<TextEntityInfo> ExtractTextEntitiesWithHeight(string filePath)
|
||||
{
|
||||
var attRefEntities = new List<TextEntityInfo>();
|
||||
var otherTextEntities = new List<TextEntityInfo>();
|
||||
|
||||
try
|
||||
{
|
||||
using (var database = new Database(false, true))
|
||||
{
|
||||
database.ReadDwgFile(filePath, FileOpenMode.OpenForReadAndWriteNoShare, false, null);
|
||||
|
||||
using (var tran = database.TransactionManager.StartTransaction())
|
||||
{
|
||||
var bt = tran.GetObject(database.BlockTableId, OpenMode.ForRead) as BlockTable;
|
||||
using (var btr = tran.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForRead) as BlockTableRecord)
|
||||
{
|
||||
foreach (ObjectId entId in btr)
|
||||
{
|
||||
using (var ent = tran.GetObject(entId, OpenMode.ForRead) as Entity)
|
||||
{
|
||||
string layerName = GetLayerName(ent.LayerId, tran, database);
|
||||
|
||||
// AttributeReference 처리
|
||||
if (ent is BlockReference blr)
|
||||
{
|
||||
foreach (ObjectId attId in blr.AttributeCollection)
|
||||
{
|
||||
using (var attRef = tran.GetObject(attId, OpenMode.ForRead) as AttributeReference)
|
||||
{
|
||||
if (attRef != null)
|
||||
{
|
||||
var textString = attRef.TextString == null ? "" : attRef.TextString;
|
||||
attRefEntities.Add(new TextEntityInfo
|
||||
{
|
||||
Height = attRef.Height,
|
||||
Type = "AttRef",
|
||||
Layer = layerName,
|
||||
Tag = attRef.Tag,
|
||||
Text = textString,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// DBText 처리
|
||||
else if (ent is DBText dbText)
|
||||
{
|
||||
otherTextEntities.Add(new TextEntityInfo
|
||||
{
|
||||
Height = dbText.Height,
|
||||
Type = "DBText",
|
||||
Layer = layerName,
|
||||
Tag = "",
|
||||
Text = dbText.TextString
|
||||
});
|
||||
}
|
||||
// MText 처리
|
||||
else if (ent is MText mText)
|
||||
{
|
||||
otherTextEntities.Add(new TextEntityInfo
|
||||
{
|
||||
Height = mText.Height,
|
||||
Type = "MText",
|
||||
Layer = layerName,
|
||||
Tag = "",
|
||||
Text = mText.Contents
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tran.Commit();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
Debug.WriteLine($"? 텍스트 엔티티 추출 중 오류 ({Path.GetFileName(filePath)}): {ex.Message}");
|
||||
}
|
||||
|
||||
var sortedAttRefEntities = attRefEntities.OrderByDescending(e => e.Height).ToList();
|
||||
var sortedOtherTextEntities = otherTextEntities.OrderByDescending(e => e.Height).ToList();
|
||||
|
||||
sortedAttRefEntities.AddRange(sortedOtherTextEntities);
|
||||
return sortedAttRefEntities;
|
||||
}
|
||||
|
||||
private void ProcessEntity(Entity ent, Transaction tran, Database database, string layerName, string fileName, DwgExtractionResult result)
|
||||
{
|
||||
// AttributeDefinition 추출
|
||||
if (ent is AttributeDefinition attDef)
|
||||
{
|
||||
var titleBlockRow = new TitleBlockRowData
|
||||
{
|
||||
Type = attDef.GetType().Name,
|
||||
Name = attDef.BlockName,
|
||||
Tag = attDef.Tag,
|
||||
Prompt = attDef.Prompt,
|
||||
Value = attDef.TextString,
|
||||
Path = database.Filename,
|
||||
FileName = Path.GetFileName(database.Filename)
|
||||
};
|
||||
|
||||
result.TitleBlockRows.Add(titleBlockRow);
|
||||
|
||||
// 매핑 데이터 저장
|
||||
AddMappingData(fileName, attDef.Tag, attDef.TextString, result);
|
||||
}
|
||||
// BlockReference 및 그 안의 AttributeReference 추출
|
||||
else if (ent is BlockReference blr)
|
||||
{
|
||||
foreach (ObjectId attId in blr.AttributeCollection)
|
||||
{
|
||||
using (var attRef = tran.GetObject(attId, OpenMode.ForRead) as AttributeReference)
|
||||
{
|
||||
if (attRef != null && attRef.TextString.Trim() != "")
|
||||
{
|
||||
var titleBlockRow = new TitleBlockRowData
|
||||
{
|
||||
Type = attRef.GetType().Name,
|
||||
Name = blr.Name,
|
||||
Tag = attRef.Tag,
|
||||
Prompt = GetPromptFromAttributeReference(tran, blr, attRef.Tag),
|
||||
Value = attRef.TextString,
|
||||
Path = database.Filename,
|
||||
FileName = Path.GetFileName(database.Filename)
|
||||
};
|
||||
|
||||
result.TitleBlockRows.Add(titleBlockRow);
|
||||
|
||||
// 매핑 데이터 저장
|
||||
var aiLabel = fieldMapper.ExpresswayToAilabel(attRef.Tag);
|
||||
if (aiLabel != null)
|
||||
{
|
||||
AddMappingData(fileName, attRef.Tag, attRef.TextString, result);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// DBText 엔티티 추출 (별도 시트)
|
||||
else if (ent is DBText dbText)
|
||||
{
|
||||
var textEntityRow = new TextEntityRowData
|
||||
{
|
||||
Type = "DBText",
|
||||
Layer = layerName,
|
||||
Text = dbText.TextString,
|
||||
Path = database.Filename,
|
||||
FileName = Path.GetFileName(database.Filename)
|
||||
};
|
||||
|
||||
result.TextEntityRows.Add(textEntityRow);
|
||||
}
|
||||
// MText 엔티티 추출 (별도 시트)
|
||||
else if (ent is MText mText)
|
||||
{
|
||||
var textEntityRow = new TextEntityRowData
|
||||
{
|
||||
Type = "MText",
|
||||
Layer = layerName,
|
||||
Text = mText.Contents,
|
||||
Path = database.Filename,
|
||||
FileName = Path.GetFileName(database.Filename)
|
||||
};
|
||||
|
||||
result.TextEntityRows.Add(textEntityRow);
|
||||
}
|
||||
}
|
||||
|
||||
private void AddMappingData(string fileName, string tag, string attValue, DwgExtractionResult result)
|
||||
{
|
||||
var aiLabel = fieldMapper.ExpresswayToAilabel(tag);
|
||||
var mapKey = fieldMapper.AilabelToDocAiKey(aiLabel);
|
||||
|
||||
if (!string.IsNullOrEmpty(aiLabel))
|
||||
{
|
||||
var finalMapKey = mapKey ?? aiLabel;
|
||||
result.AddMappingData(fileName, finalMapKey, aiLabel, tag, attValue, "");
|
||||
}
|
||||
else
|
||||
{
|
||||
var finalMapKey = mapKey ?? tag;
|
||||
if (!string.IsNullOrEmpty(finalMapKey))
|
||||
{
|
||||
result.AddMappingData(fileName, finalMapKey, tag, tag, attValue, "");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private string? GetPromptFromAttributeReference(Transaction tr, BlockReference blockref, string tag)
|
||||
{
|
||||
string? prompt = null;
|
||||
|
||||
BlockTableRecord? blockDef = tr.GetObject(blockref.BlockTableRecord, OpenMode.ForRead) as BlockTableRecord;
|
||||
if (blockDef == null) return null;
|
||||
|
||||
foreach (ObjectId objId in blockDef)
|
||||
{
|
||||
AttributeDefinition? attDef = tr.GetObject(objId, OpenMode.ForRead) as AttributeDefinition;
|
||||
if (attDef != null)
|
||||
{
|
||||
if (attDef.Tag.Equals(tag, System.StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
prompt = attDef.Prompt;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return prompt;
|
||||
}
|
||||
|
||||
private string GetLayerName(ObjectId layerId, Transaction transaction, Database database)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var layerTableRecord = transaction.GetObject(layerId, OpenMode.ForRead) as LayerTableRecord)
|
||||
{
|
||||
return layerTableRecord?.Name ?? "";
|
||||
}
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
Debug.WriteLine($"Layer 이름 가져오기 오류: {ex.Message}");
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// DWG 추출 결과를 담는 클래스
|
||||
/// </summary>
|
||||
public class DwgExtractionResult
|
||||
{
|
||||
public List<TitleBlockRowData> TitleBlockRows { get; set; } = new List<TitleBlockRowData>();
|
||||
public List<TextEntityRowData> TextEntityRows { get; set; } = new List<TextEntityRowData>();
|
||||
public Dictionary<string, Dictionary<string, (string, string, string, string)>> FileToMapkeyToLabelTagValuePdf { get; set; }
|
||||
= new Dictionary<string, Dictionary<string, (string, string, string, string)>>();
|
||||
|
||||
public void AddMappingData(string fileName, string mapKey, string aiLabel, string dwgTag, string dwgValue, string pdfValue)
|
||||
{
|
||||
if (!FileToMapkeyToLabelTagValuePdf.ContainsKey(fileName))
|
||||
{
|
||||
FileToMapkeyToLabelTagValuePdf[fileName] = new Dictionary<string, (string, string, string, string)>();
|
||||
}
|
||||
|
||||
FileToMapkeyToLabelTagValuePdf[fileName][mapKey] = (aiLabel, dwgTag, dwgValue, pdfValue);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Title Block 행 데이터
|
||||
/// </summary>
|
||||
public class TitleBlockRowData
|
||||
{
|
||||
public string Type { get; set; } = "";
|
||||
public string Name { get; set; } = "";
|
||||
public string Tag { get; set; } = "";
|
||||
public string Prompt { get; set; } = "";
|
||||
public string Value { get; set; } = "";
|
||||
public string Path { get; set; } = "";
|
||||
public string FileName { get; set; } = "";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Text Entity 행 데이터
|
||||
/// </summary>
|
||||
public class TextEntityRowData
|
||||
{
|
||||
public string Type { get; set; } = "";
|
||||
public string Layer { get; set; } = "";
|
||||
public string Text { get; set; } = "";
|
||||
public string Path { get; set; } = "";
|
||||
public string FileName { get; set; } = "";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 텍스트 엔티티 정보를 담는 클래스
|
||||
/// </summary>
|
||||
public class TextEntityInfo
|
||||
{
|
||||
public double Height { get; set; }
|
||||
public string Type { get; set; } = "";
|
||||
public string Layer { get; set; } = "";
|
||||
public string Tag { get; set; } = "";
|
||||
public string Text { get; set; } = "";
|
||||
}
|
||||
}
|
||||
279
Models/ExcelDataWriter.cs
Normal file
279
Models/ExcelDataWriter.cs
Normal file
@@ -0,0 +1,279 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using Excel = Microsoft.Office.Interop.Excel;
|
||||
|
||||
namespace DwgExtractorManual.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// Excel 시트에 데이터를 쓰는 작업을 담당하는 클래스
|
||||
/// </summary>
|
||||
internal class ExcelDataWriter
|
||||
{
|
||||
private readonly ExcelManager excelManager;
|
||||
|
||||
public ExcelDataWriter(ExcelManager excelManager)
|
||||
{
|
||||
this.excelManager = excelManager ?? throw new ArgumentNullException(nameof(excelManager));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Title Block 데이터를 Excel 시트에 기록
|
||||
/// </summary>
|
||||
public void WriteTitleBlockData(List<TitleBlockRowData> titleBlockRows)
|
||||
{
|
||||
if (excelManager.TitleBlockSheet == null || titleBlockRows == null || titleBlockRows.Count == 0)
|
||||
return;
|
||||
|
||||
int currentRow = 2; // 헤더 다음 행부터 시작
|
||||
|
||||
foreach (var row in titleBlockRows)
|
||||
{
|
||||
excelManager.TitleBlockSheet.Cells[currentRow, 1] = row.Type;
|
||||
excelManager.TitleBlockSheet.Cells[currentRow, 2] = row.Name;
|
||||
excelManager.TitleBlockSheet.Cells[currentRow, 3] = row.Tag;
|
||||
excelManager.TitleBlockSheet.Cells[currentRow, 4] = row.Prompt;
|
||||
excelManager.TitleBlockSheet.Cells[currentRow, 5] = row.Value;
|
||||
excelManager.TitleBlockSheet.Cells[currentRow, 6] = row.Path;
|
||||
excelManager.TitleBlockSheet.Cells[currentRow, 7] = row.FileName;
|
||||
currentRow++;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Text Entity 데이터를 Excel 시트에 기록
|
||||
/// </summary>
|
||||
public void WriteTextEntityData(List<TextEntityRowData> textEntityRows)
|
||||
{
|
||||
if (excelManager.TextEntitiesSheet == null || textEntityRows == null || textEntityRows.Count == 0)
|
||||
return;
|
||||
|
||||
int currentRow = 2; // 헤더 다음 행부터 시작
|
||||
|
||||
foreach (var row in textEntityRows)
|
||||
{
|
||||
excelManager.TextEntitiesSheet.Cells[currentRow, 1] = row.Type;
|
||||
excelManager.TextEntitiesSheet.Cells[currentRow, 2] = row.Layer;
|
||||
excelManager.TextEntitiesSheet.Cells[currentRow, 3] = row.Text;
|
||||
excelManager.TextEntitiesSheet.Cells[currentRow, 4] = row.Path;
|
||||
excelManager.TextEntitiesSheet.Cells[currentRow, 5] = row.FileName;
|
||||
currentRow++;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 매핑 데이터를 Excel 시트에 기록
|
||||
/// </summary>
|
||||
public void WriteMappingDataToExcel(Dictionary<string, Dictionary<string, (string, string, string, string)>> mappingData)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (excelManager.MappingSheet == null || mappingData == null)
|
||||
return;
|
||||
|
||||
int currentRow = 2; // 헤더 다음 행부터 시작
|
||||
|
||||
Debug.WriteLine($"[DEBUG] Writing mapping data to Excel. Total files: {mappingData.Count}");
|
||||
|
||||
foreach (var fileEntry in mappingData)
|
||||
{
|
||||
string fileName = fileEntry.Key;
|
||||
var fileMappingData = fileEntry.Value;
|
||||
|
||||
Debug.WriteLine($"[DEBUG] Processing file: {fileName}, entries: {fileMappingData.Count}");
|
||||
|
||||
foreach (var mapEntry in fileMappingData)
|
||||
{
|
||||
string mapKey = mapEntry.Key;
|
||||
(string aiLabel, string dwgTag, string attValue, string pdfValue) = mapEntry.Value;
|
||||
|
||||
if (string.IsNullOrEmpty(fileName) || string.IsNullOrEmpty(mapKey))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// 배치 업데이트를 위한 배열 사용
|
||||
object[,] rowData = new object[1, 6];
|
||||
rowData[0, 0] = fileName;
|
||||
rowData[0, 1] = mapKey;
|
||||
rowData[0, 2] = aiLabel ?? "";
|
||||
rowData[0, 3] = dwgTag ?? "";
|
||||
rowData[0, 4] = attValue ?? "";
|
||||
rowData[0, 5] = pdfValue ?? "";
|
||||
|
||||
Excel.Range range = excelManager.MappingSheet.Range[
|
||||
excelManager.MappingSheet.Cells[currentRow, 1],
|
||||
excelManager.MappingSheet.Cells[currentRow, 6]];
|
||||
range.Value = rowData;
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
Debug.WriteLine($"? Error writing row {currentRow}: {ex.Message}");
|
||||
}
|
||||
|
||||
currentRow++;
|
||||
}
|
||||
}
|
||||
|
||||
Debug.WriteLine($"[DEBUG] Mapping data written to Excel. Total rows: {currentRow - 2}");
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
Debug.WriteLine($"? 매핑 데이터 Excel 기록 중 오류: {ex.Message}");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Excel 매핑 시트에서 FileName과 AILabel이 매칭되는 행을 찾아 Pdf_value를 업데이트
|
||||
/// </summary>
|
||||
public bool UpdateExcelRow(string fileName, string aiLabel, string pdfValue)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (excelManager.MappingSheet == null)
|
||||
return false;
|
||||
|
||||
Excel.Range usedRange = excelManager.MappingSheet.UsedRange;
|
||||
if (usedRange == null) return false;
|
||||
|
||||
int lastRow = usedRange.Rows.Count;
|
||||
|
||||
for (int row = 2; row <= lastRow; row++)
|
||||
{
|
||||
var cellFileName = excelManager.MappingSheet.Cells[row, 1]?.Value?.ToString() ?? "";
|
||||
var cellAiLabel = excelManager.MappingSheet.Cells[row, 3]?.Value?.ToString() ?? "";
|
||||
|
||||
if (string.Equals(cellFileName.Trim(), fileName.Trim(), StringComparison.OrdinalIgnoreCase) &&
|
||||
string.Equals(cellAiLabel.Trim(), aiLabel.Trim(), StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
excelManager.MappingSheet.Cells[row, 6] = pdfValue;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
Debug.WriteLine($"? Excel 행 업데이트 중 오류: {ex.Message}");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// DWG 전용 매핑 워크북을 생성하고 저장 (PDF 컬럼 제외)
|
||||
/// </summary>
|
||||
public void SaveDwgOnlyMappingWorkbook(Dictionary<string, Dictionary<string, (string, string, string, string)>> mappingData, string resultFolderPath)
|
||||
{
|
||||
try
|
||||
{
|
||||
string timestamp = DateTime.Now.ToString("yyyyMMdd_HHmmss");
|
||||
string savePath = System.IO.Path.Combine(resultFolderPath, $"{timestamp}_DwgOnly_Mapping.xlsx");
|
||||
|
||||
Debug.WriteLine($"[DEBUG] DWG 전용 매핑 워크북 생성 시작: {savePath}");
|
||||
|
||||
var dwgOnlyWorkbook = excelManager.CreateNewWorkbook();
|
||||
var dwgOnlyWorksheet = (Excel.Worksheet)dwgOnlyWorkbook.Worksheets[1];
|
||||
dwgOnlyWorksheet.Name = "DWG Mapping Data";
|
||||
|
||||
// 헤더 생성 (PDF Value 컬럼 제외)
|
||||
dwgOnlyWorksheet.Cells[1, 1] = "파일명";
|
||||
dwgOnlyWorksheet.Cells[1, 2] = "Map Key";
|
||||
dwgOnlyWorksheet.Cells[1, 3] = "AI Label";
|
||||
dwgOnlyWorksheet.Cells[1, 4] = "DWG Tag";
|
||||
dwgOnlyWorksheet.Cells[1, 5] = "DWG Value";
|
||||
|
||||
// 헤더 스타일 적용
|
||||
var headerRange = dwgOnlyWorksheet.Range["A1:E1"];
|
||||
headerRange.Font.Bold = true;
|
||||
headerRange.Interior.Color = System.Drawing.ColorTranslator.ToOle(System.Drawing.Color.LightGray);
|
||||
headerRange.Borders.LineStyle = Excel.XlLineStyle.xlContinuous;
|
||||
|
||||
// 데이터 입력
|
||||
int totalRows = mappingData.Sum(f => f.Value.Count);
|
||||
if (totalRows > 0)
|
||||
{
|
||||
object[,] data = new object[totalRows, 5];
|
||||
int row = 0;
|
||||
|
||||
foreach (var fileEntry in mappingData)
|
||||
{
|
||||
string fileName = fileEntry.Key;
|
||||
foreach (var mapEntry in fileEntry.Value)
|
||||
{
|
||||
string mapKey = mapEntry.Key;
|
||||
var (aiLabel, dwgTag, dwgValue, pdfValue) = mapEntry.Value;
|
||||
|
||||
data[row, 0] = fileName;
|
||||
data[row, 1] = mapKey;
|
||||
data[row, 2] = aiLabel;
|
||||
data[row, 3] = dwgTag;
|
||||
data[row, 4] = dwgValue;
|
||||
|
||||
row++;
|
||||
}
|
||||
}
|
||||
|
||||
Excel.Range dataRange = dwgOnlyWorksheet.Range[
|
||||
dwgOnlyWorksheet.Cells[2, 1],
|
||||
dwgOnlyWorksheet.Cells[totalRows + 1, 5]];
|
||||
dataRange.Value = data;
|
||||
}
|
||||
|
||||
dwgOnlyWorksheet.Columns.AutoFit();
|
||||
excelManager.SaveWorkbookAs(dwgOnlyWorkbook, savePath);
|
||||
|
||||
Debug.WriteLine($"? DWG 전용 매핑 워크북 저장 완료: {System.IO.Path.GetFileName(savePath)}");
|
||||
|
||||
dwgOnlyWorkbook.Close(false);
|
||||
System.GC.Collect();
|
||||
System.GC.WaitForPendingFinalizers();
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
Debug.WriteLine($"? DWG 전용 매핑 워크북 저장 중 오류: {ex.Message}");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Height 정렬된 Excel 파일 생성
|
||||
/// </summary>
|
||||
public void WriteHeightSortedData(List<TextEntityInfo> textEntities, Excel.Worksheet worksheet, string fileName)
|
||||
{
|
||||
// 헤더 설정
|
||||
worksheet.Cells[1, 1] = "Height";
|
||||
worksheet.Cells[1, 2] = "Type";
|
||||
worksheet.Cells[1, 3] = "Layer";
|
||||
worksheet.Cells[1, 4] = "Tag";
|
||||
worksheet.Cells[1, 5] = "FileName";
|
||||
worksheet.Cells[1, 6] = "Text";
|
||||
|
||||
// 헤더 스타일 적용
|
||||
var headerRange = worksheet.Range["A1:F1"];
|
||||
headerRange.Font.Bold = true;
|
||||
headerRange.Interior.Color = System.Drawing.ColorTranslator.ToOle(System.Drawing.Color.LightBlue);
|
||||
|
||||
// 데이터는 ExtractTextEntitiesWithHeight에서 이미 정렬되었으므로 다시 정렬하지 않습니다.
|
||||
|
||||
// 데이터 입력
|
||||
int row = 2;
|
||||
foreach (var entity in textEntities) // sortedEntities를 textEntities로 수정
|
||||
{
|
||||
worksheet.Cells[row, 1] = entity.Height;
|
||||
worksheet.Cells[row, 2] = entity.Type;
|
||||
worksheet.Cells[row, 3] = entity.Layer;
|
||||
worksheet.Cells[row, 4] = entity.Tag;
|
||||
worksheet.Cells[row, 5] = fileName;
|
||||
worksheet.Cells[row, 6] = entity.Text;
|
||||
row++;
|
||||
}
|
||||
|
||||
worksheet.Columns.AutoFit();
|
||||
}
|
||||
}
|
||||
}
|
||||
309
Models/ExcelManager.cs
Normal file
309
Models/ExcelManager.cs
Normal file
@@ -0,0 +1,309 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using Excel = Microsoft.Office.Interop.Excel;
|
||||
|
||||
namespace DwgExtractorManual.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// Excel COM 객체 관리 및 기본 작업을 담당하는 클래스
|
||||
/// </summary>
|
||||
internal class ExcelManager : IDisposable
|
||||
{
|
||||
public Excel.Application? ExcelApplication { get; private set; }
|
||||
public Excel.Workbook? TitleBlockWorkbook { get; private set; }
|
||||
public Excel.Workbook? MappingWorkbook { get; private set; }
|
||||
|
||||
public Excel.Worksheet? TitleBlockSheet { get; private set; }
|
||||
public Excel.Worksheet? TextEntitiesSheet { get; private set; }
|
||||
public Excel.Worksheet? MappingSheet { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Excel 애플리케이션 및 워크시트 초기화
|
||||
/// </summary>
|
||||
public void InitializeExcel()
|
||||
{
|
||||
try
|
||||
{
|
||||
var excelApp = new Excel.Application();
|
||||
ExcelApplication = excelApp;
|
||||
ExcelApplication.Visible = false; // WPF에서는 숨김 처리
|
||||
Excel.Workbook workbook = excelApp.Workbooks.Add();
|
||||
TitleBlockWorkbook = workbook;
|
||||
|
||||
// Title Block Sheet 설정 (기본 Sheet1)
|
||||
TitleBlockSheet = (Excel.Worksheet)workbook.Sheets[1];
|
||||
TitleBlockSheet.Name = "Title Block";
|
||||
SetupTitleBlockHeaders();
|
||||
|
||||
// Text Entities Sheet 추가
|
||||
TextEntitiesSheet = (Excel.Worksheet)workbook.Sheets.Add();
|
||||
TextEntitiesSheet.Name = "Text Entities";
|
||||
SetupTextEntitiesHeaders();
|
||||
|
||||
// 매핑 데이터용 워크북 및 시트 생성
|
||||
MappingWorkbook = excelApp.Workbooks.Add();
|
||||
MappingSheet = (Excel.Worksheet)MappingWorkbook.Sheets[1];
|
||||
MappingSheet.Name = "Mapping Data";
|
||||
SetupMappingHeaders();
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
Debug.WriteLine($"Excel 초기화 중 오류 발생: {ex.Message}");
|
||||
ReleaseExcelObjects();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 기존 Excel 파일을 열어 매핑 시트에 접근
|
||||
/// </summary>
|
||||
public bool OpenExistingFile(string excelFilePath)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!File.Exists(excelFilePath))
|
||||
{
|
||||
Debug.WriteLine($"? Excel 파일이 존재하지 않습니다: {excelFilePath}");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ExcelApplication == null)
|
||||
{
|
||||
ExcelApplication = new Excel.Application();
|
||||
ExcelApplication.Visible = false;
|
||||
}
|
||||
|
||||
MappingWorkbook = ExcelApplication.Workbooks.Open(excelFilePath);
|
||||
MappingSheet = (Excel.Worksheet)MappingWorkbook.Sheets["Mapping Data"];
|
||||
|
||||
if (MappingSheet == null)
|
||||
{
|
||||
Debug.WriteLine("? 'Mapping Data' 시트를 찾을 수 없습니다.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
Debug.WriteLine($"? Excel 파일 열기 중 오류: {ex.Message}");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 새로운 워크북 생성 (Height 정렬용)
|
||||
/// </summary>
|
||||
public Excel.Workbook CreateNewWorkbook()
|
||||
{
|
||||
if (ExcelApplication == null)
|
||||
{
|
||||
ExcelApplication = new Excel.Application();
|
||||
ExcelApplication.Visible = false;
|
||||
}
|
||||
return ExcelApplication.Workbooks.Add();
|
||||
}
|
||||
|
||||
// Title Block 시트 헤더 설정
|
||||
private void SetupTitleBlockHeaders()
|
||||
{
|
||||
if (TitleBlockSheet == null) return;
|
||||
|
||||
TitleBlockSheet.Cells[1, 1] = "Type"; // 예: AttributeReference, AttributeDefinition
|
||||
TitleBlockSheet.Cells[1, 2] = "Name"; // BlockReference 이름 또는 BlockDefinition 이름
|
||||
TitleBlockSheet.Cells[1, 3] = "Tag"; // Attribute Tag
|
||||
TitleBlockSheet.Cells[1, 4] = "Prompt"; // Attribute Prompt
|
||||
TitleBlockSheet.Cells[1, 5] = "Value"; // Attribute 값 (TextString)
|
||||
TitleBlockSheet.Cells[1, 6] = "Path"; // 원본 DWG 파일 전체 경로
|
||||
TitleBlockSheet.Cells[1, 7] = "FileName"; // 원본 DWG 파일 이름만
|
||||
|
||||
// 헤더 행 스타일
|
||||
Excel.Range headerRange = TitleBlockSheet.Range["A1:G1"];
|
||||
headerRange.Font.Bold = true;
|
||||
headerRange.Interior.Color = System.Drawing.ColorTranslator.ToOle(System.Drawing.Color.LightBlue);
|
||||
}
|
||||
|
||||
// Text Entities 시트 헤더 설정
|
||||
private void SetupTextEntitiesHeaders()
|
||||
{
|
||||
if (TextEntitiesSheet == null) return;
|
||||
|
||||
TextEntitiesSheet.Cells[1, 1] = "Type"; // DBText, MText
|
||||
TextEntitiesSheet.Cells[1, 2] = "Layer"; // Layer 이름
|
||||
TextEntitiesSheet.Cells[1, 3] = "Text"; // 실제 텍스트 내용
|
||||
TextEntitiesSheet.Cells[1, 4] = "Path"; // 원본 DWG 파일 전체 경로
|
||||
TextEntitiesSheet.Cells[1, 5] = "FileName"; // 원본 DWG 파일 이름만
|
||||
|
||||
// 헤더 행 스타일
|
||||
Excel.Range headerRange = TextEntitiesSheet.Range["A1:E1"];
|
||||
headerRange.Font.Bold = true;
|
||||
headerRange.Interior.Color = System.Drawing.ColorTranslator.ToOle(System.Drawing.Color.LightGreen);
|
||||
}
|
||||
|
||||
// 매핑 데이터 시트 헤더 설정
|
||||
private void SetupMappingHeaders()
|
||||
{
|
||||
if (MappingSheet == null) return;
|
||||
|
||||
MappingSheet.Cells[1, 1] = "FileName"; // 파일 이름
|
||||
MappingSheet.Cells[1, 2] = "MapKey"; // 매핑 키
|
||||
MappingSheet.Cells[1, 3] = "AILabel"; // AI 라벨
|
||||
MappingSheet.Cells[1, 4] = "DwgTag"; // DWG Tag
|
||||
MappingSheet.Cells[1, 5] = "Att_value"; // DWG 값
|
||||
MappingSheet.Cells[1, 6] = "Pdf_value"; // PDF 값 (현재는 빈 값)
|
||||
|
||||
// 헤더 행 스타일
|
||||
Excel.Range headerRange = MappingSheet.Range["A1:F1"];
|
||||
headerRange.Font.Bold = true;
|
||||
headerRange.Interior.Color = System.Drawing.ColorTranslator.ToOle(System.Drawing.Color.LightYellow);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 워크북 저장
|
||||
/// </summary>
|
||||
public bool SaveWorkbook(Excel.Workbook? workbook = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (workbook != null)
|
||||
{
|
||||
workbook.Save();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (MappingWorkbook != null)
|
||||
{
|
||||
MappingWorkbook.Save();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (TitleBlockWorkbook != null)
|
||||
{
|
||||
TitleBlockWorkbook.Save();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
Debug.WriteLine($"? Excel 파일 저장 중 오류: {ex.Message}");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 워크북을 지정된 경로에 저장
|
||||
/// </summary>
|
||||
public void SaveWorkbookAs(Excel.Workbook? workbook, string savePath)
|
||||
{
|
||||
if (workbook == null) return;
|
||||
|
||||
string? directory = Path.GetDirectoryName(savePath);
|
||||
if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory))
|
||||
{
|
||||
Directory.CreateDirectory(directory);
|
||||
}
|
||||
|
||||
workbook.SaveAs(savePath,
|
||||
FileFormat: Excel.XlFileFormat.xlOpenXMLWorkbook,
|
||||
AccessMode: Excel.XlSaveAsAccessMode.xlNoChange);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Excel 시트명으로 사용할 수 있는 유효한 이름을 생성합니다.
|
||||
/// </summary>
|
||||
public string GetValidSheetName(string originalName)
|
||||
{
|
||||
if (string.IsNullOrEmpty(originalName))
|
||||
return "Sheet";
|
||||
|
||||
// Excel 시트명에서 허용되지 않는 문자 제거
|
||||
string validName = originalName;
|
||||
char[] invalidChars = { '\\', '/', '?', '*', '[', ']', ':' };
|
||||
|
||||
foreach (char c in invalidChars)
|
||||
{
|
||||
validName = validName.Replace(c, '_');
|
||||
}
|
||||
|
||||
// 31자로 제한 (Excel 시트명 최대 길이)
|
||||
if (validName.Length > 31)
|
||||
{
|
||||
validName = validName.Substring(0, 31);
|
||||
}
|
||||
|
||||
return validName;
|
||||
}
|
||||
|
||||
public void CloseWorkbooks()
|
||||
{
|
||||
if (TitleBlockWorkbook != null)
|
||||
{
|
||||
try { TitleBlockWorkbook.Close(false); }
|
||||
catch { }
|
||||
}
|
||||
if (MappingWorkbook != null)
|
||||
{
|
||||
try { MappingWorkbook.Close(false); }
|
||||
catch { }
|
||||
}
|
||||
if (ExcelApplication != null)
|
||||
{
|
||||
try { ExcelApplication.Quit(); }
|
||||
catch { }
|
||||
}
|
||||
}
|
||||
|
||||
private void ReleaseExcelObjects()
|
||||
{
|
||||
ReleaseComObject(TitleBlockSheet);
|
||||
ReleaseComObject(TextEntitiesSheet);
|
||||
ReleaseComObject(MappingSheet);
|
||||
ReleaseComObject(TitleBlockWorkbook);
|
||||
ReleaseComObject(MappingWorkbook);
|
||||
ReleaseComObject(ExcelApplication);
|
||||
|
||||
TitleBlockSheet = null;
|
||||
TextEntitiesSheet = null;
|
||||
MappingSheet = null;
|
||||
TitleBlockWorkbook = null;
|
||||
MappingWorkbook = null;
|
||||
ExcelApplication = null;
|
||||
}
|
||||
|
||||
private void ReleaseComObject(object? obj)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (obj != null && Marshal.IsComObject(obj))
|
||||
{
|
||||
Marshal.ReleaseComObject(obj);
|
||||
}
|
||||
}
|
||||
catch (System.Exception)
|
||||
{
|
||||
// 해제 중 오류 발생 시 무시
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
try
|
||||
{
|
||||
Debug.WriteLine("[DEBUG] ExcelManager Dispose 시작");
|
||||
CloseWorkbooks();
|
||||
ReleaseExcelObjects();
|
||||
GC.Collect();
|
||||
GC.WaitForPendingFinalizers();
|
||||
Debug.WriteLine("[DEBUG] ExcelManager Dispose 완료");
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
Debug.WriteLine($"[DEBUG] ExcelManager Dispose 중 오류: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
317
Models/JsonDataProcessor.cs
Normal file
317
Models/JsonDataProcessor.cs
Normal file
@@ -0,0 +1,317 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace DwgExtractorManual.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// JSON 파일 처리 및 매핑 데이터 관리를 담당하는 클래스
|
||||
/// </summary>
|
||||
internal class JsonDataProcessor
|
||||
{
|
||||
/// <summary>
|
||||
/// JSON 파일에서 PDF 분석 결과를 읽어 매핑 데이터를 업데이트
|
||||
/// </summary>
|
||||
public bool UpdateMappingDataFromJson(Dictionary<string, Dictionary<string, (string, string, string, string)>> mappingData, string jsonFilePath)
|
||||
{
|
||||
try
|
||||
{
|
||||
Debug.WriteLine($"[DEBUG] JSON 파일에서 PDF 값 업데이트 시작: {jsonFilePath}");
|
||||
|
||||
if (!File.Exists(jsonFilePath))
|
||||
{
|
||||
Debug.WriteLine($"? JSON 파일이 존재하지 않습니다: {jsonFilePath}");
|
||||
return false;
|
||||
}
|
||||
|
||||
// JSON 파일 읽기 및 정리
|
||||
string jsonContent = File.ReadAllText(jsonFilePath, System.Text.Encoding.UTF8);
|
||||
jsonContent = CleanJsonContent(jsonContent);
|
||||
|
||||
JObject jsonData;
|
||||
try
|
||||
{
|
||||
jsonData = JObject.Parse(jsonContent);
|
||||
}
|
||||
catch (Newtonsoft.Json.JsonReaderException jsonEx)
|
||||
{
|
||||
Debug.WriteLine($"? JSON 파싱 오류: {jsonEx.Message}");
|
||||
throw new System.Exception($"PDF 분석 JSON 파일 파싱 실패: {jsonEx.Message}\n파일: {jsonFilePath}");
|
||||
}
|
||||
|
||||
var results = jsonData["results"] as JArray;
|
||||
if (results == null)
|
||||
{
|
||||
Debug.WriteLine("? JSON에서 'results' 배열을 찾을 수 없습니다.");
|
||||
return false;
|
||||
}
|
||||
|
||||
int updatedCount = 0;
|
||||
int totalEntries = 0;
|
||||
|
||||
foreach (JObject result in results)
|
||||
{
|
||||
var fileInfo = result["file_info"];
|
||||
var pdfAnalysis = result["pdf_analysis"];
|
||||
|
||||
if (fileInfo == null || pdfAnalysis == null) continue;
|
||||
|
||||
string fileName = fileInfo["name"]?.ToString();
|
||||
if (string.IsNullOrEmpty(fileName)) continue;
|
||||
|
||||
string fileNameWithoutExt = Path.GetFileNameWithoutExtension(fileName);
|
||||
|
||||
if (!mappingData.ContainsKey(fileNameWithoutExt))
|
||||
{
|
||||
Debug.WriteLine($"?? 매핑 데이터에 파일이 없습니다: {fileNameWithoutExt}");
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach (var property in pdfAnalysis.Cast<JProperty>())
|
||||
{
|
||||
string aiLabel = property.Name;
|
||||
var valueObj = property.Value as JObject;
|
||||
|
||||
if (valueObj == null) continue;
|
||||
|
||||
string pdfValue = valueObj["value"]?.ToString();
|
||||
if (string.IsNullOrEmpty(pdfValue)) continue;
|
||||
|
||||
totalEntries++;
|
||||
|
||||
var fileData = mappingData[fileNameWithoutExt];
|
||||
var matchingEntry = fileData.FirstOrDefault(kvp =>
|
||||
string.Equals(kvp.Value.Item1.Trim(), aiLabel.Trim(), StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
if (!string.IsNullOrEmpty(matchingEntry.Key))
|
||||
{
|
||||
var existingValue = matchingEntry.Value;
|
||||
fileData[matchingEntry.Key] = (existingValue.Item1, existingValue.Item2, existingValue.Item3, pdfValue);
|
||||
updatedCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Debug.WriteLine($"[DEBUG] PDF 데이터 업데이트 완료: {updatedCount}/{totalEntries} 업데이트됨");
|
||||
return true;
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
Debug.WriteLine($"? JSON에서 PDF 값 업데이트 중 오류: {ex.Message}");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 매핑 딕셔너리를 JSON 파일로 저장
|
||||
/// </summary>
|
||||
public void SaveMappingDictionary(Dictionary<string, Dictionary<string, (string, string, string, string)>> mappingData, string filePath)
|
||||
{
|
||||
try
|
||||
{
|
||||
Debug.WriteLine($"[DEBUG] 매핑 딕셔너리 저장 시작: {filePath}");
|
||||
|
||||
var serializableData = new Dictionary<string, Dictionary<string, object>>();
|
||||
|
||||
foreach (var fileEntry in mappingData)
|
||||
{
|
||||
var fileData = new Dictionary<string, object>();
|
||||
foreach (var mapEntry in fileEntry.Value)
|
||||
{
|
||||
fileData[mapEntry.Key] = new
|
||||
{
|
||||
AILabel = mapEntry.Value.Item1,
|
||||
DwgTag = mapEntry.Value.Item2,
|
||||
DwgValue = mapEntry.Value.Item3,
|
||||
PdfValue = mapEntry.Value.Item4
|
||||
};
|
||||
}
|
||||
serializableData[fileEntry.Key] = fileData;
|
||||
}
|
||||
|
||||
string jsonContent = JsonConvert.SerializeObject(serializableData, Formatting.Indented);
|
||||
File.WriteAllText(filePath, jsonContent, System.Text.Encoding.UTF8);
|
||||
|
||||
Debug.WriteLine($"? 매핑 딕셔너리 저장 완료: {Path.GetFileName(filePath)}");
|
||||
Debug.WriteLine($"?? 저장된 파일 수: {mappingData.Count}");
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
Debug.WriteLine($"? 매핑 딕셔너리 저장 중 오류: {ex.Message}");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// JSON 파일에서 매핑 딕셔너리를 로드
|
||||
/// </summary>
|
||||
public Dictionary<string, Dictionary<string, (string, string, string, string)>> LoadMappingDictionary(string filePath)
|
||||
{
|
||||
var result = new Dictionary<string, Dictionary<string, (string, string, string, string)>>();
|
||||
|
||||
try
|
||||
{
|
||||
Debug.WriteLine($"[DEBUG] 매핑 딕셔너리 로드 시작: {filePath}");
|
||||
|
||||
if (!File.Exists(filePath))
|
||||
{
|
||||
Debug.WriteLine($"?? 매핑 파일이 존재하지 않습니다: {filePath}");
|
||||
return result;
|
||||
}
|
||||
|
||||
string jsonContent = File.ReadAllText(filePath, System.Text.Encoding.UTF8);
|
||||
jsonContent = CleanJsonContent(jsonContent);
|
||||
|
||||
Dictionary<string, Dictionary<string, JObject>> deserializedData;
|
||||
try
|
||||
{
|
||||
deserializedData = JsonConvert.DeserializeObject<Dictionary<string, Dictionary<string, JObject>>>(jsonContent);
|
||||
}
|
||||
catch (Newtonsoft.Json.JsonReaderException jsonEx)
|
||||
{
|
||||
Debug.WriteLine($"? JSON 파싱 오류: {jsonEx.Message}");
|
||||
throw new System.Exception($"매핑 JSON 파일 파싱 실패: {jsonEx.Message}\n파일: {filePath}");
|
||||
}
|
||||
|
||||
if (deserializedData != null)
|
||||
{
|
||||
foreach (var fileEntry in deserializedData)
|
||||
{
|
||||
var fileData = new Dictionary<string, (string, string, string, string)>();
|
||||
|
||||
foreach (var mapEntry in fileEntry.Value)
|
||||
{
|
||||
var valueObj = mapEntry.Value;
|
||||
string aiLabel = valueObj["AILabel"]?.ToString() ?? "";
|
||||
string dwgTag = valueObj["DwgTag"]?.ToString() ?? "";
|
||||
string dwgValue = valueObj["DwgValue"]?.ToString() ?? "";
|
||||
string pdfValue = valueObj["PdfValue"]?.ToString() ?? "";
|
||||
|
||||
fileData[mapEntry.Key] = (aiLabel, dwgTag, dwgValue, pdfValue);
|
||||
}
|
||||
|
||||
result[fileEntry.Key] = fileData;
|
||||
}
|
||||
}
|
||||
|
||||
Debug.WriteLine($"? 매핑 딕셔너리 로드 완료");
|
||||
Debug.WriteLine($"?? 로드된 파일 수: {result.Count}");
|
||||
|
||||
return result;
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
Debug.WriteLine($"? 매핑 딕셔너리 로드 중 오류: {ex.Message}");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// JSON 내용을 정리하여 파싱 가능한 상태로 만듭니다.
|
||||
/// </summary>
|
||||
private string CleanJsonContent(string jsonContent)
|
||||
{
|
||||
if (string.IsNullOrEmpty(jsonContent))
|
||||
return jsonContent;
|
||||
|
||||
try
|
||||
{
|
||||
var lines = jsonContent.Split('\n');
|
||||
var cleanedLines = new List<string>();
|
||||
bool inMultiLineComment = false;
|
||||
|
||||
foreach (string line in lines)
|
||||
{
|
||||
string processedLine = line;
|
||||
|
||||
// 멀티라인 주석 처리
|
||||
if (inMultiLineComment)
|
||||
{
|
||||
int endIndex = processedLine.IndexOf("*/");
|
||||
if (endIndex >= 0)
|
||||
{
|
||||
processedLine = processedLine.Substring(endIndex + 2);
|
||||
inMultiLineComment = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
int multiLineStart = processedLine.IndexOf("/*");
|
||||
if (multiLineStart >= 0)
|
||||
{
|
||||
int multiLineEnd = processedLine.IndexOf("*/", multiLineStart + 2);
|
||||
if (multiLineEnd >= 0)
|
||||
{
|
||||
processedLine = processedLine.Substring(0, multiLineStart) +
|
||||
processedLine.Substring(multiLineEnd + 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
processedLine = processedLine.Substring(0, multiLineStart);
|
||||
inMultiLineComment = true;
|
||||
}
|
||||
}
|
||||
|
||||
// 싱글라인 주석 제거
|
||||
bool inString = false;
|
||||
bool escaped = false;
|
||||
int commentIndex = -1;
|
||||
|
||||
for (int i = 0; i < processedLine.Length - 1; i++)
|
||||
{
|
||||
char current = processedLine[i];
|
||||
char next = processedLine[i + 1];
|
||||
|
||||
if (escaped)
|
||||
{
|
||||
escaped = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (current == '\\')
|
||||
{
|
||||
escaped = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (current == '"')
|
||||
{
|
||||
inString = !inString;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!inString && current == '/' && next == '/')
|
||||
{
|
||||
commentIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (commentIndex >= 0)
|
||||
{
|
||||
processedLine = processedLine.Substring(0, commentIndex);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(processedLine))
|
||||
{
|
||||
cleanedLines.Add(processedLine);
|
||||
}
|
||||
}
|
||||
|
||||
return string.Join("\n", cleanedLines);
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
Debug.WriteLine($"? JSON 정리 중 오류: {ex.Message}");
|
||||
return jsonContent;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
0
Models/SettingsManager.cs
Normal file
0
Models/SettingsManager.cs
Normal file
Reference in New Issue
Block a user