【特性】支持不限层次的嵌套 multi_rows,即multi_rows的list,每行元素本身又可以包含multi_rows的字段

main
walon 2021-08-06 19:06:25 +08:00
parent 5c35c140b3
commit e7066c579b
3 changed files with 92 additions and 115 deletions

View File

@ -90,7 +90,7 @@ namespace Luban.Job.Cfg.DataCreators
throw new NotSupportedException();
}
public bool IsContainerAndElementNotSepType(TType type)
private static bool IsContainerAndElementNotSepType(TType type)
{
switch (type)
{
@ -119,14 +119,15 @@ namespace Luban.Job.Cfg.DataCreators
{
try
{
if (f.IsMultiRow)
{
list.Add(f.CType.Apply(this, row.GetSubTitleNamedRowOfMultiRows(fname), f.IsMultiRow, f.IsNullable));
}
else
{
list.Add(f.CType.Apply(this, row.GetSubTitleNamedRow(fname), f.IsMultiRow /* 肯定是 false */, f.IsNullable));
}
list.Add(f.CType.Apply(this, row.GetSubTitleNamedRow(fname), f.IsMultiRow, f.IsNullable));
//if (f.IsMultiRow)
//{
// list.Add(f.CType.Apply(this, row.GetSubTitleNamedRowOfMultiRows(fname), f.IsMultiRow, f.IsNullable));
//}
//else
//{
// list.Add(f.CType.Apply(this, row.GetSubTitleNamedRow(fname), f.IsMultiRow /* 肯定是 false */, f.IsNullable));
//}
}
catch (DataCreateException dce)
{
@ -246,7 +247,8 @@ namespace Luban.Job.Cfg.DataCreators
// 如果是多行数据以当前title为title,每行读入一个element
if (multirow)
{
foreach (var sub in row.GenerateSubNameRows())
//foreach (var sub in row.GenerateSubNameRows(elementType))
foreach (var sub in Sheet.NamedRow.CreateMultiRowNamedRow(row.Rows, row.SelfTitle, elementType))
{
list.Add(this.Accept(elementType, sub, false, false));
}
@ -255,17 +257,18 @@ namespace Luban.Job.Cfg.DataCreators
{
// 如果不是多行,并且定义了子标题的话。以一个子标题所占的列,读入一个数据
foreach (var sub in row.SelfTitle.SubTitleList)
{
list.Add(this.Accept(elementType, new Sheet.NamedRow(sub, row.Rows), false, false));
}
//foreach (var sub in row.SelfTitle.SubTitleList)
//{
// list.Add(this.Accept(elementType, new Sheet.NamedRow(sub, row.Rows), false, false));
//}
throw new NotSupportedException("只有multi_rows=1的list,bean类型才允许有子title");
}
return list;
}
public DType Accept(TArray type, Sheet.NamedRow x, bool multirow, bool nullable)
{
if (!(type.ElementType is TBean bean))
if (type.ElementType is not TBean bean)
{
throw new Exception($"NamedRow 只支持 bean 类型的容器");
}
@ -277,7 +280,7 @@ namespace Luban.Job.Cfg.DataCreators
public DType Accept(TList type, Sheet.NamedRow x, bool multirow, bool nullable)
{
if (!(type.ElementType is TBean bean))
if (type.ElementType is not TBean bean)
{
throw new Exception($"NamedRow 只支持 bean 类型的容器");
}

View File

@ -117,7 +117,7 @@ namespace Luban.Job.Cfg.DataSources.Excel
{
try
{
datas.AddRange(sheet.ReadMulti(type, ((DefBean)type.Bean).IsMultiRow));
datas.AddRange(sheet.ReadMulti(type));
}
catch (DataCreateException dce)
{

View File

@ -1,6 +1,8 @@
using ExcelDataReader;
using Luban.Job.Cfg.DataCreators;
using Luban.Job.Cfg.Datas;
using Luban.Job.Cfg.Defs;
using Luban.Job.Cfg.RawDefs;
using Luban.Job.Cfg.TypeVisitors;
using Luban.Job.Cfg.Utils;
using Luban.Job.Common.Types;
@ -103,6 +105,60 @@ namespace Luban.Job.Cfg.DataSources.Excel
public class NamedRow
{
public static IEnumerable<NamedRow> CreateMultiRowNamedRow(List<List<Cell>> rows, Title title, TBean bean)
{
if (!((DefBean)bean.Bean).IsMultiRow)
{
foreach (var row in rows)
{
if (Sheet.IsBlankRow(row, title.FromIndex, title.ToIndex))
{
continue;
}
yield return new NamedRow(title, row);
}
}
else
{
List<DefField> notMultiRowFields = bean.Bean.HierarchyFields.Select(f => (DefField)f).Where(f => !f.IsMultiRow).ToList();
List<List<Cell>> recordRows = null;
foreach (var row in rows)
{
// 忽略全空的行
if (Sheet.IsBlankRow(row, title.FromIndex, title.ToIndex))
{
continue;
}
// 如果非多行数据全空,说明该行属于多行数据
if (notMultiRowFields.All(f =>
{
var fieldTitle = title.SubTitles[f.Name];
return Sheet.IsBlankRow(row, fieldTitle.FromIndex, fieldTitle.ToIndex);
}))
{
if (recordRows == null)
{
recordRows = new List<List<Cell>>();
}
recordRows.Add(row);
}
else
{
if (recordRows != null)
{
yield return new NamedRow(title, recordRows);
}
recordRows = new List<List<Cell>>();
recordRows.Add(row);
}
}
if (recordRows != null)
{
yield return new NamedRow(title, recordRows);
}
}
}
public Title SelfTitle { get; }
public List<List<Cell>> Rows { get; }
@ -156,20 +212,20 @@ namespace Luban.Job.Cfg.DataSources.Excel
}
}
public NamedRow GetSubTitleNamedRow(string name)
{
Title title = this.Titles[name];
CheckEmptySinceSecondRow(name, title.FromIndex, title.ToIndex);
return new NamedRow(title, this.Rows[0]);
}
//public NamedRow GetSubTitleNamedRow(string name)
//{
// Title title = this.Titles[name];
// CheckEmptySinceSecondRow(name, title.FromIndex, title.ToIndex);
// return new NamedRow(title, this.Rows[0]);
//}
public NamedRow GetSubTitleNamedRowOfMultiRows(string name)
public NamedRow GetSubTitleNamedRow(string name)
{
Title title = Titles[name];
return new NamedRow(title, this.Rows);
}
public IEnumerable<NamedRow> GenerateSubNameRows()
public IEnumerable<NamedRow> GenerateSubNameRows(TBean bean)
{
foreach (var row in Rows)
{
@ -301,7 +357,7 @@ namespace Luban.Job.Cfg.DataSources.Excel
return true;
}
private string GetRowTag(List<Cell> row)
private static string GetRowTag(List<Cell> row)
{
if (row.Count == 0)
{
@ -531,15 +587,14 @@ namespace Luban.Job.Cfg.DataSources.Excel
}
public static bool IsBlankRow(List<Cell> row)
private static bool IsBlankRow(List<Cell> row)
{
// 第一列被策划用于表示是否注释掉此行
// 忽略此列是否空白
return row.GetRange(1, row.Count - 1).All(c => c.Value == null || (c.Value is string s && string.IsNullOrWhiteSpace(s)));
}
public static bool IsBlankRow(List<Cell> row, int fromIndex, int toIndex)
private static bool IsBlankRow(List<Cell> row, int fromIndex, int toIndex)
{
for (int i = Math.Max(1, fromIndex), n = Math.Min(toIndex, row.Count - 1); i <= n; i++)
{
@ -552,94 +607,13 @@ namespace Luban.Job.Cfg.DataSources.Excel
return true;
}
private List<Cell> GetNextRecordRow()
public IEnumerable<Record> ReadMulti(TBean type)
{
while (curReadIndex < _rowColumns.Count)
foreach (var recordNamedRow in NamedRow.CreateMultiRowNamedRow(this._rowColumns, this._rootTitle, type))
{
var row = _rowColumns[curReadIndex++];
if (IsBlankRow(row))
{
continue;
}
return row;
}
return null;
}
private bool HasNotMainKey(List<Cell> row)
{
return string.IsNullOrWhiteSpace(row[1].Value?.ToString());
}
private List<List<Cell>> GetNextRecordRows()
{
List<List<Cell>> rows = null;
while (curReadIndex < _rowColumns.Count)
{
var row = _rowColumns[curReadIndex++];
if (IsBlankRow(row))
{
continue;
}
if (rows == null)
{
rows = new List<List<Cell>>() { row };
}
else
{
if (HasNotMainKey(row))
{
rows.Add(row);
}
else
{
--curReadIndex;
return rows;
}
}
}
return rows;
}
public List<Record> ReadMulti(TBean type, bool enableMultiRowRecord)
{
var datas = new List<Record>();
for (Record data; (data = ReadOne(type, enableMultiRowRecord)) != null;)
{
datas.Add(data);
}
return datas;
}
private int curReadIndex = 0;
public Record ReadOne(TBean type, bool enableMultiRowRecord)
{
if (!enableMultiRowRecord)
{
List<Cell> row = GetNextRecordRow();
if (row == null)
{
return null;
}
bool isTest = DataUtil.IsTestTag(GetRowTag(row));
var data = (DBean)ExcelNamedRowDataCreator.Ins.ReadExcel(new NamedRow(_rootTitle, row), type);
return new Record(data, RawUrl, isTest);
}
else
{
List<List<Cell>> rows = GetNextRecordRows();
if (rows == null)
{
return null;
}
bool isTest = DataUtil.IsTestTag(GetRowTag(rows[0]));
var data = (DBean)ExcelNamedRowDataCreator.Ins.ReadExcel(new NamedRow(_rootTitle, rows), type);
return new Record(data, RawUrl, isTest);
bool isTest = DataUtil.IsTestTag(GetRowTag(recordNamedRow.Rows[0]));
var data = (DBean)ExcelNamedRowDataCreator.Ins.ReadExcel(recordNamedRow, type);
yield return new Record(data, RawUrl, isTest);
}
}
}