573 lines
22 KiB
C#
573 lines
22 KiB
C#
using DocumentFormat.OpenXml;
|
|
using DocumentFormat.OpenXml.Packaging;
|
|
using DocumentFormat.OpenXml.Wordprocessing;
|
|
using System.Text.RegularExpressions;
|
|
|
|
namespace WorkFlowCheck.BL.DocumentGenerator
|
|
{
|
|
public class SablonGenerator : IDisposable
|
|
{
|
|
private readonly List<OpenXmlElement> _currentRoot;
|
|
|
|
private MemoryStream Mem { get; }
|
|
private WordprocessingDocument Doc { get; set; }
|
|
|
|
private List<OpenXmlElement> CurrentRoot => Repeater?.SablonRoot ?? _currentRoot;
|
|
|
|
private SubSablon Repeater { get; set; }
|
|
|
|
protected class SubSablon : IDisposable
|
|
{
|
|
private List<OpenXmlElement> SablonRootBase { get; set; }
|
|
protected internal List<OpenXmlElement> SablonRoot { get; private set; }
|
|
public BookmarkStart BookmarkStart { get; }
|
|
public BookmarkEnd BookmarkEnd { get; }
|
|
|
|
protected internal SubSablon(WordprocessingDocument doc, string key)
|
|
{
|
|
var bookmark = doc.MainDocumentPart.RootElement.Descendants<BookmarkStart>()
|
|
.FirstOrDefault(x => x.Name == key);
|
|
//var parentBookmark = false;
|
|
if (bookmark != null)
|
|
{
|
|
SablonRoot = new List<OpenXmlElement>();
|
|
var nextSibling = bookmark.NextSibling();
|
|
if (nextSibling == null)
|
|
nextSibling = bookmark.Parent;
|
|
while (nextSibling != null)
|
|
{
|
|
var endBookmark = (nextSibling is BookmarkEnd end && end.Id == bookmark.Id.Value) ? end : null;
|
|
if (endBookmark == null)
|
|
{
|
|
endBookmark = nextSibling.Descendants<BookmarkEnd>().FirstOrDefault(x => x.Id == bookmark.Id.Value);
|
|
if (endBookmark != null)
|
|
SablonRoot.Add(nextSibling);
|
|
}
|
|
if (endBookmark != null)
|
|
{
|
|
bookmark.Remove();
|
|
endBookmark.Remove();
|
|
break;
|
|
}
|
|
SablonRoot.Add(nextSibling);
|
|
var tmpNextSibling = nextSibling.NextSibling();
|
|
if (tmpNextSibling == null)
|
|
{
|
|
tmpNextSibling = nextSibling.Parent;
|
|
if (tmpNextSibling != null && !(tmpNextSibling is Body) && !(tmpNextSibling is Document))
|
|
SablonRoot.Clear();
|
|
else
|
|
break;
|
|
}
|
|
nextSibling = tmpNextSibling;
|
|
}
|
|
}
|
|
|
|
if (SablonRoot != null && SablonRoot.Count > 0)
|
|
{
|
|
SablonRootBase = new List<OpenXmlElement>();
|
|
foreach (var item in SablonRoot)
|
|
{
|
|
SablonRootBase.Add(item.CloneNode(true));
|
|
}
|
|
BookmarkStart = new BookmarkStart() { Name = "repeater", Id = "1000" };
|
|
BookmarkEnd = new BookmarkEnd() { Id = "1000" };
|
|
if (SablonRoot.First().Parent != null)
|
|
{
|
|
SablonRoot.First().InsertBeforeSelf(BookmarkStart);
|
|
SablonRoot.First().InsertBeforeSelf(BookmarkEnd);
|
|
foreach (var rootItem in SablonRoot)
|
|
rootItem.Remove();
|
|
}
|
|
else
|
|
{
|
|
foreach (var rootItem in SablonRoot)
|
|
foreach (var rootItemChildElement in rootItem.ChildElements)
|
|
rootItemChildElement.Remove();
|
|
SablonRoot.First().AppendChild(BookmarkStart);
|
|
SablonRoot.First().AppendChild(BookmarkEnd);
|
|
}
|
|
Reset();
|
|
}
|
|
}
|
|
|
|
private void Insert()
|
|
{
|
|
var root = SablonRoot;
|
|
if (root.Count == 1 && root.First() is Document)
|
|
{
|
|
root = root.First().ChildElements.ToList();
|
|
}
|
|
for (var i = 0; i < root.Count; i++)
|
|
{
|
|
if (i == 0)
|
|
BookmarkStart.InsertBeforeSelf(root[i]);
|
|
else
|
|
root[i - 1].InsertAfterSelf(root[i]);
|
|
}
|
|
}
|
|
|
|
private void Reset()
|
|
{
|
|
SablonRoot.Clear();
|
|
foreach (var item in SablonRootBase)
|
|
{
|
|
SablonRoot.Add(item.CloneNode(true));
|
|
}
|
|
}
|
|
|
|
protected internal void InsertAndReset()
|
|
{
|
|
Insert();
|
|
Reset();
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
BookmarkStart?.Remove();
|
|
BookmarkEnd?.Remove();
|
|
SablonRootBase = null;
|
|
SablonRoot = null;
|
|
}
|
|
}
|
|
|
|
public IDisposable Repeat(string key)
|
|
{
|
|
Repeater = new SubSablon(Doc, key);
|
|
return Repeater;
|
|
}
|
|
|
|
public SablonGenerator(byte[] content)
|
|
{
|
|
Mem = new MemoryStream();
|
|
Mem.Write(content, 0, content.Length);
|
|
try
|
|
{
|
|
Doc = WordprocessingDocument.Open(Mem, true, new OpenSettings()
|
|
{
|
|
MarkupCompatibilityProcessSettings =
|
|
new MarkupCompatibilityProcessSettings(MarkupCompatibilityProcessMode.ProcessAllParts,
|
|
FileFormatVersions.Office2010)
|
|
});
|
|
}
|
|
catch (Exception)
|
|
{
|
|
//if (!string.IsNullOrEmpty(Config.TryGetStringValue("SablonGeneratorErrorPath")))
|
|
//{
|
|
// File.WriteAllBytes(Path.Combine(Config.GetStringValue("SablonGeneratorErrorPath"), DateTime.Now.ToString("yyyyMMddHHHmmss.content")), content);
|
|
//}
|
|
throw;
|
|
}
|
|
|
|
_currentRoot = new List<OpenXmlElement>();
|
|
CurrentRoot.AddRange(Doc.MainDocumentPart.HeaderParts.Select(x => x.RootElement));
|
|
CurrentRoot.Add(Doc.MainDocumentPart.RootElement);
|
|
CurrentRoot.AddRange(Doc.MainDocumentPart.FooterParts.Select(x => x.RootElement));
|
|
}
|
|
|
|
public static void CheckOpenXmlDocument(byte[] content)
|
|
{
|
|
WordprocessingDocument doc = null;
|
|
var mem = new MemoryStream();
|
|
mem.Write(content, 0, content.Length);
|
|
try
|
|
{
|
|
doc = WordprocessingDocument.Open(mem, true, new OpenSettings()
|
|
{
|
|
MarkupCompatibilityProcessSettings =
|
|
new MarkupCompatibilityProcessSettings(MarkupCompatibilityProcessMode.ProcessAllParts,
|
|
FileFormatVersions.Office2010)
|
|
});
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
#if DEBUG
|
|
//LoggerHelper.DiagnosticAudit.Information(DateTime.Now,
|
|
//Common.Enums.Area.BaseSystem,
|
|
//0,
|
|
//string.Format(ex.ToString()),
|
|
//new Guid().ToString());
|
|
//LoggerHelper.DiagnosticAudit.Log.Information(ex.ToString());
|
|
#else
|
|
//LoggerHelper.DiagnosticAudit.Information(DateTime.Now,
|
|
//Common.Enums.Area.BaseSystem,
|
|
//0,
|
|
//string.Format(ex.Message),
|
|
//Guid.Empty.ToString());
|
|
#endif
|
|
//throw new BusinessException("Hibás vagy nem megfelelő OpenXML állomány.");
|
|
}
|
|
finally
|
|
{
|
|
mem?.Dispose();
|
|
doc?.Dispose();
|
|
}
|
|
}
|
|
|
|
public void Generate(Dictionary<string, string> propertyDictionary)
|
|
{
|
|
ReplaceBookmarks(propertyDictionary);
|
|
if (Repeater?.SablonRoot != null) Repeater.InsertAndReset();
|
|
}
|
|
|
|
public void SimpleReplace(string key, string value)
|
|
{
|
|
value = value == null ? "" : value;
|
|
|
|
foreach (var headerPart in Doc.MainDocumentPart.HeaderParts)
|
|
SimpleReplace2(headerPart.Header, key, value);
|
|
SimpleReplace2(Doc.MainDocumentPart.Document.Body, key, value);
|
|
}
|
|
|
|
protected void SimpleReplace(OpenXmlCompositeElement target, string key, string value)
|
|
{
|
|
var keyValue = key.Replace("#", "");
|
|
var texts = target.Descendants<Text>();
|
|
Text start = null;
|
|
Text keyValueText = null;
|
|
foreach (var text in texts)
|
|
if (text.Text == "#" && start == null)
|
|
start = text;
|
|
else if (text.Text == "#" && start != null && keyValueText != null)
|
|
{
|
|
var end = text;
|
|
keyValueText.Text = value;
|
|
start.Remove();
|
|
end.Remove();
|
|
start = null;
|
|
keyValueText = null;
|
|
}
|
|
else if (start != null && text.Text.ToUpper().Contains(keyValue.ToUpper()))
|
|
keyValueText = text;
|
|
else if (text.Text.ToUpper().Contains(key.ToUpper()))
|
|
{
|
|
start = null;
|
|
keyValueText = null;
|
|
text.Text = Regex.Replace(text.Text, key, value, RegexOptions.IgnoreCase);
|
|
}
|
|
else
|
|
{
|
|
start = null;
|
|
keyValueText = null;
|
|
}
|
|
}
|
|
|
|
protected void SimpleReplace2(OpenXmlCompositeElement target, string key, string value)
|
|
{
|
|
var texts = target.Descendants<Text>();
|
|
Text start = null;
|
|
var tokens = new List<Text>();
|
|
string tokenText = "";
|
|
|
|
foreach (var text in texts)
|
|
{
|
|
if (text.Text == "#" && start == null)
|
|
{
|
|
start = text;
|
|
tokenText += text.Text;
|
|
}
|
|
else if (text.Text == "#" && start != null)
|
|
{
|
|
var end = text;
|
|
tokenText += text.Text;
|
|
|
|
if (tokenText.ToUpper() == key.ToUpper())
|
|
{
|
|
start.Text = value;
|
|
foreach (var token in tokens)
|
|
{
|
|
token.Remove();
|
|
}
|
|
tokens.Clear();
|
|
end.Remove();
|
|
start = null;
|
|
tokenText = "";
|
|
}
|
|
else
|
|
{
|
|
start = null;
|
|
tokens.Clear();
|
|
tokenText = "";
|
|
end = null;
|
|
}
|
|
}
|
|
else if (text.Text.Contains('#') && text.Text.ToUpper() == key.ToUpper())
|
|
{
|
|
text.Text = value;
|
|
}
|
|
else if (text.Text.Contains('#'))
|
|
{
|
|
|
|
}
|
|
else if (start != null)
|
|
{
|
|
tokens.Add(text);
|
|
tokenText += text.Text;
|
|
}
|
|
}
|
|
}
|
|
|
|
public void SimpleReplaceForCV(string key, string value)
|
|
{
|
|
value = value == null ? "" : value;
|
|
|
|
SimpleReplaceForCV(Doc.MainDocumentPart.Document.Body, key, value);
|
|
}
|
|
|
|
protected void SimpleReplaceForCV(OpenXmlCompositeElement target, string key, string value)
|
|
{
|
|
var keyValue = key.Replace("#", "");
|
|
var texts = target.Descendants<Text>();
|
|
Text start = null;
|
|
Text keyValueText = null;
|
|
var keyindox = "";
|
|
foreach (var text in texts)
|
|
{
|
|
if (text.Text.Contains(key))
|
|
{
|
|
text.Text = text.Text.Replace(key, value);
|
|
break;
|
|
}
|
|
|
|
if (text.Text.Contains(keyValue + "#") && start != null)
|
|
{
|
|
start.Text = "";
|
|
text.Text = text.Text.Replace(keyValue + "#", value);
|
|
break;
|
|
}
|
|
|
|
if ((text.Text == "#" || (text.Text.Contains("#") && text.Text.Count(x => x == '#') == 1)) && start == null)
|
|
{
|
|
start = text;
|
|
keyindox = start.Text;
|
|
}
|
|
else if (start != null && (text.Text == "#" || text.Text.Contains("#")))
|
|
{
|
|
for (int i = texts.ToList().IndexOf(start) + 1; i < texts.ToList().IndexOf(text) + 1; i++)
|
|
{
|
|
if (texts.ToList()[i].Text.Contains(key))
|
|
{
|
|
texts.ToList()[i].Text = texts.ToList()[i].Text.Replace(key, value);
|
|
break;
|
|
}
|
|
|
|
keyindox = keyindox + texts.ToList()[i].Text;
|
|
}
|
|
keyindox = keyindox.Replace("#", "");
|
|
if (keyindox == keyValue || keyindox.Replace(" ", "") == keyValue)
|
|
{
|
|
for (int i = texts.ToList().IndexOf(start) + 1; i < texts.ToList().IndexOf(text); i++)
|
|
{
|
|
texts.ToList()[i].Text = "";
|
|
}
|
|
start.Text = "";
|
|
text.Text = value;
|
|
}
|
|
if (keyindox.Contains(keyValue))
|
|
{
|
|
for (int i = texts.ToList().IndexOf(start) + 1; i < texts.ToList().IndexOf(text); i++)
|
|
{
|
|
texts.ToList()[i].Text = "";
|
|
}
|
|
start.Text = "";
|
|
text.Text = keyindox.Replace(keyValue, value);
|
|
}
|
|
start = null;
|
|
keyindox = "";
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
private void ReplaceBookmarks(Dictionary<string, string> propertyDictionary)
|
|
{
|
|
var bookmarkEndList = new List<BookmarkEnd>();
|
|
foreach (var item in CurrentRoot)
|
|
{
|
|
var bookmarkEnds = item.Descendants<BookmarkEnd>();
|
|
bookmarkEndList.AddRange(bookmarkEnds.ToList());
|
|
}
|
|
|
|
foreach (var docContent in CurrentRoot)
|
|
{
|
|
var bookmarkStarts = docContent.Descendants<BookmarkStart>();
|
|
|
|
var bookmarkStartList = bookmarkStarts.ToList();
|
|
if (docContent is BookmarkStart)
|
|
bookmarkStartList.Add(docContent as BookmarkStart);
|
|
|
|
for (int k = 0; k < bookmarkStartList.Count; k++)
|
|
{
|
|
Run bookmarkRun = bookmarkStartList[k].NextSibling<Run>();
|
|
if (bookmarkRun != null)
|
|
{
|
|
var bookmarkText = bookmarkRun.GetFirstChild<Text>().InnerText;
|
|
if (propertyDictionary.ContainsKey(bookmarkText))
|
|
{
|
|
var itemValue = propertyDictionary[bookmarkText];
|
|
|
|
bookmarkRun.GetFirstChild<Text>().Text = itemValue ?? string.Empty;
|
|
var id = bookmarkStartList[k].Id.Value;
|
|
bookmarkStartList[k].Remove();
|
|
var end = bookmarkEndList.Find(x => x.Id == id);
|
|
end.Remove();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Táblázat generálás (a keyinrow paramétert keresi a táblázat első sorában (nem fejléc), ezt a sort kitörli, és helyére szúrja be az új sorokat
|
|
/// amit az első paraméterben kap meg
|
|
/// </summary>
|
|
/// <param name="rowsAndCells">sorok és benne az egyes cellák tartalma</param>
|
|
/// <param name="keyInRow">első (nem fejléc) sorában lévő kulcs, ez alapján azonosítjuk be a táblázatot</param>
|
|
/// <param name="deleteEmptyRow">ha igaz, a táblázat összes meglévő sorát törli</param>
|
|
public void SetTable_Old(List<List<string>> rowsAndCells, string keyInRow, bool deleteEmptyRow = false)
|
|
{
|
|
Body bod = Doc.MainDocumentPart.Document.Body;
|
|
var table = bod.Descendants<Table>().Where(tbl => tbl.InnerText.Contains(keyInRow)).FirstOrDefault();
|
|
if (table != null)
|
|
{
|
|
if (deleteEmptyRow)
|
|
{
|
|
var firstRow = table.ChildElements.Where(x => x is TableRow).FirstOrDefault();
|
|
var deletedRows = table.ChildElements.Where(x => x is TableRow).ToList();
|
|
deletedRows.Remove(firstRow);
|
|
foreach (var item in deletedRows)
|
|
table.RemoveChild(item);
|
|
}
|
|
else
|
|
{
|
|
var deletedRow = table.ChildElements.Where(x => x is TableRow).LastOrDefault();
|
|
table.RemoveChild<TableRow>(deletedRow as TableRow);
|
|
}
|
|
|
|
foreach (var row in rowsAndCells)
|
|
{
|
|
List<OpenXmlElement> cells = new List<OpenXmlElement>();
|
|
|
|
foreach (var cell in row)
|
|
{
|
|
var tableCell = new TableCell(new Paragraph(new Run(new Text(cell))));
|
|
cells.Add(tableCell);
|
|
}
|
|
|
|
table.Append(new TableRow(cells));
|
|
}
|
|
}
|
|
}
|
|
public void SetTable(List<List<string>> rowsAndCells, string keyInRow, bool deleteEmptyRow = false)
|
|
{
|
|
Body bod = Doc.MainDocumentPart.Document.Body;
|
|
var table = bod.Descendants<Table>().Where(tbl => tbl.InnerText.Contains(keyInRow)).FirstOrDefault();
|
|
if (table != null)
|
|
{
|
|
TableRow formatRow = null;
|
|
|
|
// Megkeressük az első sort és elmentjük a formázást
|
|
if (deleteEmptyRow)
|
|
{
|
|
var firstRow = table.ChildElements.OfType<TableRow>().FirstOrDefault();
|
|
if (firstRow != null)
|
|
{
|
|
formatRow = (TableRow)firstRow.CloneNode(true); // Az első sor másolása formázással
|
|
var deletedRows = table.ChildElements.OfType<TableRow>().ToList();
|
|
foreach (var item in deletedRows)
|
|
table.RemoveChild(item);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
var deletedRow = table.ChildElements.OfType<TableRow>().LastOrDefault();
|
|
if (deletedRow != null)
|
|
{
|
|
formatRow = (TableRow)deletedRow.CloneNode(true); // Az utolsó sor másolása formázással
|
|
table.RemoveChild(deletedRow);
|
|
}
|
|
}
|
|
|
|
// Új sorok beszúrása a mentett formázással
|
|
foreach (var row in rowsAndCells)
|
|
{
|
|
List<OpenXmlElement> cells = new List<OpenXmlElement>();
|
|
|
|
for (int i = 0; i < row.Count; i++)
|
|
{
|
|
var cellText = row[i].Replace("#", "");
|
|
|
|
// Ha van formázási minta, alkalmazzuk
|
|
TableCell newCell;
|
|
if (formatRow != null && i < formatRow.Elements<TableCell>().Count())
|
|
{
|
|
var formatCell = formatRow.Elements<TableCell>().ElementAt(i);
|
|
var clonedCell = (TableCell)formatCell.CloneNode(true);
|
|
var para = clonedCell.Descendants<Paragraph>().FirstOrDefault();
|
|
|
|
// Ha van beágyazott szöveg, frissítjük a tartalmát
|
|
if (para != null)
|
|
{
|
|
var run = para.Descendants<Run>().FirstOrDefault();
|
|
if (run != null)
|
|
{
|
|
run.RemoveAllChildren<Text>();
|
|
run.AppendChild(new Text(cellText));
|
|
}
|
|
}
|
|
|
|
newCell = clonedCell;
|
|
}
|
|
else
|
|
{
|
|
// Alapértelmezett cella, ha nincs formázási minta
|
|
newCell = new TableCell(new Paragraph(new Run(new Text(cellText))));
|
|
}
|
|
|
|
cells.Add(newCell);
|
|
}
|
|
|
|
table.Append(new TableRow(cells));
|
|
}
|
|
}
|
|
}
|
|
|
|
public byte[] CloseAndGetDocument()
|
|
{
|
|
Doc.Dispose();
|
|
Doc = null;
|
|
return Mem.ToArray();
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
Doc?.Dispose();
|
|
Mem.Dispose();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Hozzáfűzi a már megnyitott fájlhoz a paraméterként kapott dokumentum tartalmát.
|
|
/// </summary>
|
|
/// <param name="document"></param>
|
|
/// <param name="addPageBreak"></param>
|
|
public void AppendDocument(byte[] document, bool addPageBreak = true)
|
|
{
|
|
var mainPart = Doc.MainDocumentPart;
|
|
string altChunkId = "AltChunk_" + Guid.NewGuid().ToString().Replace("-", "");
|
|
|
|
var chunk = mainPart.AddAlternativeFormatImportPart(AlternativeFormatImportPartType.WordprocessingML, altChunkId);
|
|
chunk.FeedData(new MemoryStream(document));
|
|
|
|
// oldaltörés, ha kell
|
|
if (addPageBreak)
|
|
{
|
|
mainPart.Document.Body.AppendChild(new Paragraph(new Run(new Break() { Type = BreakValues.Page })));
|
|
}
|
|
|
|
mainPart.Document.Body.AppendChild(new AltChunk() { Id = altChunkId });
|
|
|
|
mainPart.Document.Save();
|
|
}
|
|
}
|
|
}
|