0
# Transform Operations
1
2
JMESPath-based data transformation and filtering capabilities with custom query language support, sorting functionality, and data manipulation tools.
3
4
## Capabilities
5
6
### Query Configuration
7
8
Configure custom query creation and execution functions for data transformation.
9
10
```javascript { .api }
11
/**
12
* Custom query configuration in editor options
13
*/
14
interface QueryConfiguration {
15
/** Function to create query string from query options */
16
createQuery?: (json: any, queryOptions: QueryOptions) => string;
17
18
/** Function to execute query string on JSON data */
19
executeQuery?: (json: any, query: string) => any;
20
21
/** Description text for the query language */
22
queryDescription?: string;
23
}
24
```
25
26
### Query Options Structure
27
28
Structure for transformation query options used in the Transform modal.
29
30
```javascript { .api }
31
interface QueryOptions {
32
/** Filter configuration */
33
filter?: {
34
/** Field to filter on, or '@' for the value itself */
35
field: string | "@";
36
37
/** Comparison operator */
38
relation: "==" | "!=" | "<" | "<=" | ">" | ">=";
39
40
/** Value to compare against */
41
value: string;
42
};
43
44
/** Sort configuration */
45
sort?: {
46
/** Field to sort by, or '@' for the value itself */
47
field: string | "@";
48
49
/** Sort direction */
50
direction: "asc" | "desc";
51
};
52
53
/** Projection configuration */
54
projection?: {
55
/** Array of field names to include in output */
56
fields: string[];
57
};
58
}
59
```
60
61
**Usage Example:**
62
63
```javascript
64
// Example query options for filtering and sorting users
65
const queryOptions = {
66
filter: {
67
field: "age",
68
relation: ">=",
69
value: "18"
70
},
71
sort: {
72
field: "name",
73
direction: "asc"
74
},
75
projection: {
76
fields: ["name", "email", "age"]
77
}
78
};
79
```
80
81
### Built-in JMESPath Support
82
83
JSONEditor includes built-in JMESPath query support for data transformation.
84
85
```javascript { .api }
86
// Default JMESPath query functions (internal)
87
const defaultJMESPathConfig = {
88
createQuery: (json, queryOptions) => {
89
// Converts QueryOptions to JMESPath query string
90
// Example output: "users[?age >= `18`] | sort_by(@, &name) | [].{name: name, email: email}"
91
},
92
93
executeQuery: (json, jmespathQuery) => {
94
// Executes JMESPath query on JSON data
95
// Returns transformed data
96
},
97
98
queryDescription: "Uses JMESPath query language. See <a href='http://jmespath.org/'>jmespath.org</a> for syntax."
99
};
100
```
101
102
### Custom Query Language
103
104
Implement a custom query language to replace the default JMESPath functionality.
105
106
```javascript { .api }
107
// Custom SQL-like query language example
108
const customQueryConfig = {
109
createQuery: (json, queryOptions) => {
110
let query = "SELECT";
111
112
// Projection
113
if (queryOptions.projection) {
114
query += " " + queryOptions.projection.fields.join(", ");
115
} else {
116
query += " *";
117
}
118
119
query += " FROM data";
120
121
// Filter
122
if (queryOptions.filter) {
123
const field = queryOptions.filter.field === "@" ? "value" : queryOptions.filter.field;
124
query += ` WHERE ${field} ${queryOptions.filter.relation} '${queryOptions.filter.value}'`;
125
}
126
127
// Sort
128
if (queryOptions.sort) {
129
const field = queryOptions.sort.field === "@" ? "value" : queryOptions.sort.field;
130
query += ` ORDER BY ${field} ${queryOptions.sort.direction.toUpperCase()}`;
131
}
132
133
return query;
134
},
135
136
executeQuery: (json, sqlQuery) => {
137
// Custom SQL-like query execution logic
138
return executeCustomSQL(json, sqlQuery);
139
},
140
141
queryDescription: "Uses a custom SQL-like syntax for data transformation."
142
};
143
144
const options = {
145
mode: "tree",
146
createQuery: customQueryConfig.createQuery,
147
executeQuery: customQueryConfig.executeQuery,
148
queryDescription: customQueryConfig.queryDescription
149
};
150
```
151
152
### Enable/Disable Transform Features
153
154
Control availability of transformation functionality in the editor.
155
156
```javascript { .api }
157
/**
158
* Transform configuration options
159
*/
160
interface TransformOptions {
161
/** Enable transform/filter functionality */
162
enableTransform?: boolean;
163
164
/** Enable sorting functionality */
165
enableSort?: boolean;
166
}
167
```
168
169
**Usage Example:**
170
171
```javascript
172
const options = {
173
mode: "tree",
174
enableTransform: true, // Show Transform button in menu
175
enableSort: true, // Show Sort button in menu
176
177
// Custom transform configuration
178
createQuery: customCreateQuery,
179
executeQuery: customExecuteQuery,
180
queryDescription: "Custom query language for data transformation"
181
};
182
183
const editor = new JSONEditor(container, options);
184
```
185
186
## Built-in Transformation Features
187
188
### Transform Modal
189
190
The Transform modal provides a wizard-like interface for building queries:
191
192
1. **Filter Step**: Set filtering conditions
193
2. **Sort Step**: Configure sorting options
194
3. **Projection Step**: Select fields to include
195
4. **Preview Step**: Preview results before applying
196
197
### Sort Modal
198
199
The Sort modal allows sorting of arrays and object properties:
200
201
- **Array Sorting**: Sort array elements by value or by object property
202
- **Object Sorting**: Sort object properties by key name or value
203
- **Sort Direction**: Ascending or descending order
204
- **Natural Sort**: Intelligent sorting of strings with numbers
205
206
### JMESPath Query Examples
207
208
Common JMESPath patterns supported by the default query system:
209
210
```javascript
211
// Filter examples
212
"users[?age > `25`]" // Users older than 25
213
"products[?price < `100`]" // Products under $100
214
"items[?contains(name, 'test')]" // Items with 'test' in name
215
216
// Sort examples
217
"sort_by(users, &name)" // Sort users by name (ascending)
218
"reverse(sort_by(users, &age))" // Sort users by age (descending)
219
220
// Projection examples
221
"users[].{name: name, email: email}" // Select only name and email fields
222
"products[].[name, price]" // Select name and price as arrays
223
224
// Complex transformations
225
"users[?age >= `18`] | sort_by(@, &name) | [].{name: name, adult: `true`}"
226
```
227
228
## Advanced Transform Operations
229
230
### Programmatic Data Transformation
231
232
Transform data programmatically without using the UI modals.
233
234
```javascript
235
function transformData(editor, transformFunction) {
236
const currentData = editor.get();
237
const transformedData = transformFunction(currentData);
238
editor.set(transformedData);
239
}
240
241
// Usage examples
242
transformData(editor, (data) => {
243
// Filter array elements
244
if (Array.isArray(data)) {
245
return data.filter(item => item.active === true);
246
}
247
return data;
248
});
249
250
transformData(editor, (data) => {
251
// Sort object properties
252
if (typeof data === 'object' && data !== null) {
253
const sorted = {};
254
Object.keys(data).sort().forEach(key => {
255
sorted[key] = data[key];
256
});
257
return sorted;
258
}
259
return data;
260
});
261
```
262
263
### Batch Transformations
264
265
Apply multiple transformations in sequence.
266
267
```javascript
268
function applyTransformations(editor, transformations) {
269
let data = editor.get();
270
271
transformations.forEach(transform => {
272
data = transform(data);
273
});
274
275
editor.set(data);
276
}
277
278
// Usage
279
const transformations = [
280
// Filter active users
281
(data) => data.users ? { ...data, users: data.users.filter(u => u.active) } : data,
282
283
// Sort users by name
284
(data) => data.users ? { ...data, users: data.users.sort((a, b) => a.name.localeCompare(b.name)) } : data,
285
286
// Add computed field
287
(data) => data.users ? {
288
...data,
289
users: data.users.map(u => ({ ...u, displayName: u.firstName + ' ' + u.lastName }))
290
} : data
291
];
292
293
applyTransformations(editor, transformations);
294
```
295
296
### Custom Transform UI
297
298
Create custom transformation interfaces that integrate with JSONEditor.
299
300
```javascript
301
function createCustomTransformUI(editor) {
302
const transformButton = document.createElement('button');
303
transformButton.textContent = 'Custom Transform';
304
transformButton.onclick = () => {
305
const data = editor.get();
306
307
// Show custom transform dialog
308
showCustomTransformDialog(data, (transformedData) => {
309
editor.set(transformedData);
310
});
311
};
312
313
// Add button to custom toolbar
314
document.getElementById('custom-toolbar').appendChild(transformButton);
315
}
316
317
function showCustomTransformDialog(data, onApply) {
318
// Create modal with custom transformation options
319
const modal = document.createElement('div');
320
modal.className = 'transform-modal';
321
322
// Add transformation controls
323
const controls = createTransformControls(data);
324
modal.appendChild(controls);
325
326
// Apply button
327
const applyButton = document.createElement('button');
328
applyButton.textContent = 'Apply Transform';
329
applyButton.onclick = () => {
330
const transformedData = applyCustomTransform(data, getTransformSettings());
331
onApply(transformedData);
332
document.body.removeChild(modal);
333
};
334
335
modal.appendChild(applyButton);
336
document.body.appendChild(modal);
337
}
338
```
339
340
### Query Result Analysis
341
342
Analyze and validate transformation results.
343
344
```javascript
345
function analyzeTransformResult(originalData, transformedData) {
346
const analysis = {
347
originalSize: JSON.stringify(originalData).length,
348
transformedSize: JSON.stringify(transformedData).length,
349
compressionRatio: 0,
350
itemsChanged: 0,
351
itemsRemoved: 0,
352
itemsAdded: 0
353
};
354
355
analysis.compressionRatio = analysis.transformedSize / analysis.originalSize;
356
357
// Count changes (simplified)
358
if (Array.isArray(originalData) && Array.isArray(transformedData)) {
359
analysis.itemsRemoved = Math.max(0, originalData.length - transformedData.length);
360
analysis.itemsAdded = Math.max(0, transformedData.length - originalData.length);
361
}
362
363
return analysis;
364
}
365
366
// Usage
367
const original = editor.get();
368
const transformed = executeTransform(original, query);
369
const analysis = analyzeTransformResult(original, transformed);
370
371
console.log(`Transform reduced size by ${((1 - analysis.compressionRatio) * 100).toFixed(1)}%`);
372
```
373
374
## Transform Configuration Examples
375
376
### JMESPath with Custom Description
377
378
```javascript
379
const options = {
380
mode: "tree",
381
enableTransform: true,
382
queryDescription: `
383
<h4>Custom JMESPath Guide</h4>
384
<p>Use JMESPath syntax to filter and transform your data:</p>
385
<ul>
386
<li><code>items[?price < 100]</code> - Filter by price</li>
387
<li><code>sort_by(users, &name)</code> - Sort by name</li>
388
<li><code>users[].{name: name, email: email}</code> - Project fields</li>
389
</ul>
390
<p><a href="https://jmespath.org" target="_blank">Full JMESPath documentation</a></p>
391
`
392
};
393
```
394
395
### GraphQL-style Query Language
396
397
```javascript
398
const graphQLQueryConfig = {
399
createQuery: (json, queryOptions) => {
400
let query = "{\n";
401
402
if (queryOptions.projection) {
403
queryOptions.projection.fields.forEach(field => {
404
query += ` ${field}\n`;
405
});
406
}
407
408
query += "}";
409
410
if (queryOptions.filter) {
411
query += `\nwhere: { ${queryOptions.filter.field}: { ${queryOptions.filter.relation}: "${queryOptions.filter.value}" } }`;
412
}
413
414
return query;
415
},
416
417
executeQuery: (json, graphQLQuery) => {
418
// Custom GraphQL-style execution
419
return executeGraphQLStyleQuery(json, graphQLQuery);
420
},
421
422
queryDescription: "GraphQL-style query syntax for data selection and filtering."
423
};
424
```
425
426
### MongoDB-style Query Language
427
428
```javascript
429
const mongoQueryConfig = {
430
createQuery: (json, queryOptions) => {
431
const pipeline = [];
432
433
// Match stage (filter)
434
if (queryOptions.filter) {
435
const matchStage = { $match: {} };
436
const field = queryOptions.filter.field === "@" ? "_value" : queryOptions.filter.field;
437
438
switch (queryOptions.filter.relation) {
439
case "==":
440
matchStage.$match[field] = queryOptions.filter.value;
441
break;
442
case ">=":
443
matchStage.$match[field] = { $gte: parseFloat(queryOptions.filter.value) };
444
break;
445
// ... other operators
446
}
447
448
pipeline.push(matchStage);
449
}
450
451
// Sort stage
452
if (queryOptions.sort) {
453
const sortStage = { $sort: {} };
454
const field = queryOptions.sort.field === "@" ? "_value" : queryOptions.sort.field;
455
sortStage.$sort[field] = queryOptions.sort.direction === "asc" ? 1 : -1;
456
pipeline.push(sortStage);
457
}
458
459
// Project stage
460
if (queryOptions.projection) {
461
const projectStage = { $project: {} };
462
queryOptions.projection.fields.forEach(field => {
463
projectStage.$project[field] = 1;
464
});
465
pipeline.push(projectStage);
466
}
467
468
return JSON.stringify(pipeline, null, 2);
469
},
470
471
executeQuery: (json, mongoQuery) => {
472
// Execute MongoDB-style aggregation pipeline
473
return executeMongoStyleQuery(json, JSON.parse(mongoQuery));
474
},
475
476
queryDescription: "MongoDB aggregation pipeline syntax for data transformation."
477
};
478
```