-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtemplate.go
150 lines (133 loc) · 3.41 KB
/
template.go
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
package Record2Excel
import (
"fmt"
"reflect"
"strings"
)
type template struct {
t reflect.Type
items *itemNode
}
type itemNode struct {
name string
tagName string
fieldPath string
subItems []*itemNode
key2Index map[string]int
}
func (t template) depth() int {
return t.items.depth() - 1
}
func (n itemNode) depth() int {
if len(n.subItems) == 0 {
return 1
}
maxDepth := 0
for _, child := range n.subItems {
childDepth := child.depth()
if childDepth > maxDepth {
maxDepth = childDepth
}
}
return maxDepth + 1
}
func newTemplate(model any) (template, error) {
return template{
t: reflect.TypeOf(model),
items: buildItemTree(model, reflect.TypeOf(model), ""),
}, nil
}
func buildItemTree(model any, t reflect.Type, parentPath string) *itemNode {
// 处理指针类型,我们需要其指向的元素类型
if t.Kind() == reflect.Ptr {
t = t.Elem()
}
// 创建当前节点
node := &itemNode{
name: t.Name(),
fieldPath: parentPath,
subItems: []*itemNode{},
key2Index: make(map[string]int),
}
if t.Kind() == reflect.Slice {
t = t.Elem()
}
if t.Kind() == reflect.Struct {
for i := 0; i < t.NumField(); i++ {
field := t.Field(i)
// 构建完整的字段路径
fieldPath := field.Name
if parentPath != "" {
fieldPath = parentPath + "." + field.Name
}
// 为当前字段创建 itemNode,并递归处理嵌套结构体字段
childNode := buildItemTree(model, field.Type, fieldPath)
childNode.name = field.Name // 更新为实际的字段名
childNode.tagName = field.Name
if name, ok := field.Tag.Lookup("excel"); ok {
childNode.tagName = name
}
childNode.fieldPath = fieldPath
node.subItems = append(node.subItems, childNode)
}
} else if t.Kind() == reflect.Map {
val, err := getValueByPath(model, parentPath)
if err != nil {
panic(err)
}
//mapKeys := reflect.ValueOf(val).MapKeys()
//sort.Slice(mapKeys, func(i, j int) bool {
// return mapKeys[i].String() < mapKeys[j].String()
//})
//for _, key := range mapKeys {
// childNode := &itemNode{
// name: key.String(),
// tagName: key.String(),
// fieldPath: parentPath + "." + key.String(),
// subItems: []*itemNode{},
// }
// node.subItems = append(node.subItems, childNode)
//}
mapIter := reflect.ValueOf(val).MapRange()
for mapIter.Next() {
key := mapIter.Key().Interface().(string)
childNode := &itemNode{
name: key,
tagName: key,
fieldPath: parentPath + "." + key,
subItems: []*itemNode{},
}
node.subItems = append(node.subItems, childNode)
node.key2Index[key] = len(node.subItems) - 1
}
}
return node
}
func (t template) GetField(path string) (string, error) {
val, err := getValueByPath(reflect.New(t.t).Elem().Interface(), path)
if err != nil {
return "", err
}
return fmt.Sprintf("%v", val), nil
}
func getValueByPath(v any, path string) (any, error) {
// 将路径分割成部分
pathParts := strings.Split(path, ".")
val := reflect.ValueOf(v)
// 遍历路径的每一部分,逐步深入
for _, part := range pathParts {
// 确保当前值可以被遍历
if val.Kind() == reflect.Ptr {
val = val.Elem()
}
if val.Kind() != reflect.Struct {
return nil, fmt.Errorf("not a struct or has no field '%s'", part)
}
val = val.FieldByName(part)
if !val.IsValid() {
return nil, fmt.Errorf("field not found: %s", part)
}
}
// 返回找到的值
return val.Interface(), nil
}