Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[MEDIDEV-509] First iteration. #16

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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>
Dm17r1y marked this conversation as resolved.
Show resolved Hide resolved
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