");
sb.AppendLine($"
{Escape(title)}
");
sb.AppendLine($"
{Escape(coverSubtitle)}
");
sb.AppendLine($"
{DateTime.Now:yyyy년 MM월 dd일}
");
sb.AppendLine("
");
}
sb.AppendLine("");
if (string.IsNullOrWhiteSpace(coverSubtitle))
sb.AppendLine($"
{Escape(title)}
");
// TOC 생성
if (toc && sections.Count > 1)
{
sb.AppendLine("
");
sb.AppendLine("
📋 목차
");
sb.AppendLine("
");
for (int i = 0; i < sections.Count; i++)
{
var indent = sections[i].Level > 1 ? " style=\"padding-left:20px\"" : "";
sb.AppendLine($"- {Escape(sections[i].Heading)}
");
}
sb.AppendLine("
");
sb.AppendLine("
");
}
// 섹션 본문
for (int i = 0; i < sections.Count; i++)
{
var (heading, content, level) = sections[i];
var tag = level <= 1 ? "h2" : "h3";
sb.AppendLine($"<{tag} id=\"section-{i + 1}\">{Escape(heading)}{tag}>");
sb.AppendLine($"
{content}
");
}
sb.AppendLine("
");
sb.AppendLine("");
sb.AppendLine("");
File.WriteAllText(path, sb.ToString(), Encoding.UTF8);
var issues = ValidateBasic(sb.ToString());
return issues.Count > 0
? $" ⚠ 품질 검증 이슈 {issues.Count}건: {string.Join("; ", issues)}"
: " ✓ 품질 검증 통과";
}
private string AssembleDocx(string path, string title, List<(string Heading, string Content, int Level)> sections,
string? headerText, string? footerText)
{
// DOCX 조립: DocxSkill의 sections 형식으로 변환하여 OpenXML 사용
using var doc = DocumentFormat.OpenXml.Packaging.WordprocessingDocument.Create(
path, DocumentFormat.OpenXml.WordprocessingDocumentType.Document);
var mainPart = doc.AddMainDocumentPart();
// 기본 스타일 파트 추가 (styles.xml — 없으면 Word에서 글꼴/서식 깨짐)
var stylesPart = mainPart.AddNewPart