ParsePath converts a JSONPath-style path into the path components accepted by Get, Set, Delete, ArrayEach, and EachKey. SYS-REQ-114
(jsonPath string)
| 15 | // by Get, Set, Delete, ArrayEach, and EachKey. |
| 16 | // SYS-REQ-114 |
| 17 | func ParsePath(jsonPath string) ([]string, error) { |
| 18 | if jsonPath == "" { |
| 19 | return nil, errEmptyPath |
| 20 | } |
| 21 | |
| 22 | switch { |
| 23 | case jsonPath == "$": |
| 24 | return []string{}, nil |
| 25 | case strings.HasPrefix(jsonPath, "$."): |
| 26 | jsonPath = jsonPath[2:] |
| 27 | case strings.HasPrefix(jsonPath, "$["): |
| 28 | jsonPath = jsonPath[1:] |
| 29 | case jsonPath[0] == '$': |
| 30 | return nil, errMalformedPath |
| 31 | } |
| 32 | |
| 33 | if jsonPath == "" { |
| 34 | return nil, errMalformedPath |
| 35 | } |
| 36 | |
| 37 | // A path component is either a dot-delimited key or bracket notation. |
| 38 | // Counting both separators gives an exact capacity for ordinary paths and |
| 39 | // a safe upper bound for quoted keys containing dots or brackets. |
| 40 | parts := make([]string, 0, 1+strings.Count(jsonPath, ".")+strings.Count(jsonPath, "[")) |
| 41 | |
| 42 | for pos := 0; pos < len(jsonPath); { |
| 43 | switch jsonPath[pos] { |
| 44 | case '.': |
| 45 | return nil, errMalformedPath |
| 46 | case '"': |
| 47 | key, next, err := parseQuotedPathKey(jsonPath, pos) |
| 48 | if err != nil { |
| 49 | return nil, err |
| 50 | } |
| 51 | parts = append(parts, key) |
| 52 | pos = next |
| 53 | case '[': |
| 54 | // A root array path or a bracket immediately following a dot has |
| 55 | // no key component before its index. |
| 56 | default: |
| 57 | start := pos |
| 58 | for pos < len(jsonPath) && jsonPath[pos] != '.' && jsonPath[pos] != '[' { |
| 59 | if jsonPath[pos] == ']' || jsonPath[pos] == '"' { |
| 60 | return nil, errMalformedPath |
| 61 | } |
| 62 | pos++ |
| 63 | } |
| 64 | if start == pos { |
| 65 | return nil, errMalformedPath |
| 66 | } |
| 67 | parts = append(parts, jsonPath[start:pos]) |
| 68 | } |
| 69 | |
| 70 | for pos < len(jsonPath) && jsonPath[pos] == '[' { |
| 71 | component, next, err := parseBracketPathComponent(jsonPath, pos) |
| 72 | if err != nil { |
| 73 | return nil, err |
| 74 | } |