From 4613169811112ab748015b7e48d3730fca785ec5 Mon Sep 17 00:00:00 2001 From: walon Date: Thu, 14 Oct 2021 19:52:30 +0800 Subject: [PATCH] =?UTF-8?q?=E3=80=90=E9=87=8D=E6=9E=84=E3=80=91=E9=87=8D?= =?UTF-8?q?=E6=9E=84excel=E8=A7=A3=E6=9E=90=E4=BB=A3=E7=A0=81=E5=8F=8A?= =?UTF-8?q?=E5=B0=86field=E4=B8=8A=E7=9A=84=E5=B1=9E=E6=80=A7=E7=A7=BB?= =?UTF-8?q?=E5=88=B0type?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Source/DataCreators/ExcelDataCreator.cs | 613 ----------------- .../DataCreators/ExcelNamedRowDataCreator.cs | 630 +++++++++--------- .../DataCreators/ExcelStreamDataCreator.cs | 467 +++++++++++++ .../Source/DataCreators/JsonDataCreator.cs | 12 +- .../Source/DataCreators/LuaDataCreator.cs | 12 +- .../DataCreators/MultiRowExcelDataCreator.cs | 276 ++++---- .../Source/DataCreators/SheetDataCreator.cs | 570 ++++++++++++++++ .../Source/DataCreators/StringDataCreator.cs | 12 +- .../Source/DataCreators/XmlDataCreator.cs | 12 +- .../Source/DataCreators/YamlDataCreator.cs | 12 +- .../DataSources/Excel/ExcelDataSource.cs | 106 +-- .../Source/DataSources/Excel/ExcelStream.cs | 12 +- .../Source/DataSources/Excel/RawSheet.cs | 17 + .../DataSources/Excel/RawSheetTableDefInfo.cs | 22 + .../Source/DataSources/Excel/Sheet.cs | 608 +---------------- .../Source/DataSources/Excel/SheetLoadUtil.cs | 466 +++++++++++++ .../Source/DataSources/Excel/TitleRow.cs | 237 +++++++ .../Source/DataVisitors/ResourceExportor.cs | 58 +- .../Source/DataVisitors/ValidatorVisitor.cs | 302 ++++----- src/Luban.Job.Cfg/Source/Datas/DByte.cs | 14 +- src/Luban.Job.Cfg/Source/Datas/DDouble.cs | 7 +- src/Luban.Job.Cfg/Source/Datas/DFint.cs | 7 +- src/Luban.Job.Cfg/Source/Datas/DFloat.cs | 2 +- src/Luban.Job.Cfg/Source/Datas/DFlong.cs | 7 +- src/Luban.Job.Cfg/Source/Datas/DFshort.cs | 7 +- src/Luban.Job.Cfg/Source/Datas/DInt.cs | 2 + src/Luban.Job.Cfg/Source/Datas/DShort.cs | 7 +- src/Luban.Job.Cfg/Source/Defs/CfgDefLoader.cs | 152 +---- src/Luban.Job.Cfg/Source/Defs/DefField.cs | 198 +++--- src/Luban.Job.Cfg/Source/RawDefs/CfgField.cs | 28 +- .../TypeVisitors/DeepCompareTypeDefine.cs | 48 +- src/Luban.Job.Cfg/Source/Utils/DataUtil.cs | 6 +- .../Source/Validators/ValidatorFactory.cs | 50 +- 33 files changed, 2685 insertions(+), 2294 deletions(-) delete mode 100644 src/Luban.Job.Cfg/Source/DataCreators/ExcelDataCreator.cs create mode 100644 src/Luban.Job.Cfg/Source/DataCreators/ExcelStreamDataCreator.cs create mode 100644 src/Luban.Job.Cfg/Source/DataCreators/SheetDataCreator.cs create mode 100644 src/Luban.Job.Cfg/Source/DataSources/Excel/RawSheet.cs create mode 100644 src/Luban.Job.Cfg/Source/DataSources/Excel/RawSheetTableDefInfo.cs create mode 100644 src/Luban.Job.Cfg/Source/DataSources/Excel/SheetLoadUtil.cs create mode 100644 src/Luban.Job.Cfg/Source/DataSources/Excel/TitleRow.cs diff --git a/src/Luban.Job.Cfg/Source/DataCreators/ExcelDataCreator.cs b/src/Luban.Job.Cfg/Source/DataCreators/ExcelDataCreator.cs deleted file mode 100644 index 02bb9be..0000000 --- a/src/Luban.Job.Cfg/Source/DataCreators/ExcelDataCreator.cs +++ /dev/null @@ -1,613 +0,0 @@ -using Bright.Collections; -using Luban.Common.Utils; -using Luban.Job.Cfg.Datas; -using Luban.Job.Cfg.DataSources.Excel; -using Luban.Job.Cfg.Defs; -using Luban.Job.Cfg.Utils; -using Luban.Job.Common.Types; -using Luban.Job.Common.TypeVisitors; -using System; -using System.Collections.Generic; -using System.Runtime.Serialization; - -namespace Luban.Job.Cfg.DataCreators -{ - enum EReadPolicy - { - SKIP_NULL_CELL = 0x1, - SKIP_BLANK_CELL = 0x2, - NULL_AS_NULL = 0x4, - NULL_STR_AS_NULL = 0x8, - } - - class InvalidExcelDataException : Exception - { - public InvalidExcelDataException() - { - } - - public InvalidExcelDataException(string message) : base(message) - { - } - - public InvalidExcelDataException(string message, Exception innerException) : base(message, innerException) - { - } - - protected InvalidExcelDataException(SerializationInfo info, StreamingContext context) : base(info, context) - { - } - } - - class ExcelDataCreator : ITypeFuncVisitor - { - public static ExcelDataCreator Ins { get; } = new ExcelDataCreator(); - - private bool CheckNull(bool nullable, object o) - { - return nullable && (o == null || (o is string s && s == "null")); - } - - private bool CheckIsDefault(bool namedMode, object value) - { - if (namedMode) - { - if (value == null || (value is string s && string.IsNullOrEmpty(s))) - { - return true; - } - } - return false; - } - - private static bool CreateBool(object x) - { - if (x is bool b) - { - return b; - } - var s = x.ToString().ToLower().Trim(); - switch (s) - { - case "true": - case "是": return true; - case "false": - case "否": return false; - default: throw new InvalidExcelDataException($"{s} 不是 bool 类型的值 (true 或 false)"); - } - } - - public DType Accept(TBool type, DefField field, ExcelStream x, DefAssembly ass) - { - if (x.NamedMode && x.IncludeNullAndEmptySize != 1) - { - throw new InvalidExcelDataException("在标题头对应模式下必须正好占据1个单元格"); - } - - var d = x.Read(x.NamedMode); - if (CheckNull(type.IsNullable, d)) - { - return null; - } - if (CheckIsDefault(x.NamedMode, d)) - { - return field?.DefalutDtypeValue ?? DBool.ValueOf(false); - } - return DBool.ValueOf(CreateBool(d)); - } - - public DType Accept(TByte type, DefField field, ExcelStream x, DefAssembly ass) - { - if (x.NamedMode && x.IncludeNullAndEmptySize != 1) - { - throw new InvalidExcelDataException("在标题头对应模式下必须正好占据1个单元格"); - } - var d = x.Read(x.NamedMode); - if (CheckNull(type.IsNullable, d)) - { - return null; - } - if (CheckIsDefault(x.NamedMode, d)) - { - return field?.DefalutDtypeValue ?? DByte.Default; - } - if (!byte.TryParse(d.ToString(), out byte v)) - { - throw new InvalidExcelDataException($"{d} 不是 byte 类型值"); - } - return new DByte(v); - } - - public DType Accept(TShort type, DefField field, ExcelStream x, DefAssembly ass) - { - if (x.NamedMode && x.IncludeNullAndEmptySize != 1) - { - throw new InvalidExcelDataException("在标题头对应模式下必须正好占据1个单元格"); - } - var d = x.Read(x.NamedMode); - if (CheckNull(type.IsNullable, d)) - { - return null; - } - if (CheckIsDefault(x.NamedMode, d)) - { - return field?.DefalutDtypeValue ?? DShort.Default; - } - if (!short.TryParse(d.ToString(), out short v)) - { - throw new InvalidExcelDataException($"{d} 不是 short 类型值"); - } - return new DShort(v); - } - - public DType Accept(TFshort type, DefField field, ExcelStream x, DefAssembly ass) - { - if (x.NamedMode && x.IncludeNullAndEmptySize != 1) - { - throw new InvalidExcelDataException("在标题头对应模式下必须正好占据1个单元格"); - } - var d = x.Read(x.NamedMode); - if (CheckNull(type.IsNullable, d)) - { - return null; - } - if (CheckIsDefault(x.NamedMode, d)) - { - return field?.DefalutDtypeValue ?? DFshort.Default; - } - if (!short.TryParse(d.ToString(), out short v)) - { - throw new InvalidExcelDataException($"{d} 不是 short 类型值"); - } - return new DFshort(v); - } - - public DType Accept(TInt type, DefField field, ExcelStream x, DefAssembly ass) - { - if (x.NamedMode && x.IncludeNullAndEmptySize != 1) - { - throw new InvalidExcelDataException("在标题头对应模式下必须正好占据1个单元格"); - } - var d = x.Read(x.NamedMode); - if (CheckNull(type.IsNullable, d)) - { - return null; - } - if (CheckIsDefault(x.NamedMode, d)) - { - return field?.DefalutDtypeValue ?? DInt.ValueOf(0); - } - var ds = d.ToString(); - if (field?.Remapper is TEnum te) - { - if (te.DefineEnum.TryValueByNameOrAlias(ds, out var c)) - { - return DInt.ValueOf(c); - } - } - if (!int.TryParse(ds, out var v)) - { - throw new InvalidExcelDataException($"{d} 不是 int 类型值"); - } - return DInt.ValueOf(v); - } - - public DType Accept(TFint type, DefField field, ExcelStream x, DefAssembly ass) - { - if (x.NamedMode && x.IncludeNullAndEmptySize != 1) - { - throw new InvalidExcelDataException("在标题头对应模式下必须正好占据1个单元格"); - } - var d = x.Read(x.NamedMode); - if (CheckNull(type.IsNullable, d)) - { - return null; - } - if (CheckIsDefault(x.NamedMode, d)) - { - return field?.DefalutDtypeValue ?? DFint.Default; - } - var ds = d.ToString(); - if (field?.Remapper is TEnum te) - { - if (te.DefineEnum.TryValueByNameOrAlias(ds, out var c)) - { - return new DFint(c); - } - } - if (!int.TryParse(ds, out var v)) - { - throw new InvalidExcelDataException($"{d} 不是 int 类型值"); - } - return new DFint(v); - } - - public DType Accept(TLong type, DefField field, ExcelStream x, DefAssembly ass) - { - if (x.NamedMode && x.IncludeNullAndEmptySize != 1) - { - throw new InvalidExcelDataException("在标题头对应模式下必须正好占据1个单元格"); - } - var d = x.Read(x.NamedMode); - if (CheckNull(type.IsNullable, d)) - { - return null; - } - if (CheckIsDefault(x.NamedMode, d)) - { - return field?.DefalutDtypeValue ?? DLong.Default; - } - var ds = d.ToString(); - if (field?.Remapper is TEnum te) - { - if (te.DefineEnum.TryValueByNameOrAlias(ds, out var c)) - { - return DLong.ValueOf(c); - } - } - if (!long.TryParse(ds, out var v)) - { - throw new InvalidExcelDataException($"{d} 不是 long 类型值"); - } - return DLong.ValueOf(v); - } - - public DType Accept(TFlong type, DefField field, ExcelStream x, DefAssembly ass) - { - if (x.NamedMode && x.IncludeNullAndEmptySize != 1) - { - throw new InvalidExcelDataException("在标题头对应模式下必须正好占据1个单元格"); - } - var d = x.Read(x.NamedMode); - if (CheckNull(type.IsNullable, d)) - { - return null; - } - if (CheckIsDefault(x.NamedMode, d)) - { - return field?.DefalutDtypeValue ?? DFlong.Default; - } - var ds = d.ToString(); - if (field?.Remapper is TEnum te) - { - if (te.DefineEnum.TryValueByNameOrAlias(ds, out var c)) - { - return new DFlong(c); - } - } - if (!long.TryParse(ds, out var v)) - { - throw new InvalidExcelDataException($"{d} 不是 long 类型值"); - } - return new DFlong(v); - } - - public DType Accept(TFloat type, DefField field, ExcelStream x, DefAssembly ass) - { - if (x.NamedMode && x.IncludeNullAndEmptySize != 1) - { - throw new InvalidExcelDataException("在标题头对应模式下必须正好占据1个单元格"); - } - var d = x.Read(x.NamedMode); - if (CheckNull(type.IsNullable, d)) - { - return null; - } - if (CheckIsDefault(x.NamedMode, d)) - { - return field?.DefalutDtypeValue ?? DFloat.ValueOf(0); - } - if (!float.TryParse(d.ToString(), out var v)) - { - throw new InvalidExcelDataException($"{d} 不是 float 类型值"); - } - return DFloat.ValueOf(v); - } - - public DType Accept(TDouble type, DefField field, ExcelStream x, DefAssembly ass) - { - if (x.NamedMode && x.IncludeNullAndEmptySize != 1) - { - throw new InvalidExcelDataException("在标题头对应模式下必须正好占据1个单元格"); - } - var d = x.Read(x.NamedMode); - if (CheckNull(type.IsNullable, d)) - { - return null; - } - if (CheckIsDefault(x.NamedMode, d)) - { - return field?.DefalutDtypeValue ?? DDouble.Default; - } - if (!double.TryParse(d.ToString(), out var v)) - { - throw new InvalidExcelDataException($"{d} 不是 double 类型值"); - } - return new DDouble(v); - } - - public DType Accept(TEnum type, DefField field, ExcelStream x, DefAssembly ass) - { - var d = x.Read(x.NamedMode); - if (CheckNull(type.IsNullable, d)) - { - return null; - } - if (CheckIsDefault(x.NamedMode, d) && field?.DefalutDtypeValue != null) - { - return field?.DefalutDtypeValue; - } - return new DEnum(type, d.ToString().Trim()); - } - - public DType Accept(TString type, DefField field, ExcelStream x, DefAssembly ass) - { - if (x.NamedMode && x.IncludeNullAndEmptySize != 1) - { - throw new InvalidExcelDataException("excel string类型在标题头对应模式下必须正好占据一个单元格"); - } - var d = x.Read(x.NamedMode); - if (CheckIsDefault(x.NamedMode, d) && field?.DefalutDtypeValue != null) - { - return field.DefalutDtypeValue; - } - var s = ParseString(d); - if (s == null) - { - if (type.IsNullable) - { - return null; - } - else - { - throw new InvalidExcelDataException("字段不是nullable类型,不能为null"); - } - } - return DString.ValueOf(s); - } - - public DType Accept(TBytes type, DefField field, ExcelStream x, DefAssembly ass) - { - throw new NotImplementedException(); - } - - private static string ParseString(object d) - { - if (d == null) - { - return string.Empty; - } - else if (d is string s) - { - return DataUtil.UnEscapeString(s); - } - else - { - return d.ToString(); - } - } - - public DType Accept(TText type, DefField field, ExcelStream x, DefAssembly ass) - { - if (x.NamedMode && x.IncludeNullAndEmptySize != 2) - { - throw new InvalidExcelDataException("excel text 类型在标题头对应模式下必须正好占据2个单元格"); - } - string key = ParseString(x.Read(x.NamedMode)); - if (key == null) - { - if (type.IsNullable) - { - return null; - } - else - { - throw new InvalidExcelDataException("该字段不是nullable类型,不能为null"); - } - } - - string text = ParseString(x.Read(x.NamedMode)); - DataUtil.ValidateText(key, text); - return new DText(key, text); - } - - private List CreateBeanFields(DefBean bean, ExcelStream stream, DefAssembly ass) - { - var list = new List(); - foreach (DefField f in bean.HierarchyFields) - { - try - { - string sep = f.ActualSep; - if (string.IsNullOrWhiteSpace(sep)) - { - list.Add(f.CType.Apply(this, f, stream, ass)); - } - else - { - list.Add(f.CType.Apply(this, f, new ExcelStream(stream.ReadCell(), sep, false), ass)); - } - } - catch (DataCreateException dce) - { - dce.Push(bean, f); - throw; - } - catch (Exception e) - { - var dce = new DataCreateException(e, stream.LastReadDataInfo); - dce.Push(bean, f); - throw dce; - } - } - return list; - } - - public DType Accept(TBean type, DefField field, ExcelStream x, DefAssembly ass) - { - var originBean = (DefBean)type.Bean; - - if (originBean.IsAbstractType) - { - string subType = x.Read().ToString(); - if (subType.ToLower().Trim() == DefBean.BEAN_NULL_STR) - { - if (!type.IsNullable) - { - throw new InvalidExcelDataException($"type:{type.Bean.FullName}不是可空类型. 不能为空"); - } - return null; - } - string fullType = TypeUtil.MakeFullName(originBean.Namespace, subType); - DefBean implType = (DefBean)originBean.GetNotAbstractChildType(subType); - if (implType == null) - { - throw new InvalidExcelDataException($"type:{fullType} 不是bean类型"); - } - return new DBean(originBean, implType, CreateBeanFields(implType, x, ass)); - } - else - { - if (type.IsNullable) - { - string subType = x.Read().ToString().Trim(); - if (subType == DefBean.BEAN_NULL_STR) - { - return null; - } - else if (subType != DefBean.BEAN_NOT_NULL_STR && subType != originBean.Name) - { - throw new Exception($"type:'{type.Bean.FullName}' 可空标识:'{subType}' 不合法(只能为{DefBean.BEAN_NOT_NULL_STR}或{DefBean.BEAN_NULL_STR}或{originBean.Name})"); - } - } - return new DBean(originBean, originBean, CreateBeanFields(originBean, x, ass)); - } - } - - // 容器类统统不支持 type.IsNullable - // 因为貌似没意义? - public List ReadList(TType type, DefField field, ExcelStream stream, DefAssembly ass) - { - stream.NamedMode = false; - string sep = type is TBean bean ? ((DefBean)bean.Bean).Sep : null; - var datas = new List(); - while (!stream.TryReadEOF()) - { - if (string.IsNullOrWhiteSpace(sep)) - { - datas.Add(type.Apply(this, field, stream, ass)); - } - else - { - datas.Add(type.Apply(this, field, new ExcelStream(stream.ReadCell(), sep, false), ass)); ; - } - } - return datas; - } - - public DType Accept(TArray type, DefField field, ExcelStream x, DefAssembly ass) - { - return new DArray(type, ReadList(type.ElementType, field, x, ass)); - } - - public DType Accept(TList type, DefField field, ExcelStream x, DefAssembly ass) - { - return new DList(type, ReadList(type.ElementType, field, x, ass)); - } - - public DType Accept(TSet type, DefField field, ExcelStream x, DefAssembly ass) - { - return new DSet(type, ReadList(type.ElementType, field, x, ass)); - } - - public DType Accept(TMap type, DefField field, ExcelStream x, DefAssembly ass) - { - x.NamedMode = false; - string sep = type.ValueType is TBean bean ? ((DefBean)bean.Bean).Sep : null; - - var datas = new Dictionary(); - while (!x.TryReadEOF()) - { - var key = type.KeyType.Apply(this, null, x, ass); - var value = string.IsNullOrWhiteSpace(sep) ? type.ValueType.Apply(this, null, x, ass) : type.ValueType.Apply(this, null, new ExcelStream(x.ReadCell(), sep, false), ass); - if (!datas.TryAdd(key, value)) - { - throw new InvalidExcelDataException($"map 的 key:{key} 重复"); - } - } - return new DMap(type, datas); - } - - public DType Accept(TVector2 type, DefField field, ExcelStream x, DefAssembly ass) - { - if (x.NamedMode && x.IncludeNullAndEmptySize != 1) - { - throw new InvalidExcelDataException("在标题头对应模式下必须正好占据1个单元格"); - } - var d = x.Read(x.NamedMode); - if (CheckNull(type.IsNullable, d)) - { - return null; - } - if (CheckIsDefault(x.NamedMode, d)) - { - return field?.DefalutDtypeValue ?? DVector2.Default; - } - return DataUtil.CreateVector(type, d.ToString()); - } - - public DType Accept(TVector3 type, DefField field, ExcelStream x, DefAssembly ass) - { - if (x.NamedMode && x.IncludeNullAndEmptySize != 1) - { - throw new InvalidExcelDataException("在标题头对应模式下必须正好占据1个单元格"); - } - var d = x.Read(x.NamedMode); - if (CheckNull(type.IsNullable, d)) - { - return null; - } - if (CheckIsDefault(x.NamedMode, d)) - { - return field?.DefalutDtypeValue ?? DVector3.Default; - } - return DataUtil.CreateVector(type, d.ToString()); - } - - public DType Accept(TVector4 type, DefField field, ExcelStream x, DefAssembly ass) - { - if (x.NamedMode && x.IncludeNullAndEmptySize != 1) - { - throw new InvalidExcelDataException("在标题头对应模式下必须正好占据1个单元格"); - } - var d = x.Read(x.NamedMode); - if (CheckNull(type.IsNullable, d)) - { - return null; - } - if (CheckIsDefault(x.NamedMode, d)) - { - return field?.DefalutDtypeValue ?? DVector4.Default; - } - return DataUtil.CreateVector(type, d.ToString()); - } - - public DType Accept(TDateTime type, DefField field, ExcelStream x, DefAssembly ass) - { - var d = x.Read(); - if (CheckNull(type.IsNullable, d)) - { - return null; - } - if (CheckIsDefault(x.NamedMode, d) && field?.DefalutDtypeValue != null) - { - return field?.DefalutDtypeValue; - } - if (d is System.DateTime datetime) - { - return new DDateTime(datetime); - } - return DataUtil.CreateDateTime(d.ToString()); - } - } -} diff --git a/src/Luban.Job.Cfg/Source/DataCreators/ExcelNamedRowDataCreator.cs b/src/Luban.Job.Cfg/Source/DataCreators/ExcelNamedRowDataCreator.cs index 440e170..8330da9 100644 --- a/src/Luban.Job.Cfg/Source/DataCreators/ExcelNamedRowDataCreator.cs +++ b/src/Luban.Job.Cfg/Source/DataCreators/ExcelNamedRowDataCreator.cs @@ -1,352 +1,350 @@ -using Luban.Common.Utils; -using Luban.Job.Cfg.Datas; -using Luban.Job.Cfg.DataSources.Excel; -using Luban.Job.Cfg.Defs; -using Luban.Job.Cfg.TypeVisitors; -using Luban.Job.Common.Types; -using Luban.Job.Common.TypeVisitors; -using System; -using System.Collections.Generic; +//using Luban.Common.Utils; +//using Luban.Job.Cfg.Datas; +//using Luban.Job.Cfg.DataSources.Excel; +//using Luban.Job.Cfg.Defs; +//using Luban.Job.Cfg.TypeVisitors; +//using Luban.Job.Common.Types; +//using Luban.Job.Common.TypeVisitors; +//using System; +//using System.Collections.Generic; -namespace Luban.Job.Cfg.DataCreators -{ - class ExcelNamedRowDataCreator : ITypeFuncVisitor - { - public static ExcelNamedRowDataCreator Ins { get; } = new ExcelNamedRowDataCreator(); +//namespace Luban.Job.Cfg.DataCreators +//{ +// class ExcelNamedRowDataCreator : ITypeFuncVisitor +// { +// public static ExcelNamedRowDataCreator Ins { get; } = new ExcelNamedRowDataCreator(); - public DType ReadExcel(Sheet.NamedRow row, TBean btype) - { - return Accept(btype, row, false, false); - } +// public DType ReadExcel(TitleRow row, TBean btype) +// { +// return Accept(btype, row, false, false); +// } - public DType Accept(TBool type, Sheet.NamedRow x, bool multirow, bool nullable) - { - throw new NotSupportedException(); - } +// public DType Accept(TBool type, TitleRow x, bool multirow, bool nullable) +// { +// throw new NotSupportedException(); +// } - public DType Accept(TByte type, Sheet.NamedRow x, bool multirow, bool nullable) - { - throw new NotSupportedException(); - } +// public DType Accept(TByte type, TitleRow x, bool multirow, bool nullable) +// { +// throw new NotSupportedException(); +// } - public DType Accept(TShort type, Sheet.NamedRow x, bool multirow, bool nullable) - { - throw new NotSupportedException(); - } +// public DType Accept(TShort type, TitleRow x, bool multirow, bool nullable) +// { +// throw new NotSupportedException(); +// } - public DType Accept(TFshort type, Sheet.NamedRow x, bool multirow, bool nullable) - { - throw new NotSupportedException(); - } +// public DType Accept(TFshort type, TitleRow x, bool multirow, bool nullable) +// { +// throw new NotSupportedException(); +// } - public DType Accept(TInt type, Sheet.NamedRow x, bool multirow, bool nullable) - { - throw new NotSupportedException(); - } +// public DType Accept(TInt type, TitleRow x, bool multirow, bool nullable) +// { +// throw new NotSupportedException(); +// } - public DType Accept(TFint type, Sheet.NamedRow x, bool multirow, bool nullable) - { - throw new NotSupportedException(); - } +// public DType Accept(TFint type, TitleRow x, bool multirow, bool nullable) +// { +// throw new NotSupportedException(); +// } - public DType Accept(TLong type, Sheet.NamedRow x, bool multirow, bool nullable) - { - throw new NotSupportedException(); - } +// public DType Accept(TLong type, TitleRow x, bool multirow, bool nullable) +// { +// throw new NotSupportedException(); +// } - public DType Accept(TFlong type, Sheet.NamedRow x, bool multirow, bool nullable) - { - throw new NotSupportedException(); - } +// public DType Accept(TFlong type, TitleRow x, bool multirow, bool nullable) +// { +// throw new NotSupportedException(); +// } - public DType Accept(TFloat type, Sheet.NamedRow x, bool multirow, bool nullable) - { - throw new NotSupportedException(); - } +// public DType Accept(TFloat type, TitleRow x, bool multirow, bool nullable) +// { +// throw new NotSupportedException(); +// } - public DType Accept(TDouble type, Sheet.NamedRow x, bool multirow, bool nullable) - { - throw new NotSupportedException(); - } +// public DType Accept(TDouble type, TitleRow x, bool multirow, bool nullable) +// { +// throw new NotSupportedException(); +// } - public DType Accept(TEnum type, Sheet.NamedRow x, bool multirow, bool nullable) - { - throw new NotSupportedException(); - } +// public DType Accept(TEnum type, TitleRow x, bool multirow, bool nullable) +// { +// throw new NotSupportedException(); +// } - public DType Accept(TString type, Sheet.NamedRow x, bool multirow, bool nullable) - { - throw new NotSupportedException(); - } +// public DType Accept(TString type, TitleRow x, bool multirow, bool nullable) +// { +// throw new NotSupportedException(); +// } - public DType Accept(TBytes type, Sheet.NamedRow x, bool multirow, bool nullable) - { - throw new NotSupportedException(); - } +// public DType Accept(TBytes type, TitleRow x, bool multirow, bool nullable) +// { +// throw new NotSupportedException(); +// } - public DType Accept(TText type, Sheet.NamedRow x, bool multirow, bool nullable) - { - throw new NotSupportedException(); - } +// public DType Accept(TText type, TitleRow x, bool multirow, bool nullable) +// { +// throw new NotSupportedException(); +// } - private static bool IsContainerAndElementNotSepType(TType type) - { - switch (type) - { - case TArray ta: return ta.ElementType.Apply(IsNotSepTypeVisitor.Ins); - case TList tl: return tl.ElementType.Apply(IsNotSepTypeVisitor.Ins); - case TSet ts: return ts.ElementType.Apply(IsNotSepTypeVisitor.Ins); - case TMap tm: return tm.KeyType.Apply(IsNotSepTypeVisitor.Ins) && tm.ValueType.Apply(IsNotSepTypeVisitor.Ins); - default: return false; - } - throw new NotImplementedException(); - } +// private static bool IsContainerAndElementNotSepType(TType type) +// { +// switch (type) +// { +// case TArray ta: return ta.ElementType.Apply(IsNotSepTypeVisitor.Ins); +// case TList tl: return tl.ElementType.Apply(IsNotSepTypeVisitor.Ins); +// case TSet ts: return ts.ElementType.Apply(IsNotSepTypeVisitor.Ins); +// case TMap tm: return tm.KeyType.Apply(IsNotSepTypeVisitor.Ins) && tm.ValueType.Apply(IsNotSepTypeVisitor.Ins); +// default: return false; +// } +// throw new NotImplementedException(); +// } - private List CreateBeanFields(DefBean bean, Sheet.NamedRow row) - { - var list = new List(); - foreach (DefField f in bean.HierarchyFields) - { - string fname = f.Name; - Title title = row.GetTitle(fname); - if (title == null) - { - throw new Exception($"bean:'{bean.FullName}' 缺失 列:'{fname}',请检查是否写错或者遗漏"); - } - // 多级标题 - if (title.SubTitles.Count > 0) - { - try - { - list.Add(f.CType.Apply(this, row.GetSubTitleNamedRow(fname), f.IsMultiRow, f.IsNullable)); - } - catch (DataCreateException dce) - { - dce.Push(bean, f); - throw; - } - catch (Exception e) - { - var dce = new DataCreateException(e, $"列:{fname}"); - dce.Push(bean, f); - throw dce; - } - } - else - { - string sep = f.ActualSep; - if (string.IsNullOrWhiteSpace(sep) && IsContainerAndElementNotSepType(f.CType)) - { - sep = ";,"; - } +// private List CreateBeanFields(DefBean bean, TitleRow row) +// { +// var list = new List(); +// foreach (DefField f in bean.HierarchyFields) +// { +// string fname = f.Name; +// Title title = row.GetTitle(fname); +// if (title == null) +// { +// throw new Exception($"bean:'{bean.FullName}' 缺失 列:'{fname}',请检查是否写错或者遗漏"); +// } +// // 多级标题 +// if (title.SubTitles.Count > 0) +// { +// try +// { +// list.Add(f.CType.Apply(this, row.GetSubTitleNamedRow(fname), f.IsMultiRow, f.IsNullable)); +// } +// catch (DataCreateException dce) +// { +// dce.Push(bean, f); +// throw; +// } +// catch (Exception e) +// { +// var dce = new DataCreateException(e, $"列:{fname}"); +// dce.Push(bean, f); +// throw dce; +// } +// } +// else +// { +// string sep = ""; +// if (string.IsNullOrWhiteSpace(sep) && IsContainerAndElementNotSepType(f.CType)) +// { +// sep = ";,"; +// } - if (f.IsMultiRow) - { - try - { - if (f.CType.IsCollection) - { - list.Add(f.CType.Apply(MultiRowExcelDataCreator.Ins, row.GetColumnOfMultiRows(f.Name, sep, f.IsRowOrient), f.IsNullable, (DefAssembly)bean.AssemblyBase)); - } - else - { - list.Add(f.CType.Apply(ExcelDataCreator.Ins, f, row.GetMultiRowStream(f.Name, sep, f.IsRowOrient), (DefAssembly)bean.AssemblyBase)); - } - } - catch (DataCreateException dce) - { - dce.Push(bean, f); - throw; - } - catch (Exception e) - { - var dce = new DataCreateException(e, ""); - dce.Push(bean, f); - throw dce; - } - } - else - { - ExcelStream stream = row.GetColumn(f.Name, sep, !f.CType.Apply(IsMultiData.Ins)); - try - { - list.Add(f.CType.Apply(ExcelDataCreator.Ins, f, stream, (DefAssembly)bean.AssemblyBase)); - } - catch (DataCreateException dce) - { - dce.Push(bean, f); - throw; - } - catch (Exception e) - { - var dce = new DataCreateException(e, stream.LastReadDataInfo); - dce.Push(bean, f); - throw dce; - } - } - } - } - return list; - } +// if (f.IsMultiRow) +// { +// try +// { +// if (f.CType.IsCollection) +// { +// list.Add(f.CType.Apply(MultiRowExcelDataCreator.Ins, row.GetColumnOfMultiRows(f.Name, sep), f.IsNullable, (DefAssembly)bean.AssemblyBase)); +// } +// else +// { +// list.Add(f.CType.Apply(ExcelDataCreator.Ins, f, row.GetMultiRowStream(f.Name, sep), (DefAssembly)bean.AssemblyBase)); +// } +// } +// catch (DataCreateException dce) +// { +// dce.Push(bean, f); +// throw; +// } +// catch (Exception e) +// { +// var dce = new DataCreateException(e, ""); +// dce.Push(bean, f); +// throw dce; +// } +// } +// else +// { +// //ExcelStream stream = row.GetColumn(f.Name, sep, !f.CType.Apply(IsMultiData.Ins)); +// ExcelStream stream = row.GetColumn(f.Name); +// try +// { +// list.Add(f.CType.Apply(ExcelDataCreator.Ins, f, stream, (DefAssembly)bean.AssemblyBase)); +// } +// catch (DataCreateException dce) +// { +// dce.Push(bean, f); +// throw; +// } +// catch (Exception e) +// { +// var dce = new DataCreateException(e, stream.LastReadDataInfo); +// dce.Push(bean, f); +// throw dce; +// } +// } +// } +// } +// return list; +// } - public DType Accept(TBean type, Sheet.NamedRow row, bool multirow, bool nullable) - { - var originBean = (DefBean)type.Bean; - if (originBean.IsAbstractType) - { - string subType = row.GetColumn(DefBean.TYPE_NAME_KEY, null, true).Read().ToString().Trim(); - if (subType.ToLower() == DefBean.BEAN_NULL_STR) - { - if (!type.IsNullable) - { - throw new Exception($"type:'{type}' 不是可空类型 '{type.Bean.FullName}?' , 不能为空"); - } - return null; - } - string fullType = TypeUtil.MakeFullName(originBean.Namespace, subType); - DefBean implType = (DefBean)originBean.GetNotAbstractChildType(subType); - if (implType == null) - { - throw new Exception($"type:'{fullType}' 不是 bean 类型"); - } - return new DBean(originBean, implType, CreateBeanFields(implType, row)); - } - else - { - if (type.IsNullable) - { - string subType = row.GetColumn(DefBean.TYPE_NAME_KEY, null, true).Read().ToString().Trim(); - if (subType == DefBean.BEAN_NULL_STR) - { - return null; - } - else if (subType != DefBean.BEAN_NOT_NULL_STR && subType != originBean.Name) - { - throw new Exception($"type:'{type.Bean.FullName}' 可空标识:'{subType}' 不合法(只能为{DefBean.BEAN_NOT_NULL_STR}或{DefBean.BEAN_NULL_STR}或{originBean.Name})"); - } - } +// public DType Accept(TBean type, TitleRow row, bool multirow, bool nullable) +// { +// var originBean = (DefBean)type.Bean; +// if (originBean.IsAbstractType) +// { +// string subType = row.GetColumn(DefBean.TYPE_NAME_KEY).Read().ToString().Trim(); +// if (subType.ToLower() == DefBean.BEAN_NULL_STR) +// { +// if (!type.IsNullable) +// { +// throw new Exception($"type:'{type}' 不是可空类型 '{type.Bean.FullName}?' , 不能为空"); +// } +// return null; +// } +// string fullType = TypeUtil.MakeFullName(originBean.Namespace, subType); +// DefBean implType = (DefBean)originBean.GetNotAbstractChildType(subType); +// if (implType == null) +// { +// throw new Exception($"type:'{fullType}' 不是 bean 类型"); +// } +// return new DBean(originBean, implType, CreateBeanFields(implType, row)); +// } +// else +// { +// if (type.IsNullable) +// { +// string subType = row.GetColumn(DefBean.TYPE_NAME_KEY).Read().ToString().Trim(); +// if (subType == DefBean.BEAN_NULL_STR) +// { +// return null; +// } +// else if (subType != DefBean.BEAN_NOT_NULL_STR && subType != originBean.Name) +// { +// throw new Exception($"type:'{type.Bean.FullName}' 可空标识:'{subType}' 不合法(只能为{DefBean.BEAN_NOT_NULL_STR}或{DefBean.BEAN_NULL_STR}或{originBean.Name})"); +// } +// } - return new DBean(originBean, originBean, CreateBeanFields(originBean, row)); - } - } +// return new DBean(originBean, originBean, CreateBeanFields(originBean, row)); +// } +// } - private List ReadList(TBean elementType, Sheet.NamedRow row, bool multirow) - { - var list = new List(); - // 如果是多行数据,以当前title为title,每行读入一个element - if (multirow) - { - //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)); - } - } - else - { - // 如果不是多行,并且定义了子标题的话。以一个子标题所占的列,读入一个数据 +// private List ReadList(TBean elementType, TitleRow row, bool multirow) +// { +// var list = new List(); +// // 如果是多行数据,以当前title为title,每行读入一个element +// if (multirow) +// { +// //foreach (var sub in row.GenerateSubNameRows(elementType)) +// foreach (var sub in row.Elements) +// { +// list.Add(this.Accept(elementType, sub, false, false)); +// } +// } +// else +// { +// // 如果不是多行,并且定义了子标题的话。以一个子标题所占的列,读入一个数据 - //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; - } +// //foreach (var sub in row.SelfTitle.SubTitleList) +// //{ +// // list.Add(this.Accept(elementType, new TitleRow(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 not TBean bean) - { - throw new Exception($"NamedRow 只支持 bean 类型的容器"); - } - else - { - return new DArray(type, ReadList(bean, x, multirow)); - } - } +// public DType Accept(TArray type, TitleRow x, bool multirow, bool nullable) +// { +// if (type.ElementType is not TBean bean) +// { +// throw new Exception($"NamedRow 只支持 bean 类型的容器"); +// } +// else +// { +// return new DArray(type, ReadList(bean, x, multirow)); +// } +// } - public DType Accept(TList type, Sheet.NamedRow x, bool multirow, bool nullable) - { - if (type.ElementType is not TBean bean) - { - throw new Exception($"NamedRow 只支持 bean 类型的容器"); - } - else - { - return new DList(type, ReadList(bean, x, multirow)); - } - } +// public DType Accept(TList type, TitleRow x, bool multirow, bool nullable) +// { +// if (type.ElementType is not TBean bean) +// { +// throw new Exception($"NamedRow 只支持 bean 类型的容器"); +// } +// else +// { +// return new DList(type, ReadList(bean, x, multirow)); +// } +// } - public DType Accept(TSet type, Sheet.NamedRow x, bool multirow, bool nullable) - { - throw new NotSupportedException(); - } +// public DType Accept(TSet type, TitleRow x, bool multirow, bool nullable) +// { +// throw new NotSupportedException(); +// } - private bool TryCreateColumnStream(Sheet.NamedRow x, Title title, out ExcelStream stream) - { - var cells = new List(); - for (int i = title.FromIndex; i <= title.ToIndex; i++) - { - foreach (var row in x.Rows) - { - if (row.Count > i) - { - var value = row[i].Value; - if (!(value == null || (value is string s && string.IsNullOrEmpty(s)))) - { - cells.Add(row[i]); - } - } - } - } - if (cells.Count > 0) - { - stream = new ExcelStream(cells, 0, cells.Count - 1, "", false); - return true; - } - stream = null; - return false; - } +// private bool TryCreateColumnStream(TitleRow x, Title title, out ExcelStream stream) +// { +// var cells = new List(); +// for (int i = title.FromIndex; i <= title.ToIndex; i++) +// { +// foreach (var row in x.Rows) +// { +// if (row.Count > i) +// { +// var value = row[i].Value; +// if (!(value == null || (value is string s && string.IsNullOrEmpty(s)))) +// { +// cells.Add(row[i]); +// } +// } +// } +// } +// if (cells.Count > 0) +// { +// stream = new ExcelStream(cells, 0, cells.Count - 1, "", false); +// return true; +// } +// stream = null; +// return false; +// } - public DType Accept(TMap type, Sheet.NamedRow x, bool multirow, bool nullable) - { - var map = new Dictionary(); - foreach (var e in x.Titles) - { - if (TryCreateColumnStream(x, e.Value, out var stream)) - { - var keyData = type.KeyType.Apply(StringDataCreator.Ins, e.Key); - var valueData = type.ValueType.Apply(ExcelDataCreator.Ins, null, stream, DefAssembly.LocalAssebmly); - map.Add(keyData, valueData); - } - } - return new DMap(type, map); - } +// public DType Accept(TMap type, TitleRow x, bool multirow, bool nullable) +// { +// var map = new Dictionary(); +// foreach (var e in x.Fields) +// { +// var keyData = type.KeyType.Apply(StringDataCreator.Ins, e.Key); +// var valueData = type.ValueType.Apply(ExcelDataCreator.Ins, null, e.Value.AsStream, DefAssembly.LocalAssebmly); +// map.Add(keyData, valueData); +// } +// return new DMap(type, map); +// } - public DType Accept(TVector2 type, Sheet.NamedRow x, bool multirow, bool nullable) - { - throw new NotSupportedException(); - } +// public DType Accept(TVector2 type, TitleRow x, bool multirow, bool nullable) +// { +// throw new NotSupportedException(); +// } - public DType Accept(TVector3 type, Sheet.NamedRow x, bool multirow, bool nullable) - { - throw new NotSupportedException(); - } +// public DType Accept(TVector3 type, TitleRow x, bool multirow, bool nullable) +// { +// throw new NotSupportedException(); +// } - public DType Accept(TVector4 type, Sheet.NamedRow x, bool multirow, bool nullable) - { - throw new NotSupportedException(); - } +// public DType Accept(TVector4 type, TitleRow x, bool multirow, bool nullable) +// { +// throw new NotSupportedException(); +// } - public DType Accept(TDateTime type, Sheet.NamedRow x, bool multirow, bool nullable) - { - throw new NotSupportedException(); - } - } -} +// public DType Accept(TDateTime type, TitleRow x, bool multirow, bool nullable) +// { +// throw new NotSupportedException(); +// } +// } +//} diff --git a/src/Luban.Job.Cfg/Source/DataCreators/ExcelStreamDataCreator.cs b/src/Luban.Job.Cfg/Source/DataCreators/ExcelStreamDataCreator.cs new file mode 100644 index 0000000..6eb2486 --- /dev/null +++ b/src/Luban.Job.Cfg/Source/DataCreators/ExcelStreamDataCreator.cs @@ -0,0 +1,467 @@ +using Bright.Collections; +using Luban.Common.Utils; +using Luban.Job.Cfg.Datas; +using Luban.Job.Cfg.DataSources.Excel; +using Luban.Job.Cfg.Defs; +using Luban.Job.Cfg.Utils; +using Luban.Job.Common.Types; +using Luban.Job.Common.TypeVisitors; +using System; +using System.Collections.Generic; +using System.Runtime.Serialization; + +namespace Luban.Job.Cfg.DataCreators +{ + class InvalidExcelDataException : Exception + { + public InvalidExcelDataException() + { + } + + public InvalidExcelDataException(string message) : base(message) + { + } + + public InvalidExcelDataException(string message, Exception innerException) : base(message, innerException) + { + } + + protected InvalidExcelDataException(SerializationInfo info, StreamingContext context) : base(info, context) + { + } + } + + class ExcelStreamDataCreator : ITypeFuncVisitor + { + public static ExcelStreamDataCreator Ins { get; } = new ExcelStreamDataCreator(); + + private bool CheckNull(bool nullable, object o) + { + return nullable && (o == null || (o is string s && s == "null")); + } + + private static bool CreateBool(object x) + { + if (x is bool b) + { + return b; + } + var s = x.ToString().ToLower().Trim(); + switch (s) + { + case "true": + case "是": return true; + case "false": + case "否": return false; + default: throw new InvalidExcelDataException($"{s} 不是 bool 类型的值 (true 或 false)"); + } + } + + public DType Accept(TBool type, ExcelStream x) + { + + var d = x.Read(); + if (CheckNull(type.IsNullable, d)) + { + return null; + } + return DBool.ValueOf(CreateBool(d)); + } + + public DType Accept(TByte type, ExcelStream x) + { + var d = x.Read(); + if (CheckNull(type.IsNullable, d)) + { + return null; + } + if (!byte.TryParse(d.ToString(), out byte v)) + { + throw new InvalidExcelDataException($"{d} 不是 byte 类型值"); + } + return DByte.ValueOf(v); + } + + public DType Accept(TShort type, ExcelStream x) + { + var d = x.Read(); + if (CheckNull(type.IsNullable, d)) + { + return null; + } + if (!short.TryParse(d.ToString(), out short v)) + { + throw new InvalidExcelDataException($"{d} 不是 short 类型值"); + } + return DShort.ValueOf(v); + } + + public DType Accept(TFshort type, ExcelStream x) + { + var d = x.Read(); + if (CheckNull(type.IsNullable, d)) + { + return null; + } + if (!short.TryParse(d.ToString(), out short v)) + { + throw new InvalidExcelDataException($"{d} 不是 short 类型值"); + } + return DFshort.ValueOf(v); + } + + public DType Accept(TInt type, ExcelStream x) + { + var d = x.Read(); + if (CheckNull(type.IsNullable, d)) + { + return null; + } + var ds = d.ToString(); + //if (field?.Remapper is TEnum te) + //{ + // if (te.DefineEnum.TryValueByNameOrAlias(ds, out var c)) + // { + // return DInt.ValueOf(c); + // } + //} + if (!int.TryParse(ds, out var v)) + { + throw new InvalidExcelDataException($"{d} 不是 int 类型值"); + } + return DInt.ValueOf(v); + } + + public DType Accept(TFint type, ExcelStream x) + { + var d = x.Read(); + if (CheckNull(type.IsNullable, d)) + { + return null; + } + var ds = d.ToString(); + //if (field?.Remapper is TEnum te) + //{ + // if (te.DefineEnum.TryValueByNameOrAlias(ds, out var c)) + // { + // return new DFint(c); + // } + //} + if (!int.TryParse(ds, out var v)) + { + throw new InvalidExcelDataException($"{d} 不是 int 类型值"); + } + return DFint.ValueOf(v); + } + + public DType Accept(TLong type, ExcelStream x) + { + var d = x.Read(); + if (CheckNull(type.IsNullable, d)) + { + return null; + } + var ds = d.ToString(); + //if (field?.Remapper is TEnum te) + //{ + // if (te.DefineEnum.TryValueByNameOrAlias(ds, out var c)) + // { + // return DLong.ValueOf(c); + // } + //} + if (!long.TryParse(ds, out var v)) + { + throw new InvalidExcelDataException($"{d} 不是 long 类型值"); + } + return DLong.ValueOf(v); + } + + public DType Accept(TFlong type, ExcelStream x) + { + var d = x.Read(); + if (CheckNull(type.IsNullable, d)) + { + return null; + } + var ds = d.ToString(); + //if (field?.Remapper is TEnum te) + //{ + // if (te.DefineEnum.TryValueByNameOrAlias(ds, out var c)) + // { + // return new DFlong(c); + // } + //} + if (!long.TryParse(ds, out var v)) + { + throw new InvalidExcelDataException($"{d} 不是 long 类型值"); + } + return DFlong.ValueOf(v); + } + + public DType Accept(TFloat type, ExcelStream x) + { + var d = x.Read(); + if (CheckNull(type.IsNullable, d)) + { + return null; + } + if (!float.TryParse(d.ToString(), out var v)) + { + throw new InvalidExcelDataException($"{d} 不是 float 类型值"); + } + return DFloat.ValueOf(v); + } + + public DType Accept(TDouble type, ExcelStream x) + { + var d = x.Read(); + if (CheckNull(type.IsNullable, d)) + { + return null; + } + if (!double.TryParse(d.ToString(), out var v)) + { + throw new InvalidExcelDataException($"{d} 不是 double 类型值"); + } + return DDouble.ValueOf(v); + } + + public DType Accept(TEnum type, ExcelStream x) + { + var d = x.Read(); + if (CheckNull(type.IsNullable, d)) + { + return null; + } + return new DEnum(type, d.ToString().Trim()); + } + + public DType Accept(TString type, ExcelStream x) + { + var d = x.Read(); + var s = ParseString(d); + if (s == null) + { + if (type.IsNullable) + { + return null; + } + else + { + throw new InvalidExcelDataException("字段不是nullable类型,不能为null"); + } + } + return DString.ValueOf(s); + } + + public DType Accept(TBytes type, ExcelStream x) + { + throw new NotImplementedException(); + } + + private static string ParseString(object d) + { + if (d == null) + { + return string.Empty; + } + else if (d is string s) + { + return DataUtil.UnEscapeString(s); + } + else + { + return d.ToString(); + } + } + + public DType Accept(TText type, ExcelStream x) + { + string key = ParseString(x.Read()); + if (key == null) + { + if (type.IsNullable) + { + return null; + } + else + { + throw new InvalidExcelDataException("该字段不是nullable类型,不能为null"); + } + } + + string text = ParseString(x.Read()); + DataUtil.ValidateText(key, text); + return new DText(key, text); + } + + private List CreateBeanFields(DefBean bean, ExcelStream stream) + { + var list = new List(); + foreach (DefField f in bean.HierarchyFields) + { + try + { + string sep = f.Tags.TryGetValue("tag", out var s) ? s : null; + if (string.IsNullOrWhiteSpace(sep)) + { + list.Add(f.CType.Apply(this, stream)); + } + else + { + list.Add(f.CType.Apply(this, new ExcelStream(stream.ReadCell(), sep))); + } + } + catch (DataCreateException dce) + { + dce.Push(bean, f); + throw; + } + catch (Exception e) + { + var dce = new DataCreateException(e, stream.LastReadDataInfo); + dce.Push(bean, f); + throw dce; + } + } + return list; + } + + public DType Accept(TBean type, ExcelStream x) + { + var originBean = (DefBean)type.Bean; + + if (originBean.IsAbstractType) + { + string subType = x.Read().ToString(); + if (subType.ToLower().Trim() == DefBean.BEAN_NULL_STR) + { + if (!type.IsNullable) + { + throw new InvalidExcelDataException($"type:{type.Bean.FullName}不是可空类型. 不能为空"); + } + return null; + } + string fullType = TypeUtil.MakeFullName(originBean.Namespace, subType); + DefBean implType = (DefBean)originBean.GetNotAbstractChildType(subType); + if (implType == null) + { + throw new InvalidExcelDataException($"type:{fullType} 不是bean类型"); + } + return new DBean(originBean, implType, CreateBeanFields(implType, x)); + } + else + { + if (type.IsNullable) + { + string subType = x.Read().ToString().Trim(); + if (subType == DefBean.BEAN_NULL_STR) + { + return null; + } + else if (subType != DefBean.BEAN_NOT_NULL_STR && subType != originBean.Name) + { + throw new Exception($"type:'{type.Bean.FullName}' 可空标识:'{subType}' 不合法(只能为{DefBean.BEAN_NOT_NULL_STR}或{DefBean.BEAN_NULL_STR}或{originBean.Name})"); + } + } + return new DBean(originBean, originBean, CreateBeanFields(originBean, x)); + } + } + + // 容器类统统不支持 type.IsNullable + // 因为貌似没意义? + public List ReadList(TType type, ExcelStream stream) + { + string sep = type is TBean bean ? ((DefBean)bean.Bean).Sep : null; + var datas = new List(); + while (!stream.TryReadEOF()) + { + if (string.IsNullOrWhiteSpace(sep)) + { + datas.Add(type.Apply(this, stream)); + } + else + { + datas.Add(type.Apply(this, new ExcelStream(stream.ReadCell(), sep))); ; + } + } + return datas; + } + + public DType Accept(TArray type, ExcelStream x) + { + return new DArray(type, ReadList(type.ElementType, x)); + } + + public DType Accept(TList type, ExcelStream x) + { + return new DList(type, ReadList(type.ElementType, x)); + } + + public DType Accept(TSet type, ExcelStream x) + { + return new DSet(type, ReadList(type.ElementType, x)); + } + + public DType Accept(TMap type, ExcelStream x) + { + string sep = type.ValueType is TBean bean ? ((DefBean)bean.Bean).Sep : null; + + var datas = new Dictionary(); + while (!x.TryReadEOF()) + { + 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)); + if (!datas.TryAdd(key, value)) + { + throw new InvalidExcelDataException($"map 的 key:{key} 重复"); + } + } + return new DMap(type, datas); + } + + public DType Accept(TVector2 type, ExcelStream x) + { + var d = x.Read(); + if (CheckNull(type.IsNullable, d)) + { + return null; + } + return DataUtil.CreateVector(type, d.ToString()); + } + + public DType Accept(TVector3 type, ExcelStream x) + { + var d = x.Read(); + if (CheckNull(type.IsNullable, d)) + { + return null; + } + return DataUtil.CreateVector(type, d.ToString()); + } + + public DType Accept(TVector4 type, ExcelStream x) + { + var d = x.Read(); + if (CheckNull(type.IsNullable, d)) + { + return null; + } + return DataUtil.CreateVector(type, d.ToString()); + } + + public DType Accept(TDateTime type, ExcelStream x) + { + var d = x.Read(); + if (CheckNull(type.IsNullable, d)) + { + return null; + } + if (d is System.DateTime datetime) + { + return new DDateTime(datetime); + } + return DataUtil.CreateDateTime(d.ToString()); + } + } +} diff --git a/src/Luban.Job.Cfg/Source/DataCreators/JsonDataCreator.cs b/src/Luban.Job.Cfg/Source/DataCreators/JsonDataCreator.cs index c687a9f..bf53be2 100644 --- a/src/Luban.Job.Cfg/Source/DataCreators/JsonDataCreator.cs +++ b/src/Luban.Job.Cfg/Source/DataCreators/JsonDataCreator.cs @@ -22,17 +22,17 @@ namespace Luban.Job.Cfg.DataCreators public DType Accept(TByte type, JsonElement x, DefAssembly ass) { - return new DByte(x.GetByte()); + return DByte.ValueOf(x.GetByte()); } public DType Accept(TShort type, JsonElement x, DefAssembly ass) { - return new DShort(x.GetInt16()); + return DShort.ValueOf(x.GetInt16()); } public DType Accept(TFshort type, JsonElement x, DefAssembly ass) { - return new DFshort(x.GetInt16()); + return DFshort.ValueOf(x.GetInt16()); } public DType Accept(TInt type, JsonElement x, DefAssembly ass) @@ -42,7 +42,7 @@ namespace Luban.Job.Cfg.DataCreators public DType Accept(TFint type, JsonElement x, DefAssembly ass) { - return new DFint(x.GetInt32()); + return DFint.ValueOf(x.GetInt32()); } public DType Accept(TLong type, JsonElement x, DefAssembly ass) @@ -52,7 +52,7 @@ namespace Luban.Job.Cfg.DataCreators public DType Accept(TFlong type, JsonElement x, DefAssembly ass) { - return new DFlong(x.GetInt64()); + return DFlong.ValueOf(x.GetInt64()); } public DType Accept(TFloat type, JsonElement x, DefAssembly ass) @@ -62,7 +62,7 @@ namespace Luban.Job.Cfg.DataCreators public DType Accept(TDouble type, JsonElement x, DefAssembly ass) { - return new DDouble(x.GetDouble()); + return DDouble.ValueOf(x.GetDouble()); } public DType Accept(TEnum type, JsonElement x, DefAssembly ass) diff --git a/src/Luban.Job.Cfg/Source/DataCreators/LuaDataCreator.cs b/src/Luban.Job.Cfg/Source/DataCreators/LuaDataCreator.cs index 8c40f79..f8ac290 100644 --- a/src/Luban.Job.Cfg/Source/DataCreators/LuaDataCreator.cs +++ b/src/Luban.Job.Cfg/Source/DataCreators/LuaDataCreator.cs @@ -23,17 +23,17 @@ namespace Luban.Job.Cfg.DataCreators public DType Accept(TByte type, object x, DefAssembly ass) { - return new DByte((byte)(int)x); + return DByte.ValueOf((byte)(int)x); } public DType Accept(TShort type, object x, DefAssembly ass) { - return new DShort((short)(int)x); + return DShort.ValueOf((short)(int)x); } public DType Accept(TFshort type, object x, DefAssembly ass) { - return new DFshort((short)(int)x); + return DFshort.ValueOf((short)(int)x); } public DType Accept(TInt type, object x, DefAssembly ass) @@ -43,7 +43,7 @@ namespace Luban.Job.Cfg.DataCreators public DType Accept(TFint type, object x, DefAssembly ass) { - return new DFint((int)x); + return DFint.ValueOf((int)x); } private long ToLong(object x) @@ -89,7 +89,7 @@ namespace Luban.Job.Cfg.DataCreators public DType Accept(TFlong type, object x, DefAssembly ass) { - return new DFlong(ToLong(x)); + return DFlong.ValueOf(ToLong(x)); } public DType Accept(TFloat type, object x, DefAssembly ass) @@ -99,7 +99,7 @@ namespace Luban.Job.Cfg.DataCreators public DType Accept(TDouble type, object x, DefAssembly ass) { - return new DDouble(ToDouble(x)); + return DDouble.ValueOf(ToDouble(x)); } public DType Accept(TEnum type, object x, DefAssembly ass) diff --git a/src/Luban.Job.Cfg/Source/DataCreators/MultiRowExcelDataCreator.cs b/src/Luban.Job.Cfg/Source/DataCreators/MultiRowExcelDataCreator.cs index 9b8211d..68d392b 100644 --- a/src/Luban.Job.Cfg/Source/DataCreators/MultiRowExcelDataCreator.cs +++ b/src/Luban.Job.Cfg/Source/DataCreators/MultiRowExcelDataCreator.cs @@ -1,163 +1,163 @@ -using Luban.Job.Cfg.Datas; -using Luban.Job.Cfg.DataSources.Excel; -using Luban.Job.Cfg.Defs; -using Luban.Job.Common.Types; -using Luban.Job.Common.TypeVisitors; -using System; -using System.Collections.Generic; +//using Luban.Job.Cfg.Datas; +//using Luban.Job.Cfg.DataSources.Excel; +//using Luban.Job.Cfg.Defs; +//using Luban.Job.Common.Types; +//using Luban.Job.Common.TypeVisitors; +//using System; +//using System.Collections.Generic; -namespace Luban.Job.Cfg.DataCreators -{ - class MultiRowExcelDataCreator : ITypeFuncVisitor, bool, DefAssembly, DType> - { - public static MultiRowExcelDataCreator Ins { get; } = new MultiRowExcelDataCreator(); +//namespace Luban.Job.Cfg.DataCreators +//{ +// class MultiRowExcelDataCreator : ITypeFuncVisitor, bool, DefAssembly, DType> +// { +// public static MultiRowExcelDataCreator Ins { get; } = new MultiRowExcelDataCreator(); - public DType Accept(TBool type, IEnumerable x, bool y, DefAssembly ass) - { - throw new NotImplementedException(); - } +// public DType Accept(TBool type, IEnumerable x, bool y, DefAssembly ass) +// { +// throw new NotImplementedException(); +// } - public DType Accept(TByte type, IEnumerable x, bool y, DefAssembly ass) - { - throw new NotImplementedException(); - } +// public DType Accept(TByte type, IEnumerable x, bool y, DefAssembly ass) +// { +// throw new NotImplementedException(); +// } - public DType Accept(TShort type, IEnumerable x, bool y, DefAssembly ass) - { - throw new NotImplementedException(); - } +// public DType Accept(TShort type, IEnumerable x, bool y, DefAssembly ass) +// { +// throw new NotImplementedException(); +// } - public DType Accept(TFshort type, IEnumerable x, bool y, DefAssembly ass) - { - throw new NotImplementedException(); - } +// public DType Accept(TFshort type, IEnumerable x, bool y, DefAssembly ass) +// { +// throw new NotImplementedException(); +// } - public DType Accept(TInt type, IEnumerable x, bool y, DefAssembly ass) - { - throw new NotImplementedException(); - } +// public DType Accept(TInt type, IEnumerable x, bool y, DefAssembly ass) +// { +// throw new NotImplementedException(); +// } - public DType Accept(TFint type, IEnumerable x, bool y, DefAssembly ass) - { - throw new NotImplementedException(); - } +// public DType Accept(TFint type, IEnumerable x, bool y, DefAssembly ass) +// { +// throw new NotImplementedException(); +// } - public DType Accept(TLong type, IEnumerable x, bool y, DefAssembly ass) - { - throw new NotImplementedException(); - } +// public DType Accept(TLong type, IEnumerable x, bool y, DefAssembly ass) +// { +// throw new NotImplementedException(); +// } - public DType Accept(TFlong type, IEnumerable x, bool y, DefAssembly ass) - { - throw new NotImplementedException(); - } +// public DType Accept(TFlong type, IEnumerable x, bool y, DefAssembly ass) +// { +// throw new NotImplementedException(); +// } - public DType Accept(TFloat type, IEnumerable x, bool y, DefAssembly ass) - { - throw new NotImplementedException(); - } +// public DType Accept(TFloat type, IEnumerable x, bool y, DefAssembly ass) +// { +// throw new NotImplementedException(); +// } - public DType Accept(TDouble type, IEnumerable x, bool y, DefAssembly ass) - { - throw new NotImplementedException(); - } +// public DType Accept(TDouble type, IEnumerable x, bool y, DefAssembly ass) +// { +// throw new NotImplementedException(); +// } - public DType Accept(TEnum type, IEnumerable x, bool y, DefAssembly ass) - { - throw new NotImplementedException(); - } +// public DType Accept(TEnum type, IEnumerable x, bool y, DefAssembly ass) +// { +// throw new NotImplementedException(); +// } - public DType Accept(TString type, IEnumerable x, bool y, DefAssembly ass) - { - throw new NotImplementedException(); - } +// public DType Accept(TString type, IEnumerable x, bool y, DefAssembly ass) +// { +// throw new NotImplementedException(); +// } - public DType Accept(TBytes type, IEnumerable x, bool y, DefAssembly ass) - { - throw new NotImplementedException(); - } +// public DType Accept(TBytes type, IEnumerable x, bool y, DefAssembly ass) +// { +// throw new NotImplementedException(); +// } - public DType Accept(TText type, IEnumerable x, bool y, DefAssembly ass) - { - throw new NotImplementedException(); - } +// public DType Accept(TText type, IEnumerable x, bool y, DefAssembly ass) +// { +// throw new NotImplementedException(); +// } - public DType Accept(TBean type, IEnumerable x, bool y, DefAssembly ass) - { - throw new NotImplementedException(); - } +// public DType Accept(TBean type, IEnumerable x, bool y, DefAssembly ass) +// { +// throw new NotImplementedException(); +// } - private List ReadMultiRow(TType type, IEnumerable rows, DefAssembly ass) - { - var list = new List(); - foreach (var stream in rows) - { - try - { - list.Add(type.Apply(ExcelDataCreator.Ins, null, stream, ass)); - } - catch (Exception e) - { - var dce = new DataCreateException(e, stream.LastReadDataInfo); - throw dce; - } - } - return list; - } +// private List ReadMultiRow(TType type, IEnumerable rows, DefAssembly ass) +// { +// var list = new List(); +// foreach (var stream in rows) +// { +// try +// { +// list.Add(type.Apply(ExcelStreamDataCreator.Ins, null, stream, ass)); +// } +// catch (Exception e) +// { +// var dce = new DataCreateException(e, stream.LastReadDataInfo); +// throw dce; +// } +// } +// return list; +// } - public DType Accept(TArray type, IEnumerable x, bool y, DefAssembly ass) - { - return new DArray(type, ReadMultiRow(type.ElementType, x, ass)); - } +// public DType Accept(TArray type, IEnumerable x, bool y, DefAssembly ass) +// { +// return new DArray(type, ReadMultiRow(type.ElementType, x, ass)); +// } - public DType Accept(TList type, IEnumerable x, bool y, DefAssembly ass) - { - return new DList(type, ReadMultiRow(type.ElementType, x, ass)); - } +// public DType Accept(TList type, IEnumerable x, bool y, DefAssembly ass) +// { +// return new DList(type, ReadMultiRow(type.ElementType, x, ass)); +// } - public DType Accept(TSet type, IEnumerable x, bool y, DefAssembly ass) - { - return new DSet(type, ReadMultiRow(type.ElementType, x, ass)); - } +// public DType Accept(TSet type, IEnumerable x, bool y, DefAssembly ass) +// { +// return new DSet(type, ReadMultiRow(type.ElementType, x, ass)); +// } - public DType Accept(TMap type, IEnumerable rows, bool y, DefAssembly ass) - { - var map = new Dictionary(); - foreach (var stream in rows) - { - try - { - DType key = type.KeyType.Apply(ExcelDataCreator.Ins, null, stream, ass); - DType value = type.ValueType.Apply(ExcelDataCreator.Ins, null, stream, ass); - map.Add(key, value); - } - catch (Exception e) - { - var dce = new DataCreateException(e, stream.LastReadDataInfo); - throw dce; - } - } - return new DMap(type, map); - } +// public DType Accept(TMap type, IEnumerable rows, bool y, DefAssembly ass) +// { +// var map = new Dictionary(); +// foreach (var stream in rows) +// { +// try +// { +// DType key = type.KeyType.Apply(ExcelStreamDataCreator.Ins, null, stream, ass); +// DType value = type.ValueType.Apply(ExcelStreamDataCreator.Ins, null, stream, ass); +// map.Add(key, value); +// } +// catch (Exception e) +// { +// var dce = new DataCreateException(e, stream.LastReadDataInfo); +// throw dce; +// } +// } +// return new DMap(type, map); +// } - public DType Accept(TVector2 type, IEnumerable x, bool y, DefAssembly ass) - { - throw new NotImplementedException(); - } +// public DType Accept(TVector2 type, IEnumerable x, bool y, DefAssembly ass) +// { +// throw new NotImplementedException(); +// } - public DType Accept(TVector3 type, IEnumerable x, bool y, DefAssembly ass) - { - throw new NotImplementedException(); - } +// public DType Accept(TVector3 type, IEnumerable x, bool y, DefAssembly ass) +// { +// throw new NotImplementedException(); +// } - public DType Accept(TVector4 type, IEnumerable x, bool y, DefAssembly ass) - { - throw new NotImplementedException(); - } +// public DType Accept(TVector4 type, IEnumerable x, bool y, DefAssembly ass) +// { +// throw new NotImplementedException(); +// } - public DType Accept(TDateTime type, IEnumerable x, bool y, DefAssembly ass) - { - throw new NotImplementedException(); - } - } -} +// public DType Accept(TDateTime type, IEnumerable x, bool y, DefAssembly ass) +// { +// throw new NotImplementedException(); +// } +// } +//} diff --git a/src/Luban.Job.Cfg/Source/DataCreators/SheetDataCreator.cs b/src/Luban.Job.Cfg/Source/DataCreators/SheetDataCreator.cs new file mode 100644 index 0000000..8080391 --- /dev/null +++ b/src/Luban.Job.Cfg/Source/DataCreators/SheetDataCreator.cs @@ -0,0 +1,570 @@ +using Luban.Common.Utils; +using Luban.Job.Cfg.Datas; +using Luban.Job.Cfg.DataSources.Excel; +using Luban.Job.Cfg.Defs; +using Luban.Job.Cfg.TypeVisitors; +using Luban.Job.Cfg.Utils; +using Luban.Job.Common.Types; +using Luban.Job.Common.TypeVisitors; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Luban.Job.Cfg.DataCreators +{ + class SheetDataCreator : ITypeFuncVisitor + { + public static SheetDataCreator Ins { get; } = new(); + + private bool CheckNull(bool nullable, object o) + { + return nullable && (o == null || (o is string s && s == "null")); + } + + private bool CheckDefault(object o) + { + return o == null || (o is string s && s.Length == 0); + } + + public DType Accept(TBool type, Sheet sheet, TitleRow row) + { + object x = row.Current.Value; + if (CheckNull(type.IsNullable, x)) + { + return null; + } + if (CheckDefault(x)) + { + return DBool.ValueOf(false); + } + if (x is bool v) + { + return DBool.ValueOf(v); + } + return DBool.ValueOf(bool.Parse(x.ToString())); + } + + public DType Accept(TByte type, Sheet sheet, TitleRow row) + { + object x = row.Current.Value; + if (CheckNull(type.IsNullable, x)) + { + return null; + } + if (CheckDefault(x)) + { + return DByte.Default; + } + return DByte.ValueOf(byte.Parse(x.ToString())); + } + + public DType Accept(TShort type, Sheet sheet, TitleRow row) + { + object x = row.Current.Value; + if (CheckNull(type.IsNullable, x)) + { + return null; + } + if (CheckDefault(x)) + { + return DShort.Default; + } + return DShort.ValueOf(short.Parse(x.ToString())); + } + + public DType Accept(TFshort type, Sheet sheet, TitleRow row) + { + object x = row.Current.Value; + if (CheckNull(type.IsNullable, x)) + { + return null; + } + if (CheckDefault(x)) + { + return DFshort.Default; + } + return DFshort.ValueOf(short.Parse(x.ToString())); + } + + public DType Accept(TInt type, Sheet sheet, TitleRow row) + { + object x = row.Current.Value; + if (CheckNull(type.IsNullable, x)) + { + return null; + } + if (CheckDefault(x)) + { + return DInt.Default; + } + return DInt.ValueOf(int.Parse(x.ToString())); + } + + public DType Accept(TFint type, Sheet sheet, TitleRow row) + { + object x = row.Current.Value; + if (CheckNull(type.IsNullable, x)) + { + return null; + } + if (CheckDefault(x)) + { + return DFint.Default; + } + return DFint.ValueOf(int.Parse(x.ToString())); + } + + public DType Accept(TLong type, Sheet sheet, TitleRow row) + { + object x = row.Current.Value; + if (CheckNull(type.IsNullable, x)) + { + return null; + } + if (CheckDefault(x)) + { + return DLong.Default; + } + return DLong.ValueOf(long.Parse(x.ToString())); + } + + public DType Accept(TFlong type, Sheet sheet, TitleRow row) + { + object x = row.Current.Value; + if (CheckNull(type.IsNullable, x)) + { + return null; + } + if (CheckDefault(x)) + { + return DFlong.Default; + } + return DFlong.ValueOf(long.Parse(x.ToString())); + } + + public DType Accept(TFloat type, Sheet sheet, TitleRow row) + { + object x = row.Current.Value; + if (CheckNull(type.IsNullable, x)) + { + return null; + } + if (CheckDefault(x)) + { + return DFloat.Default; + } + return DFloat.ValueOf(float.Parse(x.ToString())); + } + + public DType Accept(TDouble type, Sheet sheet, TitleRow row) + { + object x = row.Current.Value; + if (CheckNull(type.IsNullable, x)) + { + return null; + } + if (CheckDefault(x)) + { + return DDouble.Default; + } + return DDouble.ValueOf(double.Parse(x.ToString())); + } + + public DType Accept(TEnum type, Sheet sheet, TitleRow row) + { + object x = row.Current.Value; + if (CheckNull(type.IsNullable, x)) + { + return null; + } + return new DEnum(type, x.ToString()); + } + + + private static string ParseString(object d) + { + if (d == null) + { + return string.Empty; + } + else if (d is string s) + { + return DataUtil.UnEscapeString(s); + } + else + { + return d.ToString(); + } + } + + public DType Accept(TString type, Sheet sheet, TitleRow row) + { + var s = ParseString(row.Current); + if (s == null) + { + if (type.IsNullable) + { + return null; + } + else + { + throw new InvalidExcelDataException("字段不是nullable类型,不能为null"); + } + } + return DString.ValueOf(s); + } + + public DType Accept(TBytes type, Sheet sheet, TitleRow row) + { + throw new NotImplementedException(); + } + + public DType Accept(TText type, Sheet sheet, TitleRow row) + { + string key; + string text; + var sep = GetSep(type); + if (!string.IsNullOrWhiteSpace(sep)) + { + var keyText = row.Current.ToString().Split(sep); + if (keyText.Length != 2) + { + throw new Exception($"'{row.Current}' 不是合法text值"); + } + key = ParseString(keyText[0]); + text = ParseString(keyText[1]); + } + else + { + if (row.Row.Count != 2) + { + throw new Exception($"text 要求两个字段"); + } + key = ParseString(row.Row[0].Value); + text = ParseString(row.Row[1].Value); + } + DataUtil.ValidateText(key, text); + return new DText(key, text); + } + + private List CreateBeanFields(DefBean bean, Sheet sheet, TitleRow row) + { + var list = new List(); + foreach (DefField f in bean.HierarchyFields) + { + string fname = f.Name; + TitleRow field = row.GetSubTitleNamedRow(fname); + if (field == null) + { + throw new Exception($"bean:'{bean.FullName}' 缺失 列:'{fname}',请检查是否写错或者遗漏"); + } + try + { + list.Add(f.CType.Apply(this, sheet, field)); + } + catch (DataCreateException dce) + { + dce.Push(bean, f); + throw; + } + catch (Exception e) + { + var dce = new DataCreateException(e, $"列:{fname}"); + dce.Push(bean, f); + throw dce; + } + } + return list; + } + + public DType Accept(TBean type, Sheet sheet, TitleRow row) + { + string sep = GetSep(type); + + if (row.Row != null) + { + var s = row.AsStream(sep); + return type.Apply(ExcelStreamDataCreator.Ins, s); + + + } + else if (row.Rows != null) + { + throw new NotSupportedException(); + //var s = row.AsMultiRowStream(sep); + //return new DArray(type, ReadList(type.ElementType, s)); + } + else if (row.Fields != null) + { + var originBean = (DefBean)type.Bean; + if (originBean.IsAbstractType) + { + string subType = row.GetSubTitleNamedRow(DefBean.TYPE_NAME_KEY).Current.Value.ToString().Trim(); + if (subType.ToLower() == DefBean.BEAN_NULL_STR) + { + if (!type.IsNullable) + { + throw new Exception($"type:'{type}' 不是可空类型 '{type.Bean.FullName}?' , 不能为空"); + } + return null; + } + string fullType = TypeUtil.MakeFullName(originBean.Namespace, subType); + DefBean implType = (DefBean)originBean.GetNotAbstractChildType(subType); + if (implType == null) + { + throw new Exception($"type:'{fullType}' 不是 bean 类型"); + } + return new DBean(originBean, implType, CreateBeanFields(implType, sheet, row)); + } + else + { + if (type.IsNullable) + { + string subType = row.GetSubTitleNamedRow(DefBean.TYPE_NAME_KEY).Current.Value.ToString().Trim(); + if (subType == DefBean.BEAN_NULL_STR) + { + return null; + } + else if (subType != DefBean.BEAN_NOT_NULL_STR && subType != originBean.Name) + { + throw new Exception($"type:'{type.Bean.FullName}' 可空标识:'{subType}' 不合法(只能为{DefBean.BEAN_NOT_NULL_STR}或{DefBean.BEAN_NULL_STR}或{originBean.Name})"); + } + } + + return new DBean(originBean, originBean, CreateBeanFields(originBean, sheet, row)); + } + + + } + else if (row.Elements != null) + { + throw new NotSupportedException(); + } + else + { + throw new Exception(); + } + } + + public string GetSep(TType type) + { + if (type.Tags.TryGetValue("sep", out var s) && !string.IsNullOrWhiteSpace(s)) + { + return s; + } + switch (type) + { + case TArray ta: return ta.ElementType.Apply(IsNotSepTypeVisitor.Ins) ? "," : ""; + case TList ta: return ta.ElementType.Apply(IsNotSepTypeVisitor.Ins) ? "," : ""; + case TSet ta: return ta.ElementType.Apply(IsNotSepTypeVisitor.Ins) ? "," : ""; + default: return ""; + } + } + + public List ReadList(TType type, ExcelStream stream) + { + var datas = new List(); + while (!stream.TryReadEOF()) + { + datas.Add(type.Apply(ExcelStreamDataCreator.Ins, stream)); + } + return datas; + } + + private static List ReadList(TType type, IEnumerable streams) + { + var datas = new List(); + foreach (var stream in streams) + { + while (!stream.TryReadEOF()) + { + datas.Add(type.Apply(ExcelStreamDataCreator.Ins, stream)); + } + } + return datas; + } + + public DType Accept(TArray type, Sheet sheet, TitleRow row) + { + string sep = GetSep(type); + + if (row.Row != null) + { + var s = row.AsStream(sep); + return new DArray(type, ReadList(type.ElementType, s)); + } + else if (row.Rows != null) + { + var s = row.AsMultiRowStream(sep); + return new DArray(type, ReadList(type.ElementType, s)); + } + else if (row.Fields != null) + { + throw new NotSupportedException(); + } + else if (row.Elements != null) + { + return new DArray(type, row.Elements.Select(e => type.ElementType.Apply(this, sheet, e)).ToList()); + } + else + { + throw new Exception(); + } + } + + public DType Accept(TList type, Sheet sheet, TitleRow row) + { + string sep = GetSep(type); + + if (row.Row != null) + { + var s = row.AsStream(sep); + return new DList(type, ReadList(type.ElementType, s)); + } + else if (row.Rows != null) + { + var s = row.AsMultiRowStream(sep); + return new DList(type, ReadList(type.ElementType, s)); + } + else if (row.Fields != null) + { + throw new NotSupportedException(); + } + else if (row.Elements != null) + { + return new DList(type, row.Elements.Select(e => type.ElementType.Apply(this, sheet, e)).ToList()); + } + else + { + throw new Exception(); + } + } + + public DType Accept(TSet type, Sheet sheet, TitleRow row) + { + string sep = GetSep(type); + + if (row.Row != null) + { + var s = row.AsStream(sep); + return new DSet(type, ReadList(type.ElementType, s)); + } + else if (row.Rows != null) + { + var s = row.AsMultiRowStream(sep); + return new DSet(type, ReadList(type.ElementType, s)); + } + else if (row.Fields != null) + { + throw new NotSupportedException(); + } + else if (row.Elements != null) + { + throw new NotSupportedException(); + } + else + { + throw new Exception(); + } + } + + public DType Accept(TMap type, Sheet sheet, TitleRow row) + { + string sep = GetSep(type); + + if (row.Row != null) + { + var s = row.AsStream(sep); + var datas = new Dictionary(); + + while (!s.TryReadEOF()) + { + var key = type.KeyType.Apply(ExcelStreamDataCreator.Ins, s); + var value = type.ValueType.Apply(ExcelStreamDataCreator.Ins, s); + datas.Add(key, value); + } + + return new DMap(type, datas); + } + else if (row.Rows != null) + { + var datas = new Dictionary(); + foreach (ExcelStream s in row.AsMultiRowStream(sep)) + { + while (!s.TryReadEOF()) + { + var key = type.KeyType.Apply(ExcelStreamDataCreator.Ins, s); + var value = type.ValueType.Apply(ExcelStreamDataCreator.Ins, s); + datas.Add(key, value); + } + } + return new DMap(type, datas); + } + else if (row.Fields != null) + { + var datas = new Dictionary(); + foreach (var e in row.Fields) + { + var keyData = type.KeyType.Apply(StringDataCreator.Ins, e.Key); + var valueData = type.ValueType.Apply(ExcelStreamDataCreator.Ins, e.Value.AsStream(sep)); + datas.Add(keyData, valueData); + } + return new DMap(type, datas); + } + else if (row.Elements != null) + { + throw new NotSupportedException(); + } + else + { + throw new Exception(); + } + } + + public DType Accept(TVector2 type, Sheet sheet, TitleRow row) + { + var d = row.Current.Value; + if (CheckNull(type.IsNullable, d)) + { + return null; + } + return DataUtil.CreateVector(type, d.ToString()); + } + + public DType Accept(TVector3 type, Sheet sheet, TitleRow row) + { + var d = row.Current.Value; + if (CheckNull(type.IsNullable, d)) + { + return null; + } + return DataUtil.CreateVector(type, d.ToString()); + } + + public DType Accept(TVector4 type, Sheet sheet, TitleRow row) + { + var d = row.Current.Value; + if (CheckNull(type.IsNullable, d)) + { + return null; + } + return DataUtil.CreateVector(type, d.ToString()); + } + + public DType Accept(TDateTime type, Sheet sheet, TitleRow row) + { + var d = row.Current.Value; + if (CheckNull(type.IsNullable, d)) + { + return null; + } + if (d is System.DateTime datetime) + { + return new DDateTime(datetime); + } + return DataUtil.CreateDateTime(d.ToString()); + } + } +} diff --git a/src/Luban.Job.Cfg/Source/DataCreators/StringDataCreator.cs b/src/Luban.Job.Cfg/Source/DataCreators/StringDataCreator.cs index 17cca5f..ca044ba 100644 --- a/src/Luban.Job.Cfg/Source/DataCreators/StringDataCreator.cs +++ b/src/Luban.Job.Cfg/Source/DataCreators/StringDataCreator.cs @@ -25,7 +25,7 @@ namespace Luban.Job.Cfg.DataCreators { if (byte.TryParse(x, out var b)) { - return new DByte(b); + return DByte.ValueOf(b); } else { @@ -37,7 +37,7 @@ namespace Luban.Job.Cfg.DataCreators { if (short.TryParse(x, out var b)) { - return new DShort(b); + return DShort.ValueOf(b); } else { @@ -49,7 +49,7 @@ namespace Luban.Job.Cfg.DataCreators { if (short.TryParse(x, out var b)) { - return new DFshort(b); + return DFshort.ValueOf(b); } else { @@ -73,7 +73,7 @@ namespace Luban.Job.Cfg.DataCreators { if (int.TryParse(x, out var b)) { - return new DFint(b); + return DFint.ValueOf(b); } else { @@ -97,7 +97,7 @@ namespace Luban.Job.Cfg.DataCreators { if (long.TryParse(x, out var b)) { - return new DFlong(b); + return DFlong.ValueOf(b); } else { @@ -121,7 +121,7 @@ namespace Luban.Job.Cfg.DataCreators { if (double.TryParse(x, out var b)) { - return new DDouble(b); + return DDouble.ValueOf(b); } else { diff --git a/src/Luban.Job.Cfg/Source/DataCreators/XmlDataCreator.cs b/src/Luban.Job.Cfg/Source/DataCreators/XmlDataCreator.cs index 6db20e8..943cc76 100644 --- a/src/Luban.Job.Cfg/Source/DataCreators/XmlDataCreator.cs +++ b/src/Luban.Job.Cfg/Source/DataCreators/XmlDataCreator.cs @@ -23,17 +23,17 @@ namespace Luban.Job.Cfg.DataCreators public DType Accept(TByte type, XElement x, DefAssembly ass) { - return new DByte(byte.Parse(x.Value.Trim())); + return DByte.ValueOf(byte.Parse(x.Value.Trim())); } public DType Accept(TShort type, XElement x, DefAssembly ass) { - return new DShort(short.Parse(x.Value.Trim())); + return DShort.ValueOf(short.Parse(x.Value.Trim())); } public DType Accept(TFshort type, XElement x, DefAssembly ass) { - return new DFshort(short.Parse(x.Value.Trim())); + return DFshort.ValueOf(short.Parse(x.Value.Trim())); } public DType Accept(TInt type, XElement x, DefAssembly ass) @@ -43,7 +43,7 @@ namespace Luban.Job.Cfg.DataCreators public DType Accept(TFint type, XElement x, DefAssembly ass) { - return new DFint(int.Parse(x.Value.Trim())); + return DFint.ValueOf(int.Parse(x.Value.Trim())); } public DType Accept(TLong type, XElement x, DefAssembly ass) @@ -53,7 +53,7 @@ namespace Luban.Job.Cfg.DataCreators public DType Accept(TFlong type, XElement x, DefAssembly ass) { - return new DFlong(long.Parse(x.Value.Trim())); + return DFlong.ValueOf(long.Parse(x.Value.Trim())); } public DType Accept(TFloat type, XElement x, DefAssembly ass) @@ -63,7 +63,7 @@ namespace Luban.Job.Cfg.DataCreators public DType Accept(TDouble type, XElement x, DefAssembly ass) { - return new DDouble(double.Parse(x.Value.Trim())); + return DDouble.ValueOf(double.Parse(x.Value.Trim())); } public DType Accept(TEnum type, XElement x, DefAssembly ass) diff --git a/src/Luban.Job.Cfg/Source/DataCreators/YamlDataCreator.cs b/src/Luban.Job.Cfg/Source/DataCreators/YamlDataCreator.cs index 7cc0b7f..9af8d09 100644 --- a/src/Luban.Job.Cfg/Source/DataCreators/YamlDataCreator.cs +++ b/src/Luban.Job.Cfg/Source/DataCreators/YamlDataCreator.cs @@ -33,17 +33,17 @@ namespace Luban.Job.Cfg.DataCreators public DType Accept(TByte type, YamlNode x, DefAssembly y) { - return new DByte(byte.Parse(GetLowerTextValue(x))); + return DByte.ValueOf(byte.Parse(GetLowerTextValue(x))); } public DType Accept(TShort type, YamlNode x, DefAssembly y) { - return new DShort(short.Parse(GetLowerTextValue(x))); + return DShort.ValueOf(short.Parse(GetLowerTextValue(x))); } public DType Accept(TFshort type, YamlNode x, DefAssembly y) { - return new DFshort(short.Parse(GetLowerTextValue(x))); + return DFshort.ValueOf(short.Parse(GetLowerTextValue(x))); } public DType Accept(TInt type, YamlNode x, DefAssembly y) @@ -53,7 +53,7 @@ namespace Luban.Job.Cfg.DataCreators public DType Accept(TFint type, YamlNode x, DefAssembly y) { - return new DFint(int.Parse(GetLowerTextValue(x))); + return DFint.ValueOf(int.Parse(GetLowerTextValue(x))); } public DType Accept(TLong type, YamlNode x, DefAssembly y) @@ -63,7 +63,7 @@ namespace Luban.Job.Cfg.DataCreators public DType Accept(TFlong type, YamlNode x, DefAssembly y) { - return new DFlong(long.Parse(GetLowerTextValue(x))); + return DFlong.ValueOf(long.Parse(GetLowerTextValue(x))); } public DType Accept(TFloat type, YamlNode x, DefAssembly y) @@ -73,7 +73,7 @@ namespace Luban.Job.Cfg.DataCreators public DType Accept(TDouble type, YamlNode x, DefAssembly y) { - return new DDouble(double.Parse(GetLowerTextValue(x))); + return DDouble.ValueOf(double.Parse(GetLowerTextValue(x))); } public DType Accept(TEnum type, YamlNode x, DefAssembly y) diff --git a/src/Luban.Job.Cfg/Source/DataSources/Excel/ExcelDataSource.cs b/src/Luban.Job.Cfg/Source/DataSources/Excel/ExcelDataSource.cs index 6d38dda..ae9bf5f 100644 --- a/src/Luban.Job.Cfg/Source/DataSources/Excel/ExcelDataSource.cs +++ b/src/Luban.Job.Cfg/Source/DataSources/Excel/ExcelDataSource.cs @@ -16,96 +16,27 @@ namespace Luban.Job.Cfg.DataSources.Excel private readonly List _sheets = new List(); - private System.Text.Encoding DetectCsvEncoding(Stream fs) - { - Ude.CharsetDetector cdet = new Ude.CharsetDetector(); - cdet.Feed(fs); - cdet.DataEnd(); - fs.Seek(0, SeekOrigin.Begin); - if (cdet.Charset != null) - { - s_logger.Debug("Charset: {}, confidence: {}", cdet.Charset, cdet.Confidence); - return System.Text.Encoding.GetEncoding(cdet.Charset) ?? System.Text.Encoding.Default; - } - else - { - return System.Text.Encoding.Default; - } - } - public override void Load(string rawUrl, string sheetName, Stream stream) { s_logger.Trace("{filename} {sheet}", rawUrl, sheetName); RawUrl = rawUrl; - string ext = Path.GetExtension(rawUrl); - using (var reader = ext != ".csv" ? ExcelReaderFactory.CreateReader(stream) : ExcelReaderFactory.CreateCsvReader(stream, new ExcelReaderConfiguration() { FallbackEncoding = DetectCsvEncoding(stream) })) - { - do - { - if (sheetName == null || reader.Name == sheetName) - { - try - { - var sheet = ReadSheet(rawUrl, reader); - if (sheet != null) - { - _sheets.Add(sheet); - } - } - catch (Exception e) - { - throw new Exception($"excel:{rawUrl} sheet:{reader.Name} 读取失败.", e); - } - } - } while (reader.NextResult()); + + foreach (RawSheet rawSheet in SheetLoadUtil.LoadRawSheets(rawUrl, sheetName, stream)) + { + var sheet = new Sheet(rawUrl, sheetName); + sheet.Load(rawSheet); } + if (_sheets.Count == 0) { throw new Exception($"excel:{rawUrl} 不包含有效的单元薄(有效单元薄的A0单元格必须是##)."); } } - public Sheet LoadFirstSheet(string rawUrl, string sheetName, Stream stream) + public RawSheetTableDefInfo LoadTableDefInfo(string rawUrl, string sheetName, Stream stream) { - s_logger.Trace("{filename} {sheet}", rawUrl, sheetName); - RawUrl = rawUrl; - string ext = Path.GetExtension(rawUrl); - using (var reader = ext != ".csv" ? ExcelReaderFactory.CreateReader(stream) : ExcelReaderFactory.CreateCsvReader(stream)) - { - do - { - if (sheetName == null || reader.Name == sheetName) - { - try - { - var sheet = ReadSheetHeader(rawUrl, reader); - if (sheet != null) - { - return sheet; - } - } - catch (Exception e) - { - throw new Exception($"excel:{rawUrl} sheet:{reader.Name} 读取失败.", e); - } - - } - } while (reader.NextResult()); - } - throw new Exception($"excel:{rawUrl} 不包含有效的单元薄(有效单元薄的A0单元格必须是##)."); - } - - private Sheet ReadSheet(string url, IExcelDataReader reader) - { - var sheet = new Sheet(url, reader.Name ?? ""); - return sheet.Load(reader, false) ? sheet : null; - } - - private Sheet ReadSheetHeader(string url, IExcelDataReader reader) - { - var sheet = new Sheet(url, reader.Name ?? ""); - return sheet.Load(reader, true) ? sheet : null; + return null; } public override List ReadMulti(TBean type) @@ -115,7 +46,11 @@ namespace Luban.Job.Cfg.DataSources.Excel { try { - datas.AddRange(sheet.ReadMulti(type)); + foreach (TitleRow row in sheet.GetRows()) + { + var data = (DBean)type.Apply(SheetDataCreator.Ins, sheet, row); + datas.Add(new Record(data, sheet.RawUrl, row.Tags)); + } } catch (DataCreateException dce) { @@ -132,13 +67,14 @@ namespace Luban.Job.Cfg.DataSources.Excel public override Record ReadOne(TBean type) { - var datas = ReadMulti(type); - switch (datas.Count) - { - case 1: return datas[0]; - case 0: throw new Exception($"单例表不能为空,必须包含且只包含1个记录"); - default: throw new Exception($"单例表必须恰好包含1个记录. 但当前记录数为:{datas.Count}"); - } + //var datas = ReadMulti(type); + //switch (datas.Count) + //{ + // case 1: return datas[0]; + // case 0: throw new Exception($"单例表不能为空,必须包含且只包含1个记录"); + // default: throw new Exception($"单例表必须恰好包含1个记录. 但当前记录数为:{datas.Count}"); + //} + throw new NotSupportedException(); } } } diff --git a/src/Luban.Job.Cfg/Source/DataSources/Excel/ExcelStream.cs b/src/Luban.Job.Cfg/Source/DataSources/Excel/ExcelStream.cs index d3eb008..48720b4 100644 --- a/src/Luban.Job.Cfg/Source/DataSources/Excel/ExcelStream.cs +++ b/src/Luban.Job.Cfg/Source/DataSources/Excel/ExcelStream.cs @@ -18,15 +18,8 @@ namespace Luban.Job.Cfg.DataSources.Excel private readonly int _toIndex; private int _curIndex; - - /// - /// NamedMode下 string可以用空白表达空字符串,而不必用null或"" - /// - public bool NamedMode { get; set; } - - public ExcelStream(List datas, int fromIndex, int toIndex, string sep, bool namedMode) + public ExcelStream(List datas, int fromIndex, int toIndex, string sep) { - NamedMode = namedMode; if (string.IsNullOrWhiteSpace(sep)) { this._datas = datas; @@ -54,9 +47,8 @@ namespace Luban.Job.Cfg.DataSources.Excel } } - public ExcelStream(Cell cell, string sep, bool namedMode) + public ExcelStream(Cell cell, string sep) { - NamedMode = namedMode; if (string.IsNullOrWhiteSpace(sep)) { this._datas = new List { cell }; diff --git a/src/Luban.Job.Cfg/Source/DataSources/Excel/RawSheet.cs b/src/Luban.Job.Cfg/Source/DataSources/Excel/RawSheet.cs new file mode 100644 index 0000000..09616eb --- /dev/null +++ b/src/Luban.Job.Cfg/Source/DataSources/Excel/RawSheet.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Luban.Job.Cfg.DataSources.Excel +{ + + + class RawSheet + { + public Title Title { get; init; } + + public List> Cells { get; init; } + } +} diff --git a/src/Luban.Job.Cfg/Source/DataSources/Excel/RawSheetTableDefInfo.cs b/src/Luban.Job.Cfg/Source/DataSources/Excel/RawSheetTableDefInfo.cs new file mode 100644 index 0000000..6ba1d0f --- /dev/null +++ b/src/Luban.Job.Cfg/Source/DataSources/Excel/RawSheetTableDefInfo.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Luban.Job.Cfg.DataSources.Excel +{ + class FieldInfo + { + public string Type { get; init; } + + public string BriefDesc { get; init; } + + public string DetailDesc { get; init; } + } + + class RawSheetTableDefInfo + { + public Dictionary FieldInfos { get; init; } + } +} diff --git a/src/Luban.Job.Cfg/Source/DataSources/Excel/Sheet.cs b/src/Luban.Job.Cfg/Source/DataSources/Excel/Sheet.cs index 8db5eb2..3241b8b 100644 --- a/src/Luban.Job.Cfg/Source/DataSources/Excel/Sheet.cs +++ b/src/Luban.Job.Cfg/Source/DataSources/Excel/Sheet.cs @@ -2,7 +2,6 @@ using Bright.Collections; using ExcelDataReader; using Luban.Job.Cfg.DataCreators; using Luban.Job.Cfg.Datas; -using Luban.Job.Cfg.Defs; using Luban.Job.Cfg.Utils; using Luban.Job.Common.Types; using Luban.Job.Common.Utils; @@ -12,224 +11,14 @@ using System.Linq; namespace Luban.Job.Cfg.DataSources.Excel { + class Sheet { private static readonly NLog.Logger s_logger = NLog.LogManager.GetCurrentClassLogger(); - private const int TITLE_MIN_ROW_NUM = 2; - private const int TITLE_MAX_ROW_NUM = 10; - private const int TITLE_DEFAULT_ROW_NUM = 3; - - private bool IsOrientRow { get; set; } = true; // 以行为数据读取方向 - - public int HeaderRowCount { get; private set; } = TITLE_DEFAULT_ROW_NUM; // 默认有三行是标题行. 第一行是字段名,第二行是中文描述,第三行是注释 - - public int AttrRowCount { get; private set; } - - public string RawUrl { get; } - public string Name { get; } - private List> _rowColumns; - - private Title _rootTitle; - - public List RootFields => _rootTitle.SubTitleList; - - public List<List<Cell>> RowColumns => _rowColumns; - - - - 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 && 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 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; } - - public Dictionary<string, Title> Titles => SelfTitle.SubTitles; - - public List<Title> TitleList => SelfTitle.SubTitleList; - - public NamedRow(Title selfTitle, List<Cell> row) - { - SelfTitle = selfTitle; - Rows = new List<List<Cell>>() { row }; - } - - public NamedRow(Title selfTitle, List<List<Cell>> rows) - { - SelfTitle = selfTitle; - Rows = rows; - } - - 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) - { - return Titles.TryGetValue(name, out var title) ? title : null; - } - - public ExcelStream GetColumn(string name, string sep, bool namedMode) - { - 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 NamedRow GetSubTitleNamedRow(string name) - { - Title title = Titles[name]; - return new NamedRow(title, this.Rows); - } - - public IEnumerable<NamedRow> GenerateSubNameRows(TBean bean) - { - foreach (var row in Rows) - { - if (SelfTitle != null ? IsBlankRow(row, SelfTitle.FromIndex, SelfTitle.ToIndex) : IsBlankRow(row)) - { - continue; - } - yield return new NamedRow(SelfTitle, row); - } - } - - public IEnumerable<ExcelStream> GetColumnOfMultiRows(string name, string sep, bool isRowOrient) - { - 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},请检查是否写错或者遗漏"); - } - } - - - public ExcelStream GetMultiRowStream(string name, string sep, bool isRowOrient) - { - if (Titles.TryGetValue(name, out var title)) - { - if (isRowOrient) - { - var totalCells = Rows.SelectMany(r => r.GetRange(title.FromIndex, title.ToIndex - title.FromIndex + 1)) - .Where(c => c.Value != null && !(c.Value is string s && string.IsNullOrWhiteSpace(s))).ToList(); - return new ExcelStream(totalCells, 0, totalCells.Count - 1, sep, false); - } - else - { - throw new NotSupportedException($"bean类型多行数据不支持纵向填写"); - } - } - else - { - throw new Exception($"单元薄 缺失 列:{name},请检查是否写错或者遗漏"); - } - } - } + public string RawUrl { get; } public Sheet(string rawUrl, string name) { @@ -237,401 +26,14 @@ namespace Luban.Job.Cfg.DataSources.Excel this.Name = name; } - public bool Load(IExcelDataReader reader, bool headerOnly) + public void Load(RawSheet rawSheet) { - //s_logger.Info("read sheet:{sheet}", reader.Name); - if (!ParseMeta(reader)) - { - return false; - } - - LoadRemainRows(reader, headerOnly); - - return true; - } - - private bool ParseMeta(IExcelDataReader reader) - { - if (!reader.Read() || reader.FieldCount == 0) - { - return false; - } - // meta 行 必须以 ##为第一个单元格内容,紧接着 key:value 形式 表达meta属性 - if (reader.GetString(0) != "##") - { - return false; - } - - for (int i = 1, n = reader.FieldCount; i < n; i++) - { - var attr = reader.GetString(i); - if (string.IsNullOrWhiteSpace(attr)) - { - continue; - } - - var ss = attr.Split(':', '='); - if (ss.Length != 2) - { - throw new Exception($"单元薄 meta 定义出错. attribute:{attr}"); - } - string key = ss[0].ToLower(); - string value = ss[1].ToLower(); - switch (key) - { - case "orientation": - { - IsOrientRow = DefUtil.ParseOrientation(value); - break; - } - case "title_rows": - { - if (!int.TryParse(value, out var v)) - { - throw new Exception($"单元薄 meta 定义 title_rows:{value} 属性值只能为整数[{TITLE_MIN_ROW_NUM},{TITLE_MAX_ROW_NUM}]"); - } - if (v < TITLE_MIN_ROW_NUM || v > TITLE_MAX_ROW_NUM) - { - throw new Exception($"单元薄 title_rows 应该在 [{TITLE_MIN_ROW_NUM},{TITLE_MAX_ROW_NUM}] 范围内,默认是{TITLE_DEFAULT_ROW_NUM}"); - } - HeaderRowCount = v; - break; - } - case "table": - { - break; - } - default: - { - throw new Exception($"非法单元薄 meta 属性定义 {attr}, 合法属性有: orientation=r|row|c|column,title_rows=<number>"); - } - } - } - return true; - } - - private static string GetRowTag(List<Cell> row) - { - if (row.Count == 0) - { - return null; - } - if (row[0].Value == null) - { - return null; - } - return row[0].Value.ToString().Trim(); - } - - private void InitSubTitles(Title parentTitle, List<List<Cell>> rows, CellRange[] mergeCells, int maxDepth, int depth, int fromColumn, int toColumn) - { - List<Cell> row = rows[depth]; - - //if (row.Count > fromColumn) - //{ - // row = row.GetRange(fromColumn, Math.Min(row.Count, toColumn + 1) - fromColumn); - //} - - - foreach (var mergeCell in mergeCells) - { - if (mergeCell.FromRow == depth + 1 && mergeCell.FromColumn >= fromColumn && mergeCell.ToColumn <= toColumn) - { - string subTitleName = row[mergeCell.FromColumn].Value?.ToString()?.Trim(); - if (!string.IsNullOrWhiteSpace(subTitleName)) - { - var newTitle = new Title() { Name = subTitleName, FromIndex = mergeCell.FromColumn, ToIndex = mergeCell.ToColumn }; - if (depth + 1 < maxDepth) - { - InitSubTitles(newTitle, rows, mergeCells, maxDepth, depth + 1, mergeCell.FromColumn, mergeCell.ToColumn); - } - - parentTitle.AddSubTitle(newTitle); - } - } - } - - for (int i = fromColumn; i <= toColumn; i++) - { - if (i >= row.Count) - { - break; - } - - var name = row[i].Value?.ToString()?.Trim(); - if (string.IsNullOrWhiteSpace(name)) - { - continue; - } - - if (parentTitle.SubTitles.TryGetValue(name, out var oldTitle)) - { - if (oldTitle.FromIndex != i) - { - throw new Exception($"sub title 列:{name} 重复"); - } - else - { - continue; - } - } - var newTitle = new Title() { Name = name, FromIndex = i, ToIndex = i }; - if (depth + 1 < maxDepth) - { - InitSubTitles(newTitle, rows, mergeCells, maxDepth, depth + 1, i, i); - } - parentTitle.AddSubTitle(newTitle); - } - } - - const string ROOT_TITLE_NAME = "__<root>__"; - - private void LoadRemainRows(IExcelDataReader reader, bool headerOnly) - { - // TODO 优化性能 - // 几个思路 - // 1. 没有 title 的列不加载 - // 2. 空行优先跳过 - // 3. 跳过null或者empty的单元格 - var rows = new List<List<Cell>>(); - int rowIndex = 0; - while (reader.Read()) - { - ++rowIndex; // 第1行是 meta ,标题及数据行从第2行开始 - // 重点优化横表的headerOnly模式, 此模式下只读前几行标题行,不读数据行 - if (headerOnly && this.IsOrientRow && rowIndex > this.HeaderRowCount) - { - break; - } - var row = new List<Cell>(); - for (int i = 0, n = reader.FieldCount; i < n; i++) - { - row.Add(new Cell(rowIndex, i, reader.GetValue(i))); - } - rows.Add(row); - } - - if (IsOrientRow) - { - this._rowColumns = rows; - } - else - { - // 转置这个行列 - int maxColumn = rows.Select(r => r.Count).Max(); - this._rowColumns = new List<List<Cell>>(); - for (int i = 0; i < maxColumn; i++) - { - var row = new List<Cell>(); - for (int j = 0; j < rows.Count; j++) - { - row.Add(i < rows[j].Count ? rows[j][i] : new Cell(j + 1, i, null)); - } - this._rowColumns.Add(row); - } - } - - if (this._rowColumns.Count < 1) - { - throw new Exception($"没有定义字段名行"); - } - - _rootTitle = new Title() { Root = true, Name = ROOT_TITLE_NAME, FromIndex = 1, ToIndex = rows.Select(r => r.Count).Max() - 1 }; - - int fieldRowCount = 1; - int attrRowCount = 1; - if (reader.MergeCells != null) - { - if (IsOrientRow) - { - foreach (var mergeCell in reader.MergeCells) - { - if (mergeCell.FromRow == 1 && mergeCell.FromColumn == 0 && mergeCell.ToColumn == 0) - { - fieldRowCount = mergeCell.ToRow - mergeCell.FromRow + 1; - break; - } - } - foreach (var mergeCell in reader.MergeCells) - { - if (mergeCell.FromRow == 1 + fieldRowCount && mergeCell.FromColumn == 0 && mergeCell.ToColumn == 0) - { - attrRowCount = mergeCell.ToRow - mergeCell.FromRow + 1; - break; - } - } - } - - - foreach (var mergeCell in reader.MergeCells) - { - if (IsOrientRow) - { - //if (mergeCell.FromRow <= 1 && mergeCell.ToRow >= 1) - if (mergeCell.FromRow == 1) - { - // 标题 行 - fieldRowCount = Math.Max(fieldRowCount, mergeCell.ToRow - mergeCell.FromRow + 1); - var titleName = _rowColumns[0][mergeCell.FromColumn].Value?.ToString()?.Trim(); - if (string.IsNullOrWhiteSpace(titleName)) - { - continue; - } - - var newTitle = new Title() { Name = titleName, FromIndex = mergeCell.FromColumn, ToIndex = mergeCell.ToColumn }; - if (fieldRowCount > 1) - { - InitSubTitles(newTitle, rows, reader.MergeCells, fieldRowCount, 1, mergeCell.FromColumn, mergeCell.ToColumn); - } - _rootTitle.AddSubTitle(newTitle); - //s_logger.Info("=== sheet:{sheet} title:{title}", Name, newTitle); - } - } - else - { - if (mergeCell.FromColumn <= 0 && mergeCell.ToColumn >= 0) - { - // 标题 行 - var titleName = _rowColumns[0][mergeCell.FromRow - 1].Value?.ToString()?.Trim(); - if (string.IsNullOrWhiteSpace(titleName)) - { - continue; - } - - _rootTitle.AddSubTitle(new Title() { Name = titleName, FromIndex = mergeCell.FromRow - 1, ToIndex = mergeCell.ToRow - 1 }); - } - } - - } - } - this.AttrRowCount = attrRowCount; - - //TODO 其实有bug. 未处理只占一列的 多级标题头 - - // 上面的代码处理完Merge列,接下来处理非Merge的列 - var titleRow = _rowColumns[0]; - for (int i = 0; i < titleRow.Count; i++) - { - var name = titleRow[i].Value?.ToString()?.Trim(); - if (string.IsNullOrWhiteSpace(name)) - { - continue; - } - - if (_rootTitle.SubTitles.TryGetValue(name, out var oldTitle)) - { - if (oldTitle.FromIndex != i) - { - throw new Exception($"列:{name} 重复"); - } - else - { - continue; - } - } - _rootTitle.AddSubTitle(new Title() { Name = name, FromIndex = i, ToIndex = i }); - } - if (_rootTitle.SubTitleList.Count == 0) - { - throw new Exception($"没有定义任何有效 列"); - } - _rootTitle.SortSubTitles(); - - if (headerOnly) - { - // 删除字段名行,保留属性行开始的行 - this._rowColumns.RemoveRange(0, Math.Min(fieldRowCount, this._rowColumns.Count)); - } - else - { - // 删除所有标题行,包含字段名行、属性行、标题、描述等等非有效数据行 - this._rowColumns.RemoveRange(0, Math.Min(HeaderRowCount, this._rowColumns.Count)); - // 删除忽略的记录行 - this._rowColumns.RemoveAll(row => DataUtil.IsIgnoreTag(GetRowTag(row))); - } } - private static bool IsBlankRow(List<Cell> row) + public IEnumerable<TitleRow> GetRows() { - // 第一列被策划用于表示是否注释掉此行 - // 忽略此列是否空白 - return row.GetRange(1, row.Count - 1).All(c => c.Value == null || (c.Value is string s && string.IsNullOrWhiteSpace(s))); - } - - 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++) - { - var v = row[i].Value; - if (v != null && !(v is string s && string.IsNullOrEmpty(s))) - { - return false; - } - } - 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; - } - - private static bool IsBlankColumn(List<List<Cell>> rows, int column) - { - foreach (List<Cell> row in rows) - { - if (column >= row.Count) - { - continue; - } - var v = row[column].Value; - if (v != null && !(v is string s && string.IsNullOrEmpty(s))) - { - return false; - } - } - return true; - } - - public IEnumerable<Record> ReadMulti(TBean type) - { - foreach (var recordNamedRow in NamedRow.CreateMultiRowNamedRow(this._rowColumns, this._rootTitle, type)) - { - var tags = DataUtil.ParseTags(GetRowTag(recordNamedRow.Rows[0])); - var data = (DBean)ExcelNamedRowDataCreator.Ins.ReadExcel(recordNamedRow, type); - yield return new Record(data, RawUrl, tags); - } + yield return null; } } } diff --git a/src/Luban.Job.Cfg/Source/DataSources/Excel/SheetLoadUtil.cs b/src/Luban.Job.Cfg/Source/DataSources/Excel/SheetLoadUtil.cs new file mode 100644 index 0000000..75b4ab6 --- /dev/null +++ b/src/Luban.Job.Cfg/Source/DataSources/Excel/SheetLoadUtil.cs @@ -0,0 +1,466 @@ +using ExcelDataReader; +using Luban.Job.Common.Utils; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Luban.Job.Cfg.DataSources.Excel +{ + static class SheetLoadUtil + { + private static readonly NLog.Logger s_logger = NLog.LogManager.GetCurrentClassLogger(); + + private const int TITLE_MIN_ROW_NUM = 2; + private const int TITLE_MAX_ROW_NUM = 10; + private const int TITLE_DEFAULT_ROW_NUM = 3; + + //private bool IsOrientRow { get; set; } = true; // 以行为数据读取方向 + + //public int HeaderRowCount { get; private set; } = TITLE_DEFAULT_ROW_NUM; // 默认有三行是标题行. 第一行是字段名,第二行是中文描述,第三行是注释 + + //public int AttrRowCount { get; private set; } + + //public string RawUrl { get; } + + //public string Name { get; } + + //private List<List<Cell>> _rowColumns; + + //private Title _rootTitle; + + //public List<Title> RootFields => _rootTitle.SubTitleList; + + //public List<List<Cell>> RowColumns => _rowColumns; + + private static System.Text.Encoding DetectCsvEncoding(Stream fs) + { + Ude.CharsetDetector cdet = new Ude.CharsetDetector(); + cdet.Feed(fs); + cdet.DataEnd(); + fs.Seek(0, SeekOrigin.Begin); + if (cdet.Charset != null) + { + s_logger.Debug("Charset: {}, confidence: {}", cdet.Charset, cdet.Confidence); + return System.Text.Encoding.GetEncoding(cdet.Charset) ?? System.Text.Encoding.Default; + } + else + { + return System.Text.Encoding.Default; + } + } + + public static IEnumerable<RawSheet> LoadRawSheets(string rawUrl, string sheetName, Stream stream) + { + s_logger.Trace("{filename} {sheet}", rawUrl, sheetName); + string ext = Path.GetExtension(rawUrl); + using (var reader = ext != ".csv" ? ExcelReaderFactory.CreateReader(stream) : ExcelReaderFactory.CreateCsvReader(stream, new ExcelReaderConfiguration() { FallbackEncoding = DetectCsvEncoding(stream) })) + { + do + { + if (sheetName == null || reader.Name == sheetName) + { + RawSheet sheet; + try + { + sheet = ParseRawSheet(reader); + } + catch (Exception e) + { + throw new Exception($"excel:{rawUrl} sheet:{reader.Name} 读取失败.", e); + } + if (sheet != null) + { + yield return sheet; + } + } + } while (reader.NextResult()); + } + } + + private static RawSheet ParseRawSheet(IExcelDataReader reader) + { + bool orientRow; + int titleRowNum; + + if (!TryParseMeta(reader, out orientRow, out titleRowNum, out var _)) + { + return null; + } + var cells = ParseRawSheetContent(reader, orientRow); + var title = ParseTitle(cells, reader.MergeCells, orientRow); + cells.RemoveRange(0, Math.Min(titleRowNum, cells.Count)); + return new RawSheet() { Title = title, Cells = cells }; + } + + private static int GetTitleRowNum(CellRange[] mergeCells, bool orientRow) + { + if (mergeCells == null) + { + return 1; + } + if (orientRow) + { + foreach (var mergeCell in mergeCells) + { + if (mergeCell.FromRow == 1 && mergeCell.FromColumn == 0) + { + return mergeCell.ToRow - mergeCell.FromRow + 1; + } + } + } + else + { + foreach (var mergeCell in mergeCells) + { + if (mergeCell.FromColumn == 1 && mergeCell.FromRow == 0) + { + return mergeCell.ToColumn - mergeCell.FromColumn + 1; + } + } + } + return 1; + } + + public static Title ParseTitle(List<List<Cell>> cells, CellRange[] mergeCells, bool orientRow) + { + var rootTitle = new Title() { Root = true, Name = "__root__", FromIndex = 0, ToIndex = cells.Select(r => r.Count).Max() - 1 }; + + int titleRowNum = GetTitleRowNum(mergeCells, orientRow); + + ParseSubTitles(rootTitle, cells, mergeCells, orientRow, 1, titleRowNum); + + rootTitle.SortSubTitles(); + + if (rootTitle.SubTitleList.Count == 0) + { + throw new Exception($"没有定义任何有效 列"); + } + return rootTitle; + } + + private static bool IsIgnoreTitle(string title) + { + return string.IsNullOrEmpty(title) || title.StartsWith('#'); + } + + private static (string Name, string Sep) ParseNameAndMetaAttrs(string nameAndAttrs) + { + var attrs = nameAndAttrs.Split('&'); + + string titleName = attrs[0]; + string sep = ""; + foreach (var attrPair in attrs.Skip(1)) + { + var pairs = attrPair.Split('='); + if (pairs.Length != 2) + { + throw new Exception($"invalid title: {nameAndAttrs}"); + } + switch (pairs[0]) + { + case "sep": + { + sep = pairs[1]; + break; + } + default: + { + throw new Exception($"invalid title: {nameAndAttrs}"); + } + } + } + return (titleName, sep); + } + + private static void ParseSubTitles(Title title, List<List<Cell>> cells, CellRange[] mergeCells, bool orientRow, int curDepth, int maxDepth) + { + + var titleRow = cells[curDepth - 1]; + foreach (var mergeCell in mergeCells) + { + Title subTitle = null; + if (orientRow) + { + //if (mergeCell.FromRow <= 1 && mergeCell.ToRow >= 1) + if (mergeCell.FromRow == curDepth) + { + var nameAndAttrs = titleRow[mergeCell.FromColumn].Value?.ToString()?.Trim(); + if (IsIgnoreTitle(nameAndAttrs)) + { + continue; + } + var (titleName, sep) = ParseNameAndMetaAttrs(nameAndAttrs); + subTitle = new Title() { Name = titleName, Sep = sep, FromIndex = mergeCell.FromColumn, ToIndex = mergeCell.ToColumn }; + //s_logger.Info("=== sheet:{sheet} title:{title}", Name, newTitle); + } + } + else + { + if (mergeCell.FromColumn == curDepth - 1) + { + // 标题 行 + var nameAndAttrs = titleRow[mergeCell.FromRow - 1].Value?.ToString()?.Trim(); + if (IsIgnoreTitle(nameAndAttrs)) + { + continue; + } + var (titleName, sep) = ParseNameAndMetaAttrs(nameAndAttrs); + subTitle = new Title() { Name = titleName, Sep = sep, FromIndex = mergeCell.FromRow - 1, ToIndex = mergeCell.ToRow - 1 }; + } + } + if (subTitle == null) + { + continue; + } + + if (curDepth < maxDepth) + { + ParseSubTitles(subTitle, cells, mergeCells, orientRow, curDepth + 1, maxDepth); + } + title.AddSubTitle(subTitle); + + } + + for (int i = 0; i < titleRow.Count; i++) + { + var nameAndAttrs = titleRow[i].Value?.ToString()?.Trim(); + if (IsIgnoreTitle(nameAndAttrs)) + { + continue; + } + var (titleName, sep) = ParseNameAndMetaAttrs(nameAndAttrs); + + if (title.SubTitles.TryGetValue(titleName, out var oldTitle)) + { + if (oldTitle.FromIndex != i) + { + throw new Exception($"列:{titleName} 重复"); + } + else + { + continue; + } + } + title.AddSubTitle(new Title() { Name = titleName, Sep = sep, FromIndex = i, ToIndex = i }); + } + } + + + public static RawSheetTableDefInfo LoadSheetTableDefInfo(string rawUrl, string sheetName, Stream stream) + { + s_logger.Trace("{filename} {sheet}", rawUrl, sheetName); + string ext = Path.GetExtension(rawUrl); + //using (var reader = ext != ".csv" ? ExcelReaderFactory.CreateReader(stream) : ExcelReaderFactory.CreateCsvReader(stream, new ExcelReaderConfiguration() { FallbackEncoding = DetectCsvEncoding(stream) })) + //{ + // do + // { + // if (sheetName == null || reader.Name == sheetName) + // { + // try + // { + // var sheet = ReadSheet(rawUrl, reader); + // if (sheet != null) + // { + // _sheets.Add(sheet); + // } + // } + // catch (Exception e) + // { + // throw new Exception($"excel:{rawUrl} sheet:{reader.Name} 读取失败.", e); + // } + + // } + // } while (reader.NextResult()); + //} + return null; + } + + public static bool TryParseMeta(IExcelDataReader reader, out bool orientRow, out int titleRows, out string tableName) + { + orientRow = true; + titleRows = TITLE_DEFAULT_ROW_NUM; + tableName = ""; + if (!reader.Read() || reader.FieldCount == 0) + { + return false; + } + // meta 行 必须以 ##为第一个单元格内容,紧接着 key:value 形式 表达meta属性 + if (reader.GetString(0) != "##") + { + return false; + } + + for (int i = 1, n = reader.FieldCount; i < n; i++) + { + var attr = reader.GetString(i)?.Trim(); + if (string.IsNullOrWhiteSpace(attr)) + { + continue; + } + + var ss = attr.Split('='); + if (ss.Length != 2) + { + throw new Exception($"单元薄 meta 定义出错. attribute:{attr}"); + } + string key = ss[0].Trim().ToLower(); + string value = ss[1].Trim().ToLower(); + switch (key) + { + case "orientation": + { + orientRow = DefUtil.ParseOrientation(value); + break; + } + case "title_rows": + { + if (!int.TryParse(value, out var v)) + { + throw new Exception($"单元薄 meta 定义 title_rows:{value} 属性值只能为整数[{TITLE_MIN_ROW_NUM},{TITLE_MAX_ROW_NUM}]"); + } + if (v < TITLE_MIN_ROW_NUM || v > TITLE_MAX_ROW_NUM) + { + throw new Exception($"单元薄 title_rows 应该在 [{TITLE_MIN_ROW_NUM},{TITLE_MAX_ROW_NUM}] 范围内,默认是{TITLE_DEFAULT_ROW_NUM}"); + } + titleRows = v; + break; + } + case "table": + { + tableName = value; + break; + } + default: + { + throw new Exception($"非法单元薄 meta 属性定义 {attr}, 合法属性有: orientation=r|row|c|column,title_rows=<number>,table=<tableName>"); + } + } + } + return true; + } + + private static List<List<Cell>> ParseRawSheetContent(IExcelDataReader reader, bool orientRow) + { + // TODO 优化性能 + // 几个思路 + // 1. 没有 title 的列不加载 + // 2. 空行优先跳过 + // 3. 跳过null或者empty的单元格 + var originRows = new List<List<Cell>>(); + int rowIndex = 0; + while (reader.Read()) + { + ++rowIndex; // 第1行是 meta ,标题及数据行从第2行开始 + var row = new List<Cell>(); + for (int i = 0, n = reader.FieldCount; i < n; i++) + { + row.Add(new Cell(rowIndex, i, reader.GetValue(i))); + } + originRows.Add(row); + } + + List<List<Cell>> finalRows; + + if (orientRow) + { + finalRows = originRows; + } + else + { + // 转置这个行列 + int maxColumn = originRows.Select(r => r.Count).Max(); + finalRows = new List<List<Cell>>(); + for (int i = 0; i < maxColumn; i++) + { + var row = new List<Cell>(); + for (int j = 0; j < originRows.Count; j++) + { + row.Add(i < originRows[j].Count ? originRows[j][i] : new Cell(j + 1, i, null)); + } + finalRows.Add(row); + } + } + return finalRows; + } + + + + 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))); + } + + 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++) + { + var v = row[i].Value; + if (v != null && !(v is string s && string.IsNullOrEmpty(s))) + { + return false; + } + } + 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; + } + + private static bool IsBlankColumn(List<List<Cell>> rows, int column) + { + foreach (List<Cell> row in rows) + { + if (column >= row.Count) + { + continue; + } + var v = row[column].Value; + if (v != null && !(v is string s && string.IsNullOrEmpty(s))) + { + return false; + } + } + return true; + } + + + + } +} diff --git a/src/Luban.Job.Cfg/Source/DataSources/Excel/TitleRow.cs b/src/Luban.Job.Cfg/Source/DataSources/Excel/TitleRow.cs new file mode 100644 index 0000000..151fc26 --- /dev/null +++ b/src/Luban.Job.Cfg/Source/DataSources/Excel/TitleRow.cs @@ -0,0 +1,237 @@ +using Luban.Job.Cfg.Defs; +using Luban.Job.Common.Types; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Luban.Job.Cfg.DataSources.Excel +{ + class TitleRow + { + 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 Cell Current => Row[0]; + + public List<Cell> Row { get; } + + public List<List<Cell>> Rows { get; } + + public Dictionary<string, TitleRow> Fields { get; } + + public List<TitleRow> Elements { get; } + + public ExcelStream AsStream(string sep) => new ExcelStream(Row, 0, Row.Count - 1, sep); + + public bool HasSubFields => Fields != null || Elements != null; + + public TitleRow(Title selfTitle, List<Cell> row) + { + SelfTitle = selfTitle; + Row = row; + } + + public TitleRow(Title selfTitle, List<List<Cell>> rows) + { + SelfTitle = selfTitle; + Rows = rows; + } + + public TitleRow(Title selfTitle, Dictionary<string, TitleRow> fields) + { + SelfTitle = selfTitle; + Fields = fields; + } + + public TitleRow(Title selfTitle, List<TitleRow> elements) + { + SelfTitle = selfTitle; + Elements = elements; + } + + 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) + { + 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) + { + //Title title = Titles[name]; + //return new TitleRow(title, this.Rows); + 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) + { + foreach (var ele in GetSubTitleNamedRow(name).Elements) + { + 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},请检查是否写错或者遗漏"); + //} + } + + + public IEnumerable<ExcelStream> AsMultiRowStream(string sep) + { + //if (Titles.TryGetValue(name, out var title)) + //{ + // if (isRowOrient) + // { + // var totalCells = Rows.SelectMany(r => r.GetRange(title.FromIndex, title.ToIndex - title.FromIndex + 1)) + // .Where(c => c.Value != null && !(c.Value is string s && string.IsNullOrWhiteSpace(s))).ToList(); + // return new ExcelStream(totalCells, 0, totalCells.Count - 1, sep, false); + // } + // else + // { + // throw new NotSupportedException($"bean类型多行数据不支持纵向填写"); + // } + //} + //else + //{ + // throw new Exception($"单元薄 缺失 列:{name},请检查是否写错或者遗漏"); + //} + throw new NotSupportedException(); + } + } +} diff --git a/src/Luban.Job.Cfg/Source/DataVisitors/ResourceExportor.cs b/src/Luban.Job.Cfg/Source/DataVisitors/ResourceExportor.cs index ff35393..e52ec82 100644 --- a/src/Luban.Job.Cfg/Source/DataVisitors/ResourceExportor.cs +++ b/src/Luban.Job.Cfg/Source/DataVisitors/ResourceExportor.cs @@ -68,10 +68,11 @@ namespace Luban.Job.Cfg.DataVisitors public void Accept(DString type, DefField x, List<ResourceInfo> y) { - if (!string.IsNullOrEmpty(type.Value)) - { - y.Add(new ResourceInfo() { Resource = type.Value, Tag = x.ResourceTag }); - } + //if (!string.IsNullOrEmpty(type.Value)) + //{ + // y.Add(new ResourceInfo() { Resource = type.Value, Tag = x.ResourceTag }); + //} + throw new NotSupportedException(); } public void Accept(DBytes type, DefField x, List<ResourceInfo> y) @@ -91,26 +92,28 @@ namespace Luban.Job.Cfg.DataVisitors { return; } - int index = 0; - foreach (DType fieldData in type.Fields) - { - var fieldDef = (DefField)def.HierarchyFields[index++]; - if (fieldDef.IsResource) - { - fieldData.Apply(this, fieldDef, y); - } - } + //int index = 0; + //foreach (DType fieldData in type.Fields) + //{ + // var fieldDef = (DefField)def.HierarchyFields[index++]; + // if (fieldDef.IsResource) + // { + // fieldData.Apply(this, fieldDef, y); + // } + //} + throw new NotSupportedException(); } private void Accept(DefField def, List<DType> datas, TType elementType, List<ResourceInfo> ress) { - if (def.IsResource || (elementType is TBean)) - { - foreach (var e in datas) - { - e.Apply(this, def, ress); - } - } + //if (def.IsResource || (elementType is TBean)) + //{ + // foreach (var e in datas) + // { + // e.Apply(this, def, ress); + // } + //} + throw new NotSupportedException(); } public void Accept(DArray type, DefField x, List<ResourceInfo> y) @@ -130,13 +133,14 @@ namespace Luban.Job.Cfg.DataVisitors public void Accept(DMap type, DefField x, List<ResourceInfo> y) { - if (x.IsResource || (type.Type.ValueType is TBean)) - { - foreach (var e in type.Datas.Values) - { - e.Apply(this, x, y); - } - } + //if (x.IsResource || (type.Type.ValueType is TBean)) + //{ + // foreach (var e in type.Datas.Values) + // { + // e.Apply(this, x, y); + // } + //} + throw new NotSupportedException(); } public void Accept(DVector2 type, DefField x, List<ResourceInfo> y) diff --git a/src/Luban.Job.Cfg/Source/DataVisitors/ValidatorVisitor.cs b/src/Luban.Job.Cfg/Source/DataVisitors/ValidatorVisitor.cs index 814fd70..243adfa 100644 --- a/src/Luban.Job.Cfg/Source/DataVisitors/ValidatorVisitor.cs +++ b/src/Luban.Job.Cfg/Source/DataVisitors/ValidatorVisitor.cs @@ -117,165 +117,165 @@ namespace Luban.Job.Cfg.DataVisitors { return; } - var defFields = record.ImplType.HierarchyFields; - int i = 0; - foreach (var fieldValue in record.Fields) - { - var defField = (DefField)defFields[i++]; - _path.Push(defField.Name); - switch (defField.CType) - { - case TArray a: - { - if (defField.ValueValidators.Count > 0) - { - var arr = (DArray)fieldValue; - int index = 0; - foreach (var value in arr.Datas) - { - _path.Push(index++); - foreach (var v in defField.ValueValidators) - { - v.Validate(Ctx, value, defField.IsNullable); - } - _path.Pop(); - } + //var defFields = record.ImplType.HierarchyFields; + //int i = 0; + //foreach (var fieldValue in record.Fields) + //{ + // var defField = (DefField)defFields[i++]; + // _path.Push(defField.Name); + // switch (defField.CType) + // { + // case TArray a: + // { + // if (defField.ValueValidators.Count > 0) + // { + // var arr = (DArray)fieldValue; + // int index = 0; + // foreach (var value in arr.Datas) + // { + // _path.Push(index++); + // foreach (var v in defField.ValueValidators) + // { + // v.Validate(Ctx, value, defField.IsNullable); + // } + // _path.Pop(); + // } - } - if (a.ElementType is TBean) - { - var arr = (DArray)fieldValue; - int index = 0; - foreach (var value in arr.Datas) - { - _path.Push(index++); - Accept((DBean)value, assembly); - _path.Pop(); - } + // } + // if (a.ElementType is TBean) + // { + // var arr = (DArray)fieldValue; + // int index = 0; + // foreach (var value in arr.Datas) + // { + // _path.Push(index++); + // Accept((DBean)value, assembly); + // _path.Pop(); + // } - } - break; - } - case TList b: - { - if (defField.ValueValidators.Count > 0) - { - var arr = (DList)fieldValue; - int index = 0; - foreach (var value in arr.Datas) - { - _path.Push(index++); - foreach (var v in defField.ValueValidators) - { - v.Validate(Ctx, value, false); - } - _path.Pop(); - } + // } + // break; + // } + // case TList b: + // { + // if (defField.ValueValidators.Count > 0) + // { + // var arr = (DList)fieldValue; + // int index = 0; + // foreach (var value in arr.Datas) + // { + // _path.Push(index++); + // foreach (var v in defField.ValueValidators) + // { + // v.Validate(Ctx, value, false); + // } + // _path.Pop(); + // } - } - if (b.ElementType is TBean tb) - { - var arr = (DList)fieldValue; - int index = 0; - foreach (var value in arr.Datas) - { - _path.Push(index++); - Accept((DBean)value, assembly); - _path.Pop(); - } + // } + // if (b.ElementType is TBean tb) + // { + // var arr = (DList)fieldValue; + // int index = 0; + // foreach (var value in arr.Datas) + // { + // _path.Push(index++); + // Accept((DBean)value, assembly); + // _path.Pop(); + // } - if (defField.IndexField != null) - { - var indexSet = new HashSet<DType>(); - if (!tb.GetBeanAs<DefBean>().TryGetField(defField.Index, out var _, out var indexOfIndexField)) - { - throw new Exception("impossible"); - } - foreach (var value in arr.Datas) - { - _path.Push(index++); - DType indexValue = ((DBean)value).Fields[indexOfIndexField]; - if (!indexSet.Add(indexValue)) - { - throw new Exception($"'{TypeUtil.MakeFullName(_path)}' index:'{indexValue}' 重复"); - } - _path.Pop(); - } - } - } - break; - } - case TSet c: - { - if (defField.ValueValidators.Count > 0) - { - var arr = (DSet)fieldValue; - foreach (var value in arr.Datas) - { - foreach (var v in defField.ValueValidators) - { - v.Validate(Ctx, value, false); - } - } + // if (defField.IndexField != null) + // { + // var indexSet = new HashSet<DType>(); + // if (!tb.GetBeanAs<DefBean>().TryGetField(defField.Index, out var _, out var indexOfIndexField)) + // { + // throw new Exception("impossible"); + // } + // foreach (var value in arr.Datas) + // { + // _path.Push(index++); + // DType indexValue = ((DBean)value).Fields[indexOfIndexField]; + // if (!indexSet.Add(indexValue)) + // { + // throw new Exception($"'{TypeUtil.MakeFullName(_path)}' index:'{indexValue}' 重复"); + // } + // _path.Pop(); + // } + // } + // } + // break; + // } + // case TSet c: + // { + // if (defField.ValueValidators.Count > 0) + // { + // var arr = (DSet)fieldValue; + // foreach (var value in arr.Datas) + // { + // foreach (var v in defField.ValueValidators) + // { + // v.Validate(Ctx, value, false); + // } + // } - } - break; - } + // } + // break; + // } - case TMap m: - { - DMap map = (DMap)fieldValue; - if (defField.KeyValidators.Count > 0) - { - foreach (var key in map.Datas.Keys) - { - _path.Push(key); - foreach (var v in defField.KeyValidators) - { - v.Validate(Ctx, key, false); - } - _path.Pop(); - } - } - if (defField.ValueValidators.Count > 0) - { - foreach (var value in map.Datas.Values) - { - _path.Push(value); - foreach (var v in defField.ValueValidators) - { - v.Validate(Ctx, value, false); - } + // case TMap m: + // { + // DMap map = (DMap)fieldValue; + // if (defField.KeyValidators.Count > 0) + // { + // foreach (var key in map.Datas.Keys) + // { + // _path.Push(key); + // foreach (var v in defField.KeyValidators) + // { + // v.Validate(Ctx, key, false); + // } + // _path.Pop(); + // } + // } + // if (defField.ValueValidators.Count > 0) + // { + // foreach (var value in map.Datas.Values) + // { + // _path.Push(value); + // foreach (var v in defField.ValueValidators) + // { + // v.Validate(Ctx, value, false); + // } - if (value is DBean dv) - { - Accept(dv, assembly); - } - _path.Pop(); - } - } - break; - } - case TBean n: - { - Accept((DBean)fieldValue, assembly); - break; - } - default: - { - if (defField.Validators.Count > 0) - { - foreach (var v in defField.Validators) - { - v.Validate(Ctx, fieldValue, defField.IsNullable); - } - } - break; - } - } - _path.Pop(); - } + // if (value is DBean dv) + // { + // Accept(dv, assembly); + // } + // _path.Pop(); + // } + // } + // break; + // } + // case TBean n: + // { + // Accept((DBean)fieldValue, assembly); + // break; + // } + // default: + // { + // if (defField.Validators.Count > 0) + // { + // foreach (var v in defField.Validators) + // { + // v.Validate(Ctx, fieldValue, defField.IsNullable); + // } + // } + // break; + // } + // } + // _path.Pop(); + //} } public void Accept(DArray type, DefAssembly x) diff --git a/src/Luban.Job.Cfg/Source/Datas/DByte.cs b/src/Luban.Job.Cfg/Source/Datas/DByte.cs index 2f6e12e..6cdeab0 100644 --- a/src/Luban.Job.Cfg/Source/Datas/DByte.cs +++ b/src/Luban.Job.Cfg/Source/Datas/DByte.cs @@ -6,9 +6,21 @@ namespace Luban.Job.Cfg.Datas { public static DByte Default { get; } = new DByte(0); + public static DByte ValueOf(byte x) + { + if (x == 0) + { + return Default; + } + else + { + return new DByte(x); + } + } + public override string TypeName => "byte"; - public DByte(byte x) : base(x) + private DByte(byte x) : base(x) { } diff --git a/src/Luban.Job.Cfg/Source/Datas/DDouble.cs b/src/Luban.Job.Cfg/Source/Datas/DDouble.cs index 5efd7c0..ec86027 100644 --- a/src/Luban.Job.Cfg/Source/Datas/DDouble.cs +++ b/src/Luban.Job.Cfg/Source/Datas/DDouble.cs @@ -6,9 +6,14 @@ namespace Luban.Job.Cfg.Datas { public static DDouble Default { get; } = new DDouble(0); + public static DDouble ValueOf(double x) + { + return x == 0 ? Default : new DDouble(x); + } + public override string TypeName => "double"; - public DDouble(double x) : base(x) + private DDouble(double x) : base(x) { } diff --git a/src/Luban.Job.Cfg/Source/Datas/DFint.cs b/src/Luban.Job.Cfg/Source/Datas/DFint.cs index 8a14237..b2f5d85 100644 --- a/src/Luban.Job.Cfg/Source/Datas/DFint.cs +++ b/src/Luban.Job.Cfg/Source/Datas/DFint.cs @@ -6,9 +6,14 @@ namespace Luban.Job.Cfg.Datas { public static DFint Default { get; } = new DFint(0); + public static DFint ValueOf(int x) + { + return x == 0 ? Default : new DFint(x); + } + public override string TypeName => "fint"; - public DFint(int x) : base(x) + private DFint(int x) : base(x) { } diff --git a/src/Luban.Job.Cfg/Source/Datas/DFloat.cs b/src/Luban.Job.Cfg/Source/Datas/DFloat.cs index 20bb155..7912eee 100644 --- a/src/Luban.Job.Cfg/Source/Datas/DFloat.cs +++ b/src/Luban.Job.Cfg/Source/Datas/DFloat.cs @@ -4,7 +4,7 @@ namespace Luban.Job.Cfg.Datas { public class DFloat : DType<float> { - private static DFloat Default { get; } = new DFloat(0); + public static DFloat Default { get; } = new DFloat(0); public override string TypeName => "float"; diff --git a/src/Luban.Job.Cfg/Source/Datas/DFlong.cs b/src/Luban.Job.Cfg/Source/Datas/DFlong.cs index 1b039ed..34f5b66 100644 --- a/src/Luban.Job.Cfg/Source/Datas/DFlong.cs +++ b/src/Luban.Job.Cfg/Source/Datas/DFlong.cs @@ -6,9 +6,14 @@ namespace Luban.Job.Cfg.Datas { public static DFlong Default { get; } = new DFlong(0); + public static DFlong ValueOf(long x) + { + return x == 0 ? Default : new DFlong(x); + } + public override string TypeName => "flong"; - public DFlong(long x) : base(x) + private DFlong(long x) : base(x) { } diff --git a/src/Luban.Job.Cfg/Source/Datas/DFshort.cs b/src/Luban.Job.Cfg/Source/Datas/DFshort.cs index c5ba4af..476ae40 100644 --- a/src/Luban.Job.Cfg/Source/Datas/DFshort.cs +++ b/src/Luban.Job.Cfg/Source/Datas/DFshort.cs @@ -6,9 +6,14 @@ namespace Luban.Job.Cfg.Datas { public static DFshort Default { get; } = new DFshort(0); + public static DFshort ValueOf(short x) + { + return x == 0 ? Default : new DFshort(0); + } + public override string TypeName => "fshort"; - public DFshort(short x) : base(x) + private DFshort(short x) : base(x) { } diff --git a/src/Luban.Job.Cfg/Source/Datas/DInt.cs b/src/Luban.Job.Cfg/Source/Datas/DInt.cs index a2c668d..79c6814 100644 --- a/src/Luban.Job.Cfg/Source/Datas/DInt.cs +++ b/src/Luban.Job.Cfg/Source/Datas/DInt.cs @@ -15,6 +15,8 @@ namespace Luban.Job.Cfg.Datas } } + public static DInt Default => s_pool[0]; + public static DInt ValueOf(int x) { if (x >= 0 && x < POOL_SIZE) diff --git a/src/Luban.Job.Cfg/Source/Datas/DShort.cs b/src/Luban.Job.Cfg/Source/Datas/DShort.cs index 1fd70c2..4803b90 100644 --- a/src/Luban.Job.Cfg/Source/Datas/DShort.cs +++ b/src/Luban.Job.Cfg/Source/Datas/DShort.cs @@ -6,9 +6,14 @@ namespace Luban.Job.Cfg.Datas { public static DShort Default { get; } = new DShort(0); + public static DShort ValueOf(short x) + { + return x == 0 ? Default : new DShort(x); + } + public override string TypeName => "short"; - public DShort(short x) : base(x) + private DShort(short x) : base(x) { } diff --git a/src/Luban.Job.Cfg/Source/Defs/CfgDefLoader.cs b/src/Luban.Job.Cfg/Source/Defs/CfgDefLoader.cs index a02de99..29a4cf0 100644 --- a/src/Luban.Job.Cfg/Source/Defs/CfgDefLoader.cs +++ b/src/Luban.Job.Cfg/Source/Defs/CfgDefLoader.cs @@ -126,40 +126,6 @@ namespace Luban.Job.Cfg.Defs _cfgGroups.Add(new Group() { Names = groupNames }); } - private void FillValueValidator(CfgField f, string attrValue, string validatorName) - { - if (!string.IsNullOrWhiteSpace(attrValue)) - { - var validator = new Validator() { Type = validatorName, Rule = attrValue }; - f.Validators.Add(validator); - f.ValueValidators.Add(validator); - } - } - - private void FillValidators(string defineFile, string key, string attr, List<Validator> result) - { - if (!string.IsNullOrWhiteSpace(attr)) - { -#if !LUBAN_LITE - foreach (var validatorStr in attr.Split('#', StringSplitOptions.RemoveEmptyEntries)) -#else - foreach (var validatorStr in attr.Split('#')) -#endif - { - var sepIndex = validatorStr.IndexOf(':'); - if (sepIndex <= 0) - { - throw new Exception($"定义文件:{defineFile} key:'{key}' attr:'{attr}' 不是合法的 validator 定义 (key1:value1#key2:value2 ...)"); - } -#if !LUBAN_LITE - result.Add(new Validator() { Type = validatorStr[..sepIndex], Rule = validatorStr[(sepIndex + 1)..] }); -#else - result.Add(new Validator() { Type = validatorStr.Substring(0, sepIndex), Rule = validatorStr.Substring(sepIndex + 1, validatorStr.Length - sepIndex - 1) }); -#endif - } - } - } - private readonly List<string> _serviceAttrs = new List<string> { "name", "manager", "group" }; private void AddService(XElement e) @@ -325,36 +291,36 @@ namespace Luban.Job.Cfg.Defs var file = inputFileInfos[0]; var source = new ExcelDataSource(); var stream = new MemoryStream(await this.Agent.GetFromCacheOrReadAllBytesAsync(file.ActualFile, file.MD5)); - var sheet = source.LoadFirstSheet(file.OriginFile, file.SheetName, stream); + var tableDefInfo = source.LoadTableDefInfo(file.OriginFile, file.SheetName, stream); var cb = new CfgBean() { Namespace = table.Namespace, Name = table.ValueType, }; - var rc = sheet.RowColumns; - var attrRow = sheet.RowColumns[0]; - if (rc.Count < sheet.AttrRowCount + 1) + //var rc = sheet.RowColumns; + //var attrRow = sheet.RowColumns[0]; + //if (rc.Count < sheet.AttrRowCount + 1) + //{ + // throw new Exception($"table:'{table.Name}' file:{file.OriginFile} 至少包含 属性行和标题行"); + //} + //var titleRow = sheet.RowColumns[sheet.AttrRowCount]; + //// 有可能没有注释行,此时使用标题行,这个是必须有的 + //var descRow = sheet.HeaderRowCount >= sheet.AttrRowCount + 2 ? sheet.RowColumns[sheet.AttrRowCount + 1] : titleRow; + foreach (var (name, f) in tableDefInfo.FieldInfos) { - throw new Exception($"table:'{table.Name}' file:{file.OriginFile} 至少包含 属性行和标题行"); - } - var titleRow = sheet.RowColumns[sheet.AttrRowCount]; - // 有可能没有注释行,此时使用标题行,这个是必须有的 - var descRow = sheet.HeaderRowCount >= sheet.AttrRowCount + 2 ? sheet.RowColumns[sheet.AttrRowCount + 1] : titleRow; - foreach (var f in sheet.RootFields) - { - var cf = new CfgField() { Name = f.Name, Id = 0 }; + var cf = new CfgField() { Name = name, Id = 0 }; - string[] attrs = (attrRow[f.FromIndex].Value?.ToString() ?? "").Trim().Split('&').Select(s => s.Trim()).ToArray(); + string[] attrs = f.Type.Trim().Split('&').Select(s => s.Trim()).ToArray(); if (attrs.Length == 0 || string.IsNullOrWhiteSpace(attrs[0])) { - throw new Exception($"table:'{table.Name}' file:{file.OriginFile} title:'{f.Name}' type missing!"); + throw new Exception($"table:'{table.Name}' file:{file.OriginFile} title:'{name}' type missing!"); } // 优先取desc行,如果为空,则取title行 - cf.Comment = descRow[f.FromIndex].Value?.ToString(); + cf.Comment = f.BriefDesc; if (string.IsNullOrWhiteSpace(cf.Comment)) { - cf.Comment = titleRow[f.FromIndex].Value?.ToString(); + cf.Comment = f.DetailDesc; } if (string.IsNullOrWhiteSpace(cf.Comment)) { @@ -372,7 +338,7 @@ namespace Luban.Job.Cfg.Defs #endif if (pair.Length != 2) { - throw new Exception($"table:'{table.Name}' file:{file.OriginFile} title:'{f.Name}' attr:'{attrs[i]}' is invalid!"); + throw new Exception($"table:'{table.Name}' file:{file.OriginFile} title:'{name}' attr:'{attrs[i]}' is invalid!"); } var attrName = pair[0].Trim(); var attrValue = pair[1].Trim(); @@ -383,23 +349,13 @@ namespace Luban.Job.Cfg.Defs cf.Index = attrValue; break; } - case "sep": - { - cf.Sep = attrValue; - break; - } case "ref": case "path": case "range": { - var validator = new Validator() { Type = attrName, Rule = attrValue }; - cf.Validators.Add(validator); - cf.ValueValidators.Add(validator); - break; - } - case "multi_rows": - { - cf.IsMultiRow = attrValue == "1" || attrValue.Equals("true", StringComparison.OrdinalIgnoreCase); + //var validator = new Validator() { Type = attrName, Rule = attrValue }; + //cf.Validators.Add(validator); + //cf.ValueValidators.Add(validator); break; } case "group": @@ -412,29 +368,14 @@ namespace Luban.Job.Cfg.Defs cf.Comment = attrValue; break; } - case "convert": - { - cf.Converter = attrValue; - break; - } - case "default": - { - cf.DefaultValue = attrValue; - break; - } case "tags": { cf.Tags = attrValue; break; } - case "orientation": - { - cf.IsRowOrient = DefUtil.ParseOrientation(attrValue); - break; - } default: { - throw new Exception($"table:'{table.Name}' file:{file.OriginFile} title:'{f.Name}' attr:'{attrs[i]}' is invalid!"); + throw new Exception($"table:'{table.Name}' file:{file.OriginFile} title:'{name}' attr:'{attrs[i]}' is invalid!"); } } } @@ -665,7 +606,7 @@ namespace Luban.Job.Cfg.Defs new CfgField() { Name = "sep", Type = "string" }, new CfgField() { Name = "comment", Type = "string" }, new CfgField() { Name = "tags", Type = "string" }, - new CfgField() { Name = "fields", Type = "list,__FieldInfo__", IsMultiRow = true }, + new CfgField() { Name = "fields", Type = "list,__FieldInfo__" }, } }) { @@ -714,21 +655,10 @@ namespace Luban.Job.Cfg.Defs (b.GetField("name") as DString).Value.Trim(), (b.GetField("type") as DString).Value.Trim(), (b.GetField("index") as DString).Value.Trim(), - (b.GetField("sep") as DString).Value.Trim(), - (b.GetField("is_multi_rows") as DBool).Value, (b.GetField("group") as DString).Value, - "", - "", (b.GetField("comment") as DString).Value.Trim(), - (b.GetField("ref") as DString).Value.Trim(), - (b.GetField("path") as DString).Value.Trim(), - "", - "", - "", - "", (b.GetField("tags") as DString).Value.Trim(), - false, - DefUtil.ParseOrientation((b.GetField("orientation") as DString).Value) + false )).ToList(), }; this._beans.Add(curBean); @@ -771,41 +701,25 @@ namespace Luban.Job.Cfg.Defs return CreateField(defineFile, XmlUtil.GetRequiredAttribute(e, "name"), XmlUtil.GetRequiredAttribute(e, "type"), XmlUtil.GetOptionalAttribute(e, "index"), - XmlUtil.GetOptionalAttribute(e, "sep"), - XmlUtil.GetOptionBoolAttribute(e, "multi_rows"), XmlUtil.GetOptionalAttribute(e, "group"), - XmlUtil.GetOptionalAttribute(e, "res"), - XmlUtil.GetOptionalAttribute(e, "convert"), XmlUtil.GetOptionalAttribute(e, "comment"), - XmlUtil.GetOptionalAttribute(e, "ref"), - XmlUtil.GetOptionalAttribute(e, "path"), - XmlUtil.GetOptionalAttribute(e, "range"), - XmlUtil.GetOptionalAttribute(e, "key_validator"), - XmlUtil.GetOptionalAttribute(e, "value_validator"), - XmlUtil.GetOptionalAttribute(e, "validator"), XmlUtil.GetOptionalAttribute(e, "tags"), - false, - DefUtil.ParseOrientation(XmlUtil.GetOptionalAttribute(e, "orientation")) + false ); } - private Field CreateField(string defileFile, string name, string type, string index, string sep, bool isMultiRow, string group, string resource, string converter, - string comment, string refs, string path, string range, string keyValidator, string valueValidator, string validator, string tags, - bool ignoreNameValidation, bool isRowOrient) + private Field CreateField(string defileFile, string name, string type, string index, string group, + string comment, string tags, + bool ignoreNameValidation) { var f = new CfgField() { Name = name, Index = index, - Sep = sep, - IsMultiRow = isMultiRow, Groups = CreateGroups(group), - Resource = resource, - Converter = converter, Comment = comment, Tags = tags, IgnoreNameValidation = ignoreNameValidation, - IsRowOrient = isRowOrient, }; // 字段与table的默认组不一样。 @@ -822,13 +736,13 @@ namespace Luban.Job.Cfg.Defs f.Type = type; - FillValueValidator(f, refs, "ref"); - FillValueValidator(f, path, "path"); // (ue4|unity|normal|regex);xxx;xxx - FillValueValidator(f, range, "range"); + //FillValueValidator(f, refs, "ref"); + //FillValueValidator(f, path, "path"); // (ue4|unity|normal|regex);xxx;xxx + //FillValueValidator(f, range, "range"); - FillValidators(defileFile, "key_validator", keyValidator, f.KeyValidators); - FillValidators(defileFile, "value_validator", valueValidator, f.ValueValidators); - FillValidators(defileFile, "validator", validator, f.Validators); + //FillValidators(defileFile, "key_validator", keyValidator, f.KeyValidators); + //FillValidators(defileFile, "value_validator", valueValidator, f.ValueValidators); + //FillValidators(defileFile, "validator", validator, f.Validators); return f; } diff --git a/src/Luban.Job.Cfg/Source/Defs/DefField.cs b/src/Luban.Job.Cfg/Source/Defs/DefField.cs index d2d3b1f..0ee71af 100644 --- a/src/Luban.Job.Cfg/Source/Defs/DefField.cs +++ b/src/Luban.Job.Cfg/Source/Defs/DefField.cs @@ -109,23 +109,6 @@ namespace Luban.Job.Cfg.Defs } } - public string Sep { get; set; } - - // 如果没有指定sep - // 如果是bean,且指定了sep,则使用此值 - // 如果是vectorN,使用 , - public string ActualSep => string.IsNullOrWhiteSpace(Sep) ? (CType is TBean bean ? ((DefBean)bean.Bean).Sep : "") : Sep; - - public List<IValidator> KeyValidators { get; } = new List<IValidator>(); - - public List<IValidator> ValueValidators { get; } = new List<IValidator>(); - - public List<IValidator> Validators { get; } = new List<IValidator>(); - - public string ResourceTag { get; } - - public bool IsResource => !string.IsNullOrEmpty(ResourceTag); - public string CsRefVarName => $"{CsStyleName}_Ref"; public string JavaRefVarName => $"{JavaStyleName}_Ref"; @@ -150,49 +133,36 @@ namespace Luban.Job.Cfg.Defs public bool HasRecursiveText => HasRecursiveRef; - public string DefaultValue { get; } - - public DType DefalutDtypeValue { get; private set; } - - public bool IsRowOrient { get; } public DefField(DefTypeBase host, CfgField f, int idOffset) : base(host, f, idOffset) { Index = f.Index; - Sep = f.Sep; - this.IsMultiRow = this.RawIsMultiRow = f.IsMultiRow; - ResourceTag = f.Resource; - this.Validators.AddRange(f.Validators.Select(v => ValidatorFactory.Create(v))); - this.KeyValidators.AddRange(f.KeyValidators.Select(v => ValidatorFactory.Create(v))); - this.ValueValidators.AddRange(f.ValueValidators.Select(v => ValidatorFactory.Create(v))); this.Groups = f.Groups; this.RawDefine = f; - this.DefaultValue = f.DefaultValue; - this.IsRowOrient = f.IsRowOrient; } public override void Compile() { base.Compile(); - foreach (var v in this.Validators) - { - v.Compile(this); - } + //foreach (var v in this.Validators) + //{ + // v.Compile(this); + //} - foreach (var v in this.KeyValidators) - { - v.Compile(this); - } + //foreach (var v in this.KeyValidators) + //{ + // v.Compile(this); + //} - foreach (var v in this.ValueValidators) - { - v.Compile(this); - } + //foreach (var v in this.ValueValidators) + //{ + // v.Compile(this); + //} - if (!string.IsNullOrWhiteSpace(this.DefaultValue)) - { - this.DefalutDtypeValue = CType.Apply(StringDataCreator.Ins, this.DefaultValue); - } + //if (!string.IsNullOrWhiteSpace(this.DefaultValue)) + //{ + // this.DefalutDtypeValue = CType.Apply(StringDataCreator.Ins, this.DefaultValue); + //} switch (CType) { @@ -247,10 +217,6 @@ namespace Luban.Job.Cfg.Defs throw new Exception($"只有容器类型才支持 multi_line 属性"); } - if (string.IsNullOrEmpty(Sep) && CType is TBean bean) - { - Sep = bean.GetBeanAs<DefBean>().Sep; - } if (!string.IsNullOrEmpty(Index)) { if ((CType is TArray tarray) && (tarray.ElementType is TBean b)) @@ -273,35 +239,35 @@ namespace Luban.Job.Cfg.Defs } } - if (!CType.IsCollection && !(CType.IsBean)) - { - this.Ref = (RefValidator)this.Validators.FirstOrDefault(v => v is RefValidator); - } + //if (!CType.IsCollection && !(CType.IsBean)) + //{ + // this.Ref = (RefValidator)this.Validators.FirstOrDefault(v => v is RefValidator); + //} - if (!string.IsNullOrEmpty(this.RawDefine.Converter)) - { - this.Remapper = AssemblyBase.GetDefTType(HostType.Namespace, this.RawDefine.Converter, this.IsNullable) as TEnum; - if (this.Remapper == null) - { - throw new Exception($"type:'{HostType.FullName}' field:'{Name}' converter:'{this.RawDefine.Converter}' not exists"); - } - } + //if (!string.IsNullOrEmpty(this.RawDefine.Converter)) + //{ + // this.Remapper = AssemblyBase.GetDefTType(HostType.Namespace, this.RawDefine.Converter, this.IsNullable) as TEnum; + // if (this.Remapper == null) + // { + // throw new Exception($"type:'{HostType.FullName}' field:'{Name}' converter:'{this.RawDefine.Converter}' not exists"); + // } + //} - // 检查所引用的表是否导出了 - if (NeedExport) - { - var allValidators = new List<IValidator>(this.Validators); - allValidators.AddRange(this.KeyValidators); - allValidators.AddRange(this.ValueValidators); + //// 检查所引用的表是否导出了 + //if (NeedExport) + //{ + // var allValidators = new List<IValidator>(this.Validators); + // allValidators.AddRange(this.KeyValidators); + // allValidators.AddRange(this.ValueValidators); - foreach (var val in allValidators) - { - if (val is RefValidator refValidator && !Assembly.GetCfgTable(refValidator.FirstTable).NeedExport) - { - throw new Exception($"type:'{HostType.FullName}' field:'{Name}' ref 引用的表:'{refValidator.FirstTable}' 没有导出"); - } - } - } + // foreach (var val in allValidators) + // { + // if (val is RefValidator refValidator && !Assembly.GetCfgTable(refValidator.FirstTable).NeedExport) + // { + // throw new Exception($"type:'{HostType.FullName}' field:'{Name}' ref 引用的表:'{refValidator.FirstTable}' 没有导出"); + // } + // } + //} } public override void PostCompile() @@ -310,49 +276,49 @@ namespace Luban.Job.Cfg.Defs // 检查 字段类型 与 所引用的表的key是否一致 - foreach (var val in KeyValidators) - { - if (val is RefValidator refValidator) - { - var cfgTable = Assembly.GetCfgTable(refValidator.FirstTable); - if (CType is TMap mapType) - { - if (mapType.KeyType.GetType() != cfgTable.KeyTType.GetType()) - { - throw new Exception($"type:'{HostType.FullName}' field:'{Name}' key类型:'{mapType.KeyType.GetType()}' 与 被引用的表:'{cfgTable.FullName}' key类型:'{cfgTable.KeyTType.GetType()}' 不一致"); - } - } - else - { - throw new Exception($"type:'{HostType.FullName}' field:'{Name}' 不是 map类型. 不能指定 key_validator 引用"); - } - } - } + //foreach (var val in KeyValidators) + //{ + // if (val is RefValidator refValidator) + // { + // var cfgTable = Assembly.GetCfgTable(refValidator.FirstTable); + // if (CType is TMap mapType) + // { + // if (mapType.KeyType.GetType() != cfgTable.KeyTType.GetType()) + // { + // throw new Exception($"type:'{HostType.FullName}' field:'{Name}' key类型:'{mapType.KeyType.GetType()}' 与 被引用的表:'{cfgTable.FullName}' key类型:'{cfgTable.KeyTType.GetType()}' 不一致"); + // } + // } + // else + // { + // throw new Exception($"type:'{HostType.FullName}' field:'{Name}' 不是 map类型. 不能指定 key_validator 引用"); + // } + // } + //} - var remainValidators = new List<IValidator>(this.Validators); - remainValidators.AddRange(this.ValueValidators); - foreach (var val in remainValidators) - { - if (val is RefValidator refValidator) - { - var cfgTable = Assembly.GetCfgTable(refValidator.FirstTable); - TType valueType; - switch (CType) - { - case TArray ta: valueType = ta.ElementType; break; - case TList tl: valueType = tl.ElementType; break; - case TSet ts: valueType = ts.ElementType; break; - case TMap tm: valueType = tm.ValueType; break; - default: valueType = CType; break; - } + //var remainValidators = new List<IValidator>(this.Validators); + //remainValidators.AddRange(this.ValueValidators); + //foreach (var val in remainValidators) + //{ + // if (val is RefValidator refValidator) + // { + // var cfgTable = Assembly.GetCfgTable(refValidator.FirstTable); + // TType valueType; + // switch (CType) + // { + // case TArray ta: valueType = ta.ElementType; break; + // case TList tl: valueType = tl.ElementType; break; + // case TSet ts: valueType = ts.ElementType; break; + // case TMap tm: valueType = tm.ValueType; break; + // default: valueType = CType; break; + // } - if (valueType.GetType() != cfgTable.KeyTType.GetType()) - { - throw new Exception($"type:'{HostType.FullName}' field:'{Name}' 类型:'{valueType.GetType()}' 与 被引用的表:'{cfgTable.FullName}' key类型:'{cfgTable.KeyTType.GetType()}' 不一致"); - } + // if (valueType.GetType() != cfgTable.KeyTType.GetType()) + // { + // throw new Exception($"type:'{HostType.FullName}' field:'{Name}' 类型:'{valueType.GetType()}' 与 被引用的表:'{cfgTable.FullName}' key类型:'{cfgTable.KeyTType.GetType()}' 不一致"); + // } - } - } + // } + //} } } } diff --git a/src/Luban.Job.Cfg/Source/RawDefs/CfgField.cs b/src/Luban.Job.Cfg/Source/RawDefs/CfgField.cs index bdebf75..d2e2ae1 100644 --- a/src/Luban.Job.Cfg/Source/RawDefs/CfgField.cs +++ b/src/Luban.Job.Cfg/Source/RawDefs/CfgField.cs @@ -3,36 +3,10 @@ using System.Collections.Generic; namespace Luban.Job.Cfg.RawDefs { - - public class Validator - { - public string Type { get; set; } - - public string Rule { get; set; } - } - public class CfgField : Field { - public string Index { get; set; } = ""; - - public string Sep { get; set; } = ""; - - public bool IsMultiRow { get; set; } - - public string Resource { get; set; } = ""; - - public string Converter { get; set; } = ""; - - public string DefaultValue { get; set; } = ""; - - public bool IsRowOrient { get; set; } = true; + public string Index { get; set; } public List<string> Groups { get; set; } = new List<string>(); - - public List<Validator> KeyValidators { get; } = new List<Validator>(); - - public List<Validator> ValueValidators { get; } = new List<Validator>(); - - public List<Validator> Validators { get; } = new List<Validator>(); } } diff --git a/src/Luban.Job.Cfg/Source/TypeVisitors/DeepCompareTypeDefine.cs b/src/Luban.Job.Cfg/Source/TypeVisitors/DeepCompareTypeDefine.cs index 564ce67..1a82915 100644 --- a/src/Luban.Job.Cfg/Source/TypeVisitors/DeepCompareTypeDefine.cs +++ b/src/Luban.Job.Cfg/Source/TypeVisitors/DeepCompareTypeDefine.cs @@ -55,23 +55,23 @@ namespace Luban.Job.Cfg.TypeVisitors return false; } - bool IsValidatorEquals(List<Validator> vs1, List<Validator> vs2) - { - if (vs1.Count != vs2.Count) - { - return false; - } - for (int i = 0; i < vs1.Count; i++) - { - var v1 = vs1[i]; - var v2 = vs2[i]; - if (v1.Type != v2.Type || v1.Rule != v2.Rule) - { - return false; - } - } - return true; - } + //bool IsValidatorEquals(List<Validator> vs1, List<Validator> vs2) + //{ + // if (vs1.Count != vs2.Count) + // { + // return false; + // } + // for (int i = 0; i < vs1.Count; i++) + // { + // var v1 = vs1[i]; + // var v2 = vs2[i]; + // if (v1.Type != v2.Type || v1.Rule != v2.Rule) + // { + // return false; + // } + // } + // return true; + //} if (ctx.TryGetValue(a, out var e)) { @@ -103,16 +103,16 @@ namespace Luban.Job.Cfg.TypeVisitors if (f1.Name != f2.Name || f1.NeedExport != f2.NeedExport || f1.Index != f2.Index - || f1.Sep != f2.Sep -#if !LUBAN_LITE - || f1.ResourceTag != f2.ResourceTag -#endif + // || f1.Sep != f2.Sep + //#if !LUBAN_LITE + // || f1.ResourceTag != f2.ResourceTag + //#endif || f1.IsMultiRow != f2.IsMultiRow || f1.CType.IsNullable != f2.CType.IsNullable || f1.CType.GetType() != f2.CType.GetType() - || !IsValidatorEquals(f1.RawDefine.Validators, f2.RawDefine.Validators) - || !IsValidatorEquals(f1.RawDefine.KeyValidators, f2.RawDefine.KeyValidators) - || !IsValidatorEquals(f1.RawDefine.ValueValidators, f2.RawDefine.ValueValidators) + //|| !IsValidatorEquals(f1.RawDefine.Validators, f2.RawDefine.Validators) + //|| !IsValidatorEquals(f1.RawDefine.KeyValidators, f2.RawDefine.KeyValidators) + //|| !IsValidatorEquals(f1.RawDefine.ValueValidators, f2.RawDefine.ValueValidators) ) { return setupNotEqual(); diff --git a/src/Luban.Job.Cfg/Source/Utils/DataUtil.cs b/src/Luban.Job.Cfg/Source/Utils/DataUtil.cs index 12f9f22..5075e0e 100644 --- a/src/Luban.Job.Cfg/Source/Utils/DataUtil.cs +++ b/src/Luban.Job.Cfg/Source/Utils/DataUtil.cs @@ -21,7 +21,7 @@ namespace Luban.Job.Cfg.Utils public static DType CreateVector(TVector2 type, string x) { - var values = DataUtil.SplitVectorString(x); + var values = SplitVectorString(x); return new DVector2(new System.Numerics.Vector2(float.Parse(values[0]), float.Parse(values[1]))); @@ -29,7 +29,7 @@ namespace Luban.Job.Cfg.Utils public static DType CreateVector(TVector3 type, string x) { - var values = DataUtil.SplitVectorString(x); + var values = SplitVectorString(x); return new DVector3(new System.Numerics.Vector3(float.Parse(values[0]), float.Parse(values[1]), float.Parse(values[2]))); @@ -37,7 +37,7 @@ namespace Luban.Job.Cfg.Utils public static DType CreateVector(TVector4 type, string x) { - var values = DataUtil.SplitVectorString(x); + var values = SplitVectorString(x); return new DVector4(new System.Numerics.Vector4(float.Parse(values[0]), float.Parse(values[1]), float.Parse(values[2]), float.Parse(values[3]))); } diff --git a/src/Luban.Job.Cfg/Source/Validators/ValidatorFactory.cs b/src/Luban.Job.Cfg/Source/Validators/ValidatorFactory.cs index f1279b1..b567694 100644 --- a/src/Luban.Job.Cfg/Source/Validators/ValidatorFactory.cs +++ b/src/Luban.Job.Cfg/Source/Validators/ValidatorFactory.cs @@ -4,29 +4,29 @@ using System.Linq; namespace Luban.Job.Cfg.Validators { - static class ValidatorFactory - { - private static readonly NLog.Logger s_logger = NLog.LogManager.GetCurrentClassLogger(); - public static IValidator Create(Validator validator) - { - s_logger.Debug("== create validator {type}:{rule}", validator.Type, validator.Rule); - switch (validator.Type) - { - case RefValidator.NAME: - { - return new RefValidator(validator.Rule.Split(',').ToList()); - } - case PathValidator.NAME: - { - return new PathValidator(validator.Rule);//.Split(',').ToList()); - } - case RangeValidator.NAME: - { - return new RangeValidator(validator.Rule); - } - default: - throw new NotSupportedException("unknown validator type:" + validator.Type); - } - } - } + //static class ValidatorFactory + //{ + // private static readonly NLog.Logger s_logger = NLog.LogManager.GetCurrentClassLogger(); + // public static IValidator Create(Validator validator) + // { + // s_logger.Debug("== create validator {type}:{rule}", validator.Type, validator.Rule); + // switch (validator.Type) + // { + // case RefValidator.NAME: + // { + // return new RefValidator(validator.Rule.Split(',').ToList()); + // } + // case PathValidator.NAME: + // { + // return new PathValidator(validator.Rule);//.Split(',').ToList()); + // } + // case RangeValidator.NAME: + // { + // return new RangeValidator(validator.Rule); + // } + // default: + // throw new NotSupportedException("unknown validator type:" + validator.Type); + // } + // } + //} }