【重构】重构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.Job.Cfg.Datas;
using Luban.Job.Cfg.DataSources.Excel;
using Luban.Job.Cfg.Defs;
using Luban.Job.Cfg.TypeVisitors;
using Luban.Job.Common.Types;
using Luban.Job.Common.TypeVisitors;
using System;
using System.Collections.Generic;
//using Luban.Common.Utils;
//using Luban.Job.Cfg.Datas;
//using Luban.Job.Cfg.DataSources.Excel;
//using Luban.Job.Cfg.Defs;
//using Luban.Job.Cfg.TypeVisitors;
//using Luban.Job.Common.Types;
//using Luban.Job.Common.TypeVisitors;
//using System;
//using System.Collections.Generic;
namespace Luban.Job.Cfg.DataCreators
{
class ExcelNamedRowDataCreator : ITypeFuncVisitor<Sheet.NamedRow, bool, bool, DType>
{
public static ExcelNamedRowDataCreator Ins { get; } = new ExcelNamedRowDataCreator();
//namespace Luban.Job.Cfg.DataCreators
//{
// class ExcelNamedRowDataCreator : ITypeFuncVisitor<TitleRow, 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 ReadExcel(TitleRow row, TBean btype)
// {
// return Accept(btype, row, false, false);
// }
public DType Accept(TBool type, Sheet.NamedRow x, bool multirow, bool nullable)
{
throw new NotSupportedException();
}
// public DType Accept(TBool type, TitleRow x, bool multirow, bool nullable)
// {
// throw new NotSupportedException();
// }
public DType Accept(TByte type, Sheet.NamedRow x, bool multirow, bool nullable)
{
throw new NotSupportedException();
}
// public DType Accept(TByte type, TitleRow x, bool multirow, bool nullable)
// {
// throw new NotSupportedException();
// }
public DType Accept(TShort type, Sheet.NamedRow x, bool multirow, bool nullable)
{
throw new NotSupportedException();
}
// public DType Accept(TShort type, TitleRow x, bool multirow, bool nullable)
// {
// throw new NotSupportedException();
// }
public DType Accept(TFshort type, Sheet.NamedRow x, bool multirow, bool nullable)
{
throw new NotSupportedException();
}
// public DType Accept(TFshort type, TitleRow x, bool multirow, bool nullable)
// {
// throw new NotSupportedException();
// }
public DType Accept(TInt type, Sheet.NamedRow x, bool multirow, bool nullable)
{
throw new NotSupportedException();
}
// public DType Accept(TInt type, TitleRow x, bool multirow, bool nullable)
// {
// throw new NotSupportedException();
// }
public DType Accept(TFint type, Sheet.NamedRow x, bool multirow, bool nullable)
{
throw new NotSupportedException();
}
// public DType Accept(TFint type, TitleRow x, bool multirow, bool nullable)
// {
// throw new NotSupportedException();
// }
public DType Accept(TLong type, Sheet.NamedRow x, bool multirow, bool nullable)
{
throw new NotSupportedException();
}
// public DType Accept(TLong type, TitleRow x, bool multirow, bool nullable)
// {
// throw new NotSupportedException();
// }
public DType Accept(TFlong type, Sheet.NamedRow x, bool multirow, bool nullable)
{
throw new NotSupportedException();
}
// public DType Accept(TFlong type, TitleRow x, bool multirow, bool nullable)
// {
// throw new NotSupportedException();
// }
public DType Accept(TFloat type, Sheet.NamedRow x, bool multirow, bool nullable)
{
throw new NotSupportedException();
}
// public DType Accept(TFloat type, TitleRow x, bool multirow, bool nullable)
// {
// throw new NotSupportedException();
// }
public DType Accept(TDouble type, Sheet.NamedRow x, bool multirow, bool nullable)
{
throw new NotSupportedException();
}
// public DType Accept(TDouble type, TitleRow x, bool multirow, bool nullable)
// {
// throw new NotSupportedException();
// }
public DType Accept(TEnum type, Sheet.NamedRow x, bool multirow, bool nullable)
{
throw new NotSupportedException();
}
// public DType Accept(TEnum type, TitleRow x, bool multirow, bool nullable)
// {
// throw new NotSupportedException();
// }
public DType Accept(TString type, Sheet.NamedRow x, bool multirow, bool nullable)
{
throw new NotSupportedException();
}
// public DType Accept(TString type, TitleRow x, bool multirow, bool nullable)
// {
// throw new NotSupportedException();
// }
public DType Accept(TBytes type, Sheet.NamedRow x, bool multirow, bool nullable)
{
throw new NotSupportedException();
}
// public DType Accept(TBytes type, TitleRow x, bool multirow, bool nullable)
// {
// throw new NotSupportedException();
// }
public DType Accept(TText type, Sheet.NamedRow x, bool multirow, bool nullable)
{
throw new NotSupportedException();
}
// public DType Accept(TText type, TitleRow x, bool multirow, bool nullable)
// {
// throw new NotSupportedException();
// }
private static bool IsContainerAndElementNotSepType(TType type)
{
switch (type)
{
case TArray ta: return ta.ElementType.Apply(IsNotSepTypeVisitor.Ins);
case TList tl: return tl.ElementType.Apply(IsNotSepTypeVisitor.Ins);
case TSet ts: return ts.ElementType.Apply(IsNotSepTypeVisitor.Ins);
case TMap tm: return tm.KeyType.Apply(IsNotSepTypeVisitor.Ins) && tm.ValueType.Apply(IsNotSepTypeVisitor.Ins);
default: return false;
}
throw new NotImplementedException();
}
// private static bool IsContainerAndElementNotSepType(TType type)
// {
// switch (type)
// {
// case TArray ta: return ta.ElementType.Apply(IsNotSepTypeVisitor.Ins);
// case TList tl: return tl.ElementType.Apply(IsNotSepTypeVisitor.Ins);
// case TSet ts: return ts.ElementType.Apply(IsNotSepTypeVisitor.Ins);
// case TMap tm: return tm.KeyType.Apply(IsNotSepTypeVisitor.Ins) && tm.ValueType.Apply(IsNotSepTypeVisitor.Ins);
// default: return false;
// }
// throw new NotImplementedException();
// }
private List<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 = ";,";
}
// 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.IsRowOrient), f.IsNullable, (DefAssembly)bean.AssemblyBase));
}
else
{
list.Add(f.CType.Apply(ExcelDataCreator.Ins, f, row.GetMultiRowStream(f.Name, sep, f.IsRowOrient), (DefAssembly)bean.AssemblyBase));
}
}
catch (DataCreateException dce)
{
dce.Push(bean, f);
throw;
}
catch (Exception e)
{
var dce = new DataCreateException(e, "");
dce.Push(bean, f);
throw dce;
}
}
else
{
ExcelStream stream = row.GetColumn(f.Name, sep, !f.CType.Apply(IsMultiData.Ins));
try
{
list.Add(f.CType.Apply(ExcelDataCreator.Ins, f, stream, (DefAssembly)bean.AssemblyBase));
}
catch (DataCreateException dce)
{
dce.Push(bean, f);
throw;
}
catch (Exception e)
{
var dce = new DataCreateException(e, stream.LastReadDataInfo);
dce.Push(bean, f);
throw dce;
}
}
}
}
return list;
}
// if (f.IsMultiRow)
// {
// try
// {
// if (f.CType.IsCollection)
// {
// list.Add(f.CType.Apply(MultiRowExcelDataCreator.Ins, row.GetColumnOfMultiRows(f.Name, sep), f.IsNullable, (DefAssembly)bean.AssemblyBase));
// }
// else
// {
// list.Add(f.CType.Apply(ExcelDataCreator.Ins, f, row.GetMultiRowStream(f.Name, sep), (DefAssembly)bean.AssemblyBase));
// }
// }
// catch (DataCreateException dce)
// {
// dce.Push(bean, f);
// throw;
// }
// catch (Exception e)
// {
// var dce = new DataCreateException(e, "");
// dce.Push(bean, f);
// throw dce;
// }
// }
// else
// {
// //ExcelStream stream = row.GetColumn(f.Name, sep, !f.CType.Apply(IsMultiData.Ins));
// ExcelStream stream = row.GetColumn(f.Name);
// try
// {
// list.Add(f.CType.Apply(ExcelDataCreator.Ins, f, stream, (DefAssembly)bean.AssemblyBase));
// }
// catch (DataCreateException dce)
// {
// dce.Push(bean, f);
// throw;
// }
// catch (Exception e)
// {
// var dce = new DataCreateException(e, stream.LastReadDataInfo);
// dce.Push(bean, f);
// throw dce;
// }
// }
// }
// }
// return list;
// }
public DType Accept(TBean type, Sheet.NamedRow row, bool multirow, bool nullable)
{
var originBean = (DefBean)type.Bean;
if (originBean.IsAbstractType)
{
string subType = row.GetColumn(DefBean.TYPE_NAME_KEY, null, true).Read().ToString().Trim();
if (subType.ToLower() == DefBean.BEAN_NULL_STR)
{
if (!type.IsNullable)
{
throw new Exception($"type:'{type}' 不是可空类型 '{type.Bean.FullName}?' , 不能为空");
}
return null;
}
string fullType = TypeUtil.MakeFullName(originBean.Namespace, subType);
DefBean implType = (DefBean)originBean.GetNotAbstractChildType(subType);
if (implType == null)
{
throw new Exception($"type:'{fullType}' 不是 bean 类型");
}
return new DBean(originBean, implType, CreateBeanFields(implType, row));
}
else
{
if (type.IsNullable)
{
string subType = row.GetColumn(DefBean.TYPE_NAME_KEY, null, true).Read().ToString().Trim();
if (subType == DefBean.BEAN_NULL_STR)
{
return null;
}
else if (subType != DefBean.BEAN_NOT_NULL_STR && subType != originBean.Name)
{
throw new Exception($"type:'{type.Bean.FullName}' 可空标识:'{subType}' 不合法(只能为{DefBean.BEAN_NOT_NULL_STR}或{DefBean.BEAN_NULL_STR}或{originBean.Name})");
}
}
// public DType Accept(TBean type, TitleRow row, bool multirow, bool nullable)
// {
// var originBean = (DefBean)type.Bean;
// if (originBean.IsAbstractType)
// {
// string subType = row.GetColumn(DefBean.TYPE_NAME_KEY).Read().ToString().Trim();
// if (subType.ToLower() == DefBean.BEAN_NULL_STR)
// {
// if (!type.IsNullable)
// {
// throw new Exception($"type:'{type}' 不是可空类型 '{type.Bean.FullName}?' , 不能为空");
// }
// return null;
// }
// string fullType = TypeUtil.MakeFullName(originBean.Namespace, subType);
// DefBean implType = (DefBean)originBean.GetNotAbstractChildType(subType);
// if (implType == null)
// {
// throw new Exception($"type:'{fullType}' 不是 bean 类型");
// }
// return new DBean(originBean, implType, CreateBeanFields(implType, row));
// }
// else
// {
// if (type.IsNullable)
// {
// string subType = row.GetColumn(DefBean.TYPE_NAME_KEY).Read().ToString().Trim();
// if (subType == DefBean.BEAN_NULL_STR)
// {
// return null;
// }
// else if (subType != DefBean.BEAN_NOT_NULL_STR && subType != originBean.Name)
// {
// throw new Exception($"type:'{type.Bean.FullName}' 可空标识:'{subType}' 不合法(只能为{DefBean.BEAN_NOT_NULL_STR}或{DefBean.BEAN_NULL_STR}或{originBean.Name})");
// }
// }
return new DBean(originBean, originBean, CreateBeanFields(originBean, row));
}
}
// return new DBean(originBean, originBean, CreateBeanFields(originBean, row));
// }
// }
private List<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
{
// 如果不是多行,并且定义了子标题的话。以一个子标题所占的列,读入一个数据
// private List<DType> ReadList(TBean elementType, TitleRow row, bool multirow)
// {
// 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
// {
// // 如果不是多行,并且定义了子标题的话。以一个子标题所占的列,读入一个数据
//foreach (var sub in row.SelfTitle.SubTitleList)
//{
// list.Add(this.Accept(elementType, new Sheet.NamedRow(sub, row.Rows), false, false));
//}
throw new NotSupportedException("只有multi_rows=1的list,bean类型才允许有子title");
}
return list;
}
// //foreach (var sub in row.SelfTitle.SubTitleList)
// //{
// // list.Add(this.Accept(elementType, new TitleRow(sub, row.Rows), false, false));
// //}
// throw new NotSupportedException("只有multi_rows=1的list,bean类型才允许有子title");
// }
// return list;
// }
public DType Accept(TArray type, Sheet.NamedRow x, bool multirow, bool nullable)
{
if (type.ElementType is not TBean bean)
{
throw new Exception($"NamedRow 只支持 bean 类型的容器");
}
else
{
return new DArray(type, ReadList(bean, x, multirow));
}
}
// public DType Accept(TArray type, TitleRow x, bool multirow, bool nullable)
// {
// if (type.ElementType is not TBean bean)
// {
// throw new Exception($"NamedRow 只支持 bean 类型的容器");
// }
// else
// {
// return new DArray(type, ReadList(bean, x, multirow));
// }
// }
public DType Accept(TList type, Sheet.NamedRow x, bool multirow, bool nullable)
{
if (type.ElementType is not TBean bean)
{
throw new Exception($"NamedRow 只支持 bean 类型的容器");
}
else
{
return new DList(type, ReadList(bean, x, multirow));
}
}
// public DType Accept(TList type, TitleRow x, bool multirow, bool nullable)
// {
// if (type.ElementType is not TBean bean)
// {
// throw new Exception($"NamedRow 只支持 bean 类型的容器");
// }
// else
// {
// return new DList(type, ReadList(bean, x, multirow));
// }
// }
public DType Accept(TSet type, Sheet.NamedRow x, bool multirow, bool nullable)
{
throw new NotSupportedException();
}
// public DType Accept(TSet type, TitleRow x, bool multirow, bool nullable)
// {
// throw new NotSupportedException();
// }
private bool TryCreateColumnStream(Sheet.NamedRow x, Title title, out ExcelStream stream)
{
var cells = new List<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;
}
// 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, Sheet.NamedRow x, bool multirow, bool nullable)
{
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(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, Sheet.NamedRow x, bool multirow, bool nullable)
{
throw new NotSupportedException();
}
// public DType Accept(TVector2 type, TitleRow x, bool multirow, bool nullable)
// {
// throw new NotSupportedException();
// }
public DType Accept(TVector3 type, Sheet.NamedRow x, bool multirow, bool nullable)
{
throw new NotSupportedException();
}
// public DType Accept(TVector3 type, TitleRow x, bool multirow, bool nullable)
// {
// throw new NotSupportedException();
// }
public DType Accept(TVector4 type, Sheet.NamedRow x, bool multirow, bool nullable)
{
throw new NotSupportedException();
}
// public DType Accept(TVector4 type, TitleRow x, bool multirow, bool nullable)
// {
// throw new NotSupportedException();
// }
public DType Accept(TDateTime type, Sheet.NamedRow x, bool multirow, bool nullable)
{
throw new NotSupportedException();
}
}
}
// public DType Accept(TDateTime type, TitleRow x, bool multirow, bool nullable)
// {
// throw new NotSupportedException();
// }
// }
//}

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)
{
return new DByte(x.GetByte());
return DByte.ValueOf(x.GetByte());
}
public DType Accept(TShort type, JsonElement x, DefAssembly ass)
{
return new DShort(x.GetInt16());
return DShort.ValueOf(x.GetInt16());
}
public DType Accept(TFshort type, JsonElement x, DefAssembly ass)
{
return new DFshort(x.GetInt16());
return DFshort.ValueOf(x.GetInt16());
}
public DType Accept(TInt type, JsonElement x, DefAssembly ass)
@ -42,7 +42,7 @@ namespace Luban.Job.Cfg.DataCreators
public DType Accept(TFint type, JsonElement x, DefAssembly ass)
{
return new DFint(x.GetInt32());
return DFint.ValueOf(x.GetInt32());
}
public DType Accept(TLong type, JsonElement x, DefAssembly ass)
@ -52,7 +52,7 @@ namespace Luban.Job.Cfg.DataCreators
public DType Accept(TFlong type, JsonElement x, DefAssembly ass)
{
return new DFlong(x.GetInt64());
return DFlong.ValueOf(x.GetInt64());
}
public DType Accept(TFloat type, JsonElement x, DefAssembly ass)
@ -62,7 +62,7 @@ namespace Luban.Job.Cfg.DataCreators
public DType Accept(TDouble type, JsonElement x, DefAssembly ass)
{
return new DDouble(x.GetDouble());
return DDouble.ValueOf(x.GetDouble());
}
public DType Accept(TEnum type, JsonElement x, DefAssembly ass)

View File

@ -23,17 +23,17 @@ namespace Luban.Job.Cfg.DataCreators
public DType Accept(TByte type, object x, DefAssembly ass)
{
return new DByte((byte)(int)x);
return DByte.ValueOf((byte)(int)x);
}
public DType Accept(TShort type, object x, DefAssembly ass)
{
return new DShort((short)(int)x);
return DShort.ValueOf((short)(int)x);
}
public DType Accept(TFshort type, object x, DefAssembly ass)
{
return new DFshort((short)(int)x);
return DFshort.ValueOf((short)(int)x);
}
public DType Accept(TInt type, object x, DefAssembly ass)
@ -43,7 +43,7 @@ namespace Luban.Job.Cfg.DataCreators
public DType Accept(TFint type, object x, DefAssembly ass)
{
return new DFint((int)x);
return DFint.ValueOf((int)x);
}
private long ToLong(object x)
@ -89,7 +89,7 @@ namespace Luban.Job.Cfg.DataCreators
public DType Accept(TFlong type, object x, DefAssembly ass)
{
return new DFlong(ToLong(x));
return DFlong.ValueOf(ToLong(x));
}
public DType Accept(TFloat type, object x, DefAssembly ass)
@ -99,7 +99,7 @@ namespace Luban.Job.Cfg.DataCreators
public DType Accept(TDouble type, object x, DefAssembly ass)
{
return new DDouble(ToDouble(x));
return DDouble.ValueOf(ToDouble(x));
}
public DType Accept(TEnum type, object x, DefAssembly ass)

View File

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

View File

@ -23,17 +23,17 @@ namespace Luban.Job.Cfg.DataCreators
public DType Accept(TByte type, XElement x, DefAssembly ass)
{
return new DByte(byte.Parse(x.Value.Trim()));
return DByte.ValueOf(byte.Parse(x.Value.Trim()));
}
public DType Accept(TShort type, XElement x, DefAssembly ass)
{
return new DShort(short.Parse(x.Value.Trim()));
return DShort.ValueOf(short.Parse(x.Value.Trim()));
}
public DType Accept(TFshort type, XElement x, DefAssembly ass)
{
return new DFshort(short.Parse(x.Value.Trim()));
return DFshort.ValueOf(short.Parse(x.Value.Trim()));
}
public DType Accept(TInt type, XElement x, DefAssembly ass)
@ -43,7 +43,7 @@ namespace Luban.Job.Cfg.DataCreators
public DType Accept(TFint type, XElement x, DefAssembly ass)
{
return new DFint(int.Parse(x.Value.Trim()));
return DFint.ValueOf(int.Parse(x.Value.Trim()));
}
public DType Accept(TLong type, XElement x, DefAssembly ass)
@ -53,7 +53,7 @@ namespace Luban.Job.Cfg.DataCreators
public DType Accept(TFlong type, XElement x, DefAssembly ass)
{
return new DFlong(long.Parse(x.Value.Trim()));
return DFlong.ValueOf(long.Parse(x.Value.Trim()));
}
public DType Accept(TFloat type, XElement x, DefAssembly ass)
@ -63,7 +63,7 @@ namespace Luban.Job.Cfg.DataCreators
public DType Accept(TDouble type, XElement x, DefAssembly ass)
{
return new DDouble(double.Parse(x.Value.Trim()));
return DDouble.ValueOf(double.Parse(x.Value.Trim()));
}
public DType Accept(TEnum type, XElement x, DefAssembly ass)

View File

@ -33,17 +33,17 @@ namespace Luban.Job.Cfg.DataCreators
public DType Accept(TByte type, YamlNode x, DefAssembly y)
{
return new DByte(byte.Parse(GetLowerTextValue(x)));
return DByte.ValueOf(byte.Parse(GetLowerTextValue(x)));
}
public DType Accept(TShort type, YamlNode x, DefAssembly y)
{
return new DShort(short.Parse(GetLowerTextValue(x)));
return DShort.ValueOf(short.Parse(GetLowerTextValue(x)));
}
public DType Accept(TFshort type, YamlNode x, DefAssembly y)
{
return new DFshort(short.Parse(GetLowerTextValue(x)));
return DFshort.ValueOf(short.Parse(GetLowerTextValue(x)));
}
public DType Accept(TInt type, YamlNode x, DefAssembly y)
@ -53,7 +53,7 @@ namespace Luban.Job.Cfg.DataCreators
public DType Accept(TFint type, YamlNode x, DefAssembly y)
{
return new DFint(int.Parse(GetLowerTextValue(x)));
return DFint.ValueOf(int.Parse(GetLowerTextValue(x)));
}
public DType Accept(TLong type, YamlNode x, DefAssembly y)
@ -63,7 +63,7 @@ namespace Luban.Job.Cfg.DataCreators
public DType Accept(TFlong type, YamlNode x, DefAssembly y)
{
return new DFlong(long.Parse(GetLowerTextValue(x)));
return DFlong.ValueOf(long.Parse(GetLowerTextValue(x)));
}
public DType Accept(TFloat type, YamlNode x, DefAssembly y)
@ -73,7 +73,7 @@ namespace Luban.Job.Cfg.DataCreators
public DType Accept(TDouble type, YamlNode x, DefAssembly y)
{
return new DDouble(double.Parse(GetLowerTextValue(x)));
return DDouble.ValueOf(double.Parse(GetLowerTextValue(x)));
}
public DType Accept(TEnum type, YamlNode x, DefAssembly y)

View File

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

View File

@ -18,15 +18,8 @@ namespace Luban.Job.Cfg.DataSources.Excel
private readonly int _toIndex;
private int _curIndex;
/// <summary>
/// NamedMode下 string可以用空白表达空字符串而不必用null或""
/// </summary>
public bool NamedMode { get; set; }
public ExcelStream(List<Cell> datas, int fromIndex, int toIndex, string sep, bool namedMode)
public ExcelStream(List<Cell> datas, int fromIndex, int toIndex, string sep)
{
NamedMode = namedMode;
if (string.IsNullOrWhiteSpace(sep))
{
this._datas = datas;
@ -54,9 +47,8 @@ namespace Luban.Job.Cfg.DataSources.Excel
}
}
public ExcelStream(Cell cell, string sep, bool namedMode)
public ExcelStream(Cell cell, string sep)
{
NamedMode = namedMode;
if (string.IsNullOrWhiteSpace(sep))
{
this._datas = new List<Cell> { 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 Luban.Job.Cfg.DataCreators;
using Luban.Job.Cfg.Datas;
using Luban.Job.Cfg.Defs;
using Luban.Job.Cfg.Utils;
using Luban.Job.Common.Types;
using Luban.Job.Common.Utils;
@ -12,224 +11,14 @@ using System.Linq;
namespace Luban.Job.Cfg.DataSources.Excel
{
class Sheet
{
private static readonly NLog.Logger s_logger = NLog.LogManager.GetCurrentClassLogger();
private const int TITLE_MIN_ROW_NUM = 2;
private const int TITLE_MAX_ROW_NUM = 10;
private const int TITLE_DEFAULT_ROW_NUM = 3;
private bool IsOrientRow { get; set; } = true; // 以行为数据读取方向
public int HeaderRowCount { get; private set; } = TITLE_DEFAULT_ROW_NUM; // 默认有三行是标题行. 第一行是字段名,第二行是中文描述,第三行是注释
public int AttrRowCount { get; private set; }
public string RawUrl { get; }
public string Name { get; }
private List<List<Cell>> _rowColumns;
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 string RawUrl { get; }
public Sheet(string rawUrl, string name)
{
@ -237,401 +26,14 @@ namespace Luban.Job.Cfg.DataSources.Excel
this.Name = name;
}
public bool Load(IExcelDataReader reader, bool headerOnly)
public void Load(RawSheet rawSheet)
{
//s_logger.Info("read sheet:{sheet}", reader.Name);
if (!ParseMeta(reader))
{
return false;
}
LoadRemainRows(reader, headerOnly);
return true;
}
private bool ParseMeta(IExcelDataReader reader)
{
if (!reader.Read() || reader.FieldCount == 0)
{
return false;
}
// meta 行 必须以 ##为第一个单元格内容,紧接着 key:value 形式 表达meta属性
if (reader.GetString(0) != "##")
{
return false;
}
for (int i = 1, n = reader.FieldCount; i < n; i++)
{
var attr = reader.GetString(i);
if (string.IsNullOrWhiteSpace(attr))
{
continue;
}
var ss = attr.Split(':', '=');
if (ss.Length != 2)
{
throw new Exception($"单元薄 meta 定义出错. attribute:{attr}");
}
string key = ss[0].ToLower();
string value = ss[1].ToLower();
switch (key)
{
case "orientation":
{
IsOrientRow = DefUtil.ParseOrientation(value);
break;
}
case "title_rows":
{
if (!int.TryParse(value, out var v))
{
throw new Exception($"单元薄 meta 定义 title_rows:{value} 属性值只能为整数[{TITLE_MIN_ROW_NUM},{TITLE_MAX_ROW_NUM}]");
}
if (v < TITLE_MIN_ROW_NUM || v > TITLE_MAX_ROW_NUM)
{
throw new Exception($"单元薄 title_rows 应该在 [{TITLE_MIN_ROW_NUM},{TITLE_MAX_ROW_NUM}] 范围内,默认是{TITLE_DEFAULT_ROW_NUM}");
}
HeaderRowCount = v;
break;
}
case "table":
{
break;
}
default:
{
throw new Exception($"非法单元薄 meta 属性定义 {attr}, 合法属性有: orientation=r|row|c|column,title_rows=<number>");
}
}
}
return true;
}
private static string GetRowTag(List<Cell> row)
{
if (row.Count == 0)
{
return null;
}
if (row[0].Value == null)
{
return null;
}
return row[0].Value.ToString().Trim();
}
private void InitSubTitles(Title parentTitle, List<List<Cell>> rows, CellRange[] mergeCells, int maxDepth, int depth, int fromColumn, int toColumn)
{
List<Cell> row = rows[depth];
//if (row.Count > fromColumn)
//{
// row = row.GetRange(fromColumn, Math.Min(row.Count, toColumn + 1) - fromColumn);
//}
foreach (var mergeCell in mergeCells)
{
if (mergeCell.FromRow == depth + 1 && mergeCell.FromColumn >= fromColumn && mergeCell.ToColumn <= toColumn)
{
string subTitleName = row[mergeCell.FromColumn].Value?.ToString()?.Trim();
if (!string.IsNullOrWhiteSpace(subTitleName))
{
var newTitle = new Title() { Name = subTitleName, FromIndex = mergeCell.FromColumn, ToIndex = mergeCell.ToColumn };
if (depth + 1 < maxDepth)
{
InitSubTitles(newTitle, rows, mergeCells, maxDepth, depth + 1, mergeCell.FromColumn, mergeCell.ToColumn);
}
parentTitle.AddSubTitle(newTitle);
}
}
}
for (int i = fromColumn; i <= toColumn; i++)
{
if (i >= row.Count)
{
break;
}
var name = row[i].Value?.ToString()?.Trim();
if (string.IsNullOrWhiteSpace(name))
{
continue;
}
if (parentTitle.SubTitles.TryGetValue(name, out var oldTitle))
{
if (oldTitle.FromIndex != i)
{
throw new Exception($"sub title 列:{name} 重复");
}
else
{
continue;
}
}
var newTitle = new Title() { Name = name, FromIndex = i, ToIndex = i };
if (depth + 1 < maxDepth)
{
InitSubTitles(newTitle, rows, mergeCells, maxDepth, depth + 1, i, i);
}
parentTitle.AddSubTitle(newTitle);
}
}
const string ROOT_TITLE_NAME = "__<root>__";
private void LoadRemainRows(IExcelDataReader reader, bool headerOnly)
{
// TODO 优化性能
// 几个思路
// 1. 没有 title 的列不加载
// 2. 空行优先跳过
// 3. 跳过null或者empty的单元格
var rows = new List<List<Cell>>();
int rowIndex = 0;
while (reader.Read())
{
++rowIndex; // 第1行是 meta 标题及数据行从第2行开始
// 重点优化横表的headerOnly模式 此模式下只读前几行标题行,不读数据行
if (headerOnly && this.IsOrientRow && rowIndex > this.HeaderRowCount)
{
break;
}
var row = new List<Cell>();
for (int i = 0, n = reader.FieldCount; i < n; i++)
{
row.Add(new Cell(rowIndex, i, reader.GetValue(i)));
}
rows.Add(row);
}
if (IsOrientRow)
{
this._rowColumns = rows;
}
else
{
// 转置这个行列
int maxColumn = rows.Select(r => r.Count).Max();
this._rowColumns = new List<List<Cell>>();
for (int i = 0; i < maxColumn; i++)
{
var row = new List<Cell>();
for (int j = 0; j < rows.Count; j++)
{
row.Add(i < rows[j].Count ? rows[j][i] : new Cell(j + 1, i, null));
}
this._rowColumns.Add(row);
}
}
if (this._rowColumns.Count < 1)
{
throw new Exception($"没有定义字段名行");
}
_rootTitle = new Title() { Root = true, Name = ROOT_TITLE_NAME, FromIndex = 1, ToIndex = rows.Select(r => r.Count).Max() - 1 };
int fieldRowCount = 1;
int attrRowCount = 1;
if (reader.MergeCells != null)
{
if (IsOrientRow)
{
foreach (var mergeCell in reader.MergeCells)
{
if (mergeCell.FromRow == 1 && mergeCell.FromColumn == 0 && mergeCell.ToColumn == 0)
{
fieldRowCount = mergeCell.ToRow - mergeCell.FromRow + 1;
break;
}
}
foreach (var mergeCell in reader.MergeCells)
{
if (mergeCell.FromRow == 1 + fieldRowCount && mergeCell.FromColumn == 0 && mergeCell.ToColumn == 0)
{
attrRowCount = mergeCell.ToRow - mergeCell.FromRow + 1;
break;
}
}
}
foreach (var mergeCell in reader.MergeCells)
{
if (IsOrientRow)
{
//if (mergeCell.FromRow <= 1 && mergeCell.ToRow >= 1)
if (mergeCell.FromRow == 1)
{
// 标题 行
fieldRowCount = Math.Max(fieldRowCount, mergeCell.ToRow - mergeCell.FromRow + 1);
var titleName = _rowColumns[0][mergeCell.FromColumn].Value?.ToString()?.Trim();
if (string.IsNullOrWhiteSpace(titleName))
{
continue;
}
var newTitle = new Title() { Name = titleName, FromIndex = mergeCell.FromColumn, ToIndex = mergeCell.ToColumn };
if (fieldRowCount > 1)
{
InitSubTitles(newTitle, rows, reader.MergeCells, fieldRowCount, 1, mergeCell.FromColumn, mergeCell.ToColumn);
}
_rootTitle.AddSubTitle(newTitle);
//s_logger.Info("=== sheet:{sheet} title:{title}", Name, newTitle);
}
}
else
{
if (mergeCell.FromColumn <= 0 && mergeCell.ToColumn >= 0)
{
// 标题 行
var titleName = _rowColumns[0][mergeCell.FromRow - 1].Value?.ToString()?.Trim();
if (string.IsNullOrWhiteSpace(titleName))
{
continue;
}
_rootTitle.AddSubTitle(new Title() { Name = titleName, FromIndex = mergeCell.FromRow - 1, ToIndex = mergeCell.ToRow - 1 });
}
}
}
}
this.AttrRowCount = attrRowCount;
//TODO 其实有bug. 未处理只占一列的 多级标题头
// 上面的代码处理完Merge列,接下来处理非Merge的列
var titleRow = _rowColumns[0];
for (int i = 0; i < titleRow.Count; i++)
{
var name = titleRow[i].Value?.ToString()?.Trim();
if (string.IsNullOrWhiteSpace(name))
{
continue;
}
if (_rootTitle.SubTitles.TryGetValue(name, out var oldTitle))
{
if (oldTitle.FromIndex != i)
{
throw new Exception($"列:{name} 重复");
}
else
{
continue;
}
}
_rootTitle.AddSubTitle(new Title() { Name = name, FromIndex = i, ToIndex = i });
}
if (_rootTitle.SubTitleList.Count == 0)
{
throw new Exception($"没有定义任何有效 列");
}
_rootTitle.SortSubTitles();
if (headerOnly)
{
// 删除字段名行,保留属性行开始的行
this._rowColumns.RemoveRange(0, Math.Min(fieldRowCount, this._rowColumns.Count));
}
else
{
// 删除所有标题行,包含字段名行、属性行、标题、描述等等非有效数据行
this._rowColumns.RemoveRange(0, Math.Min(HeaderRowCount, this._rowColumns.Count));
// 删除忽略的记录行
this._rowColumns.RemoveAll(row => DataUtil.IsIgnoreTag(GetRowTag(row)));
}
}
private static bool IsBlankRow(List<Cell> row)
public IEnumerable<TitleRow> GetRows()
{
// 第一列被策划用于表示是否注释掉此行
// 忽略此列是否空白
return row.GetRange(1, row.Count - 1).All(c => c.Value == null || (c.Value is string s && string.IsNullOrWhiteSpace(s)));
}
private static bool IsBlankRow(List<Cell> row, int fromIndex, int toIndex)
{
for (int i = Math.Max(1, fromIndex), n = Math.Min(toIndex, row.Count - 1); i <= n; i++)
{
var v = row[i].Value;
if (v != null && !(v is string s && string.IsNullOrEmpty(s)))
{
return false;
}
}
return true;
}
private static bool IsSameRow(List<Cell> row1, List<Cell> row2, int fromIndex, int toIndex)
{
if (row2.Count < toIndex - 1)
{
return false;
}
for (int i = Math.Max(1, fromIndex), n = Math.Min(toIndex, row1.Count - 1); i <= n; i++)
{
var v1 = row1[i].Value;
var v2 = row2[i].Value;
if (v1 != v2)
{
if (v1 == null)
{
if (!(v2 is string s && string.IsNullOrWhiteSpace(s)))
{
return false;
}
}
else if (v2 == null)
{
if (!(v1 is string s && string.IsNullOrWhiteSpace(s)))
{
return false;
}
}
else
{
return v1.ToString() == v2.ToString();
}
}
}
return true;
}
private static bool IsBlankColumn(List<List<Cell>> rows, int column)
{
foreach (List<Cell> row in rows)
{
if (column >= row.Count)
{
continue;
}
var v = row[column].Value;
if (v != null && !(v is string s && string.IsNullOrEmpty(s)))
{
return false;
}
}
return true;
}
public IEnumerable<Record> ReadMulti(TBean type)
{
foreach (var recordNamedRow in NamedRow.CreateMultiRowNamedRow(this._rowColumns, this._rootTitle, type))
{
var tags = DataUtil.ParseTags(GetRowTag(recordNamedRow.Rows[0]));
var data = (DBean)ExcelNamedRowDataCreator.Ins.ReadExcel(recordNamedRow, type);
yield return new Record(data, RawUrl, tags);
}
yield return null;
}
}
}

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

View File

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

View File

@ -6,9 +6,21 @@ namespace Luban.Job.Cfg.Datas
{
public static DByte Default { get; } = new DByte(0);
public static DByte ValueOf(byte x)
{
if (x == 0)
{
return Default;
}
else
{
return new DByte(x);
}
}
public override string TypeName => "byte";
public DByte(byte x) : base(x)
private DByte(byte x) : base(x)
{
}

View File

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

View File

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

View File

@ -4,7 +4,7 @@ namespace Luban.Job.Cfg.Datas
{
public class DFloat : DType<float>
{
private static DFloat Default { get; } = new DFloat(0);
public static DFloat Default { get; } = new DFloat(0);
public override string TypeName => "float";

View File

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

View File

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

View File

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

View File

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

View File

@ -126,40 +126,6 @@ namespace Luban.Job.Cfg.Defs
_cfgGroups.Add(new Group() { Names = groupNames });
}
private void FillValueValidator(CfgField f, string attrValue, string validatorName)
{
if (!string.IsNullOrWhiteSpace(attrValue))
{
var validator = new Validator() { Type = validatorName, Rule = attrValue };
f.Validators.Add(validator);
f.ValueValidators.Add(validator);
}
}
private void FillValidators(string defineFile, string key, string attr, List<Validator> result)
{
if (!string.IsNullOrWhiteSpace(attr))
{
#if !LUBAN_LITE
foreach (var validatorStr in attr.Split('#', StringSplitOptions.RemoveEmptyEntries))
#else
foreach (var validatorStr in attr.Split('#'))
#endif
{
var sepIndex = validatorStr.IndexOf(':');
if (sepIndex <= 0)
{
throw new Exception($"定义文件:{defineFile} key:'{key}' attr:'{attr}' 不是合法的 validator 定义 (key1:value1#key2:value2 ...)");
}
#if !LUBAN_LITE
result.Add(new Validator() { Type = validatorStr[..sepIndex], Rule = validatorStr[(sepIndex + 1)..] });
#else
result.Add(new Validator() { Type = validatorStr.Substring(0, sepIndex), Rule = validatorStr.Substring(sepIndex + 1, validatorStr.Length - sepIndex - 1) });
#endif
}
}
}
private readonly List<string> _serviceAttrs = new List<string> { "name", "manager", "group" };
private void AddService(XElement e)
@ -325,36 +291,36 @@ namespace Luban.Job.Cfg.Defs
var file = inputFileInfos[0];
var source = new ExcelDataSource();
var stream = new MemoryStream(await this.Agent.GetFromCacheOrReadAllBytesAsync(file.ActualFile, file.MD5));
var sheet = source.LoadFirstSheet(file.OriginFile, file.SheetName, stream);
var tableDefInfo = source.LoadTableDefInfo(file.OriginFile, file.SheetName, stream);
var cb = new CfgBean() { Namespace = table.Namespace, Name = table.ValueType, };
var rc = sheet.RowColumns;
var attrRow = sheet.RowColumns[0];
if (rc.Count < sheet.AttrRowCount + 1)
//var rc = sheet.RowColumns;
//var attrRow = sheet.RowColumns[0];
//if (rc.Count < sheet.AttrRowCount + 1)
//{
// throw new Exception($"table:'{table.Name}' file:{file.OriginFile} 至少包含 属性行和标题行");
//}
//var titleRow = sheet.RowColumns[sheet.AttrRowCount];
//// 有可能没有注释行,此时使用标题行,这个是必须有的
//var descRow = sheet.HeaderRowCount >= sheet.AttrRowCount + 2 ? sheet.RowColumns[sheet.AttrRowCount + 1] : titleRow;
foreach (var (name, f) in tableDefInfo.FieldInfos)
{
throw new Exception($"table:'{table.Name}' file:{file.OriginFile} 至少包含 属性行和标题行");
}
var titleRow = sheet.RowColumns[sheet.AttrRowCount];
// 有可能没有注释行,此时使用标题行,这个是必须有的
var descRow = sheet.HeaderRowCount >= sheet.AttrRowCount + 2 ? sheet.RowColumns[sheet.AttrRowCount + 1] : titleRow;
foreach (var f in sheet.RootFields)
{
var cf = new CfgField() { Name = f.Name, Id = 0 };
var cf = new CfgField() { Name = name, Id = 0 };
string[] attrs = (attrRow[f.FromIndex].Value?.ToString() ?? "").Trim().Split('&').Select(s => s.Trim()).ToArray();
string[] attrs = f.Type.Trim().Split('&').Select(s => s.Trim()).ToArray();
if (attrs.Length == 0 || string.IsNullOrWhiteSpace(attrs[0]))
{
throw new Exception($"table:'{table.Name}' file:{file.OriginFile} title:'{f.Name}' type missing!");
throw new Exception($"table:'{table.Name}' file:{file.OriginFile} title:'{name}' type missing!");
}
// 优先取desc行如果为空,则取title行
cf.Comment = descRow[f.FromIndex].Value?.ToString();
cf.Comment = f.BriefDesc;
if (string.IsNullOrWhiteSpace(cf.Comment))
{
cf.Comment = titleRow[f.FromIndex].Value?.ToString();
cf.Comment = f.DetailDesc;
}
if (string.IsNullOrWhiteSpace(cf.Comment))
{
@ -372,7 +338,7 @@ namespace Luban.Job.Cfg.Defs
#endif
if (pair.Length != 2)
{
throw new Exception($"table:'{table.Name}' file:{file.OriginFile} title:'{f.Name}' attr:'{attrs[i]}' is invalid!");
throw new Exception($"table:'{table.Name}' file:{file.OriginFile} title:'{name}' attr:'{attrs[i]}' is invalid!");
}
var attrName = pair[0].Trim();
var attrValue = pair[1].Trim();
@ -383,23 +349,13 @@ namespace Luban.Job.Cfg.Defs
cf.Index = attrValue;
break;
}
case "sep":
{
cf.Sep = attrValue;
break;
}
case "ref":
case "path":
case "range":
{
var validator = new Validator() { Type = attrName, Rule = attrValue };
cf.Validators.Add(validator);
cf.ValueValidators.Add(validator);
break;
}
case "multi_rows":
{
cf.IsMultiRow = attrValue == "1" || attrValue.Equals("true", StringComparison.OrdinalIgnoreCase);
//var validator = new Validator() { Type = attrName, Rule = attrValue };
//cf.Validators.Add(validator);
//cf.ValueValidators.Add(validator);
break;
}
case "group":
@ -412,29 +368,14 @@ namespace Luban.Job.Cfg.Defs
cf.Comment = attrValue;
break;
}
case "convert":
{
cf.Converter = attrValue;
break;
}
case "default":
{
cf.DefaultValue = attrValue;
break;
}
case "tags":
{
cf.Tags = attrValue;
break;
}
case "orientation":
{
cf.IsRowOrient = DefUtil.ParseOrientation(attrValue);
break;
}
default:
{
throw new Exception($"table:'{table.Name}' file:{file.OriginFile} title:'{f.Name}' attr:'{attrs[i]}' is invalid!");
throw new Exception($"table:'{table.Name}' file:{file.OriginFile} title:'{name}' attr:'{attrs[i]}' is invalid!");
}
}
}
@ -665,7 +606,7 @@ namespace Luban.Job.Cfg.Defs
new CfgField() { Name = "sep", Type = "string" },
new CfgField() { Name = "comment", Type = "string" },
new CfgField() { Name = "tags", Type = "string" },
new CfgField() { Name = "fields", Type = "list,__FieldInfo__", IsMultiRow = true },
new CfgField() { Name = "fields", Type = "list,__FieldInfo__" },
}
})
{
@ -714,21 +655,10 @@ namespace Luban.Job.Cfg.Defs
(b.GetField("name") as DString).Value.Trim(),
(b.GetField("type") as DString).Value.Trim(),
(b.GetField("index") as DString).Value.Trim(),
(b.GetField("sep") as DString).Value.Trim(),
(b.GetField("is_multi_rows") as DBool).Value,
(b.GetField("group") as DString).Value,
"",
"",
(b.GetField("comment") as DString).Value.Trim(),
(b.GetField("ref") as DString).Value.Trim(),
(b.GetField("path") as DString).Value.Trim(),
"",
"",
"",
"",
(b.GetField("tags") as DString).Value.Trim(),
false,
DefUtil.ParseOrientation((b.GetField("orientation") as DString).Value)
false
)).ToList(),
};
this._beans.Add(curBean);
@ -771,41 +701,25 @@ namespace Luban.Job.Cfg.Defs
return CreateField(defineFile, XmlUtil.GetRequiredAttribute(e, "name"),
XmlUtil.GetRequiredAttribute(e, "type"),
XmlUtil.GetOptionalAttribute(e, "index"),
XmlUtil.GetOptionalAttribute(e, "sep"),
XmlUtil.GetOptionBoolAttribute(e, "multi_rows"),
XmlUtil.GetOptionalAttribute(e, "group"),
XmlUtil.GetOptionalAttribute(e, "res"),
XmlUtil.GetOptionalAttribute(e, "convert"),
XmlUtil.GetOptionalAttribute(e, "comment"),
XmlUtil.GetOptionalAttribute(e, "ref"),
XmlUtil.GetOptionalAttribute(e, "path"),
XmlUtil.GetOptionalAttribute(e, "range"),
XmlUtil.GetOptionalAttribute(e, "key_validator"),
XmlUtil.GetOptionalAttribute(e, "value_validator"),
XmlUtil.GetOptionalAttribute(e, "validator"),
XmlUtil.GetOptionalAttribute(e, "tags"),
false,
DefUtil.ParseOrientation(XmlUtil.GetOptionalAttribute(e, "orientation"))
false
);
}
private Field CreateField(string defileFile, string name, string type, string index, string sep, bool isMultiRow, string group, string resource, string converter,
string comment, string refs, string path, string range, string keyValidator, string valueValidator, string validator, string tags,
bool ignoreNameValidation, bool isRowOrient)
private Field CreateField(string defileFile, string name, string type, string index, string group,
string comment, string tags,
bool ignoreNameValidation)
{
var f = new CfgField()
{
Name = name,
Index = index,
Sep = sep,
IsMultiRow = isMultiRow,
Groups = CreateGroups(group),
Resource = resource,
Converter = converter,
Comment = comment,
Tags = tags,
IgnoreNameValidation = ignoreNameValidation,
IsRowOrient = isRowOrient,
};
// 字段与table的默认组不一样。
@ -822,13 +736,13 @@ namespace Luban.Job.Cfg.Defs
f.Type = type;
FillValueValidator(f, refs, "ref");
FillValueValidator(f, path, "path"); // (ue4|unity|normal|regex);xxx;xxx
FillValueValidator(f, range, "range");
//FillValueValidator(f, refs, "ref");
//FillValueValidator(f, path, "path"); // (ue4|unity|normal|regex);xxx;xxx
//FillValueValidator(f, range, "range");
FillValidators(defileFile, "key_validator", keyValidator, f.KeyValidators);
FillValidators(defileFile, "value_validator", valueValidator, f.ValueValidators);
FillValidators(defileFile, "validator", validator, f.Validators);
//FillValidators(defileFile, "key_validator", keyValidator, f.KeyValidators);
//FillValidators(defileFile, "value_validator", valueValidator, f.ValueValidators);
//FillValidators(defileFile, "validator", validator, f.Validators);
return f;
}

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

View File

@ -3,36 +3,10 @@ using System.Collections.Generic;
namespace Luban.Job.Cfg.RawDefs
{
public class Validator
{
public string Type { get; set; }
public string Rule { get; set; }
}
public class CfgField : Field
{
public string Index { get; set; } = "";
public string Sep { get; set; } = "";
public bool IsMultiRow { get; set; }
public string Resource { get; set; } = "";
public string Converter { get; set; } = "";
public string DefaultValue { get; set; } = "";
public bool IsRowOrient { get; set; } = true;
public string Index { get; set; }
public List<string> Groups { get; set; } = new List<string>();
public List<Validator> KeyValidators { get; } = new List<Validator>();
public List<Validator> ValueValidators { get; } = new List<Validator>();
public List<Validator> Validators { get; } = new List<Validator>();
}
}

View File

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

View File

@ -21,7 +21,7 @@ namespace Luban.Job.Cfg.Utils
public static DType CreateVector(TVector2 type, string x)
{
var values = DataUtil.SplitVectorString(x);
var values = SplitVectorString(x);
return new DVector2(new System.Numerics.Vector2(float.Parse(values[0]), float.Parse(values[1])));
@ -29,7 +29,7 @@ namespace Luban.Job.Cfg.Utils
public static DType CreateVector(TVector3 type, string x)
{
var values = DataUtil.SplitVectorString(x);
var values = SplitVectorString(x);
return new DVector3(new System.Numerics.Vector3(float.Parse(values[0]), float.Parse(values[1]), float.Parse(values[2])));
@ -37,7 +37,7 @@ namespace Luban.Job.Cfg.Utils
public static DType CreateVector(TVector4 type, string x)
{
var values = DataUtil.SplitVectorString(x);
var values = SplitVectorString(x);
return new DVector4(new System.Numerics.Vector4(float.Parse(values[0]), float.Parse(values[1]), float.Parse(values[2]), float.Parse(values[3])));
}

View File

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