【重构】重构excel解析代码及将field上的属性移到type

main
walon 2021-10-14 19:52:30 +08:00
parent 4308db1a83
commit 4613169811
33 changed files with 2685 additions and 2294 deletions

View File

@ -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<DefField, ExcelStream, DefAssembly, DType>
{
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<DType> CreateBeanFields(DefBean bean, ExcelStream stream, DefAssembly ass)
{
var list = new List<DType>();
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<DType> 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<DType>();
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<DType, DType>();
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());
}
}
}

View File

@ -1,352 +1,350 @@
using Luban.Common.Utils; //using Luban.Common.Utils;
using Luban.Job.Cfg.Datas; //using Luban.Job.Cfg.Datas;
using Luban.Job.Cfg.DataSources.Excel; //using Luban.Job.Cfg.DataSources.Excel;
using Luban.Job.Cfg.Defs; //using Luban.Job.Cfg.Defs;
using Luban.Job.Cfg.TypeVisitors; //using Luban.Job.Cfg.TypeVisitors;
using Luban.Job.Common.Types; //using Luban.Job.Common.Types;
using Luban.Job.Common.TypeVisitors; //using Luban.Job.Common.TypeVisitors;
using System; //using System;
using System.Collections.Generic; //using System.Collections.Generic;
namespace Luban.Job.Cfg.DataCreators //namespace Luban.Job.Cfg.DataCreators
{
class ExcelNamedRowDataCreator : ITypeFuncVisitor<Sheet.NamedRow, bool, bool, DType>
{
public static ExcelNamedRowDataCreator Ins { get; } = new ExcelNamedRowDataCreator();
public DType ReadExcel(Sheet.NamedRow 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(TByte type, Sheet.NamedRow 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(TFshort type, Sheet.NamedRow 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(TFint type, Sheet.NamedRow 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(TFlong type, Sheet.NamedRow 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(TDouble type, Sheet.NamedRow 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(TString type, Sheet.NamedRow 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(TText type, Sheet.NamedRow 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 List<DType> CreateBeanFields(DefBean bean, Sheet.NamedRow row)
{
var list = new List<DType>();
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 = ";,";
}
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;
}
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})");
}
}
return new DBean(originBean, originBean, CreateBeanFields(originBean, row));
}
}
private List<DType> ReadList(TBean elementType, Sheet.NamedRow row, bool multirow)
{
var list = new List<DType>();
// 如果是多行数据以当前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
{
// 如果不是多行,并且定义了子标题的话。以一个子标题所占的列,读入一个数据
//foreach (var sub in row.SelfTitle.SubTitleList)
//{ //{
// list.Add(this.Accept(elementType, new Sheet.NamedRow(sub, row.Rows), false, false)); // class ExcelNamedRowDataCreator : ITypeFuncVisitor<TitleRow, bool, bool, DType>
// {
// public static ExcelNamedRowDataCreator Ins { get; } = new ExcelNamedRowDataCreator();
// public DType ReadExcel(TitleRow row, TBean btype)
// {
// return Accept(btype, row, 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) // public DType Accept(TBool type, TitleRow x, bool multirow, bool nullable)
{ // {
if (type.ElementType is not TBean bean) // throw new NotSupportedException();
{ // }
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) // public DType Accept(TByte type, TitleRow x, bool multirow, bool nullable)
{ // {
if (type.ElementType is not TBean bean) // throw new NotSupportedException();
{ // }
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) // public DType Accept(TShort type, TitleRow x, bool multirow, bool nullable)
{ // {
throw new NotSupportedException(); // throw new NotSupportedException();
} // }
// public DType Accept(TFshort type, TitleRow 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, TitleRow 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, TitleRow 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, TitleRow 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, TitleRow 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, 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 List<DType> CreateBeanFields(DefBean bean, TitleRow row)
// {
// var list = new List<DType>();
// 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.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;
// }
private bool TryCreateColumnStream(Sheet.NamedRow x, Title title, out ExcelStream stream) // public DType Accept(TBean type, TitleRow row, bool multirow, bool nullable)
{ // {
var cells = new List<Cell>(); // var originBean = (DefBean)type.Bean;
for (int i = title.FromIndex; i <= title.ToIndex; i++) // if (originBean.IsAbstractType)
{ // {
foreach (var row in x.Rows) // string subType = row.GetColumn(DefBean.TYPE_NAME_KEY).Read().ToString().Trim();
{ // if (subType.ToLower() == DefBean.BEAN_NULL_STR)
if (row.Count > i) // {
{ // if (!type.IsNullable)
var value = row[i].Value; // {
if (!(value == null || (value is string s && string.IsNullOrEmpty(s)))) // throw new Exception($"type:'{type}' 不是可空类型 '{type.Bean.FullName}?' , 不能为空");
{ // }
cells.Add(row[i]); // return null;
} // }
} // string fullType = TypeUtil.MakeFullName(originBean.Namespace, subType);
} // DefBean implType = (DefBean)originBean.GetNotAbstractChildType(subType);
} // if (implType == null)
if (cells.Count > 0) // {
{ // throw new Exception($"type:'{fullType}' 不是 bean 类型");
stream = new ExcelStream(cells, 0, cells.Count - 1, "", false); // }
return true; // return new DBean(originBean, implType, CreateBeanFields(implType, row));
} // }
stream = null; // else
return false; // {
} // 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})");
// }
// }
public DType Accept(TMap type, Sheet.NamedRow x, bool multirow, bool nullable) // return new DBean(originBean, originBean, CreateBeanFields(originBean, row));
{ // }
var map = new Dictionary<DType, DType>(); // }
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(TVector2 type, Sheet.NamedRow x, bool multirow, bool nullable)
{
throw new NotSupportedException();
}
public DType Accept(TVector3 type, Sheet.NamedRow x, bool multirow, bool nullable) // private List<DType> ReadList(TBean elementType, TitleRow row, bool multirow)
{ // {
throw new NotSupportedException(); // var list = new List<DType>();
} // // 如果是多行数据以当前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
// {
// // 如果不是多行,并且定义了子标题的话。以一个子标题所占的列,读入一个数据
public DType Accept(TVector4 type, Sheet.NamedRow x, bool multirow, bool nullable) // //foreach (var sub in row.SelfTitle.SubTitleList)
{ // //{
throw new NotSupportedException(); // // 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(TDateTime type, Sheet.NamedRow x, bool multirow, bool nullable) // public DType Accept(TArray type, TitleRow x, bool multirow, bool nullable)
{ // {
throw new NotSupportedException(); // 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, 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, TitleRow x, bool multirow, bool nullable)
// {
// throw new NotSupportedException();
// }
// private bool TryCreateColumnStream(TitleRow x, Title title, out ExcelStream stream)
// {
// var cells = new List<Cell>();
// 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, TitleRow x, bool multirow, bool nullable)
// {
// var map = new Dictionary<DType, DType>();
// 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, TitleRow 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, TitleRow x, bool multirow, bool nullable)
// {
// throw new NotSupportedException();
// }
// public DType Accept(TDateTime type, TitleRow x, bool multirow, bool nullable)
// {
// throw new NotSupportedException();
// }
// }
//}

View File

@ -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<ExcelStream, DType>
{
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<DType> CreateBeanFields(DefBean bean, ExcelStream stream)
{
var list = new List<DType>();
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<DType> ReadList(TType type, ExcelStream stream)
{
string sep = type is TBean bean ? ((DefBean)bean.Bean).Sep : null;
var datas = new List<DType>();
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<DType, DType>();
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());
}
}
}

View File

@ -22,17 +22,17 @@ namespace Luban.Job.Cfg.DataCreators
public DType Accept(TByte type, JsonElement x, DefAssembly ass) 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) 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) 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) 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) 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) 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) 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) 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) 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) public DType Accept(TEnum type, JsonElement x, DefAssembly ass)

View File

@ -23,17 +23,17 @@ namespace Luban.Job.Cfg.DataCreators
public DType Accept(TByte type, object x, DefAssembly ass) 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) 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) 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) 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) public DType Accept(TFint type, object x, DefAssembly ass)
{ {
return new DFint((int)x); return DFint.ValueOf((int)x);
} }
private long ToLong(object x) private long ToLong(object x)
@ -89,7 +89,7 @@ namespace Luban.Job.Cfg.DataCreators
public DType Accept(TFlong type, object x, DefAssembly ass) 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) 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) 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) public DType Accept(TEnum type, object x, DefAssembly ass)

View File

@ -1,163 +1,163 @@
using Luban.Job.Cfg.Datas; //using Luban.Job.Cfg.Datas;
using Luban.Job.Cfg.DataSources.Excel; //using Luban.Job.Cfg.DataSources.Excel;
using Luban.Job.Cfg.Defs; //using Luban.Job.Cfg.Defs;
using Luban.Job.Common.Types; //using Luban.Job.Common.Types;
using Luban.Job.Common.TypeVisitors; //using Luban.Job.Common.TypeVisitors;
using System; //using System;
using System.Collections.Generic; //using System.Collections.Generic;
namespace Luban.Job.Cfg.DataCreators //namespace Luban.Job.Cfg.DataCreators
{ //{
class MultiRowExcelDataCreator : ITypeFuncVisitor<IEnumerable<ExcelStream>, bool, DefAssembly, DType> // class MultiRowExcelDataCreator : ITypeFuncVisitor<IEnumerable<ExcelStream>, bool, DefAssembly, DType>
{ // {
public static MultiRowExcelDataCreator Ins { get; } = new MultiRowExcelDataCreator(); // public static MultiRowExcelDataCreator Ins { get; } = new MultiRowExcelDataCreator();
public DType Accept(TBool type, IEnumerable<ExcelStream> x, bool y, DefAssembly ass) // public DType Accept(TBool type, IEnumerable<ExcelStream> x, bool y, DefAssembly ass)
{ // {
throw new NotImplementedException(); // throw new NotImplementedException();
} // }
public DType Accept(TByte type, IEnumerable<ExcelStream> x, bool y, DefAssembly ass) // public DType Accept(TByte type, IEnumerable<ExcelStream> x, bool y, DefAssembly ass)
{ // {
throw new NotImplementedException(); // throw new NotImplementedException();
} // }
public DType Accept(TShort type, IEnumerable<ExcelStream> x, bool y, DefAssembly ass) // public DType Accept(TShort type, IEnumerable<ExcelStream> x, bool y, DefAssembly ass)
{ // {
throw new NotImplementedException(); // throw new NotImplementedException();
} // }
public DType Accept(TFshort type, IEnumerable<ExcelStream> x, bool y, DefAssembly ass) // public DType Accept(TFshort type, IEnumerable<ExcelStream> x, bool y, DefAssembly ass)
{ // {
throw new NotImplementedException(); // throw new NotImplementedException();
} // }
public DType Accept(TInt type, IEnumerable<ExcelStream> x, bool y, DefAssembly ass) // public DType Accept(TInt type, IEnumerable<ExcelStream> x, bool y, DefAssembly ass)
{ // {
throw new NotImplementedException(); // throw new NotImplementedException();
} // }
public DType Accept(TFint type, IEnumerable<ExcelStream> x, bool y, DefAssembly ass) // public DType Accept(TFint type, IEnumerable<ExcelStream> x, bool y, DefAssembly ass)
{ // {
throw new NotImplementedException(); // throw new NotImplementedException();
} // }
public DType Accept(TLong type, IEnumerable<ExcelStream> x, bool y, DefAssembly ass) // public DType Accept(TLong type, IEnumerable<ExcelStream> x, bool y, DefAssembly ass)
{ // {
throw new NotImplementedException(); // throw new NotImplementedException();
} // }
public DType Accept(TFlong type, IEnumerable<ExcelStream> x, bool y, DefAssembly ass) // public DType Accept(TFlong type, IEnumerable<ExcelStream> x, bool y, DefAssembly ass)
{ // {
throw new NotImplementedException(); // throw new NotImplementedException();
} // }
public DType Accept(TFloat type, IEnumerable<ExcelStream> x, bool y, DefAssembly ass) // public DType Accept(TFloat type, IEnumerable<ExcelStream> x, bool y, DefAssembly ass)
{ // {
throw new NotImplementedException(); // throw new NotImplementedException();
} // }
public DType Accept(TDouble type, IEnumerable<ExcelStream> x, bool y, DefAssembly ass) // public DType Accept(TDouble type, IEnumerable<ExcelStream> x, bool y, DefAssembly ass)
{ // {
throw new NotImplementedException(); // throw new NotImplementedException();
} // }
public DType Accept(TEnum type, IEnumerable<ExcelStream> x, bool y, DefAssembly ass) // public DType Accept(TEnum type, IEnumerable<ExcelStream> x, bool y, DefAssembly ass)
{ // {
throw new NotImplementedException(); // throw new NotImplementedException();
} // }
public DType Accept(TString type, IEnumerable<ExcelStream> x, bool y, DefAssembly ass) // public DType Accept(TString type, IEnumerable<ExcelStream> x, bool y, DefAssembly ass)
{ // {
throw new NotImplementedException(); // throw new NotImplementedException();
} // }
public DType Accept(TBytes type, IEnumerable<ExcelStream> x, bool y, DefAssembly ass) // public DType Accept(TBytes type, IEnumerable<ExcelStream> x, bool y, DefAssembly ass)
{ // {
throw new NotImplementedException(); // throw new NotImplementedException();
} // }
public DType Accept(TText type, IEnumerable<ExcelStream> x, bool y, DefAssembly ass) // public DType Accept(TText type, IEnumerable<ExcelStream> x, bool y, DefAssembly ass)
{ // {
throw new NotImplementedException(); // throw new NotImplementedException();
} // }
public DType Accept(TBean type, IEnumerable<ExcelStream> x, bool y, DefAssembly ass) // public DType Accept(TBean type, IEnumerable<ExcelStream> x, bool y, DefAssembly ass)
{ // {
throw new NotImplementedException(); // throw new NotImplementedException();
} // }
private List<DType> ReadMultiRow(TType type, IEnumerable<ExcelStream> rows, DefAssembly ass) // private List<DType> ReadMultiRow(TType type, IEnumerable<ExcelStream> rows, DefAssembly ass)
{ // {
var list = new List<DType>(); // var list = new List<DType>();
foreach (var stream in rows) // foreach (var stream in rows)
{ // {
try // try
{ // {
list.Add(type.Apply(ExcelDataCreator.Ins, null, stream, ass)); // list.Add(type.Apply(ExcelStreamDataCreator.Ins, null, stream, ass));
} // }
catch (Exception e) // catch (Exception e)
{ // {
var dce = new DataCreateException(e, stream.LastReadDataInfo); // var dce = new DataCreateException(e, stream.LastReadDataInfo);
throw dce; // throw dce;
} // }
} // }
return list; // return list;
} // }
public DType Accept(TArray type, IEnumerable<ExcelStream> x, bool y, DefAssembly ass) // public DType Accept(TArray type, IEnumerable<ExcelStream> x, bool y, DefAssembly ass)
{ // {
return new DArray(type, ReadMultiRow(type.ElementType, x, ass)); // return new DArray(type, ReadMultiRow(type.ElementType, x, ass));
} // }
public DType Accept(TList type, IEnumerable<ExcelStream> x, bool y, DefAssembly ass) // public DType Accept(TList type, IEnumerable<ExcelStream> x, bool y, DefAssembly ass)
{ // {
return new DList(type, ReadMultiRow(type.ElementType, x, ass)); // return new DList(type, ReadMultiRow(type.ElementType, x, ass));
} // }
public DType Accept(TSet type, IEnumerable<ExcelStream> x, bool y, DefAssembly ass) // public DType Accept(TSet type, IEnumerable<ExcelStream> x, bool y, DefAssembly ass)
{ // {
return new DSet(type, ReadMultiRow(type.ElementType, x, ass)); // return new DSet(type, ReadMultiRow(type.ElementType, x, ass));
} // }
public DType Accept(TMap type, IEnumerable<ExcelStream> rows, bool y, DefAssembly ass) // public DType Accept(TMap type, IEnumerable<ExcelStream> rows, bool y, DefAssembly ass)
{ // {
var map = new Dictionary<DType, DType>(); // var map = new Dictionary<DType, DType>();
foreach (var stream in rows) // foreach (var stream in rows)
{ // {
try // try
{ // {
DType key = type.KeyType.Apply(ExcelDataCreator.Ins, null, stream, ass); // DType key = type.KeyType.Apply(ExcelStreamDataCreator.Ins, null, stream, ass);
DType value = type.ValueType.Apply(ExcelDataCreator.Ins, null, stream, ass); // DType value = type.ValueType.Apply(ExcelStreamDataCreator.Ins, null, stream, ass);
map.Add(key, value); // map.Add(key, value);
} // }
catch (Exception e) // catch (Exception e)
{ // {
var dce = new DataCreateException(e, stream.LastReadDataInfo); // var dce = new DataCreateException(e, stream.LastReadDataInfo);
throw dce; // throw dce;
} // }
} // }
return new DMap(type, map); // return new DMap(type, map);
} // }
public DType Accept(TVector2 type, IEnumerable<ExcelStream> x, bool y, DefAssembly ass) // public DType Accept(TVector2 type, IEnumerable<ExcelStream> x, bool y, DefAssembly ass)
{ // {
throw new NotImplementedException(); // throw new NotImplementedException();
} // }
public DType Accept(TVector3 type, IEnumerable<ExcelStream> x, bool y, DefAssembly ass) // public DType Accept(TVector3 type, IEnumerable<ExcelStream> x, bool y, DefAssembly ass)
{ // {
throw new NotImplementedException(); // throw new NotImplementedException();
} // }
public DType Accept(TVector4 type, IEnumerable<ExcelStream> x, bool y, DefAssembly ass) // public DType Accept(TVector4 type, IEnumerable<ExcelStream> x, bool y, DefAssembly ass)
{ // {
throw new NotImplementedException(); // throw new NotImplementedException();
} // }
public DType Accept(TDateTime type, IEnumerable<ExcelStream> x, bool y, DefAssembly ass) // public DType Accept(TDateTime type, IEnumerable<ExcelStream> x, bool y, DefAssembly ass)
{ // {
throw new NotImplementedException(); // throw new NotImplementedException();
} // }
} // }
} //}

View File

@ -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<Sheet, TitleRow, DType>
{
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<DType> CreateBeanFields(DefBean bean, Sheet sheet, TitleRow row)
{
var list = new List<DType>();
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<DType> ReadList(TType type, ExcelStream stream)
{
var datas = new List<DType>();
while (!stream.TryReadEOF())
{
datas.Add(type.Apply(ExcelStreamDataCreator.Ins, stream));
}
return datas;
}
private static List<DType> ReadList(TType type, IEnumerable<ExcelStream> streams)
{
var datas = new List<DType>();
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<DType, DType>();
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<DType, DType>();
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<DType, DType>();
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());
}
}
}

View File

@ -25,7 +25,7 @@ namespace Luban.Job.Cfg.DataCreators
{ {
if (byte.TryParse(x, out var b)) if (byte.TryParse(x, out var b))
{ {
return new DByte(b); return DByte.ValueOf(b);
} }
else else
{ {
@ -37,7 +37,7 @@ namespace Luban.Job.Cfg.DataCreators
{ {
if (short.TryParse(x, out var b)) if (short.TryParse(x, out var b))
{ {
return new DShort(b); return DShort.ValueOf(b);
} }
else else
{ {
@ -49,7 +49,7 @@ namespace Luban.Job.Cfg.DataCreators
{ {
if (short.TryParse(x, out var b)) if (short.TryParse(x, out var b))
{ {
return new DFshort(b); return DFshort.ValueOf(b);
} }
else else
{ {
@ -73,7 +73,7 @@ namespace Luban.Job.Cfg.DataCreators
{ {
if (int.TryParse(x, out var b)) if (int.TryParse(x, out var b))
{ {
return new DFint(b); return DFint.ValueOf(b);
} }
else else
{ {
@ -97,7 +97,7 @@ namespace Luban.Job.Cfg.DataCreators
{ {
if (long.TryParse(x, out var b)) if (long.TryParse(x, out var b))
{ {
return new DFlong(b); return DFlong.ValueOf(b);
} }
else else
{ {
@ -121,7 +121,7 @@ namespace Luban.Job.Cfg.DataCreators
{ {
if (double.TryParse(x, out var b)) if (double.TryParse(x, out var b))
{ {
return new DDouble(b); return DDouble.ValueOf(b);
} }
else else
{ {

View File

@ -23,17 +23,17 @@ namespace Luban.Job.Cfg.DataCreators
public DType Accept(TByte type, XElement x, DefAssembly ass) 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) 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) 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) 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) 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) 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) 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) 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) 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) public DType Accept(TEnum type, XElement x, DefAssembly ass)

View File

@ -33,17 +33,17 @@ namespace Luban.Job.Cfg.DataCreators
public DType Accept(TByte type, YamlNode x, DefAssembly y) 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) 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) 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) 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) 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) 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) 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) 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) 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) public DType Accept(TEnum type, YamlNode x, DefAssembly y)

View File

@ -16,96 +16,27 @@ namespace Luban.Job.Cfg.DataSources.Excel
private readonly List<Sheet> _sheets = new List<Sheet>(); private readonly List<Sheet> _sheets = new List<Sheet>();
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) public override void Load(string rawUrl, string sheetName, Stream stream)
{ {
s_logger.Trace("{filename} {sheet}", rawUrl, sheetName); s_logger.Trace("{filename} {sheet}", rawUrl, sheetName);
RawUrl = rawUrl; RawUrl = rawUrl;
string ext = Path.GetExtension(rawUrl);
using (var reader = ext != ".csv" ? ExcelReaderFactory.CreateReader(stream) : ExcelReaderFactory.CreateCsvReader(stream, new ExcelReaderConfiguration() { FallbackEncoding = DetectCsvEncoding(stream) }))
foreach (RawSheet rawSheet in SheetLoadUtil.LoadRawSheets(rawUrl, sheetName, stream))
{ {
do var sheet = new Sheet(rawUrl, sheetName);
{ sheet.Load(rawSheet);
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());
}
if (_sheets.Count == 0) if (_sheets.Count == 0)
{ {
throw new Exception($"excel:{rawUrl} 不包含有效的单元薄(有效单元薄的A0单元格必须是##)."); 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); return null;
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;
} }
public override List<Record> ReadMulti(TBean type) public override List<Record> ReadMulti(TBean type)
@ -115,7 +46,11 @@ namespace Luban.Job.Cfg.DataSources.Excel
{ {
try 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) catch (DataCreateException dce)
{ {
@ -132,13 +67,14 @@ namespace Luban.Job.Cfg.DataSources.Excel
public override Record ReadOne(TBean type) public override Record ReadOne(TBean type)
{ {
var datas = ReadMulti(type); //var datas = ReadMulti(type);
switch (datas.Count) //switch (datas.Count)
{ //{
case 1: return datas[0]; // case 1: return datas[0];
case 0: throw new Exception($"单例表不能为空必须包含且只包含1个记录"); // case 0: throw new Exception($"单例表不能为空必须包含且只包含1个记录");
default: throw new Exception($"单例表必须恰好包含1个记录. 但当前记录数为:{datas.Count}"); // default: throw new Exception($"单例表必须恰好包含1个记录. 但当前记录数为:{datas.Count}");
} //}
throw new NotSupportedException();
} }
} }
} }

View File

@ -18,15 +18,8 @@ namespace Luban.Job.Cfg.DataSources.Excel
private readonly int _toIndex; private readonly int _toIndex;
private int _curIndex; private int _curIndex;
public ExcelStream(List<Cell> datas, int fromIndex, int toIndex, string sep)
/// <summary>
/// NamedMode下 string可以用空白表达空字符串而不必用null或""
/// </summary>
public bool NamedMode { get; set; }
public ExcelStream(List<Cell> datas, int fromIndex, int toIndex, string sep, bool namedMode)
{ {
NamedMode = namedMode;
if (string.IsNullOrWhiteSpace(sep)) if (string.IsNullOrWhiteSpace(sep))
{ {
this._datas = datas; 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)) if (string.IsNullOrWhiteSpace(sep))
{ {
this._datas = new List<Cell> { cell }; this._datas = new List<Cell> { cell };

View File

@ -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<List<Cell>> Cells { get; init; }
}
}

View File

@ -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<string, FieldInfo> FieldInfos { get; init; }
}
}

View File

@ -2,7 +2,6 @@ using Bright.Collections;
using ExcelDataReader; using ExcelDataReader;
using Luban.Job.Cfg.DataCreators; using Luban.Job.Cfg.DataCreators;
using Luban.Job.Cfg.Datas; using Luban.Job.Cfg.Datas;
using Luban.Job.Cfg.Defs;
using Luban.Job.Cfg.Utils; using Luban.Job.Cfg.Utils;
using Luban.Job.Common.Types; using Luban.Job.Common.Types;
using Luban.Job.Common.Utils; using Luban.Job.Common.Utils;
@ -12,224 +11,14 @@ using System.Linq;
namespace Luban.Job.Cfg.DataSources.Excel namespace Luban.Job.Cfg.DataSources.Excel
{ {
class Sheet class Sheet
{ {
private static readonly NLog.Logger s_logger = NLog.LogManager.GetCurrentClassLogger(); 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; } public string Name { get; }
private List<List<Cell>> _rowColumns; public string RawUrl { get; }
private Title _rootTitle;
public List<Title> 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 Sheet(string rawUrl, string name) public Sheet(string rawUrl, string name)
{ {
@ -237,401 +26,14 @@ namespace Luban.Job.Cfg.DataSources.Excel
this.Name = name; 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()
{ {
// 第一列被策划用于表示是否注释掉此行 yield return null;
// 忽略此列是否空白
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);
}
} }
} }
} }

View File

@ -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;
}
}
}

View File

@ -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();
}
}
}

View File

@ -68,10 +68,11 @@ namespace Luban.Job.Cfg.DataVisitors
public void Accept(DString type, DefField x, List<ResourceInfo> y) public void Accept(DString type, DefField x, List<ResourceInfo> y)
{ {
if (!string.IsNullOrEmpty(type.Value)) //if (!string.IsNullOrEmpty(type.Value))
{ //{
y.Add(new ResourceInfo() { Resource = type.Value, Tag = x.ResourceTag }); // y.Add(new ResourceInfo() { Resource = type.Value, Tag = x.ResourceTag });
} //}
throw new NotSupportedException();
} }
public void Accept(DBytes type, DefField x, List<ResourceInfo> y) public void Accept(DBytes type, DefField x, List<ResourceInfo> y)
@ -91,26 +92,28 @@ namespace Luban.Job.Cfg.DataVisitors
{ {
return; return;
} }
int index = 0; //int index = 0;
foreach (DType fieldData in type.Fields) //foreach (DType fieldData in type.Fields)
{ //{
var fieldDef = (DefField)def.HierarchyFields[index++]; // var fieldDef = (DefField)def.HierarchyFields[index++];
if (fieldDef.IsResource) // if (fieldDef.IsResource)
{ // {
fieldData.Apply(this, fieldDef, y); // fieldData.Apply(this, fieldDef, y);
} // }
} //}
throw new NotSupportedException();
} }
private void Accept(DefField def, List<DType> datas, TType elementType, List<ResourceInfo> ress) private void Accept(DefField def, List<DType> datas, TType elementType, List<ResourceInfo> ress)
{ {
if (def.IsResource || (elementType is TBean)) //if (def.IsResource || (elementType is TBean))
{ //{
foreach (var e in datas) // foreach (var e in datas)
{ // {
e.Apply(this, def, ress); // e.Apply(this, def, ress);
} // }
} //}
throw new NotSupportedException();
} }
public void Accept(DArray type, DefField x, List<ResourceInfo> y) 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) public void Accept(DMap type, DefField x, List<ResourceInfo> y)
{ {
if (x.IsResource || (type.Type.ValueType is TBean)) //if (x.IsResource || (type.Type.ValueType is TBean))
{ //{
foreach (var e in type.Datas.Values) // foreach (var e in type.Datas.Values)
{ // {
e.Apply(this, x, y); // e.Apply(this, x, y);
} // }
} //}
throw new NotSupportedException();
} }
public void Accept(DVector2 type, DefField x, List<ResourceInfo> y) public void Accept(DVector2 type, DefField x, List<ResourceInfo> y)

View File

@ -117,165 +117,165 @@ namespace Luban.Job.Cfg.DataVisitors
{ {
return; return;
} }
var defFields = record.ImplType.HierarchyFields; //var defFields = record.ImplType.HierarchyFields;
int i = 0; //int i = 0;
foreach (var fieldValue in record.Fields) //foreach (var fieldValue in record.Fields)
{ //{
var defField = (DefField)defFields[i++]; // var defField = (DefField)defFields[i++];
_path.Push(defField.Name); // _path.Push(defField.Name);
switch (defField.CType) // switch (defField.CType)
{ // {
case TArray a: // case TArray a:
{ // {
if (defField.ValueValidators.Count > 0) // if (defField.ValueValidators.Count > 0)
{ // {
var arr = (DArray)fieldValue; // var arr = (DArray)fieldValue;
int index = 0; // int index = 0;
foreach (var value in arr.Datas) // foreach (var value in arr.Datas)
{ // {
_path.Push(index++); // _path.Push(index++);
foreach (var v in defField.ValueValidators) // foreach (var v in defField.ValueValidators)
{ // {
v.Validate(Ctx, value, defField.IsNullable); // v.Validate(Ctx, value, defField.IsNullable);
} // }
_path.Pop(); // _path.Pop();
} // }
} // }
if (a.ElementType is TBean) // if (a.ElementType is TBean)
{ // {
var arr = (DArray)fieldValue; // var arr = (DArray)fieldValue;
int index = 0; // int index = 0;
foreach (var value in arr.Datas) // foreach (var value in arr.Datas)
{ // {
_path.Push(index++); // _path.Push(index++);
Accept((DBean)value, assembly); // Accept((DBean)value, assembly);
_path.Pop(); // _path.Pop();
} // }
} // }
break; // break;
} // }
case TList b: // case TList b:
{ // {
if (defField.ValueValidators.Count > 0) // if (defField.ValueValidators.Count > 0)
{ // {
var arr = (DList)fieldValue; // var arr = (DList)fieldValue;
int index = 0; // int index = 0;
foreach (var value in arr.Datas) // foreach (var value in arr.Datas)
{ // {
_path.Push(index++); // _path.Push(index++);
foreach (var v in defField.ValueValidators) // foreach (var v in defField.ValueValidators)
{ // {
v.Validate(Ctx, value, false); // v.Validate(Ctx, value, false);
} // }
_path.Pop(); // _path.Pop();
} // }
} // }
if (b.ElementType is TBean tb) // if (b.ElementType is TBean tb)
{ // {
var arr = (DList)fieldValue; // var arr = (DList)fieldValue;
int index = 0; // int index = 0;
foreach (var value in arr.Datas) // foreach (var value in arr.Datas)
{ // {
_path.Push(index++); // _path.Push(index++);
Accept((DBean)value, assembly); // Accept((DBean)value, assembly);
_path.Pop(); // _path.Pop();
} // }
if (defField.IndexField != null) // if (defField.IndexField != null)
{ // {
var indexSet = new HashSet<DType>(); // var indexSet = new HashSet<DType>();
if (!tb.GetBeanAs<DefBean>().TryGetField(defField.Index, out var _, out var indexOfIndexField)) // if (!tb.GetBeanAs<DefBean>().TryGetField(defField.Index, out var _, out var indexOfIndexField))
{ // {
throw new Exception("impossible"); // throw new Exception("impossible");
} // }
foreach (var value in arr.Datas) // foreach (var value in arr.Datas)
{ // {
_path.Push(index++); // _path.Push(index++);
DType indexValue = ((DBean)value).Fields[indexOfIndexField]; // DType indexValue = ((DBean)value).Fields[indexOfIndexField];
if (!indexSet.Add(indexValue)) // if (!indexSet.Add(indexValue))
{ // {
throw new Exception($"'{TypeUtil.MakeFullName(_path)}' index:'{indexValue}' 重复"); // throw new Exception($"'{TypeUtil.MakeFullName(_path)}' index:'{indexValue}' 重复");
} // }
_path.Pop(); // _path.Pop();
} // }
} // }
} // }
break; // break;
} // }
case TSet c: // case TSet c:
{ // {
if (defField.ValueValidators.Count > 0) // if (defField.ValueValidators.Count > 0)
{ // {
var arr = (DSet)fieldValue; // var arr = (DSet)fieldValue;
foreach (var value in arr.Datas) // foreach (var value in arr.Datas)
{ // {
foreach (var v in defField.ValueValidators) // foreach (var v in defField.ValueValidators)
{ // {
v.Validate(Ctx, value, false); // v.Validate(Ctx, value, false);
} // }
} // }
} // }
break; // break;
} // }
case TMap m: // case TMap m:
{ // {
DMap map = (DMap)fieldValue; // DMap map = (DMap)fieldValue;
if (defField.KeyValidators.Count > 0) // if (defField.KeyValidators.Count > 0)
{ // {
foreach (var key in map.Datas.Keys) // foreach (var key in map.Datas.Keys)
{ // {
_path.Push(key); // _path.Push(key);
foreach (var v in defField.KeyValidators) // foreach (var v in defField.KeyValidators)
{ // {
v.Validate(Ctx, key, false); // v.Validate(Ctx, key, false);
} // }
_path.Pop(); // _path.Pop();
} // }
} // }
if (defField.ValueValidators.Count > 0) // if (defField.ValueValidators.Count > 0)
{ // {
foreach (var value in map.Datas.Values) // foreach (var value in map.Datas.Values)
{ // {
_path.Push(value); // _path.Push(value);
foreach (var v in defField.ValueValidators) // foreach (var v in defField.ValueValidators)
{ // {
v.Validate(Ctx, value, false); // v.Validate(Ctx, value, false);
} // }
if (value is DBean dv) // if (value is DBean dv)
{ // {
Accept(dv, assembly); // Accept(dv, assembly);
} // }
_path.Pop(); // _path.Pop();
} // }
} // }
break; // break;
} // }
case TBean n: // case TBean n:
{ // {
Accept((DBean)fieldValue, assembly); // Accept((DBean)fieldValue, assembly);
break; // break;
} // }
default: // default:
{ // {
if (defField.Validators.Count > 0) // if (defField.Validators.Count > 0)
{ // {
foreach (var v in defField.Validators) // foreach (var v in defField.Validators)
{ // {
v.Validate(Ctx, fieldValue, defField.IsNullable); // v.Validate(Ctx, fieldValue, defField.IsNullable);
} // }
} // }
break; // break;
} // }
} // }
_path.Pop(); // _path.Pop();
} //}
} }
public void Accept(DArray type, DefAssembly x) public void Accept(DArray type, DefAssembly x)

View File

@ -6,9 +6,21 @@ namespace Luban.Job.Cfg.Datas
{ {
public static DByte Default { get; } = new DByte(0); 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 override string TypeName => "byte";
public DByte(byte x) : base(x) private DByte(byte x) : base(x)
{ {
} }

View File

@ -6,9 +6,14 @@ namespace Luban.Job.Cfg.Datas
{ {
public static DDouble Default { get; } = new DDouble(0); 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 override string TypeName => "double";
public DDouble(double x) : base(x) private DDouble(double x) : base(x)
{ {
} }

View File

@ -6,9 +6,14 @@ namespace Luban.Job.Cfg.Datas
{ {
public static DFint Default { get; } = new DFint(0); 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 override string TypeName => "fint";
public DFint(int x) : base(x) private DFint(int x) : base(x)
{ {
} }

View File

@ -4,7 +4,7 @@ namespace Luban.Job.Cfg.Datas
{ {
public class DFloat : DType<float> 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"; public override string TypeName => "float";

View File

@ -6,9 +6,14 @@ namespace Luban.Job.Cfg.Datas
{ {
public static DFlong Default { get; } = new DFlong(0); 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 override string TypeName => "flong";
public DFlong(long x) : base(x) private DFlong(long x) : base(x)
{ {
} }

View File

@ -6,9 +6,14 @@ namespace Luban.Job.Cfg.Datas
{ {
public static DFshort Default { get; } = new DFshort(0); 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 override string TypeName => "fshort";
public DFshort(short x) : base(x) private DFshort(short x) : base(x)
{ {
} }

View File

@ -15,6 +15,8 @@ namespace Luban.Job.Cfg.Datas
} }
} }
public static DInt Default => s_pool[0];
public static DInt ValueOf(int x) public static DInt ValueOf(int x)
{ {
if (x >= 0 && x < POOL_SIZE) if (x >= 0 && x < POOL_SIZE)

View File

@ -6,9 +6,14 @@ namespace Luban.Job.Cfg.Datas
{ {
public static DShort Default { get; } = new DShort(0); 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 override string TypeName => "short";
public DShort(short x) : base(x) private DShort(short x) : base(x)
{ {
} }

View File

@ -126,40 +126,6 @@ namespace Luban.Job.Cfg.Defs
_cfgGroups.Add(new Group() { Names = groupNames }); _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 readonly List<string> _serviceAttrs = new List<string> { "name", "manager", "group" };
private void AddService(XElement e) private void AddService(XElement e)
@ -325,36 +291,36 @@ namespace Luban.Job.Cfg.Defs
var file = inputFileInfos[0]; var file = inputFileInfos[0];
var source = new ExcelDataSource(); var source = new ExcelDataSource();
var stream = new MemoryStream(await this.Agent.GetFromCacheOrReadAllBytesAsync(file.ActualFile, file.MD5)); 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 cb = new CfgBean() { Namespace = table.Namespace, Name = table.ValueType, };
var rc = sheet.RowColumns; //var rc = sheet.RowColumns;
var attrRow = sheet.RowColumns[0]; //var attrRow = sheet.RowColumns[0];
if (rc.Count < sheet.AttrRowCount + 1) //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 cf = new CfgField() { Name = name, Id = 0 };
}
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 };
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])) 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行 // 优先取desc行如果为空,则取title行
cf.Comment = descRow[f.FromIndex].Value?.ToString(); cf.Comment = f.BriefDesc;
if (string.IsNullOrWhiteSpace(cf.Comment)) if (string.IsNullOrWhiteSpace(cf.Comment))
{ {
cf.Comment = titleRow[f.FromIndex].Value?.ToString(); cf.Comment = f.DetailDesc;
} }
if (string.IsNullOrWhiteSpace(cf.Comment)) if (string.IsNullOrWhiteSpace(cf.Comment))
{ {
@ -372,7 +338,7 @@ namespace Luban.Job.Cfg.Defs
#endif #endif
if (pair.Length != 2) 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 attrName = pair[0].Trim();
var attrValue = pair[1].Trim(); var attrValue = pair[1].Trim();
@ -383,23 +349,13 @@ namespace Luban.Job.Cfg.Defs
cf.Index = attrValue; cf.Index = attrValue;
break; break;
} }
case "sep":
{
cf.Sep = attrValue;
break;
}
case "ref": case "ref":
case "path": case "path":
case "range": case "range":
{ {
var validator = new Validator() { Type = attrName, Rule = attrValue }; //var validator = new Validator() { Type = attrName, Rule = attrValue };
cf.Validators.Add(validator); //cf.Validators.Add(validator);
cf.ValueValidators.Add(validator); //cf.ValueValidators.Add(validator);
break;
}
case "multi_rows":
{
cf.IsMultiRow = attrValue == "1" || attrValue.Equals("true", StringComparison.OrdinalIgnoreCase);
break; break;
} }
case "group": case "group":
@ -412,29 +368,14 @@ namespace Luban.Job.Cfg.Defs
cf.Comment = attrValue; cf.Comment = attrValue;
break; break;
} }
case "convert":
{
cf.Converter = attrValue;
break;
}
case "default":
{
cf.DefaultValue = attrValue;
break;
}
case "tags": case "tags":
{ {
cf.Tags = attrValue; cf.Tags = attrValue;
break; break;
} }
case "orientation":
{
cf.IsRowOrient = DefUtil.ParseOrientation(attrValue);
break;
}
default: 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 = "sep", Type = "string" },
new CfgField() { Name = "comment", Type = "string" }, new CfgField() { Name = "comment", Type = "string" },
new CfgField() { Name = "tags", Type = "string" }, new CfgField() { Name = "tags", Type = "string" },
new CfgField() { Name = "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("name") as DString).Value.Trim(),
(b.GetField("type") as DString).Value.Trim(), (b.GetField("type") as DString).Value.Trim(),
(b.GetField("index") 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("group") as DString).Value,
"",
"",
(b.GetField("comment") as DString).Value.Trim(), (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(), (b.GetField("tags") as DString).Value.Trim(),
false, false
DefUtil.ParseOrientation((b.GetField("orientation") as DString).Value)
)).ToList(), )).ToList(),
}; };
this._beans.Add(curBean); this._beans.Add(curBean);
@ -771,41 +701,25 @@ namespace Luban.Job.Cfg.Defs
return CreateField(defineFile, XmlUtil.GetRequiredAttribute(e, "name"), return CreateField(defineFile, XmlUtil.GetRequiredAttribute(e, "name"),
XmlUtil.GetRequiredAttribute(e, "type"), XmlUtil.GetRequiredAttribute(e, "type"),
XmlUtil.GetOptionalAttribute(e, "index"), XmlUtil.GetOptionalAttribute(e, "index"),
XmlUtil.GetOptionalAttribute(e, "sep"),
XmlUtil.GetOptionBoolAttribute(e, "multi_rows"),
XmlUtil.GetOptionalAttribute(e, "group"), XmlUtil.GetOptionalAttribute(e, "group"),
XmlUtil.GetOptionalAttribute(e, "res"),
XmlUtil.GetOptionalAttribute(e, "convert"),
XmlUtil.GetOptionalAttribute(e, "comment"), 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"), XmlUtil.GetOptionalAttribute(e, "tags"),
false, false
DefUtil.ParseOrientation(XmlUtil.GetOptionalAttribute(e, "orientation"))
); );
} }
private Field CreateField(string defileFile, string name, string type, string index, string sep, bool isMultiRow, string group, string resource, string converter, private Field CreateField(string defileFile, string name, string type, string index, string group,
string comment, string refs, string path, string range, string keyValidator, string valueValidator, string validator, string tags, string comment, string tags,
bool ignoreNameValidation, bool isRowOrient) bool ignoreNameValidation)
{ {
var f = new CfgField() var f = new CfgField()
{ {
Name = name, Name = name,
Index = index, Index = index,
Sep = sep,
IsMultiRow = isMultiRow,
Groups = CreateGroups(group), Groups = CreateGroups(group),
Resource = resource,
Converter = converter,
Comment = comment, Comment = comment,
Tags = tags, Tags = tags,
IgnoreNameValidation = ignoreNameValidation, IgnoreNameValidation = ignoreNameValidation,
IsRowOrient = isRowOrient,
}; };
// 字段与table的默认组不一样。 // 字段与table的默认组不一样。
@ -822,13 +736,13 @@ namespace Luban.Job.Cfg.Defs
f.Type = type; f.Type = type;
FillValueValidator(f, refs, "ref"); //FillValueValidator(f, refs, "ref");
FillValueValidator(f, path, "path"); // (ue4|unity|normal|regex);xxx;xxx //FillValueValidator(f, path, "path"); // (ue4|unity|normal|regex);xxx;xxx
FillValueValidator(f, range, "range"); //FillValueValidator(f, range, "range");
FillValidators(defileFile, "key_validator", keyValidator, f.KeyValidators); //FillValidators(defileFile, "key_validator", keyValidator, f.KeyValidators);
FillValidators(defileFile, "value_validator", valueValidator, f.ValueValidators); //FillValidators(defileFile, "value_validator", valueValidator, f.ValueValidators);
FillValidators(defileFile, "validator", validator, f.Validators); //FillValidators(defileFile, "validator", validator, f.Validators);
return f; return f;
} }

View File

@ -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 CsRefVarName => $"{CsStyleName}_Ref";
public string JavaRefVarName => $"{JavaStyleName}_Ref"; public string JavaRefVarName => $"{JavaStyleName}_Ref";
@ -150,49 +133,36 @@ namespace Luban.Job.Cfg.Defs
public bool HasRecursiveText => HasRecursiveRef; 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) public DefField(DefTypeBase host, CfgField f, int idOffset) : base(host, f, idOffset)
{ {
Index = f.Index; 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.Groups = f.Groups;
this.RawDefine = f; this.RawDefine = f;
this.DefaultValue = f.DefaultValue;
this.IsRowOrient = f.IsRowOrient;
} }
public override void Compile() public override void Compile()
{ {
base.Compile(); base.Compile();
foreach (var v in this.Validators) //foreach (var v in this.Validators)
{ //{
v.Compile(this); // v.Compile(this);
} //}
foreach (var v in this.KeyValidators) //foreach (var v in this.KeyValidators)
{ //{
v.Compile(this); // v.Compile(this);
} //}
foreach (var v in this.ValueValidators) //foreach (var v in this.ValueValidators)
{ //{
v.Compile(this); // v.Compile(this);
} //}
if (!string.IsNullOrWhiteSpace(this.DefaultValue)) //if (!string.IsNullOrWhiteSpace(this.DefaultValue))
{ //{
this.DefalutDtypeValue = CType.Apply(StringDataCreator.Ins, this.DefaultValue); // this.DefalutDtypeValue = CType.Apply(StringDataCreator.Ins, this.DefaultValue);
} //}
switch (CType) switch (CType)
{ {
@ -247,10 +217,6 @@ namespace Luban.Job.Cfg.Defs
throw new Exception($"只有容器类型才支持 multi_line 属性"); throw new Exception($"只有容器类型才支持 multi_line 属性");
} }
if (string.IsNullOrEmpty(Sep) && CType is TBean bean)
{
Sep = bean.GetBeanAs<DefBean>().Sep;
}
if (!string.IsNullOrEmpty(Index)) if (!string.IsNullOrEmpty(Index))
{ {
if ((CType is TArray tarray) && (tarray.ElementType is TBean b)) if ((CType is TArray tarray) && (tarray.ElementType is TBean b))
@ -273,35 +239,35 @@ namespace Luban.Job.Cfg.Defs
} }
} }
if (!CType.IsCollection && !(CType.IsBean)) //if (!CType.IsCollection && !(CType.IsBean))
{ //{
this.Ref = (RefValidator)this.Validators.FirstOrDefault(v => v is RefValidator); // this.Ref = (RefValidator)this.Validators.FirstOrDefault(v => v is RefValidator);
} //}
if (!string.IsNullOrEmpty(this.RawDefine.Converter)) //if (!string.IsNullOrEmpty(this.RawDefine.Converter))
{ //{
this.Remapper = AssemblyBase.GetDefTType(HostType.Namespace, this.RawDefine.Converter, this.IsNullable) as TEnum; // this.Remapper = AssemblyBase.GetDefTType(HostType.Namespace, this.RawDefine.Converter, this.IsNullable) as TEnum;
if (this.Remapper == null) // if (this.Remapper == null)
{ // {
throw new Exception($"type:'{HostType.FullName}' field:'{Name}' converter:'{this.RawDefine.Converter}' not exists"); // throw new Exception($"type:'{HostType.FullName}' field:'{Name}' converter:'{this.RawDefine.Converter}' not exists");
} // }
} //}
// 检查所引用的表是否导出了 //// 检查所引用的表是否导出了
if (NeedExport) //if (NeedExport)
{ //{
var allValidators = new List<IValidator>(this.Validators); // var allValidators = new List<IValidator>(this.Validators);
allValidators.AddRange(this.KeyValidators); // allValidators.AddRange(this.KeyValidators);
allValidators.AddRange(this.ValueValidators); // allValidators.AddRange(this.ValueValidators);
foreach (var val in allValidators) // foreach (var val in allValidators)
{ // {
if (val is RefValidator refValidator && !Assembly.GetCfgTable(refValidator.FirstTable).NeedExport) // if (val is RefValidator refValidator && !Assembly.GetCfgTable(refValidator.FirstTable).NeedExport)
{ // {
throw new Exception($"type:'{HostType.FullName}' field:'{Name}' ref 引用的表:'{refValidator.FirstTable}' 没有导出"); // throw new Exception($"type:'{HostType.FullName}' field:'{Name}' ref 引用的表:'{refValidator.FirstTable}' 没有导出");
} // }
} // }
} //}
} }
public override void PostCompile() public override void PostCompile()
@ -310,49 +276,49 @@ namespace Luban.Job.Cfg.Defs
// 检查 字段类型 与 所引用的表的key是否一致 // 检查 字段类型 与 所引用的表的key是否一致
foreach (var val in KeyValidators) //foreach (var val in KeyValidators)
{ //{
if (val is RefValidator refValidator) // if (val is RefValidator refValidator)
{ // {
var cfgTable = Assembly.GetCfgTable(refValidator.FirstTable); // var cfgTable = Assembly.GetCfgTable(refValidator.FirstTable);
if (CType is TMap mapType) // if (CType is TMap mapType)
{ // {
if (mapType.KeyType.GetType() != cfgTable.KeyTType.GetType()) // 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()}' 不一致"); // throw new Exception($"type:'{HostType.FullName}' field:'{Name}' key类型:'{mapType.KeyType.GetType()}' 与 被引用的表:'{cfgTable.FullName}' key类型:'{cfgTable.KeyTType.GetType()}' 不一致");
} // }
} // }
else // else
{ // {
throw new Exception($"type:'{HostType.FullName}' field:'{Name}' 不是 map类型. 不能指定 key_validator 引用"); // throw new Exception($"type:'{HostType.FullName}' field:'{Name}' 不是 map类型. 不能指定 key_validator 引用");
} // }
} // }
} //}
var remainValidators = new List<IValidator>(this.Validators); //var remainValidators = new List<IValidator>(this.Validators);
remainValidators.AddRange(this.ValueValidators); //remainValidators.AddRange(this.ValueValidators);
foreach (var val in remainValidators) //foreach (var val in remainValidators)
{ //{
if (val is RefValidator refValidator) // if (val is RefValidator refValidator)
{ // {
var cfgTable = Assembly.GetCfgTable(refValidator.FirstTable); // var cfgTable = Assembly.GetCfgTable(refValidator.FirstTable);
TType valueType; // TType valueType;
switch (CType) // switch (CType)
{ // {
case TArray ta: valueType = ta.ElementType; break; // case TArray ta: valueType = ta.ElementType; break;
case TList tl: valueType = tl.ElementType; break; // case TList tl: valueType = tl.ElementType; break;
case TSet ts: valueType = ts.ElementType; break; // case TSet ts: valueType = ts.ElementType; break;
case TMap tm: valueType = tm.ValueType; break; // case TMap tm: valueType = tm.ValueType; break;
default: valueType = CType; break; // default: valueType = CType; break;
} // }
if (valueType.GetType() != 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()}' 不一致"); // throw new Exception($"type:'{HostType.FullName}' field:'{Name}' 类型:'{valueType.GetType()}' 与 被引用的表:'{cfgTable.FullName}' key类型:'{cfgTable.KeyTType.GetType()}' 不一致");
} // }
} // }
} //}
} }
} }
} }

View File

@ -3,36 +3,10 @@ using System.Collections.Generic;
namespace Luban.Job.Cfg.RawDefs namespace Luban.Job.Cfg.RawDefs
{ {
public class Validator
{
public string Type { get; set; }
public string Rule { get; set; }
}
public class CfgField : Field public class CfgField : Field
{ {
public string Index { get; set; } = ""; 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 List<string> Groups { get; set; } = new List<string>(); 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>();
} }
} }

View File

@ -55,23 +55,23 @@ namespace Luban.Job.Cfg.TypeVisitors
return false; return false;
} }
bool IsValidatorEquals(List<Validator> vs1, List<Validator> vs2) //bool IsValidatorEquals(List<Validator> vs1, List<Validator> vs2)
{ //{
if (vs1.Count != vs2.Count) // if (vs1.Count != vs2.Count)
{ // {
return false; // return false;
} // }
for (int i = 0; i < vs1.Count; i++) // for (int i = 0; i < vs1.Count; i++)
{ // {
var v1 = vs1[i]; // var v1 = vs1[i];
var v2 = vs2[i]; // var v2 = vs2[i];
if (v1.Type != v2.Type || v1.Rule != v2.Rule) // if (v1.Type != v2.Type || v1.Rule != v2.Rule)
{ // {
return false; // return false;
} // }
} // }
return true; // return true;
} //}
if (ctx.TryGetValue(a, out var e)) if (ctx.TryGetValue(a, out var e))
{ {
@ -103,16 +103,16 @@ namespace Luban.Job.Cfg.TypeVisitors
if (f1.Name != f2.Name if (f1.Name != f2.Name
|| f1.NeedExport != f2.NeedExport || f1.NeedExport != f2.NeedExport
|| f1.Index != f2.Index || f1.Index != f2.Index
|| f1.Sep != f2.Sep // || f1.Sep != f2.Sep
#if !LUBAN_LITE //#if !LUBAN_LITE
|| f1.ResourceTag != f2.ResourceTag // || f1.ResourceTag != f2.ResourceTag
#endif //#endif
|| f1.IsMultiRow != f2.IsMultiRow || f1.IsMultiRow != f2.IsMultiRow
|| f1.CType.IsNullable != f2.CType.IsNullable || f1.CType.IsNullable != f2.CType.IsNullable
|| f1.CType.GetType() != f2.CType.GetType() || f1.CType.GetType() != f2.CType.GetType()
|| !IsValidatorEquals(f1.RawDefine.Validators, f2.RawDefine.Validators) //|| !IsValidatorEquals(f1.RawDefine.Validators, f2.RawDefine.Validators)
|| !IsValidatorEquals(f1.RawDefine.KeyValidators, f2.RawDefine.KeyValidators) //|| !IsValidatorEquals(f1.RawDefine.KeyValidators, f2.RawDefine.KeyValidators)
|| !IsValidatorEquals(f1.RawDefine.ValueValidators, f2.RawDefine.ValueValidators) //|| !IsValidatorEquals(f1.RawDefine.ValueValidators, f2.RawDefine.ValueValidators)
) )
{ {
return setupNotEqual(); return setupNotEqual();

View File

@ -21,7 +21,7 @@ namespace Luban.Job.Cfg.Utils
public static DType CreateVector(TVector2 type, string x) 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]))); 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) 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]))); 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) 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]))); return new DVector4(new System.Numerics.Vector4(float.Parse(values[0]), float.Parse(values[1]), float.Parse(values[2]), float.Parse(values[3])));
} }

View File

@ -4,29 +4,29 @@ using System.Linq;
namespace Luban.Job.Cfg.Validators namespace Luban.Job.Cfg.Validators
{ {
static class ValidatorFactory //static class ValidatorFactory
{ //{
private static readonly NLog.Logger s_logger = NLog.LogManager.GetCurrentClassLogger(); // private static readonly NLog.Logger s_logger = NLog.LogManager.GetCurrentClassLogger();
public static IValidator Create(Validator validator) // public static IValidator Create(Validator validator)
{ // {
s_logger.Debug("== create validator {type}:{rule}", validator.Type, validator.Rule); // s_logger.Debug("== create validator {type}:{rule}", validator.Type, validator.Rule);
switch (validator.Type) // switch (validator.Type)
{ // {
case RefValidator.NAME: // case RefValidator.NAME:
{ // {
return new RefValidator(validator.Rule.Split(',').ToList()); // return new RefValidator(validator.Rule.Split(',').ToList());
} // }
case PathValidator.NAME: // case PathValidator.NAME:
{ // {
return new PathValidator(validator.Rule);//.Split(',').ToList()); // return new PathValidator(validator.Rule);//.Split(',').ToList());
} // }
case RangeValidator.NAME: // case RangeValidator.NAME:
{ // {
return new RangeValidator(validator.Rule); // return new RangeValidator(validator.Rule);
} // }
default: // default:
throw new NotSupportedException("unknown validator type:" + validator.Type); // throw new NotSupportedException("unknown validator type:" + validator.Type);
} // }
} // }
} //}
} }