simdjson 5.0.2
Ridiculously Fast JSON
Loading...
Searching...
No Matches
jsonpathutil.h
1#ifndef SIMDJSON_JSONPATHUTIL_H
2#define SIMDJSON_JSONPATHUTIL_H
3
4#include "simdjson/error.h"
5#include <string>
6#include "simdjson/common_defs.h"
7
8#include <limits>
9#include <utility>
10
11namespace simdjson {
12namespace internal {
20simdjson_inline error_code parse_json_pointer_array_index(std::string_view json_pointer,
21 size_t &array_index,
22 size_t &token_length) noexcept {
23 array_index = 0;
24 token_length = 0;
25
26 for (; token_length < json_pointer.length() && json_pointer[token_length] != '/';
27 token_length++) {
28 uint8_t digit = uint8_t(json_pointer[token_length] - '0');
29 // Check for non-digit in array index. If it's there, we're trying to get a field in an object.
30 if (digit > 9) {
31 return INCORRECT_TYPE;
32 }
33 // 0 followed by other digits is invalid.
34 if (token_length > 0 && json_pointer[0] == '0') {
36 }
37 if (array_index >
38 (((std::numeric_limits<size_t>::max)() - digit) / 10)) {
40 }
41 array_index = array_index * 10 + digit;
42 }
43
44 // Empty string is invalid; so is a "/" with no digits before it.
45 if (token_length == 0) {
47 }
48
49 return SUCCESS;
50}
51} // namespace internal
52
58inline std::string json_path_to_pointer_conversion(std::string_view json_path) {
59 size_t i = 0;
60 // if JSONPath starts with $, skip it
61 // json_path.starts_with('$') requires C++20.
62 if (!json_path.empty() && json_path.front() == '$') {
63 i = 1;
64 }
65 if (i >= json_path.size() || (json_path[i] != '.' &&
66 json_path[i] != '[')) {
67 return "-1"; // This is just a sentinel value, the caller should check for this and return an error.
68 }
69
70 std::string result;
71 // Reserve space to reduce allocations, adjusting for potential increases due
72 // to escaping.
73 result.reserve(json_path.size() * 2);
74
75 while (i < json_path.length()) {
76 if (json_path[i] == '.') {
77 result += '/';
78 } else if (json_path[i] == '[') {
79 result += '/';
80 ++i; // Move past the '['
81 while (i < json_path.length() && json_path[i] != ']') {
82 if (json_path[i] == '~') {
83 result += "~0";
84 } else if (json_path[i] == '/') {
85 result += "~1";
86 } else {
87 result += json_path[i];
88 }
89 ++i;
90 }
91 if (i == json_path.length() || json_path[i] != ']') {
92 return "-1"; // Using sentinel value that will be handled as an error by the caller.
93 }
94 } else {
95 if (json_path[i] == '~') {
96 result += "~0";
97 } else if (json_path[i] == '/') {
98 result += "~1";
99 } else {
100 result += json_path[i];
101 }
102 }
103 ++i;
104 }
105
106 return result;
107}
108
109inline std::pair<std::string_view, std::string_view> get_next_key_and_json_path(std::string_view& json_path) {
110 std::string_view key;
111
112 if (json_path.empty()) {
113 return {key, json_path};
114 }
115 size_t i = 0;
116
117 // if JSONPath starts with $, skip it
118 if (json_path.front() == '$') {
119 i = 1;
120 }
121
122
123 if (i < json_path.length() && json_path[i] == '.') {
124 i += 1;
125 size_t key_start = i;
126
127 while (i < json_path.length() && json_path[i] != '[' && json_path[i] != '.') {
128 ++i;
129 }
130
131 key = json_path.substr(key_start, i - key_start);
132 } else if ((i + 1 < json_path.size()) && json_path[i] == '[' &&
133 (json_path[i + 1] == '\'' || json_path[i + 1] == '"')) {
134 // Bracket-quoted key: ['key'] or ["key"].
135 // Require a matching closing quote and a following ']'. If either is
136 // missing, return an empty key and the original path so callers can treat
137 // this as a parse failure (e.g. INVALID_JSON_POINTER) without advancing.
138 // Without this check, i += 2 can make i > size() and substr throws
139 // std::out_of_range, which aborts noexcept callers such as
140 // at_path_with_wildcard / for_each_at_path_with_wildcard.
141 const char quote = json_path[i + 1];
142 i += 2;
143 const size_t key_start = i;
144 while (i < json_path.length() && json_path[i] != quote) {
145 ++i;
146 }
147 if (i >= json_path.length() || // missing closing quote
148 i + 1 >= json_path.length() || // missing ]
149 json_path[i + 1] != ']') {
150 return {key, json_path};
151 }
152 key = json_path.substr(key_start, i - key_start);
153 i += 2; // past quote and ]
154 } else if ((i+2 < json_path.size()) && json_path[i] == '[' && json_path[i+1] == '*' && json_path[i+2] == ']') { // i.e [*].additional_keys or [*]["additional_keys"]
155 key = "*";
156 i += 3;
157 }
158
159
160 return std::make_pair(key, json_path.substr(i));
161}
162
163} // namespace simdjson
164#endif // SIMDJSON_JSONPATHUTIL_H
The top level simdjson namespace, containing everything the library provides.
Definition base.h:8
error_code
All possible errors returned by simdjson.
Definition error.h:19
@ INCORRECT_TYPE
JSON element has a different type than user expected.
Definition error.h:37
@ INDEX_OUT_OF_BOUNDS
JSON array index too large.
Definition error.h:39
@ SUCCESS
No error.
Definition error.h:20
@ INVALID_JSON_POINTER
Invalid JSON pointer syntax.
Definition error.h:42
std::string json_path_to_pointer_conversion(std::string_view json_path)
Converts JSONPath to JSON Pointer.