0
# Path Processing
1
2
Utilities for parsing JSONPath expressions into component objects and converting path arrays back to JSONPath strings. Essential for programmatic manipulation of JSONPath expressions and understanding their structure.
3
4
## Capabilities
5
6
### Parse Function
7
8
Parse a JSONPath expression string into an array of component objects, revealing the structure and operations of the expression.
9
10
```javascript { .api }
11
/**
12
* Parse JSONPath expression into component objects
13
* @param {string} pathExpression - JSONPath expression string (must be a valid string)
14
* @returns {Array<Object>} Array of path components with structure:
15
* {expression: {type: string, value: any}, operation?: string, scope?: string}
16
*/
17
function parse(pathExpression);
18
```
19
20
**Usage Examples:**
21
22
```javascript
23
const jp = require('jsonpath');
24
25
// Parse simple path
26
const components = jp.parse('$.store.book[0].author');
27
console.log(components);
28
// Result: [
29
// { expression: { type: 'root', value: '$' } },
30
// { expression: { type: 'identifier', value: 'store' }, operation: 'member', scope: 'child' },
31
// { expression: { type: 'identifier', value: 'book' }, operation: 'member', scope: 'child' },
32
// { expression: { type: 'numeric_literal', value: 0 }, operation: 'subscript', scope: 'child' },
33
// { expression: { type: 'identifier', value: 'author' }, operation: 'member', scope: 'child' }
34
// ]
35
36
// Parse recursive descent
37
const recursiveComponents = jp.parse('$..author');
38
console.log(recursiveComponents);
39
// Result: [
40
// { expression: { type: 'root', value: '$' } },
41
// { expression: { type: 'identifier', value: 'author' }, operation: 'member', scope: 'descendant' }
42
// ]
43
44
// Parse complex expression with filter
45
const filterComponents = jp.parse('$..book[?(@.price<10)]');
46
console.log(filterComponents);
47
// Shows script expression components with filter details
48
49
// Parse array slice
50
const sliceComponents = jp.parse('$.items[1:3:1]');
51
// Shows slice operation components
52
```
53
54
### Stringify Function
55
56
Convert a path array or parsed component array back to a JSONPath expression string.
57
58
```javascript { .api }
59
/**
60
* Convert path array or parsed components to JSONPath expression string
61
* @param {Array|string} path - Flat array of keys, array of parsed path components, or path string
62
* @returns {string} JSONPath expression string
63
*/
64
function stringify(path);
65
```
66
67
**Usage Examples:**
68
69
```javascript
70
const jp = require('jsonpath');
71
72
// Convert flat path array to JSONPath string
73
const pathArray = ['$', 'store', 'book', 0, 'author'];
74
const pathString = jp.stringify(pathArray);
75
console.log(pathString);
76
// Result: "$.store.book[0].author"
77
78
// Convert parsed components back to string
79
const components = jp.parse('$..book[*].title');
80
const reconstructed = jp.stringify(components);
81
console.log(reconstructed);
82
// Result: "$..book[*].title"
83
84
// Handle various path formats
85
const simplePath = ['$', 'users', 'john', 'age'];
86
console.log(jp.stringify(simplePath));
87
// Result: "$.users.john.age"
88
89
const arrayPath = ['$', 'data', 0, 'values', 1];
90
console.log(jp.stringify(arrayPath));
91
// Result: "$.data[0].values[1]"
92
93
// String literals are properly quoted
94
const stringPath = ['$', 'store', 'special-key', 'value'];
95
console.log(jp.stringify(stringPath));
96
// Result: "$.store['special-key'].value"
97
```
98
99
## Component Structure
100
101
### Expression Types
102
103
The `parse` function returns components with different expression types:
104
105
```javascript { .api }
106
/**
107
* JSONPath component structure
108
* @typedef {Object} JSONPathComponent
109
* @property {Object} expression - The expression object
110
* @property {string} expression.type - Expression type
111
* @property {*} expression.value - Expression value
112
* @property {string} [operation] - Operation type ('member' | 'subscript')
113
* @property {string} [scope] - Scope type ('child' | 'descendant')
114
*/
115
116
// Expression types:
117
// - 'root': Root element ($)
118
// - 'identifier': Property name (e.g., 'book', 'author')
119
// - 'numeric_literal': Array index (e.g., 0, 1, -1)
120
// - 'string_literal': Quoted property name (e.g., 'special-key')
121
// - 'wildcard': Wildcard selector (*)
122
// - 'slice': Array slice ([start:end:step])
123
// - 'union': Union selector ([0,1,2])
124
// - 'filter_expression': Filter expression (?(@.condition))
125
// - 'script_expression': Script expression ((@.length-1))
126
```
127
128
### Operation and Scope
129
130
Components include operation and scope information:
131
132
- **Operations:**
133
- `'member'`: Property access (`.property`)
134
- `'subscript'`: Bracket access (`[key]`)
135
136
- **Scopes:**
137
- `'child'`: Direct child access (`.` or `[...]`)
138
- `'descendant'`: Recursive descent (`..` or `..[...]`)
139
140
## Advanced Usage Examples
141
142
### Path Manipulation
143
144
```javascript
145
const jp = require('jsonpath');
146
147
// Parse, modify, and reconstruct paths
148
const original = '$.store.book[*].author';
149
const components = jp.parse(original);
150
151
// Change the target property
152
const lastComponent = components[components.length - 1];
153
lastComponent.expression.value = 'title';
154
155
const modified = jp.stringify(components);
156
console.log(modified);
157
// Result: "$.store.book[*].title"
158
159
// Build paths programmatically
160
function buildPath(segments) {
161
const components = [{ expression: { type: 'root', value: '$' } }];
162
163
segments.forEach(segment => {
164
if (typeof segment === 'string') {
165
components.push({
166
expression: { type: 'identifier', value: segment },
167
operation: 'member',
168
scope: 'child'
169
});
170
} else if (typeof segment === 'number') {
171
components.push({
172
expression: { type: 'numeric_literal', value: segment },
173
operation: 'subscript',
174
scope: 'child'
175
});
176
}
177
});
178
179
return jp.stringify(components);
180
}
181
182
console.log(buildPath(['users', 0, 'profile', 'name']));
183
// Result: "$.users[0].profile.name"
184
```
185
186
### Path Analysis
187
188
```javascript
189
const jp = require('jsonpath');
190
191
function analyzePath(pathExpression) {
192
const components = jp.parse(pathExpression);
193
194
const analysis = {
195
hasRecursiveDescent: components.some(c => c.scope === 'descendant'),
196
hasWildcards: components.some(c => c.expression.type === 'wildcard'),
197
hasFilters: components.some(c => c.expression.type === 'filter_expression'),
198
hasArrayAccess: components.some(c => c.operation === 'subscript'),
199
depth: components.length - 1 // Exclude root
200
};
201
202
return analysis;
203
}
204
205
console.log(analyzePath('$..book[*].author'));
206
// Result: { hasRecursiveDescent: true, hasWildcards: true, ... }
207
```
208
209
### Working with Query Results
210
211
```javascript
212
const jp = require('jsonpath');
213
214
const data = { users: [{ name: 'Alice' }, { name: 'Bob' }] };
215
216
// Get paths and convert them back to strings
217
const paths = jp.paths(data, '$..name');
218
const pathStrings = paths.map(path => jp.stringify(path));
219
console.log(pathStrings);
220
// Result: ["$.users[0].name", "$.users[1].name"]
221
222
// Use parsed components to understand structure
223
paths.forEach(path => {
224
const pathString = jp.stringify(path);
225
const components = jp.parse(pathString);
226
console.log(`Path ${pathString} has ${components.length} components`);
227
});
228
```
229
230
## Error Handling
231
232
Path processing functions handle various error conditions:
233
234
- `parse` throws `AssertionError` if argument is not a string
235
- `parse` throws `Error` for invalid JSONPath syntax
236
- `stringify` throws `AssertionError` if no path provided
237
- `stringify` throws `Error` if it can't find appropriate template for component
238
- `stringify` throws `Error` if path format is not recognized