Skip to content

Commit

Permalink
implement-async method.
Browse files Browse the repository at this point in the history
  • Loading branch information
isdaniel committed Mar 23, 2024
1 parent 5f006a1 commit 55b8ca7
Show file tree
Hide file tree
Showing 5 changed files with 101 additions and 40 deletions.
28 changes: 14 additions & 14 deletions src/MiniWord/Extensions/OpenXmlExtension.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ namespace MiniSoftware.Extensions
internal static class OpenXmlExtension
{
/// <summary>
/// 高级搜索:得到段落里面的连续字符串
/// �߼��������õ���������������ַ���
/// </summary>
/// <param name="paragraph">段落</param>
/// <returns>Item1:连续文本;Item2:块;Item3:块文本</returns>
/// <param name="paragraph">����</param>
/// <returns>Item1�������ı���Item2���飻Item3�����ı�</returns>
internal static List<Tuple<string, List<Run>, List<Text>>> GetContinuousString(this Paragraph paragraph)
{
List<Tuple<string, List<Run>, List<Text>>> tuples = new List<Tuple<string, List<Run>, List<Text>>>();
Expand All @@ -26,13 +26,13 @@ internal static List<Tuple<string, List<Run>, List<Text>>> GetContinuousString(t
var runs = new List<Run>();
var texts = new List<Text>();

//段落:所有子级
//���䣺�����Ӽ�
foreach (var pChildElement in paragraph.ChildElements)
{
//
//��
if (pChildElement is Run run)
{
//文本块
//�ı���
if (run.IsText())
{
var text = run.GetFirstChild<Text>();
Expand All @@ -50,10 +50,10 @@ internal static List<Tuple<string, List<Run>, List<Text>>> GetContinuousString(t
texts = new List<Text>();
}
}
//公式,书签...
//��ʽ����ǩ...
else
{
//跳过的类型
//����������
if (pChildElement is BookmarkStart || pChildElement is BookmarkEnd)
{

Expand Down Expand Up @@ -81,16 +81,16 @@ internal static List<Tuple<string, List<Run>, List<Text>>> GetContinuousString(t
}

/// <summary>
/// 整理字符串到连续字符串块中
/// �����ַ����������ַ�������
/// </summary>
/// <param name="texts">连续字符串块</param>
/// <param name="text">待整理字符串</param>
/// <param name="texts">�����ַ�����</param>
/// <param name="text">�������ַ���</param>
internal static void TrimStringToInContinuousString(this IEnumerable<Text> texts, string text)
{
/*
//假如块为:[A][BC][DE][FG][H]
//假如替换:[AB][E][GH]
//优化块为:[AB][C][DE][FGH][]
//�������[A][BC][DE][FG][H]
//�����滻��[AB][E][GH]
//�Ż���Ϊ��[AB][C][DE][FGH][]
*/

var allTxtx = string.Concat(texts.SelectMany(o => o.Text));
Expand Down
73 changes: 47 additions & 26 deletions src/MiniWord/MiniWord.Implment.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ namespace MiniSoftware
using A = DocumentFormat.OpenXml.Drawing;
using DW = DocumentFormat.OpenXml.Drawing.Wordprocessing;
using PIC = DocumentFormat.OpenXml.Drawing.Pictures;
using System.Threading.Tasks;
using System.Threading;

public static partial class MiniWord
{
Expand All @@ -25,22 +27,39 @@ private static void SaveAsByTemplateImpl(Stream stream, byte[] template, Diction
using (var ms = new MemoryStream())
{
ms.Write(template, 0, template.Length);
ms.Position = 0;
using (var docx = WordprocessingDocument.Open(ms, true))
{
var hc = docx.MainDocumentPart.HeaderParts.Count();
var fc = docx.MainDocumentPart.FooterParts.Count();
for (int i = 0; i < hc; i++)
docx.MainDocumentPart.HeaderParts.ElementAt(i).Header.Generate(docx, value);
for (int i = 0; i < fc; i++)
docx.MainDocumentPart.FooterParts.ElementAt(i).Footer.Generate(docx, value);
docx.MainDocumentPart.Document.Body.Generate(docx, value);
docx.Save();
}
bytes = ms.ToArray();
bytes = WriteToByte(data, ms);
}
stream.Write(bytes, 0, bytes.Length);
}

private static async Task SaveAsByTemplateImplAsync(Stream stream, byte[] template, Dictionary<string, object> data,CancellationToken token)
{
byte[] bytes = null;
using (var ms = new MemoryStream())
{
await ms.WriteAsync(template, 0, template.Length, token);
bytes = WriteToByte(data, ms);
}
await stream.WriteAsync(bytes, 0, bytes.Length,token);
}

private static byte[] WriteToByte(Dictionary<string, object> value, MemoryStream ms)
{
ms.Position = 0;
using (var docx = WordprocessingDocument.Open(ms, true))
{
var hc = docx.MainDocumentPart.HeaderParts.Count();
var fc = docx.MainDocumentPart.FooterParts.Count();
for (int i = 0; i < hc; i++)
docx.MainDocumentPart.HeaderParts.ElementAt(i).Header.Generate(docx, value);
for (int i = 0; i < fc; i++)
docx.MainDocumentPart.FooterParts.ElementAt(i).Footer.Generate(docx, value);
docx.MainDocumentPart.Document.Body.Generate(docx, value);
docx.Save();
}
return ms.ToArray();
}

private static void Generate(this OpenXmlElement xmlElement, WordprocessingDocument docx, Dictionary<string, object> tags)
{
// avoid {{tag}} like <t>{</t><t>{</t>
Expand All @@ -53,14 +72,14 @@ private static void Generate(this OpenXmlElement xmlElement, WordprocessingDocum
{
foreach (var table in tables)
{
var trs = table.Descendants<TableRow>().ToArray(); // remember toarray or system will loop OOM;
var trs = table.Descendants<TableRow>().ToArray(); // remember toarray otherwise system will loop OOM;

foreach (var tr in trs)
{
var innerText = tr.InnerText.Replace("{{foreach", "").Replace("endforeach}}", "")
.Replace("{{if(", "").Replace(")if", "").Replace("endif}}", "");
var matchs = (Regex.Matches(innerText, "(?<={{).*?\\..*?(?=}})")
.Cast<Match>().GroupBy(x => x.Value).Select(varGroup => varGroup.First().Value)).ToArray();
var matchs = Regex.Matches(innerText, "(?<={{).*?\\..*?(?=}})")
.Cast<Match>().GroupBy(x => x.Value).Select(varGroup => varGroup.First().Value).ToArray();
if (matchs.Length > 0)
{
var listKeys = matchs.Select(s => s.Split('.')[0]).Distinct().ToArray();
Expand All @@ -76,15 +95,8 @@ private static void Generate(this OpenXmlElement xmlElement, WordprocessingDocum

foreach (Dictionary<string, object> es in list)
{
var dic = new Dictionary<string, object>(); //TODO: optimize

var dic = es.ToDictionary(key => $"{listKey}.{key}", item=>item.Value);
var newTr = tr.CloneNode(true);
foreach (var e in es)
{
var dicKey = $"{listKey}.{e.Key}";
dic.Add(dicKey, e.Value);
}

ReplaceStatements(newTr, tags: dic);

ReplaceText(newTr, docx, tags: dic);
Expand Down Expand Up @@ -356,8 +368,7 @@ private static void ReplaceText(OpenXmlElement xmlElement, WordprocessingDocumen
{
if (forTags.Any(forTag => forTag.Value.Keys.Any(dictKey =>
{
var innerTag = "{{" + tag.Key + "." + dictKey + "}}";
return t.Text.Contains(innerTag);
return t.Text.Contains($@"{{{{{tag.Key}.{dictKey}}}}}");
})))
{
isMatch = true;
Expand Down Expand Up @@ -700,5 +711,15 @@ private static byte[] GetBytes(string path)
return ms.ToArray();
}
}

private static async Task<byte[]> GetByteAsync(string path)
{
using (var st = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, 4096, true))
using (var ms = new MemoryStream())
{
await st.CopyToAsync(ms);
return ms.ToArray();
}
}
}
}
25 changes: 25 additions & 0 deletions src/MiniWord/MiniWord.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,14 @@ namespace MiniSoftware
{
using DocumentFormat.OpenXml.Office2013.Excel;
using MiniSoftware.Extensions;
using MiniSoftware.Utility;
using System.Collections.Generic;
using System.ComponentModel;
using System.Dynamic;
using System.IO;
using System.Linq.Expressions;
using System.Threading;
using System.Threading.Tasks;

public static partial class MiniWord
{
Expand All @@ -31,5 +34,27 @@ public static void SaveAsByTemplate(this Stream stream, byte[] templateBytes, ob
{
SaveAsByTemplateImpl(stream, templateBytes, value.ToDictionary());
}

public static async Task SaveAsByTemplateAsync(this Stream stream, byte[] templateBytes, object value,CancellationToken token = default(CancellationToken))
{
await SaveAsByTemplateImplAsync(stream, templateBytes, value.ToDictionary(),token).ConfigureAwait(false);
}

public static async Task SaveAsByTemplateAsync(this Stream stream, string templatePath, object value,CancellationToken token = default(CancellationToken))
{
await SaveAsByTemplateImplAsync(stream, await GetByteAsync(templatePath), value.ToDictionary(),token).ConfigureAwait(false);
}

public static async Task SaveAsByTemplateAsync(string path, string templatePath, object value,CancellationToken token = default(CancellationToken))
{
using (var stream = FileHelper.CreateAsync(path))
await SaveAsByTemplateImplAsync(await stream, await GetByteAsync(templatePath), value.ToDictionary(),token);
}

public static async Task SaveAsByTemplateAsync(string path, byte[] templateBytes, object value,CancellationToken token = default(CancellationToken))
{
using (var stream = FileHelper.CreateAsync(path))
await SaveAsByTemplateImplAsync(await stream, templateBytes, value.ToDictionary(),token);
}
}
}
14 changes: 14 additions & 0 deletions src/MiniWord/Utility/FileAyncExtension.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
namespace MiniSoftware.Utility
{
using System.IO;
using System.Threading.Tasks;
internal static class FileHelper{
internal static async Task<FileStream> CreateAsync(string path)
{
using (var stream = File.Create(path))
{
return await Task.FromResult(stream);
}
}
}
}
1 change: 1 addition & 0 deletions src/MiniWord/Utility/Helpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System.ComponentModel;
using System.Dynamic;
using System.IO;
using System.Threading.Tasks;

internal static partial class Helpers
{
Expand Down

0 comments on commit 55b8ca7

Please sign in to comment.