【重构】完成数据生成重构

main
walon 2021-10-15 17:18:01 +08:00
parent 1c22887e69
commit a7dcb7f64d
14 changed files with 296 additions and 400 deletions

View File

@ -277,6 +277,7 @@ namespace Luban.Job.Cfg.DataCreators
public DType Accept(TText type, ExcelStream x) public DType Accept(TText type, ExcelStream x)
{ {
x = SepIfNeed(type, x);
string key = ParseString(x.Read()); string key = ParseString(x.Read());
if (key == null) if (key == null)
{ {
@ -302,15 +303,15 @@ namespace Luban.Job.Cfg.DataCreators
{ {
try try
{ {
string sep = f.Tags.TryGetValue("tag", out var s) ? s : null; //string sep = f.Tags.TryGetValue("tag", out var s) ? s : null;
if (string.IsNullOrWhiteSpace(sep)) //if (string.IsNullOrWhiteSpace(sep))
{ //{
list.Add(f.CType.Apply(this, stream)); list.Add(f.CType.Apply(this, stream));
} //}
else //else
{ //{
list.Add(f.CType.Apply(this, new ExcelStream(stream.ReadCell(), sep))); // list.Add(f.CType.Apply(this, new ExcelStream(stream.ReadCell(), sep)));
} //}
} }
catch (DataCreateException dce) catch (DataCreateException dce)
{ {
@ -327,9 +328,23 @@ namespace Luban.Job.Cfg.DataCreators
return list; return list;
} }
public static ExcelStream SepIfNeed(TType type, ExcelStream stream)
{
string sep = DataUtil.GetSep(type);
if (!string.IsNullOrEmpty(sep))
{
return new ExcelStream(stream.ReadCell(), sep);
}
else
{
return stream;
}
}
public DType Accept(TBean type, ExcelStream x) public DType Accept(TBean type, ExcelStream x)
{ {
var originBean = (DefBean)type.Bean; var originBean = (DefBean)type.Bean;
x = SepIfNeed(type, x);
if (originBean.IsAbstractType) if (originBean.IsAbstractType)
{ {
@ -372,46 +387,38 @@ namespace Luban.Job.Cfg.DataCreators
// 因为貌似没意义? // 因为貌似没意义?
public List<DType> ReadList(TType type, ExcelStream stream) public List<DType> ReadList(TType type, ExcelStream stream)
{ {
string sep = type is TBean bean ? ((DefBean)bean.Bean).Sep : null;
var datas = new List<DType>(); var datas = new List<DType>();
while (!stream.TryReadEOF()) while (!stream.TryReadEOF())
{
if (string.IsNullOrWhiteSpace(sep))
{ {
datas.Add(type.Apply(this, stream)); datas.Add(type.Apply(this, stream));
} }
else
{
datas.Add(type.Apply(this, new ExcelStream(stream.ReadCell(), sep))); ;
}
}
return datas; return datas;
} }
public DType Accept(TArray type, ExcelStream x) public DType Accept(TArray type, ExcelStream x)
{ {
return new DArray(type, ReadList(type.ElementType, x)); return new DArray(type, ReadList(type.ElementType, SepIfNeed(type, x)));
} }
public DType Accept(TList type, ExcelStream x) public DType Accept(TList type, ExcelStream x)
{ {
return new DList(type, ReadList(type.ElementType, x)); return new DList(type, ReadList(type.ElementType, SepIfNeed(type, x)));
} }
public DType Accept(TSet type, ExcelStream x) public DType Accept(TSet type, ExcelStream x)
{ {
return new DSet(type, ReadList(type.ElementType, x)); return new DSet(type, ReadList(type.ElementType, SepIfNeed(type, x)));
} }
public DType Accept(TMap type, ExcelStream x) public DType Accept(TMap type, ExcelStream x)
{ {
string sep = type.ValueType is TBean bean ? ((DefBean)bean.Bean).Sep : null; x = SepIfNeed(type, x);
var datas = new Dictionary<DType, DType>(); var datas = new Dictionary<DType, DType>();
while (!x.TryReadEOF()) while (!x.TryReadEOF())
{ {
var key = type.KeyType.Apply(this, x); var key = type.KeyType.Apply(this, x);
var value = string.IsNullOrWhiteSpace(sep) ? type.ValueType.Apply(this, x) : type.ValueType.Apply(this, new ExcelStream(x.ReadCell(), sep)); var value = type.ValueType.Apply(this, x);
if (!datas.TryAdd(key, value)) if (!datas.TryAdd(key, value))
{ {
throw new InvalidExcelDataException($"map 的 key:{key} 重复"); throw new InvalidExcelDataException($"map 的 key:{key} 重复");

View File

@ -31,7 +31,7 @@ namespace Luban.Job.Cfg.DataCreators
public DType Accept(TBool type, Sheet sheet, TitleRow row) public DType Accept(TBool type, Sheet sheet, TitleRow row)
{ {
object x = row.Current.Value; object x = row.Current;
if (CheckNull(type.IsNullable, x)) if (CheckNull(type.IsNullable, x))
{ {
return null; return null;
@ -49,7 +49,7 @@ namespace Luban.Job.Cfg.DataCreators
public DType Accept(TByte type, Sheet sheet, TitleRow row) public DType Accept(TByte type, Sheet sheet, TitleRow row)
{ {
object x = row.Current.Value; object x = row.Current;
if (CheckNull(type.IsNullable, x)) if (CheckNull(type.IsNullable, x))
{ {
return null; return null;
@ -63,7 +63,7 @@ namespace Luban.Job.Cfg.DataCreators
public DType Accept(TShort type, Sheet sheet, TitleRow row) public DType Accept(TShort type, Sheet sheet, TitleRow row)
{ {
object x = row.Current.Value; object x = row.Current;
if (CheckNull(type.IsNullable, x)) if (CheckNull(type.IsNullable, x))
{ {
return null; return null;
@ -77,7 +77,7 @@ namespace Luban.Job.Cfg.DataCreators
public DType Accept(TFshort type, Sheet sheet, TitleRow row) public DType Accept(TFshort type, Sheet sheet, TitleRow row)
{ {
object x = row.Current.Value; object x = row.Current;
if (CheckNull(type.IsNullable, x)) if (CheckNull(type.IsNullable, x))
{ {
return null; return null;
@ -91,7 +91,7 @@ namespace Luban.Job.Cfg.DataCreators
public DType Accept(TInt type, Sheet sheet, TitleRow row) public DType Accept(TInt type, Sheet sheet, TitleRow row)
{ {
object x = row.Current.Value; object x = row.Current;
if (CheckNull(type.IsNullable, x)) if (CheckNull(type.IsNullable, x))
{ {
return null; return null;
@ -105,7 +105,7 @@ namespace Luban.Job.Cfg.DataCreators
public DType Accept(TFint type, Sheet sheet, TitleRow row) public DType Accept(TFint type, Sheet sheet, TitleRow row)
{ {
object x = row.Current.Value; object x = row.Current;
if (CheckNull(type.IsNullable, x)) if (CheckNull(type.IsNullable, x))
{ {
return null; return null;
@ -119,7 +119,7 @@ namespace Luban.Job.Cfg.DataCreators
public DType Accept(TLong type, Sheet sheet, TitleRow row) public DType Accept(TLong type, Sheet sheet, TitleRow row)
{ {
object x = row.Current.Value; object x = row.Current;
if (CheckNull(type.IsNullable, x)) if (CheckNull(type.IsNullable, x))
{ {
return null; return null;
@ -133,7 +133,7 @@ namespace Luban.Job.Cfg.DataCreators
public DType Accept(TFlong type, Sheet sheet, TitleRow row) public DType Accept(TFlong type, Sheet sheet, TitleRow row)
{ {
object x = row.Current.Value; object x = row.Current;
if (CheckNull(type.IsNullable, x)) if (CheckNull(type.IsNullable, x))
{ {
return null; return null;
@ -147,7 +147,7 @@ namespace Luban.Job.Cfg.DataCreators
public DType Accept(TFloat type, Sheet sheet, TitleRow row) public DType Accept(TFloat type, Sheet sheet, TitleRow row)
{ {
object x = row.Current.Value; object x = row.Current;
if (CheckNull(type.IsNullable, x)) if (CheckNull(type.IsNullable, x))
{ {
return null; return null;
@ -161,7 +161,7 @@ namespace Luban.Job.Cfg.DataCreators
public DType Accept(TDouble type, Sheet sheet, TitleRow row) public DType Accept(TDouble type, Sheet sheet, TitleRow row)
{ {
object x = row.Current.Value; object x = row.Current;
if (CheckNull(type.IsNullable, x)) if (CheckNull(type.IsNullable, x))
{ {
return null; return null;
@ -175,7 +175,7 @@ namespace Luban.Job.Cfg.DataCreators
public DType Accept(TEnum type, Sheet sheet, TitleRow row) public DType Accept(TEnum type, Sheet sheet, TitleRow row)
{ {
object x = row.Current.Value; object x = row.Current;
if (CheckNull(type.IsNullable, x)) if (CheckNull(type.IsNullable, x))
{ {
return null; return null;
@ -224,12 +224,17 @@ namespace Luban.Job.Cfg.DataCreators
public DType Accept(TText type, Sheet sheet, TitleRow row) public DType Accept(TText type, Sheet sheet, TitleRow row)
{ {
if (row.Row.Count != 2) if (row.CellCount != 2)
{ {
throw new Exception($"text 要求两个字段"); throw new Exception($"text 要求两个字段");
} }
var key = ParseString(row.Row[0].Value); int startIndex = row.SelfTitle.FromIndex;
var text = ParseString(row.Row[1].Value); var key = ParseString(row.Row[startIndex].Value);
var text = ParseString(row.Row[startIndex + 1].Value);
if (type.IsNullable && key == null && text == null)
{
return null;
}
DataUtil.ValidateText(key, text); DataUtil.ValidateText(key, text);
return new DText(key, text); return new DText(key, text);
} }
@ -238,6 +243,7 @@ namespace Luban.Job.Cfg.DataCreators
{ {
var list = new List<DType>(); var list = new List<DType>();
foreach (DefField f in bean.HierarchyFields) foreach (DefField f in bean.HierarchyFields)
{ {
string fname = f.Name; string fname = f.Name;
TitleRow field = row.GetSubTitleNamedRow(fname); TitleRow field = row.GetSubTitleNamedRow(fname);
@ -266,7 +272,7 @@ namespace Luban.Job.Cfg.DataCreators
public DType Accept(TBean type, Sheet sheet, TitleRow row) public DType Accept(TBean type, Sheet sheet, TitleRow row)
{ {
string sep = GetSep(type); string sep = DataUtil.GetSep(type);
if (row.Row != null) if (row.Row != null)
{ {
@ -284,7 +290,7 @@ namespace Luban.Job.Cfg.DataCreators
var originBean = (DefBean)type.Bean; var originBean = (DefBean)type.Bean;
if (originBean.IsAbstractType) if (originBean.IsAbstractType)
{ {
string subType = row.GetSubTitleNamedRow(DefBean.TYPE_NAME_KEY).Current.Value.ToString().Trim(); string subType = row.GetSubTitleNamedRow(DefBean.TYPE_NAME_KEY).Current.ToString().Trim();
if (subType.ToLower() == DefBean.BEAN_NULL_STR) if (subType.ToLower() == DefBean.BEAN_NULL_STR)
{ {
if (!type.IsNullable) if (!type.IsNullable)
@ -305,7 +311,7 @@ namespace Luban.Job.Cfg.DataCreators
{ {
if (type.IsNullable) if (type.IsNullable)
{ {
string subType = row.GetSubTitleNamedRow(DefBean.TYPE_NAME_KEY).Current.Value.ToString().Trim(); string subType = row.GetSubTitleNamedRow(DefBean.TYPE_NAME_KEY).Current.ToString().Trim();
if (subType == DefBean.BEAN_NULL_STR) if (subType == DefBean.BEAN_NULL_STR)
{ {
return null; return null;
@ -331,23 +337,8 @@ namespace Luban.Job.Cfg.DataCreators
} }
} }
const string SimpleContainerSep = ",;";
public string GetSep(TType type)
{
if (type.Tags.TryGetValue("sep", out var s) && !string.IsNullOrWhiteSpace(s))
{
return s;
}
switch (type)
{
case TBean tb: return (tb.Bean as DefBean).Sep;
case TArray ta: return ta.ElementType.Apply(IsNotSepTypeVisitor.Ins) ? SimpleContainerSep : "";
case TList ta: return ta.ElementType.Apply(IsNotSepTypeVisitor.Ins) ? SimpleContainerSep : "";
case TSet ta: return ta.ElementType.Apply(IsNotSepTypeVisitor.Ins) ? SimpleContainerSep : "";
default: return "";
}
}
public List<DType> ReadList(TType type, ExcelStream stream) public List<DType> ReadList(TType type, ExcelStream stream)
{ {
@ -374,7 +365,7 @@ namespace Luban.Job.Cfg.DataCreators
public DType Accept(TArray type, Sheet sheet, TitleRow row) public DType Accept(TArray type, Sheet sheet, TitleRow row)
{ {
string sep = GetSep(type); string sep = DataUtil.GetSep(type);
if (row.Row != null) if (row.Row != null)
{ {
@ -402,7 +393,7 @@ namespace Luban.Job.Cfg.DataCreators
public DType Accept(TList type, Sheet sheet, TitleRow row) public DType Accept(TList type, Sheet sheet, TitleRow row)
{ {
string sep = GetSep(type); string sep = DataUtil.GetSep(type);
if (row.Row != null) if (row.Row != null)
{ {
@ -430,7 +421,7 @@ namespace Luban.Job.Cfg.DataCreators
public DType Accept(TSet type, Sheet sheet, TitleRow row) public DType Accept(TSet type, Sheet sheet, TitleRow row)
{ {
string sep = GetSep(type); string sep = DataUtil.GetSep(type);
if (row.Row != null) if (row.Row != null)
{ {
@ -458,7 +449,7 @@ namespace Luban.Job.Cfg.DataCreators
public DType Accept(TMap type, Sheet sheet, TitleRow row) public DType Accept(TMap type, Sheet sheet, TitleRow row)
{ {
string sep = GetSep(type); string sep = DataUtil.GetSep(type);
if (row.Row != null) if (row.Row != null)
{ {
@ -494,6 +485,10 @@ namespace Luban.Job.Cfg.DataCreators
foreach (var e in row.Fields) foreach (var e in row.Fields)
{ {
var keyData = type.KeyType.Apply(StringDataCreator.Ins, e.Key); var keyData = type.KeyType.Apply(StringDataCreator.Ins, e.Key);
if (Sheet.IsBlankRow(e.Value.Row, e.Value.SelfTitle.FromIndex, e.Value.SelfTitle.ToIndex))
{
continue;
}
var valueData = type.ValueType.Apply(ExcelStreamDataCreator.Ins, e.Value.AsStream(sep)); var valueData = type.ValueType.Apply(ExcelStreamDataCreator.Ins, e.Value.AsStream(sep));
datas.Add(keyData, valueData); datas.Add(keyData, valueData);
} }
@ -501,7 +496,15 @@ namespace Luban.Job.Cfg.DataCreators
} }
else if (row.Elements != null) else if (row.Elements != null)
{ {
throw new NotSupportedException(); var datas = new Dictionary<DType, DType>();
foreach (var e in row.Elements)
{
var stream = e.AsStream("");
var keyData = type.KeyType.Apply(ExcelStreamDataCreator.Ins, stream);
var valueData = type.ValueType.Apply(ExcelStreamDataCreator.Ins, stream);
datas.Add(keyData, valueData);
}
return new DMap(type, datas);
} }
else else
{ {
@ -511,37 +514,49 @@ namespace Luban.Job.Cfg.DataCreators
public DType Accept(TVector2 type, Sheet sheet, TitleRow row) public DType Accept(TVector2 type, Sheet sheet, TitleRow row)
{ {
var d = row.Current.Value; var d = row.Current;
if (CheckNull(type.IsNullable, d)) if (CheckNull(type.IsNullable, d))
{ {
return null; return null;
} }
if (CheckDefault(d))
{
return DVector2.Default;
}
return DataUtil.CreateVector(type, d.ToString()); return DataUtil.CreateVector(type, d.ToString());
} }
public DType Accept(TVector3 type, Sheet sheet, TitleRow row) public DType Accept(TVector3 type, Sheet sheet, TitleRow row)
{ {
var d = row.Current.Value; var d = row.Current;
if (CheckNull(type.IsNullable, d)) if (CheckNull(type.IsNullable, d))
{ {
return null; return null;
} }
if (CheckDefault(d))
{
return DVector3.Default;
}
return DataUtil.CreateVector(type, d.ToString()); return DataUtil.CreateVector(type, d.ToString());
} }
public DType Accept(TVector4 type, Sheet sheet, TitleRow row) public DType Accept(TVector4 type, Sheet sheet, TitleRow row)
{ {
var d = row.Current.Value; var d = row.Current;
if (CheckNull(type.IsNullable, d)) if (CheckNull(type.IsNullable, d))
{ {
return null; return null;
} }
if (CheckDefault(d))
{
return DVector4.Default;
}
return DataUtil.CreateVector(type, d.ToString()); return DataUtil.CreateVector(type, d.ToString());
} }
public DType Accept(TDateTime type, Sheet sheet, TitleRow row) public DType Accept(TDateTime type, Sheet sheet, TitleRow row)
{ {
var d = row.Current.Value; var d = row.Current;
if (CheckNull(type.IsNullable, d)) if (CheckNull(type.IsNullable, d))
{ {
return null; return null;

View File

@ -1,6 +1,7 @@
using ExcelDataReader; using ExcelDataReader;
using Luban.Job.Cfg.DataCreators; using Luban.Job.Cfg.DataCreators;
using Luban.Job.Cfg.Datas; using Luban.Job.Cfg.Datas;
using Luban.Job.Cfg.Utils;
using Luban.Job.Common.Types; using Luban.Job.Common.Types;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@ -26,6 +27,7 @@ namespace Luban.Job.Cfg.DataSources.Excel
{ {
var sheet = new Sheet(rawUrl, sheetName); var sheet = new Sheet(rawUrl, sheetName);
sheet.Load(rawSheet); sheet.Load(rawSheet);
_sheets.Add(sheet);
} }
if (_sheets.Count == 0) if (_sheets.Count == 0)
@ -36,7 +38,7 @@ namespace Luban.Job.Cfg.DataSources.Excel
public RawSheetTableDefInfo LoadTableDefInfo(string rawUrl, string sheetName, Stream stream) public RawSheetTableDefInfo LoadTableDefInfo(string rawUrl, string sheetName, Stream stream)
{ {
return null; return SheetLoadUtil.LoadSheetTableDefInfo(rawUrl, sheetName, stream);
} }
public override List<Record> ReadMulti(TBean type) public override List<Record> ReadMulti(TBean type)
@ -48,8 +50,14 @@ namespace Luban.Job.Cfg.DataSources.Excel
{ {
foreach (TitleRow row in sheet.GetRows()) foreach (TitleRow row in sheet.GetRows())
{ {
var tagRow = row.GetSubTitleNamedRow(TAG_KEY);
string tagStr = tagRow?.Current?.ToString();
if (DataUtil.IsIgnoreTag(tagStr))
{
continue;
}
var data = (DBean)type.Apply(SheetDataCreator.Ins, sheet, row); var data = (DBean)type.Apply(SheetDataCreator.Ins, sheet, row);
datas.Add(new Record(data, sheet.RawUrl, row.Tags)); datas.Add(new Record(data, sheet.RawUrl, DataUtil.ParseTags(tagStr)));
} }
} }
catch (DataCreateException dce) catch (DataCreateException dce)

View File

@ -18,9 +18,14 @@ namespace Luban.Job.Cfg.DataSources.Excel
private readonly int _toIndex; private readonly int _toIndex;
private int _curIndex; private int _curIndex;
public ExcelStream(List<Cell> datas, int fromIndex, int toIndex, string sep) private readonly string _overrideDefault;
public ExcelStream(List<Cell> datas, int fromIndex, int toIndex, string sep, string overrideDefault)
{ {
_overrideDefault = overrideDefault;
if (string.IsNullOrWhiteSpace(sep)) if (string.IsNullOrWhiteSpace(sep))
{
if (string.IsNullOrEmpty(overrideDefault))
{ {
this._datas = datas; this._datas = datas;
this._toIndex = toIndex; this._toIndex = toIndex;
@ -33,6 +38,29 @@ namespace Luban.Job.Cfg.DataSources.Excel
{ {
var cell = datas[i]; var cell = datas[i];
object d = cell.Value; object d = cell.Value;
if (!IsSkip(d))
{
this._datas.Add(cell);
}
else
{
this._datas.Add(new Cell(cell.Row, cell.Column, _overrideDefault));
}
}
this._curIndex = 0;
this._toIndex = this._datas.Count - 1;
}
}
else
{
this._datas = new List<Cell>();
for (int i = fromIndex; i <= toIndex; i++)
{
var cell = datas[i];
object d = cell.Value;
if (!IsSkip(d))
{
if (d is string s) if (d is string s)
{ {
this._datas.AddRange(DataUtil.SplitStringByAnySepChar(s, sep).Select(x => new Cell(cell.Row, cell.Column, x))); this._datas.AddRange(DataUtil.SplitStringByAnySepChar(s, sep).Select(x => new Cell(cell.Row, cell.Column, x)));
@ -42,6 +70,11 @@ namespace Luban.Job.Cfg.DataSources.Excel
this._datas.Add(cell); this._datas.Add(cell);
} }
} }
else if (!string.IsNullOrEmpty(_overrideDefault))
{
this._datas.Add(new Cell(cell.Row, cell.Column, _overrideDefault));
}
}
this._curIndex = 0; this._curIndex = 0;
this._toIndex = this._datas.Count - 1; this._toIndex = this._datas.Count - 1;
} }

View File

@ -30,12 +30,10 @@ namespace Luban.Job.Cfg.DataSources.Excel
public void Load(RawSheet rawSheet) public void Load(RawSheet rawSheet)
{ {
bool anyMultiRows = rawSheet.Title.SubTitleList.Any(t => t.SelfMultiRows);
var cells = rawSheet.Cells; var cells = rawSheet.Cells;
Title title = rawSheet.Title; Title title = rawSheet.Title;
if (!anyMultiRows) if (!title.HierarchyMultiRows)
{ {
foreach (var row in cells) foreach (var row in cells)
{ {
@ -86,14 +84,14 @@ namespace Luban.Job.Cfg.DataSources.Excel
} }
else else
{ {
if (title.SubTitleList.All(t => !t.SelfMultiRows && IsBlankRow(row, t.FromIndex, t.ToIndex))) if (title.SubTitleList.All(t => t.SelfMultiRows || IsBlankRow(row, t.FromIndex, t.ToIndex)))
{ {
oneRecordRows.Add(row); oneRecordRows.Add(row);
} }
else else
{ {
yield return oneRecordRows; yield return oneRecordRows;
oneRecordRows = null; oneRecordRows = new List<List<Cell>>() { row };
} }
} }
} }
@ -118,52 +116,54 @@ namespace Luban.Job.Cfg.DataSources.Excel
} }
else else
{ {
if (title.SelfMultiRows) var fields = new Dictionary<string, TitleRow>();
foreach (var subTitle in title.SubTitleList)
{
if (subTitle.SelfMultiRows)
{ {
var eles = new List<TitleRow>(); var eles = new List<TitleRow>();
foreach (var eleRow in SplitRows(title, rows)) if (subTitle.SubHierarchyMultiRows)
{ {
var fields = new Dictionary<string, TitleRow>(); foreach (var eleRows in SplitRows(subTitle, rows))
foreach (var subTitle in title.SubTitleList)
{ {
if (subTitle.SelfMultiRows) eles.Add(ParseMultiLineTitleRow(subTitle, eleRows));
{ }
fields.Add(subTitle.Name, ParseMultiLineTitleRow(title, eleRow));
} }
else else
{ {
fields.Add(subTitle.Name, ParseOneLineTitleRow(title, eleRow[0])); foreach (var eleRow in rows)
{
if (IsBlankRow(eleRow, subTitle.FromIndex, subTitle.ToIndex))
{
continue;
}
eles.Add(ParseOneLineTitleRow(subTitle, eleRow));
} }
} }
eles.Add(new TitleRow(title, fields)); fields.Add(subTitle.Name, new TitleRow(subTitle, eles));
}
return new TitleRow(title, eles);
} }
else else
{ {
var fields = new Dictionary<string, TitleRow>(); if (subTitle.SubHierarchyMultiRows)
foreach (var subTitle in title.SubTitleList)
{ {
if (subTitle.SelfMultiRows) fields.Add(subTitle.Name, ParseMultiLineTitleRow(subTitle, rows));
{
fields.Add(subTitle.Name, ParseMultiLineTitleRow(title, rows));
} }
else else
{ {
fields.Add(subTitle.Name, ParseOneLineTitleRow(title, rows[0])); fields.Add(subTitle.Name, ParseOneLineTitleRow(subTitle, rows[0]));
}
} }
} }
return new TitleRow(title, fields); return new TitleRow(title, fields);
} }
} }
}
public IEnumerable<TitleRow> GetRows() public IEnumerable<TitleRow> GetRows()
{ {
return Rows; return Rows;
} }
private static bool IsBlankRow(List<Cell> row, int fromIndex, int toIndex) public 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++) for (int i = Math.Max(1, fromIndex), n = Math.Min(toIndex, row.Count - 1); i <= n; i++)
{ {
@ -175,40 +175,5 @@ namespace Luban.Job.Cfg.DataSources.Excel
} }
return true; return true;
} }
private static bool IsSameRow(List<Cell> row1, List<Cell> row2, int fromIndex, int toIndex)
{
if (row2.Count < toIndex - 1)
{
return false;
}
for (int i = Math.Max(1, fromIndex), n = Math.Min(toIndex, row1.Count - 1); i <= n; i++)
{
var v1 = row1[i].Value;
var v2 = row2[i].Value;
if (v1 != v2)
{
if (v1 == null)
{
if (!(v2 is string s && string.IsNullOrWhiteSpace(s)))
{
return false;
}
}
else if (v2 == null)
{
if (!(v1 is string s && string.IsNullOrWhiteSpace(s)))
{
return false;
}
}
else
{
return v1.ToString() == v2.ToString();
}
}
}
return true;
}
} }
} }

View File

@ -108,7 +108,12 @@ namespace Luban.Job.Cfg.DataSources.Excel
public static Title ParseTitle(List<List<Cell>> cells, CellRange[] mergeCells, bool orientRow, out int titleRowNum) public static Title ParseTitle(List<List<Cell>> cells, CellRange[] mergeCells, bool orientRow, out int titleRowNum)
{ {
var rootTitle = new Title() { Root = true, Name = "__root__", FromIndex = 0, ToIndex = cells.Select(r => r.Count).Max() - 1 }; var rootTitle = new Title() {
Root = true, Name = "__root__",
Tags = new Dictionary<string, string>(),
FromIndex = 0,
ToIndex = cells.Select(r => r.Count).Max() - 1
};
titleRowNum = GetTitleRowNum(mergeCells, orientRow); titleRowNum = GetTitleRowNum(mergeCells, orientRow);
@ -150,13 +155,15 @@ namespace Luban.Job.Cfg.DataSources.Excel
{ {
var titleRow = cells[curDepth - 1]; var titleRow = cells[curDepth - 1];
if (mergeCells != null)
{
foreach (var mergeCell in mergeCells) foreach (var mergeCell in mergeCells)
{ {
Title subTitle = null; Title subTitle = null;
if (orientRow) if (orientRow)
{ {
//if (mergeCell.FromRow <= 1 && mergeCell.ToRow >= 1) //if (mergeCell.FromRow <= 1 && mergeCell.ToRow >= 1)
if (mergeCell.FromRow == curDepth) if (mergeCell.FromRow == curDepth && mergeCell.FromColumn >= title.FromIndex && mergeCell.FromColumn <= title.ToIndex)
{ {
var nameAndAttrs = titleRow[mergeCell.FromColumn].Value?.ToString()?.Trim(); var nameAndAttrs = titleRow[mergeCell.FromColumn].Value?.ToString()?.Trim();
if (IsIgnoreTitle(nameAndAttrs)) if (IsIgnoreTitle(nameAndAttrs))
@ -170,7 +177,7 @@ namespace Luban.Job.Cfg.DataSources.Excel
} }
else else
{ {
if (mergeCell.FromColumn == curDepth - 1) if (mergeCell.FromColumn == curDepth - 1 && mergeCell.FromRow - 1 >= title.FromIndex && mergeCell.FromRow - 1 <= title.ToIndex)
{ {
// 标题 行 // 标题 行
var nameAndAttrs = titleRow[mergeCell.FromRow - 1].Value?.ToString()?.Trim(); var nameAndAttrs = titleRow[mergeCell.FromRow - 1].Value?.ToString()?.Trim();
@ -194,8 +201,9 @@ namespace Luban.Job.Cfg.DataSources.Excel
title.AddSubTitle(subTitle); title.AddSubTitle(subTitle);
} }
}
for (int i = 0; i < titleRow.Count; i++) for (int i = title.FromIndex; i <= title.ToIndex; i++)
{ {
var nameAndAttrs = titleRow[i].Value?.ToString()?.Trim(); var nameAndAttrs = titleRow[i].Value?.ToString()?.Trim();
if (IsIgnoreTitle(nameAndAttrs)) if (IsIgnoreTitle(nameAndAttrs))

View File

@ -25,10 +25,14 @@ namespace Luban.Job.Cfg.DataSources.Excel
public string Sep { get; private set; } public string Sep { get; private set; }
public string Default { get; private set; }
public bool SelfMultiRows { get; private set; } public bool SelfMultiRows { get; private set; }
public bool HierarchyMultiRows { get; private set; } public bool HierarchyMultiRows { get; private set; }
public bool SubHierarchyMultiRows { get; private set; }
public void AddSubTitle(Title title) public void AddSubTitle(Title title)
{ {
if (!SubTitles.TryAdd(title.Name, title)) if (!SubTitles.TryAdd(title.Name, title))
@ -55,6 +59,7 @@ namespace Luban.Job.Cfg.DataSources.Excel
SortSubTitles(); SortSubTitles();
Sep = Tags.TryGetValue("sep", out var v) && !string.IsNullOrWhiteSpace(v) ? v : null; Sep = Tags.TryGetValue("sep", out var v) && !string.IsNullOrWhiteSpace(v) ? v : null;
SelfMultiRows = Tags.TryGetValue("multi_rows", out var v2) && (v2 == "1" || v2 == "true"); SelfMultiRows = Tags.TryGetValue("multi_rows", out var v2) && (v2 == "1" || v2 == "true");
Default = Tags.TryGetValue("default", out var v3) ? v3 : null;
if (SubTitleList.Count > 0) if (SubTitleList.Count > 0)
{ {
foreach (var sub in SubTitleList) foreach (var sub in SubTitleList)
@ -62,7 +67,8 @@ namespace Luban.Job.Cfg.DataSources.Excel
sub.Init(); sub.Init();
} }
} }
HierarchyMultiRows = SelfMultiRows || SubTitleList.Any(t => t.HierarchyMultiRows); SubHierarchyMultiRows = SubTitleList.Any(t => t.HierarchyMultiRows); ;
HierarchyMultiRows = SelfMultiRows || SubHierarchyMultiRows;
} }
public override string ToString() public override string ToString()

View File

@ -10,78 +10,61 @@ namespace Luban.Job.Cfg.DataSources.Excel
{ {
public List<string> Tags { get; } public List<string> Tags { get; }
//public static IEnumerable<TitleRow> 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 TitleRow(title, row);
// }
// }
// else
// {
// List<DefField> notMultiRowFields = bean.Bean.HierarchyFields.Select(f => (DefField)f).Where(f => !f.IsMultiRow && f.IsRowOrient).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);
// }) || (title.Root && recordRows != null && notMultiRowFields.All(f =>
// {
// var fieldTitle = title.SubTitles[f.Name];
// return Sheet.IsSameRow(row, recordRows[0], fieldTitle.FromIndex, fieldTitle.ToIndex);
// })))
// {
// if (recordRows == null)
// {
// recordRows = new List<List<Cell>>();
// }
// recordRows.Add(row);
// }
// else
// {
// if (recordRows != null)
// {
// yield return new TitleRow(title, recordRows);
// }
// recordRows = new List<List<Cell>>();
// recordRows.Add(row);
// }
// }
// if (recordRows != null)
// {
// yield return new TitleRow(title, recordRows);
// }
// }
//}
public Title SelfTitle { get; } public Title SelfTitle { get; }
public Cell Current => Row[0]; public object Current
{
get
{
var v = Row[SelfTitle.FromIndex].Value;
if (v == null || (v is string s && string.IsNullOrEmpty(s) && !string.IsNullOrEmpty(SelfTitle.Default)))
{
return SelfTitle.Default;
}
else
{
return v;
}
}
}
public List<Cell> Row { get; } public List<Cell> Row { get; }
public int CellCount => SelfTitle.ToIndex - SelfTitle.FromIndex + 1;
public List<List<Cell>> Rows { get; } public List<List<Cell>> Rows { get; }
public Dictionary<string, TitleRow> Fields { get; } public Dictionary<string, TitleRow> Fields { get; }
public List<TitleRow> Elements { get; } public List<TitleRow> Elements { get; }
public ExcelStream AsStream(string sep) => new ExcelStream(Row, 0, Row.Count - 1, sep); public ExcelStream AsStream(string sep)
{
if (string.IsNullOrEmpty(SelfTitle.Sep))
{
if (string.IsNullOrEmpty(sep))
{
return new ExcelStream(Row, SelfTitle.FromIndex, SelfTitle.ToIndex, "", SelfTitle.Default);
}
else
{
return new ExcelStream(Row, SelfTitle.FromIndex, SelfTitle.ToIndex, sep, SelfTitle.Default);
}
}
else
{
//if (string.IsNullOrEmpty(sep) || sep == SelfTitle.Sep)
//{
// return new ExcelStream(Row, SelfTitle.FromIndex, SelfTitle.ToIndex, sep);
//}
//else
//{
// SelfTitle.Sep 设置覆盖 bean的 sep设置只有这个可能
return new ExcelStream(Row, SelfTitle.FromIndex, SelfTitle.ToIndex, SelfTitle.Sep, SelfTitle.Default);
//}
}
}
public bool HasSubFields => Fields != null || Elements != null; public bool HasSubFields => Fields != null || Elements != null;
@ -111,49 +94,11 @@ namespace Luban.Job.Cfg.DataSources.Excel
public int RowCount => Rows.Count; public int RowCount => Rows.Count;
//private void CheckEmptySinceSecondRow(string name, int fromIndex, int toIndex)
//{
// for (int i = 1; i < Rows.Count; i++)
// {
// var row = Rows[i];
// if (!IsBlankRow(row, fromIndex, toIndex))
// {
// throw new Exception($"字段:{name} 不是多行字段,只能第一行填值. {Bright.Common.StringUtil.CollectionToString(row)}");
// }
// }
//}
public Title GetTitle(string name) public Title GetTitle(string name)
{ {
return SelfTitle.SubTitles.TryGetValue(name, out var title) ? title : null; return SelfTitle.SubTitles.TryGetValue(name, out var title) ? title : null;
} }
//public ExcelStream GetColumn(string name)
//{
// var field = GetSubTitleNamedRow(name);
// if (field != null)
// {
// return field.AsStream;
// }
// else
// {
// throw new Exception($"单元薄 缺失 列:{name},请检查是否写错或者遗漏");
// }
// //if (Titles.TryGetValue(name, out var title))
// //{
// // // 只有顶级root支持才允许非multi_rows字段与第一行相同时判定为同个记录
// // if (!this.SelfTitle.Root)
// // {
// // CheckEmptySinceSecondRow(name, title.FromIndex, title.ToIndex);
// // }
// // var es = new ExcelStream(Rows[0], title.FromIndex, title.ToIndex, sep, namedMode);
// // return es;
// //}
// //else
// //{
// // throw new Exception($"单元薄 缺失 列:{name},请检查是否写错或者遗漏");
// //}
//}
public TitleRow GetSubTitleNamedRow(string name) public TitleRow GetSubTitleNamedRow(string name)
{ {
@ -162,53 +107,12 @@ namespace Luban.Job.Cfg.DataSources.Excel
return Fields.TryGetValue(name, out var r) ? r : null; return Fields.TryGetValue(name, out var r) ? r : null;
} }
//public IEnumerable<TitleRow> GenerateSubNameRows(TBean bean)
//{
// foreach (var row in Rows)
// {
// if (SelfTitle != null ? IsBlankRow(row, SelfTitle.FromIndex, SelfTitle.ToIndex) : IsBlankRow(row))
// {
// continue;
// }
// yield return new TitleRow(SelfTitle, row);
// }
//}
public IEnumerable<ExcelStream> GetColumnOfMultiRows(string name, string sep) public IEnumerable<ExcelStream> GetColumnOfMultiRows(string name, string sep)
{ {
foreach (var ele in GetSubTitleNamedRow(name).Elements) foreach (var ele in GetSubTitleNamedRow(name).Elements)
{ {
yield return ele.AsStream(sep); yield return ele.AsStream(sep);
} }
//if (Titles.TryGetValue(name, out var title))
//{
// if (isRowOrient)
// {
// foreach (var row in Rows)
// {
// if (IsBlankRow(row, title.FromIndex, title.ToIndex))
// {
// continue;
// }
// yield return new ExcelStream(row, title.FromIndex, title.ToIndex, sep, false);
// }
// }
// else
// {
// for (int i = title.FromIndex; i <= title.ToIndex; i++)
// {
// if (!IsBlankColumn(Rows, i))
// {
// var cells = Rows.Where(r => r.Count > i).Select(r => r[i]).Where(v => !(v.Value == null || (v.Value is string s && string.IsNullOrEmpty(s)))).ToList();
// yield return new ExcelStream(cells, 0, cells.Count - 1, sep, false);
// }
// }
// }
//}
//else
//{
// throw new Exception($"单元薄 缺失 列:{name},请检查是否写错或者遗漏");
//}
} }

View File

@ -8,7 +8,7 @@ namespace Luban.Job.Cfg.Datas
public static DFshort ValueOf(short x) public static DFshort ValueOf(short x)
{ {
return x == 0 ? Default : new DFshort(0); return x == 0 ? Default : new DFshort(x);
} }
public override string TypeName => "fshort"; public override string TypeName => "fshort";

View File

@ -566,15 +566,10 @@ namespace Luban.Job.Cfg.Defs
{ {
new CfgField() { Name = "name", Type = "string" }, new CfgField() { Name = "name", Type = "string" },
new CfgField() { Name = "type", Type = "string" }, new CfgField() { Name = "type", Type = "string" },
new CfgField() { Name = "sep", Type = "string" },
new CfgField() { Name = "is_multi_rows", Type = "bool" },
new CfgField() { Name = "index", Type = "string" }, new CfgField() { Name = "index", Type = "string" },
new CfgField() { Name = "group", Type = "string" }, new CfgField() { Name = "group", Type = "string" },
new CfgField() { Name = "ref", Type = "string", IgnoreNameValidation = true },
new CfgField() { Name = "path", Type = "string" },
new CfgField() { Name = "comment", Type = "string" }, new CfgField() { Name = "comment", Type = "string" },
new CfgField() { Name = "tags", Type = "string" }, new CfgField() { Name = "tags", Type = "string" },
new CfgField() { Name = "orientation", Type = "string" },
} }
}) })
{ {
@ -613,7 +608,6 @@ namespace Luban.Job.Cfg.Defs
defTableRecordType.PreCompile(); defTableRecordType.PreCompile();
defTableRecordType.Compile(); defTableRecordType.Compile();
defTableRecordType.PostCompile(); defTableRecordType.PostCompile();
ass.MarkMultiRows();
var tableRecordType = TBean.Create(false, defTableRecordType); var tableRecordType = TBean.Create(false, defTableRecordType);
foreach (var file in inputFileInfos) foreach (var file in inputFileInfos)
@ -672,21 +666,11 @@ namespace Luban.Job.Cfg.Defs
private static readonly List<string> _fieldOptionalAttrs = new() private static readonly List<string> _fieldOptionalAttrs = new()
{ {
"index", "index",
"sep",
"validator",
"key_validator",
"value_validator",
"ref", "ref",
"path", "path",
"range",
"multi_rows",
"group", "group",
"res",
"convert",
"comment", "comment",
"tags", "tags",
"default",
"orientation",
}; };
private static readonly List<string> _fieldRequireAttrs = new List<string> { "name", "type" }; private static readonly List<string> _fieldRequireAttrs = new List<string> { "name", "type" };
@ -695,8 +679,20 @@ namespace Luban.Job.Cfg.Defs
{ {
ValidAttrKeys(defineFile, e, _fieldOptionalAttrs, _fieldRequireAttrs); ValidAttrKeys(defineFile, e, _fieldOptionalAttrs, _fieldRequireAttrs);
string refStr = XmlUtil.GetOptionalAttribute(e, "ref");
string typeStr = XmlUtil.GetRequiredAttribute(e, "type");
if (!string.IsNullOrWhiteSpace(refStr))
{
typeStr = typeStr + "&ref=" + refStr;
}
string pathStr = XmlUtil.GetOptionalAttribute(e, "path");
if (!string.IsNullOrWhiteSpace(pathStr))
{
typeStr = typeStr + "&path=" + pathStr;
}
return CreateField(defineFile, XmlUtil.GetRequiredAttribute(e, "name"), return CreateField(defineFile, XmlUtil.GetRequiredAttribute(e, "name"),
XmlUtil.GetRequiredAttribute(e, "type"), typeStr,
XmlUtil.GetOptionalAttribute(e, "index"), XmlUtil.GetOptionalAttribute(e, "index"),
XmlUtil.GetOptionalAttribute(e, "group"), XmlUtil.GetOptionalAttribute(e, "group"),
XmlUtil.GetOptionalAttribute(e, "comment"), XmlUtil.GetOptionalAttribute(e, "comment"),

View File

@ -263,43 +263,6 @@ namespace Luban.Job.Cfg.Defs
throw; throw;
} }
} }
// 丑陋. 怎么写更好?
// 递归 设置DefBean及DefField 的 IsMultiRow
MarkMultiRows();
}
public void MarkMultiRows()
{
var multiRowBeans = new HashSet<DefBean>();
for (bool anyMark = true; anyMark;)
{
anyMark = false;
foreach (var type in this.Types.Values)
{
if (type is DefBean beanType && !beanType.IsMultiRow)
{
bool isMultiRows;
if (beanType.IsNotAbstractType)
{
isMultiRows = beanType.HierarchyFields.Any(f => ((DefField)f).ComputeIsMultiRow());
}
else
{
isMultiRows = beanType.HierarchyNotAbstractChildren.Any(c => ((DefBean)c).IsMultiRow);
}
if (isMultiRows)
{
beanType.IsMultiRow = true;
//s_logger.Info("bean:{bean} is multi row", beanType.FullName);
anyMark = true;
}
}
}
}
} }
} }
} }

View File

@ -16,29 +16,6 @@ namespace Luban.Job.Cfg.Defs
{ {
public DefAssembly Assembly => (DefAssembly)HostType.AssemblyBase; public DefAssembly Assembly => (DefAssembly)HostType.AssemblyBase;
public bool RawIsMultiRow { get; }
public bool IsMultiRow { get; private set; }
public bool ComputeIsMultiRow()
{
if (IsMultiRow)
{
return true;
}
switch (CType)
{
case TBean b: { return IsMultiRow = ((DefBean)b.Bean).IsMultiRow; }
case TList b: { return IsMultiRow = b.ElementType is TBean b2 && ((DefBean)b2.Bean).IsMultiRow; }
case TArray b: { return IsMultiRow = b.ElementType is TBean b2 && ((DefBean)b2.Bean).IsMultiRow; }
case TMap b: { return IsMultiRow = b.ValueType is TBean b2 && ((DefBean)b2.Bean).IsMultiRow; }
default: return false;
}
}
public string Index { get; } public string Index { get; }
public List<string> Groups { get; } public List<string> Groups { get; }
@ -212,11 +189,6 @@ namespace Luban.Job.Cfg.Defs
} }
} }
if (IsMultiRow && !CType.IsCollection && !CType.IsBean)
{
throw new Exception($"只有容器类型才支持 multi_line 属性");
}
if (!string.IsNullOrEmpty(Index)) if (!string.IsNullOrEmpty(Index))
{ {
if ((CType is TArray tarray) && (tarray.ElementType is TBean b)) if ((CType is TArray tarray) && (tarray.ElementType is TBean b))

View File

@ -107,7 +107,6 @@ namespace Luban.Job.Cfg.TypeVisitors
//#if !LUBAN_LITE //#if !LUBAN_LITE
// || f1.ResourceTag != f2.ResourceTag // || f1.ResourceTag != f2.ResourceTag
//#endif //#endif
|| f1.IsMultiRow != f2.IsMultiRow
|| f1.CType.IsNullable != f2.CType.IsNullable || f1.CType.IsNullable != f2.CType.IsNullable
|| f1.CType.GetType() != f2.CType.GetType() || f1.CType.GetType() != f2.CType.GetType()
//|| !IsValidatorEquals(f1.RawDefine.Validators, f2.RawDefine.Validators) //|| !IsValidatorEquals(f1.RawDefine.Validators, f2.RawDefine.Validators)

View File

@ -1,4 +1,6 @@
using Luban.Job.Cfg.Datas; using Luban.Job.Cfg.Datas;
using Luban.Job.Cfg.Defs;
using Luban.Job.Cfg.TypeVisitors;
using Luban.Job.Common.Types; using Luban.Job.Common.Types;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@ -137,6 +139,24 @@ namespace Luban.Job.Cfg.Utils
return tags.Count > 0 ? tags : null; return tags.Count > 0 ? tags : null;
} }
const string SimpleContainerSep = ",;";
public static string GetSep(TType type)
{
if (type.Tags != null && type.Tags.TryGetValue("sep", out var s) && !string.IsNullOrWhiteSpace(s))
{
return s;
}
switch (type)
{
case TBean tb: return (tb.Bean as DefBean).Sep;
case TArray ta: return ta.ElementType.Apply(IsNotSepTypeVisitor.Ins) ? SimpleContainerSep : "";
case TList ta: return ta.ElementType.Apply(IsNotSepTypeVisitor.Ins) ? SimpleContainerSep : "";
case TSet ta: return ta.ElementType.Apply(IsNotSepTypeVisitor.Ins) ? SimpleContainerSep : "";
default: return "";
}
}
//public static string Data2String(DType data) //public static string Data2String(DType data)
//{ //{
// var s = new StringBuilder(); // var s = new StringBuilder();