namespace QWERTYkez.WordProcessor;
///
/// Множественные динамические замены с извлечением параметра из "$key|param$".
/// Переиспользует движок (форматирование Run-ов,
/// разрывы страниц, смена ориентации, разбиение на параграфы — всё как в оригинале).
///
internal static class DynamicMultiReplaceExt
{
// ============================================================
// ReplaceString (Func>)
// ============================================================
internal static void ReplaceStringMultiInBody(
Body body,
string oldValue,
Func> factory,
StringComparison comparisonType)
{
if (body is null || factory is null) return;
DynamicReplaceExt.ParsePattern(oldValue, out var prefix, out var suffix);
var paragraphs = body.Elements().ToList();
for (int i = paragraphs.Count - 1; i >= 0; i--)
ProcessDynamicStringMulti(paragraphs[i], prefix, suffix, factory, comparisonType);
}
internal static void ReplaceStringMultiInTables(
OpenXmlElement element,
string oldValue,
Func> factory,
StringComparison comparisonType)
{
if (element is null || factory is null) return;
DynamicReplaceExt.ParsePattern(oldValue, out var prefix, out var suffix);
foreach (var table in TableTextProcessor.GetAllTables(element))
{
var paragraphs = TableTextProcessor.GetTableParagraphs(table).ToList();
for (int i = paragraphs.Count - 1; i >= 0; i--)
ProcessDynamicStringMulti(paragraphs[i], prefix, suffix, factory, comparisonType);
}
}
internal static void ReplaceStringMultiInHeadersFooters(
WordprocessingDocument doc,
string oldValue,
Func> factory,
StringComparison comparisonType)
{
if (doc is null || factory is null) return;
DynamicReplaceExt.ParsePattern(oldValue, out var prefix, out var suffix);
foreach (var header in HeaderFooterProcessor.GetAllHeaders(doc))
ProcessStringMultiInElement(header, prefix, suffix, factory, comparisonType);
foreach (var footer in HeaderFooterProcessor.GetAllFooters(doc))
ProcessStringMultiInElement(footer, prefix, suffix, factory, comparisonType);
}
private static void ProcessStringMultiInElement(
OpenXmlElement element,
string prefix,
string suffix,
Func> factory,
StringComparison comparisonType)
{
var paragraphs = element.Descendants().ToList();
var tables = TableTextProcessor.GetAllTables(element).ToList();
var tableParagraphs = tables.SelectMany(t => TableTextProcessor.GetTableParagraphs(t)).ToList();
var allParagraphs = paragraphs.Concat(tableParagraphs).Distinct().ToList();
for (int i = allParagraphs.Count - 1; i >= 0; i--)
ProcessDynamicStringMulti(allParagraphs[i], prefix, suffix, factory, comparisonType);
}
private static void ProcessDynamicStringMulti(
Paragraph paragraph,
string prefix,
string suffix,
Func> factory,
StringComparison comparisonType)
{
if (paragraph is null || paragraph.Parent is null) return;
var text = paragraph.InnerText;
if (string.IsNullOrEmpty(text)) return;
var matches = DynamicReplaceExt.FindMatches(text, prefix, suffix, comparisonType);
if (matches.Count == 0) return;
// Строим словарь уникальных matchedText -> значения для этого параграфа
var dict = new Dictionary>();
for (int i = 0; i < matches.Count; i++)
{
var m = matches[i];
string matchedText = text.Substring(m.Start, m.End - m.Start);
if (dict.ContainsKey(matchedText)) continue;
IEnumerable values;
try { values = factory(m.Param); }
catch { continue; }
if (values is null) continue;
var list = values as IList ?? values.ToList();
if (list.Count == 0) continue;
dict[matchedText] = list;
}
if (dict.Count == 0) return;
var newParas = MultiReplaceExt.ProcessParagraphWithMergedBoundaries(paragraph, dict, comparisonType);
if (newParas is not null && newParas.Count > 0)
ParagraphReplacer.ReplaceParagraph(paragraph, newParas);
}
// ============================================================
// ReplaceItem (Func>)
// ============================================================
internal static void ReplaceItemMultiInBody(
Body body,
string oldValue,
Func> factory,
StringComparison comparisonType)
{
if (body is null || factory is null) return;
DynamicReplaceExt.ParsePattern(oldValue, out var prefix, out var suffix);
var paragraphs = body.Elements().ToList();
for (int i = paragraphs.Count - 1; i >= 0; i--)
ProcessDynamicItemMulti(paragraphs[i], prefix, suffix, factory, comparisonType);
}
internal static void ReplaceItemMultiInTables(
OpenXmlElement element,
string oldValue,
Func> factory,
StringComparison comparisonType)
{
if (element is null || factory is null) return;
DynamicReplaceExt.ParsePattern(oldValue, out var prefix, out var suffix);
foreach (var table in TableTextProcessor.GetAllTables(element))
{
var paragraphs = TableTextProcessor.GetTableParagraphs(table).ToList();
for (int i = paragraphs.Count - 1; i >= 0; i--)
ProcessDynamicItemMulti(paragraphs[i], prefix, suffix, factory, comparisonType);
}
}
internal static void ReplaceItemMultiInHeadersFooters(
WordprocessingDocument doc,
string oldValue,
Func> factory,
StringComparison comparisonType)
{
if (doc is null || factory is null) return;
DynamicReplaceExt.ParsePattern(oldValue, out var prefix, out var suffix);
foreach (var header in HeaderFooterProcessor.GetAllHeaders(doc))
ProcessItemMultiInElement(header, prefix, suffix, factory, comparisonType);
foreach (var footer in HeaderFooterProcessor.GetAllFooters(doc))
ProcessItemMultiInElement(footer, prefix, suffix, factory, comparisonType);
}
private static void ProcessItemMultiInElement(
OpenXmlElement element,
string prefix,
string suffix,
Func> factory,
StringComparison comparisonType)
{
var paragraphs = element.Descendants().ToList();
var tables = TableTextProcessor.GetAllTables(element).ToList();
var tableParagraphs = tables.SelectMany(t => TableTextProcessor.GetTableParagraphs(t)).ToList();
var allParagraphs = paragraphs.Concat(tableParagraphs).Distinct().ToList();
for (int i = allParagraphs.Count - 1; i >= 0; i--)
ProcessDynamicItemMulti(allParagraphs[i], prefix, suffix, factory, comparisonType);
}
private static void ProcessDynamicItemMulti(
Paragraph paragraph,
string prefix,
string suffix,
Func> factory,
StringComparison comparisonType)
{
if (paragraph is null || paragraph.Parent is null) return;
var text = paragraph.InnerText;
if (string.IsNullOrEmpty(text)) return;
var matches = DynamicReplaceExt.FindMatches(text, prefix, suffix, comparisonType);
if (matches.Count == 0) return;
var dict = new Dictionary>();
for (int i = 0; i < matches.Count; i++)
{
var m = matches[i];
string matchedText = text.Substring(m.Start, m.End - m.Start);
if (dict.ContainsKey(matchedText)) continue;
IEnumerable values;
try { values = factory(m.Param); }
catch { continue; }
if (values is null) continue;
var list = values as IList ?? values.ToList();
if (list.Count == 0) continue;
dict[matchedText] = list;
}
if (dict.Count == 0) return;
var newParas = MultiReplaceExt.ProcessParagraphWithMergedBoundaries(paragraph, dict, comparisonType);
if (newParas is not null && newParas.Count > 0)
ParagraphReplacer.ReplaceParagraph(paragraph, newParas);
}
}