YD_Event.Admin/YD_Event.Core/Certificate/DocxTemplateParser.cs

169 lines
5.9 KiB
C#
Raw Normal View History

2026-03-04 12:13:49 +08:00
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Wordprocessing;
using Furion.DependencyInjection;
namespace YD_Event.Core.Certificate
{
/// <summary>
/// DOCX模板解析器
/// </summary>
public class DocxTemplateParser : ITransient
{
private const string PlaceholderPattern = @"\{\{([^}]+)\}\}";
/// <summary>
/// 从DOCX文件中提取占位符
/// </summary>
/// <param name="docxStream">DOCX文件流</param>
/// <returns>占位符列表</returns>
public List<string> ExtractPlaceholders(Stream docxStream)
{
var placeholders = new HashSet<string>();
using (var document = WordprocessingDocument.Open(docxStream, false))
{
var body = document.MainDocumentPart?.Document?.Body;
if (body == null) return new List<string>();
// 解析段落中的占位符
foreach (var paragraph in body.Elements<Paragraph>())
{
var text = ExtractTextFromParagraph(paragraph);
var foundPlaceholders = ExtractPlaceholdersFromText(text);
foreach (var placeholder in foundPlaceholders)
{
placeholders.Add(placeholder);
}
}
// 解析表格中的占位符
foreach (var table in body.Elements<Table>())
{
var tablePlaceholders = ExtractPlaceholdersFromTable(table);
foreach (var placeholder in tablePlaceholders)
{
placeholders.Add(placeholder);
}
}
// 解析页眉页脚中的占位符
ExtractPlaceholdersFromHeaderFooter(document, placeholders);
}
return placeholders.OrderBy(x => x).ToList();
}
/// <summary>
/// 从文本中提取占位符
/// </summary>
/// <param name="text">文本内容</param>
/// <returns>占位符列表</returns>
private List<string> ExtractPlaceholdersFromText(string text)
{
var placeholders = new List<string>();
var matches = Regex.Matches(text, PlaceholderPattern);
foreach (Match match in matches)
{
var placeholder = match.Groups[1].Value.Trim();
if (!string.IsNullOrWhiteSpace(placeholder))
{
placeholders.Add(placeholder);
}
}
return placeholders;
}
/// <summary>
/// 从段落中提取文本
/// </summary>
/// <param name="paragraph">段落元素</param>
/// <returns>文本内容</returns>
private string ExtractTextFromParagraph(Paragraph paragraph)
{
return string.Join("", paragraph.Elements<Run>().Select(run =>
string.Join("", run.Elements<Text>().Select(text => text.Text))));
}
/// <summary>
/// 从表格中提取占位符
/// </summary>
/// <param name="table">表格元素</param>
/// <returns>占位符列表</returns>
private List<string> ExtractPlaceholdersFromTable(Table table)
{
var placeholders = new HashSet<string>();
foreach (var row in table.Elements<TableRow>())
{
foreach (var cell in row.Elements<TableCell>())
{
foreach (var paragraph in cell.Elements<Paragraph>())
{
var text = ExtractTextFromParagraph(paragraph);
var cellPlaceholders = ExtractPlaceholdersFromText(text);
foreach (var placeholder in cellPlaceholders)
{
placeholders.Add(placeholder);
}
}
}
}
return placeholders.ToList();
}
/// <summary>
/// 从页眉页脚中提取占位符
/// </summary>
/// <param name="document">Word文档对象</param>
/// <param name="placeholders">占位符集合</param>
private void ExtractPlaceholdersFromHeaderFooter(WordprocessingDocument document, HashSet<string> placeholders)
{
// 暂时跳过页眉页脚处理,因为API兼容性问题
// 实际项目中需要根据具体的DocumentFormat.OpenXml版本调整
}
/// <summary>
/// 验证占位符格式
/// </summary>
/// <param name="placeholder">占位符</param>
/// <returns>是否有效</returns>
public bool IsValidPlaceholder(string placeholder)
{
return !string.IsNullOrWhiteSpace(placeholder) &&
Regex.IsMatch(placeholder, @"^[a-zA-Z_][a-zA-Z0-9_]*$");
}
/// <summary>
/// 获取占位符类型
/// </summary>
/// <param name="placeholder">占位符</param>
/// <returns>占位符类型</returns>
public string GetPlaceholderType(string placeholder)
{
if (string.IsNullOrWhiteSpace(placeholder))
return "Text";
var lowerPlaceholder = placeholder.ToLowerInvariant();
if (lowerPlaceholder.Contains("date") || lowerPlaceholder.Contains("time"))
return "Date";
if (lowerPlaceholder.Contains("qr") || lowerPlaceholder.Contains("qrcode"))
return "QRCode";
if (lowerPlaceholder.Contains("image") || lowerPlaceholder.Contains("img") || lowerPlaceholder.Contains("photo"))
return "Image";
return "Text";
}
}
}