最近做了一个关于导入Excel数据的简单工具, 设计思路如下:
1.使用XML描述配置关系
2.引入简单表达式/函数对数据进行转换,处理
3.支持灵活的扩展功能.
对EXCEL的转换配置定义如下:
<transform id="ts1" source="s1" target="t1">
<columns>
<column name="ID" dataType="int" type="autoint"/>
<column name="SITECODE" source="#Replace([$.2, $.1, $.3], [c1], [SiteName,RiverName], [SiteCode])" dataType="String"/>
<column name="SITECODE2" source="#Replace([$.2, $.1, $.3], c1, [SiteName,RiverName], SiteCode)" dataType="String"/>
<column name="SITENAME" source="$.断面名称" dataType="String"/>
<column name="SAMPLINGTIME" source="#DateTime([$.采样日期], [yyyy-MM-01])" dataType="String"/>
<column name="SAMPLINGTIME2" source="#DateTime($.采样日期, yyyy-MM-01)" dataType="String"/>
<column name="SAMPLINGTIMESTR" source="#Date($.采样日期, [yyyy年MM月dd日])" dataType="String"/>
<column name="W_TEMP" source="$.4"/>
<column name="PH" source="$.5"/>
<column name="DO1" source="$.6"/>
<column name="CODcr" source="$.7"/>
<column name="NH4_N" source="$.8"/>
<column name="CODMN" source="$.9"/>
<column name="WaterGrade" source="#REPLACE([$.10], [c2], [name], [code])"/>
<column name="WaterGrade2" source="#REPLACE($.10, c2, name, code)"/>
<column name="WaterQuality" source="$.10"/>
<column name="TBR" source="#GET([s4, s5], [0],[1])"/>
<column name="SHR" source="#GET([s4, s5], [0],[3])"/>
<column name="YWZGFZR" source="#GET([s4, s5], [0],[6])"/>
<column name="TBRQ1" source="#SUBSTRING([#GET([s4, s5], [3,4], 5)], [5])"/>
<column name="TBRQ2" source="#SUBSTRING(#GET([s4, s5], 3, 5), 5)"/>
<column name="TBRQ3" source="#SUBSTRING(#GET([s4, s5], [1-3], 5), 5)"/>
<column name="TBRQ" source="#DATETIME(#.TBRQ3, yyyy-MM-dd)"/>
<column name="REMARK" source="IMPORT"/>
<column name="ADDTIME" source="%NOW%"/>
<column name="UPDATETIME" source="%NOW%"/>
</columns>
</transform>
其中, source中的各种#, $, 还有%等的字符串, 为自定义的处理函数/表达式/常量,为了简单, 现阶段函数表达式调用,只支持嵌套一层, 上面代码中的(#SUBSTRING(#GET...)
定义的优先级规则为: 函数->表达式->常量
source的内容解析, 起初使用基于字符串匹配的方式, 勉强凑合工作, 但是马上就遇到了问题:
源: #Replace([$.2, $.1, $.3], [c1], [SiteName,RiverName], [SiteCode])
解析目标: ReplaceFunctionExpression
Arguments[0]-> ExpressionCollection[3]->DataItemExpression
Arguments[1]-> c1 : StringExpression
Arguments[2]-> ExpressionCollection[2]->StringExpression
Arguments[3]-> SiteCode : StringExpression
如上:函数的参数之间是用逗号隔开的, 但是参数有可能是另一个表达式, 或者一个数组[,], 这样子, 使用切分字符串的方式来解析函数的参数(尤其是参数为其他函数/表达式)就有问题了
记得数据结构中有中缀表达式和后缀表达式解析的算法, 应该是可以实现本例的要求, 但是时间有限, 也不需要一个很强大的功能, 所以还是没有采用, 最后的解决方案, 还是采用正则表达式来解析.
最终构造的正则表达式为:
@"\[?\#(?<fn>\w+)\((?<fp>(.*?)+)\)\]?|\[(?<fp2>([-\$\.\#%\w]+,)*[-\$\.\#%\w]+)\]|\[?(?<fp3>[-\$\.\#%\w]+)\]?"
测试的样例字符串:
//#GET([s4,s5],3,5),[5],[#GET2([s6,s7],8,9)],[100],110,[$.1,s31,s41,s51,你好],weixq,[$.中国,$H.5,#.99],$.22,#DateTime([$.采样日期], [yyyy-MM-01]), [yyyy-MM-01]
输出的匹配结果:
Result:12
1.Success:[True], Index:[0], Length:[17],Value:[#GET([s4,s5],3,5)].
2.Success:[True], Index:[18], Length:[3],Value:[[5]].
3.Success:[True], Index:[22], Length:[20],Value:[[#GET2([s6,s7],8,9)]].
4.Success:[True], Index:[43], Length:[5],Value:[[100]].
5.Success:[True], Index:[49], Length:[3],Value:[110].
6.Success:[True], Index:[53], Length:[20],Value:[[$.1,s31,s41,s51,你好]].
7.Success:[True], Index:[74], Length:[5],Value:[weixq].
8.Success:[True], Index:[80], Length:[16],Value:[[$.中国,$H.5,#.99]].
9.Success:[True], Index:[97], Length:[4],Value:[$.22].
10.Success:[True], Index:[102], Length:[33], Value:[#DateTime([$.采样日期], [yyyy-MM-01])].
11.Success:[True], Index:[137], Length:[12], Value:[[yyyy-MM-01]].
12.Success:[True], Index:[150], Length:[17], Value:[[ND,%ND,%ND%,ND%]].
其中解析的结果做为下一轮函数/表达式的输入, 继续解析, 直到不能在分解.
希望能给解析自定义字符串的朋友们一点启发:)