You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

347 lines
10 KiB
C#

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

using System.Collections;
using System.Text.RegularExpressions;
using NetModular.DocX.Core;
namespace Infrastructure.Helpers;
public class WordHelper
{
/// <summary>
/// 导出word
/// </summary>
/// <param name="tempFilePath">模板路径</param>
/// <param name="outPath">保存路径</param>
/// <param name="data">数据</param>
public static void Export(string tempFilePath, string outPath, Dictionary<string, object> data)
{
bool isrewrite = true; // true=覆盖已存在的同名文件,false则反之
//if (!System.IO.Directory.Exists(outPath))
//{
// System.IO.Directory.CreateDirectory(outPath);
//}
File.Copy(tempFilePath, outPath, isrewrite);
//新建一个Word文档加载Load的方法和Create使用一样。
using (DocX document = DocX.Load(outPath))
{
ReplaceDoc(document, data); //普通文本替换
ReplaceTable(document, data); //表格处理
ReplaceList(document, data); //文本列表处理
document.Save(); //保存
}
}
private static void ReplaceDoc(DocX doc, Dictionary<string, object> data)
{
foreach (var item in doc.Paragraphs)
{
ReplaceParagraph(item, data);
}
}
private static void ReplaceList(DocX doc, Dictionary<string, object> data)
{
//一定要在 普通文本替换和表格处理之后
foreach (var p in doc.Paragraphs)
{
var li = GetListInfo(p, data);
if (li.IsList)
{
var pc = li.PTemp;
for (int i = 0; i < li.Data.Count; i++)
{
var pt = pc.InsertParagraphAfterSelf(p);
if (li.IsDict)
{
pc = ReplaceParagraph(pt, (Dictionary<string, object>)li.Data[i]);
}
else
{
pc = ReplaceParagraph(pt, li.Data[i]);
}
}
//删除模板行
li.PTemp.Remove(false);
}
else
{
//do nonthing
}
}
}
private static void ReplaceTable(DocX doc, Dictionary<string, object> data)
{
var tbs = doc.Tables;
foreach (var table in tbs)
{
//需要先判断表格是列表还是表单
var ti = GetTableInfo(table, data);
if (ti.IsList)
{
for (int i = 0; i < ti.Data.Count; i++)
{
var rt = table.InsertRow(ti.RowTemp);
rt.Height = ti.RowTemp.Height;
rt.MinHeight = ti.RowTemp.MinHeight;
if (ti.IsDict)
{
ReplaceRow(rt, (Dictionary<string, object>)ti.Data[i]);
}
else
{
ReplaceRow(rt, ti.Data[i]);
}
}
//删除模板行
ti.RowTemp.Remove();
}
else
{
//do nonthing
}
}
}
private static void ReplaceRow(Row row, Dictionary<string, object> data)
{
foreach (var cell in row.Cells)
{
foreach (var item in cell.Paragraphs)
{
ReplaceParagraph(item, data);
}
}
}
private static void ReplaceRow(Row row, object data)
{
foreach (var cell in row.Cells)
{
foreach (var item in cell.Paragraphs)
{
ReplaceParagraph(item, data);
}
}
}
private static Paragraph ReplaceParagraph(Paragraph p, Dictionary<string, object> data)
{
Paragraph pr = p;
var ms = GetMatches(p.Text);
var ks = new List<string>();
var rs = new List<string>();
foreach (Match m in ms)
{
if (m.Groups.Count > 1)
{
string text = m.Groups[1].Value;
if (text.Contains("."))
{
var ts = text.Split(".");
text = ts[ts.Length - 1];
}
ks.Add(text);
rs.Add(m.Value);
}
}
bool isCt = data.Any(op => ks.Any(o => o.Contains(op.Key)));
bool isReplace = false;
if (isCt)
{
if (ks.Count > 1)
{
for (int i = 0; i < ks.Count; i++)
{
if (data.ContainsKey(ks[i]))
{
p.ReplaceText(rs[i], data[ks[i]]?.ToString());
}
}
}
else if (ks.Count == 1)
{
string text = ks[0];
if (data.ContainsKey(text))
{
var ct = data[text]?.ToString();
var cts = ResolveText(ct);
var pc = p;
foreach (var item2 in cts)
{
if (string.IsNullOrWhiteSpace(item2)) continue;
var pt = pc.InsertParagraphAfterSelf(p);
pt.ReplaceText(rs[0], item2);
pc = pt;
pr = pc;
}
isReplace = true;
}
}
if (isReplace)
{
//删除原来段落
p.Remove(false);
}
}
return pr;
}
private static Paragraph ReplaceParagraph(Paragraph p, object data)
{
var ms = GetMatches(p.Text);
var isReplace = false;
Paragraph pr = p;
foreach (Match item1 in ms)
{
if (item1.Groups.Count > 1)
{
string text = item1.Groups[1].Value;
var ct = data?.ToString();
var cts = ResolveText(ct);
var pc = p;
foreach (var item2 in cts)
{
var pt = pc.InsertParagraphAfterSelf(p);
pt.ReplaceText(item1.Value, item2);
pc = pt;
pr = pc;
}
isReplace = true;
}
}
if (isReplace)
{
//删除原来段落
p.Remove(false);
}
return pr;
}
private static IList<string> ResolveText(string text)
{
if (string.IsNullOrEmpty(text)) return new List<string>();
text = text.Replace("\r\n", "\n").Replace("\r", "\n");
return text.Split('\n');
}
private static MatchCollection GetMatches(string text)
{
if (string.IsNullOrEmpty(text)) text = "";
Regex regex = new Regex("[#|\\$]([a-zA-Z0-9_.]+?)[#|\\$]",
RegexOptions.IgnoreCase | RegexOptions.Multiline);
return regex.Matches(text);
}
/// <summary>
/// 只获取列表匹配项
/// </summary>
/// <param name="text"></param>
/// <returns></returns>
private static MatchCollection GetListMatches(string text)
{
if (string.IsNullOrEmpty(text)) text = "";
Regex regex = new Regex("\\$([a-zA-Z0-9_.]+?)\\$", RegexOptions.IgnoreCase | RegexOptions.Multiline);
return regex.Matches(text);
}
//纯辅助方法
private class TableInfo
{
public bool IsList { get; set; }
public bool IsDict { get; set; }
public Row RowTemp { get; set; }
public IList<object> Data { get; set; }
}
//判断表格是列表还是表单
private static TableInfo GetTableInfo(Table table, Dictionary<string, object> data)
{
TableInfo result = new TableInfo();
var r0 = table.Rows[table.Rows.Count - 1];
var c0 = r0.Cells[r0.Cells.Count - 1];
var ct = c0.Paragraphs[0].Text;
var ms = GetListMatches(ct);
foreach (Match item in ms)
{
if (item.Groups.Count > 1)
{
string text = item.Groups[1].Value;
if (text.Contains("."))
{
result.IsDict = true;
text = text.Split('.')[0];
}
if (data.ContainsKey(text) && (data[text] is IList)) //判断是否是列表
{
result.RowTemp = r0;
result.IsList = true;
result.Data = new List<object>();
foreach (var item1 in (data[text] as IList))
{
result.Data.Add(item1);
}
break;
}
}
}
return result;
}
private class ListInfo
{
public bool IsList { get; set; }
public bool IsDict { get; set; }
public Paragraph PTemp { get; set; }
public IList<object> Data { get; set; }
}
private static ListInfo GetListInfo(Paragraph p, Dictionary<string, object> data)
{
ListInfo result = new ListInfo();
var ms = GetListMatches(p.Text);
foreach (Match item in ms)
{
if (item.Groups.Count > 1)
{
string text = item.Groups[1].Value;
if (text.Contains("."))
{
result.IsDict = true;
text = text.Split('.')[0];
}
if (data.ContainsKey(text) && (data[text] is IList)) //判断是否是列表
{
result.PTemp = p;
result.IsList = true;
result.Data = new List<object>();
foreach (var item1 in (data[text] as IList))
{
result.Data.Add(item1);
}
break;
}
}
}
return result;
}
}