Skip to content

Commit

Permalink
Merge pull request #16 from FredSpb/skbkontur/external-formula-evaluator
Browse files Browse the repository at this point in the history
Add IFormulaEvaluator
  • Loading branch information
Dm17r1y authored Oct 16, 2023
2 parents 25c6fb5 + dce5090 commit ececc21
Show file tree
Hide file tree
Showing 6 changed files with 72 additions and 20 deletions.
2 changes: 1 addition & 1 deletion Excel.TemplateEngine/ITemplateEngine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public interface ITemplateEngine
(TModel model, Dictionary<string, string> mappingForErrors) Parse<TModel>([NotNull] ITableParser tableParser)
where TModel : new();

public TModel LazyParse<TModel>([NotNull] LazyTableReader lazyTableReader, ObjectSize readerOffset = null)
public TModel LazyParse<TModel>([NotNull] LazyTableReader lazyTableReader, ObjectSize readerOffset = null, IFormulaEvaluator formulaEvaluator = null)
where TModel : new();
}
}
12 changes: 12 additions & 0 deletions Excel.TemplateEngine/ObjectPrinting/LazyParse/IFormulaEvaluator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#nullable enable

using DocumentFormat.OpenXml.Spreadsheet;

namespace SkbKontur.Excel.TemplateEngine.ObjectPrinting.LazyParse
{
public interface IFormulaEvaluator
{
string? TryEvaluate(
Cell cell);
}
}
35 changes: 27 additions & 8 deletions Excel.TemplateEngine/ObjectPrinting/LazyParse/LazyClassParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ namespace SkbKontur.Excel.TemplateEngine.ObjectPrinting.LazyParse
/// </summary>
internal class LazyClassParser
{
public LazyClassParser(ILog logger)
public LazyClassParser([NotNull] ILog logger)
{
this.logger = logger;
}
Expand All @@ -32,8 +32,13 @@ public LazyClassParser(ILog logger)
/// <param name="tableReader">Target document LazyTableReader.</param>
/// <param name="template"></param>
/// <param name="readerOffset">Target file offset relative to a template.</param>
/// <param name="formulaEvaluator">Target document formula evaluator.</param>
[NotNull]
public TModel Parse<TModel>([NotNull] LazyTableReader tableReader, [NotNull] RenderingTemplate template, ObjectSize readerOffset)
public TModel Parse<TModel>(
[NotNull] LazyTableReader tableReader,
[NotNull] RenderingTemplate template,
[NotNull] ObjectSize readerOffset,
[CanBeNull] IFormulaEvaluator formulaEvaluator = null)
where TModel : new()
{
var model = new TModel();
Expand All @@ -52,7 +57,10 @@ public TModel Parse<TModel>([NotNull] LazyTableReader tableReader, [NotNull] Ren
{
foreach (var templateCell in templateRow)
{
var targetCell = targetRowReader.TryReadCell(templateCell.CellPosition.Add(readerOffset));
var targetCell = targetRowReader.TryReadCell(
templateCell.CellPosition.Add(readerOffset),
formulaEvaluator);

if (targetCell == null)
continue;

Expand All @@ -71,7 +79,7 @@ public TModel Parse<TModel>([NotNull] LazyTableReader tableReader, [NotNull] Ren

var templateListCells = templateRow.SkipWhile(x => x.CellPosition.CellReference != templateCell.CellPosition.CellReference)
.ToArray();
ParseEnumerable(tableReader, model, templateListCells, enumerableType, readerOffset);
ParseEnumerable(tableReader, model, templateListCells, enumerableType, readerOffset, formulaEvaluator);
break;
}

Expand All @@ -90,7 +98,8 @@ private void ParseEnumerable([NotNull] LazyTableReader tableReader,
[NotNull] object model,
[NotNull] [ItemNotNull] ICell[] templateListCells,
[NotNull] Type enumerableType,
[NotNull] ObjectSize readerOffset)
[NotNull] ObjectSize readerOffset,
[CanBeNull] IFormulaEvaluator formulaEvaluator)
{
var firstEnumerablePath = ExcelTemplatePath.FromRawExpression(templateListCells.First().StringValue)
.SplitForEnumerableExpansion()
Expand All @@ -99,18 +108,28 @@ private void ParseEnumerable([NotNull] LazyTableReader tableReader,
var modelType = model.GetType();
var itemType = ObjectPropertiesExtractor.ExtractChildObjectTypeFromPath(modelType, firstEnumerablePath);

var items = ParseList(tableReader, itemType, templateListCells.Select(x => new SimpleCell(x.CellPosition, x.StringValue)), readerOffset);
var items = ParseList(
tableReader,
itemType,
templateListCells.Select(x => new SimpleCell(x.CellPosition, x.StringValue)),
readerOffset,
formulaEvaluator);

var withoutArrayAccess = firstEnumerablePath.WithoutArrayAccess();
var enumerableSetter = ObjectChildSetterFactory.GetEnumerableSetter(modelType, withoutArrayAccess, enumerableType, itemType);

enumerableSetter(model, items);
}

private object ParseList([NotNull] LazyTableReader tableReader, [NotNull] Type itemType, [NotNull, ItemNotNull] IEnumerable<SimpleCell> templateListCells, ObjectSize readerOffset)
private object ParseList(
[NotNull] LazyTableReader tableReader,
[NotNull] Type itemType,
[NotNull, ItemNotNull] IEnumerable<SimpleCell> templateListCells,
[NotNull] ObjectSize readerOffset,
[CanBeNull] IFormulaEvaluator formulaEvaluator)
{
return parseList.MakeGenericMethod(itemType)
.Invoke(null, new object[] {tableReader, templateListCells, true, logger, readerOffset});
.Invoke(null, new object[] {tableReader, templateListCells, true, logger, readerOffset, formulaEvaluator});
}

private void ParseSingleValue([NotNull] SimpleCell cell,
Expand Down
28 changes: 23 additions & 5 deletions Excel.TemplateEngine/ObjectPrinting/LazyParse/LazyRowReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,17 @@ public LazyRowReader([NotNull] Row row, [NotNull] IReadOnlyList<string> sharedSt
}

[NotNull]
private SimpleCell LoadCurrentCell()
private SimpleCell LoadCurrentCell(
[CanBeNull] IFormulaEvaluator formulaEvaluator)
{
var cell = (Cell)reader.LoadCurrentElement();
return ToSimpleCell(cell!);
return ToSimpleCell(cell!, formulaEvaluator);
}

[CanBeNull]
public SimpleCell TryReadCell([NotNull] ICellPosition cellPosition)
public SimpleCell TryReadCell(
[NotNull] ICellPosition cellPosition,
[CanBeNull] IFormulaEvaluator formulaEvaluator = null)
{
if (cellPosition.RowIndex != RowIndex)
throw new ArgumentException($"Incorrect cell reference. Target cell reference: {cellPosition}. Current row index: {RowIndex}.");
Expand All @@ -50,7 +53,8 @@ public SimpleCell TryReadCell([NotNull] ICellPosition cellPosition)
if (reader.ElementType != typeof(Cell))
continue;

currentCell = LoadCurrentCell();
currentCell = LoadCurrentCell(
formulaEvaluator);

if (cellPosition.ColumnIndex > currentCell!.CellPosition.ColumnIndex)
continue;
Expand All @@ -66,15 +70,29 @@ public SimpleCell TryReadCell([NotNull] ICellPosition cellPosition)
}

[NotNull]
private SimpleCell ToSimpleCell([NotNull] Cell cell)
private SimpleCell ToSimpleCell(
[NotNull] Cell cell,
[CanBeNull] IFormulaEvaluator formulaEvaluator)
{
var cellIndex = new CellPosition(cell.CellReference);

var cellValue = cell.CellValue?.InnerText;
if (cell.DataType?.Value == CellValues.SharedString && cellValue != null)
{
var i = int.Parse(cellValue);
cellValue = sharedStrings[i];
}
else if (
cell.CellFormula != null &&
formulaEvaluator != null &&
string.IsNullOrEmpty(cellValue))
{
var formulaEvaluatedValue = formulaEvaluator.TryEvaluate(
cell);

if (!string.IsNullOrEmpty(formulaEvaluatedValue))
cellValue = formulaEvaluatedValue;
}

return new SimpleCell(cellIndex, cellValue);
}
Expand Down
10 changes: 6 additions & 4 deletions Excel.TemplateEngine/ObjectPrinting/LazyParse/ListParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ public static IReadOnlyList<TItem> Parse<TItem>([NotNull] LazyTableReader tableR
[NotNull, ItemNotNull] IEnumerable<SimpleCell> templateListCells,
bool filterTemplateCells,
[NotNull] ILog logger,
[NotNull] ObjectSize readerOffset)
[NotNull] ObjectSize readerOffset,
[CanBeNull] IFormulaEvaluator formulaEvaluator = null)
{
var itemType = typeof(TItem);

Expand All @@ -49,7 +50,7 @@ public static IReadOnlyList<TItem> Parse<TItem>([NotNull] LazyTableReader tableR
while (row != null)
{
var itemDict = itemPropPaths.ToDictionary(x => x, _ => (object)null);
FillInItemDict(itemTemplate, row, itemType, itemDict, readerOffset, logger);
FillInItemDict(itemTemplate, row, itemType, itemDict, readerOffset, logger, formulaEvaluator);

if (IsRowEmpty(itemDict, impotentItemProps))
{
Expand All @@ -71,12 +72,13 @@ private static void FillInItemDict((ICellPosition CellPosition, ExcelTemplatePat
Type itemType,
Dictionary<ExcelTemplatePath, object> itemDict,
ObjectSize readerOffset,
ILog logger)
ILog logger,
IFormulaEvaluator formulaEvaluator)
{
foreach (var prop in itemTemplate)
{
var cellPosition = new CellPosition(row.RowIndex, prop.CellPosition.ColumnIndex + readerOffset.Width);
var cell = row.TryReadCell(cellPosition);
var cell = row.TryReadCell(cellPosition, formulaEvaluator);
if (cell == null || string.IsNullOrWhiteSpace(cell.CellValue))
continue;

Expand Down
5 changes: 3 additions & 2 deletions Excel.TemplateEngine/TemplateEngine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,15 +54,16 @@ public void Render<TModel>([NotNull] ITableBuilder tableBuilder, [NotNull] TMode
/// <typeparam name="TModel">Class to parse.</typeparam>
/// <param name="lazyTableReader">LazyTableReader of target xlsx file.</param>
/// <param name="readerOffset">Target file offset relative to a template.</param>
public TModel LazyParse<TModel>([NotNull] LazyTableReader lazyTableReader, ObjectSize readerOffset = null)
/// <param name="formulaEvaluator">Target file formula evaluator.</param>
public TModel LazyParse<TModel>([NotNull] LazyTableReader lazyTableReader, ObjectSize readerOffset = null, IFormulaEvaluator formulaEvaluator = null)
where TModel : new()
{
readerOffset ??= new ObjectSize(0, 0);

var renderingTemplate = templateCollection.GetTemplate(rootTemplateName) ??
throw new InvalidOperationException($"Template with name {rootTemplateName} not found in xlsx");
var parser = parserCollection.GetLazyClassParser();
return parser.Parse<TModel>(lazyTableReader, renderingTemplate, readerOffset);
return parser.Parse<TModel>(lazyTableReader, renderingTemplate, readerOffset, formulaEvaluator);
}

private const string rootTemplateName = "RootTemplate";
Expand Down

0 comments on commit ececc21

Please sign in to comment.