StringRenderExtensions.cs
5.92 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
using NCC.ClayObject.Extensions;
using NCC.Dependency;
using NCC.Extensions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
namespace NCC.Templates.Extensions
{
/// <summary>
/// 字符串渲染模板拓展类
/// </summary>
[SuppressSniffer]
public static class StringRenderExtensions
{
/// <summary>
/// 模板正则表达式
/// </summary>
private const string commonTemplatePattern = @"\{(?<p>.+?)\}";
/// <summary>
/// 读取配置模板正则表达式
/// </summary>
private const string configTemplatePattern = @"\#\((?<p>.*?)\)";
/// <summary>
/// 渲染模板
/// </summary>
/// <param name="template"></param>
/// <param name="templateData"></param>
/// <param name="encode"></param>
public static void Render(this string template, object templateData, bool encode = false)
{
if (template == null) return;
template.Render(templateData == null ? default : templateData.ToDictionary(), encode);
}
/// <summary>
/// 渲染模板
/// </summary>
/// <param name="template"></param>
/// <param name="templateData"></param>
/// <param name="encode"></param>
/// <returns></returns>
public static string Render(this string template, IDictionary<string, object> templateData, bool encode = false)
{
if (template == null) return default;
// 如果模板为空,则跳过
if (templateData == null || templateData.Count == 0) return template;
// 判断字符串是否包含模板
if (!Regex.IsMatch(template, commonTemplatePattern)) return template;
// 获取所有匹配的模板
var templateValues = Regex.Matches(template, commonTemplatePattern)
.Select(u => new {
Template = u.Groups["p"].Value,
Value = MatchTemplateValue(u.Groups["p"].Value, templateData)
});
// 循环替换模板
foreach (var item in templateValues)
{
template = template.Replace($"{{{item.Template}}}", encode ? Uri.EscapeDataString(item.Value?.ToString() ?? string.Empty) : item.Value?.ToString());
}
return template;
}
/// <summary>
/// 从配置中渲染字符串模板
/// </summary>
/// <param name="template"></param>
/// <param name="encode"></param>
/// <returns></returns>
public static string Render(this string template, bool encode = false)
{
if (template == null) return default;
// 判断字符串是否包含模板
if (!Regex.IsMatch(template, configTemplatePattern)) return template;
// 获取所有匹配的模板
var templateValues = Regex.Matches(template, configTemplatePattern)
.Select(u => new {
Template = u.Groups["p"].Value,
Value = App.Configuration[u.Groups["p"].Value]
});
// 循环替换模板
foreach (var item in templateValues)
{
template = template.Replace($"#({item.Template})", encode ? Uri.EscapeDataString(item.Value?.ToString() ?? string.Empty) : item.Value?.ToString());
}
return template;
}
/// <summary>
/// 匹配模板值
/// </summary>
/// <param name="template"></param>
/// <param name="templateData"></param>
/// <returns></returns>
private static object MatchTemplateValue(string template, IDictionary<string, object> templateData)
{
string tmpl;
if (!template.Contains('.', StringComparison.CurrentCulture)) tmpl = template;
else tmpl = template.Split('.', StringSplitOptions.RemoveEmptyEntries).First();
var templateValue = templateData.ContainsKey(tmpl) ? templateData[tmpl] : default;
return ResolveTemplateValue(template, templateValue);
}
/// <summary>
/// 解析模板的值
/// </summary>
/// <param name="template"></param>
/// <param name="data"></param>
/// <returns></returns>
private static object ResolveTemplateValue(string template, object data)
{
// 根据 . 分割模板
var propertyCrumbs = template.Split('.', StringSplitOptions.RemoveEmptyEntries);
return GetValue(propertyCrumbs, data);
// 静态本地函数
static object GetValue(string[] propertyCrumbs, object data)
{
if (data == null || propertyCrumbs == null || propertyCrumbs.Length <= 1) return data;
var dataType = data.GetType();
// 如果是基元类型则直接返回
if (dataType.IsRichPrimitive()) return data;
object value = null;
// 递归获取下一级模板值
for (var i = 1; i < propertyCrumbs.Length; i++)
{
var propery = dataType.GetProperty(propertyCrumbs[i]);
if (propery == null) break;
value = propery.GetValue(data);
if (i + 1 < propertyCrumbs.Length)
{
value = GetValue(propertyCrumbs.Skip(i).ToArray(), value);
}
else break;
}
return value;
}
}
}
}