Files
CyberStrikeAI/internal/workflow/jsonpath.go
T
2026-07-06 11:34:50 +08:00

116 lines
2.4 KiB
Go

package workflow
import (
"encoding/json"
"fmt"
"strconv"
"strings"
)
func evalJSONPathValue(input any, path string) any {
path = strings.TrimSpace(path)
if path == "" || path == "$" || path == "." {
return input
}
if strings.HasPrefix(path, "$.") {
path = strings.TrimPrefix(path, "$.")
} else if strings.HasPrefix(path, ".") {
path = strings.TrimPrefix(path, ".")
} else if strings.HasPrefix(path, "$") {
path = strings.TrimPrefix(path, "$")
}
cur := normalizeJSONInput(input)
for _, token := range parseJSONPathTokens(path) {
if token == "" {
continue
}
switch v := cur.(type) {
case map[string]any:
cur = v[token]
case []any:
idx, err := strconv.Atoi(token)
if err != nil || idx < 0 || idx >= len(v) {
return ""
}
cur = v[idx]
default:
return ""
}
}
if cur == nil {
return ""
}
return cur
}
func normalizeJSONInput(input any) any {
switch v := input.(type) {
case string:
var decoded any
if err := json.Unmarshal([]byte(v), &decoded); err == nil {
return decoded
}
return v
case []byte:
var decoded any
if err := json.Unmarshal(v, &decoded); err == nil {
return decoded
}
return string(v)
default:
return input
}
}
func parseJSONPathTokens(path string) []string {
var tokens []string
var buf strings.Builder
for i := 0; i < len(path); i++ {
ch := path[i]
switch ch {
case '.':
if buf.Len() > 0 {
tokens = append(tokens, buf.String())
buf.Reset()
}
case '[':
if buf.Len() > 0 {
tokens = append(tokens, buf.String())
buf.Reset()
}
j := i + 1
for j < len(path) && path[j] != ']' {
j++
}
if j <= len(path) {
token := strings.Trim(path[i+1:j], `"' `)
tokens = append(tokens, token)
i = j
}
default:
buf.WriteByte(ch)
}
}
if buf.Len() > 0 {
tokens = append(tokens, buf.String())
}
return tokens
}
func validateJSONPathSyntax(path string) error {
path = strings.TrimSpace(path)
if path == "" {
return fmt.Errorf("JSONPath 不能为空")
}
if !strings.HasPrefix(path, "$") && !strings.HasPrefix(path, ".") {
return fmt.Errorf("JSONPath/JQ 路径必须以 $ 或 . 开头")
}
if strings.Contains(path, "..") || strings.ContainsAny(path, "*?()|") {
return fmt.Errorf("仅支持安全路径子集,不支持通配符、递归或表达式")
}
if strings.Count(path, "[") != strings.Count(path, "]") {
return fmt.Errorf("JSONPath 方括号不匹配")
}
return nil
}