A web-based tool to view, edit, format, and validate JSON with multiple editing modes including tree, code, text, and preview
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
JMESPath-based data transformation and filtering capabilities with custom query language support, sorting functionality, and data manipulation tools.
Configure custom query creation and execution functions for data transformation.
/**
* Custom query configuration in editor options
*/
interface QueryConfiguration {
/** Function to create query string from query options */
createQuery?: (json: any, queryOptions: QueryOptions) => string;
/** Function to execute query string on JSON data */
executeQuery?: (json: any, query: string) => any;
/** Description text for the query language */
queryDescription?: string;
}Structure for transformation query options used in the Transform modal.
interface QueryOptions {
/** Filter configuration */
filter?: {
/** Field to filter on, or '@' for the value itself */
field: string | "@";
/** Comparison operator */
relation: "==" | "!=" | "<" | "<=" | ">" | ">=";
/** Value to compare against */
value: string;
};
/** Sort configuration */
sort?: {
/** Field to sort by, or '@' for the value itself */
field: string | "@";
/** Sort direction */
direction: "asc" | "desc";
};
/** Projection configuration */
projection?: {
/** Array of field names to include in output */
fields: string[];
};
}Usage Example:
// Example query options for filtering and sorting users
const queryOptions = {
filter: {
field: "age",
relation: ">=",
value: "18"
},
sort: {
field: "name",
direction: "asc"
},
projection: {
fields: ["name", "email", "age"]
}
};JSONEditor includes built-in JMESPath query support for data transformation.
// Default JMESPath query functions (internal)
const defaultJMESPathConfig = {
createQuery: (json, queryOptions) => {
// Converts QueryOptions to JMESPath query string
// Example output: "users[?age >= `18`] | sort_by(@, &name) | [].{name: name, email: email}"
},
executeQuery: (json, jmespathQuery) => {
// Executes JMESPath query on JSON data
// Returns transformed data
},
queryDescription: "Uses JMESPath query language. See <a href='http://jmespath.org/'>jmespath.org</a> for syntax."
};Implement a custom query language to replace the default JMESPath functionality.
// Custom SQL-like query language example
const customQueryConfig = {
createQuery: (json, queryOptions) => {
let query = "SELECT";
// Projection
if (queryOptions.projection) {
query += " " + queryOptions.projection.fields.join(", ");
} else {
query += " *";
}
query += " FROM data";
// Filter
if (queryOptions.filter) {
const field = queryOptions.filter.field === "@" ? "value" : queryOptions.filter.field;
query += ` WHERE ${field} ${queryOptions.filter.relation} '${queryOptions.filter.value}'`;
}
// Sort
if (queryOptions.sort) {
const field = queryOptions.sort.field === "@" ? "value" : queryOptions.sort.field;
query += ` ORDER BY ${field} ${queryOptions.sort.direction.toUpperCase()}`;
}
return query;
},
executeQuery: (json, sqlQuery) => {
// Custom SQL-like query execution logic
return executeCustomSQL(json, sqlQuery);
},
queryDescription: "Uses a custom SQL-like syntax for data transformation."
};
const options = {
mode: "tree",
createQuery: customQueryConfig.createQuery,
executeQuery: customQueryConfig.executeQuery,
queryDescription: customQueryConfig.queryDescription
};Control availability of transformation functionality in the editor.
/**
* Transform configuration options
*/
interface TransformOptions {
/** Enable transform/filter functionality */
enableTransform?: boolean;
/** Enable sorting functionality */
enableSort?: boolean;
}Usage Example:
const options = {
mode: "tree",
enableTransform: true, // Show Transform button in menu
enableSort: true, // Show Sort button in menu
// Custom transform configuration
createQuery: customCreateQuery,
executeQuery: customExecuteQuery,
queryDescription: "Custom query language for data transformation"
};
const editor = new JSONEditor(container, options);The Transform modal provides a wizard-like interface for building queries:
The Sort modal allows sorting of arrays and object properties:
Common JMESPath patterns supported by the default query system:
// Filter examples
"users[?age > `25`]" // Users older than 25
"products[?price < `100`]" // Products under $100
"items[?contains(name, 'test')]" // Items with 'test' in name
// Sort examples
"sort_by(users, &name)" // Sort users by name (ascending)
"reverse(sort_by(users, &age))" // Sort users by age (descending)
// Projection examples
"users[].{name: name, email: email}" // Select only name and email fields
"products[].[name, price]" // Select name and price as arrays
// Complex transformations
"users[?age >= `18`] | sort_by(@, &name) | [].{name: name, adult: `true`}"Transform data programmatically without using the UI modals.
function transformData(editor, transformFunction) {
const currentData = editor.get();
const transformedData = transformFunction(currentData);
editor.set(transformedData);
}
// Usage examples
transformData(editor, (data) => {
// Filter array elements
if (Array.isArray(data)) {
return data.filter(item => item.active === true);
}
return data;
});
transformData(editor, (data) => {
// Sort object properties
if (typeof data === 'object' && data !== null) {
const sorted = {};
Object.keys(data).sort().forEach(key => {
sorted[key] = data[key];
});
return sorted;
}
return data;
});Apply multiple transformations in sequence.
function applyTransformations(editor, transformations) {
let data = editor.get();
transformations.forEach(transform => {
data = transform(data);
});
editor.set(data);
}
// Usage
const transformations = [
// Filter active users
(data) => data.users ? { ...data, users: data.users.filter(u => u.active) } : data,
// Sort users by name
(data) => data.users ? { ...data, users: data.users.sort((a, b) => a.name.localeCompare(b.name)) } : data,
// Add computed field
(data) => data.users ? {
...data,
users: data.users.map(u => ({ ...u, displayName: u.firstName + ' ' + u.lastName }))
} : data
];
applyTransformations(editor, transformations);Create custom transformation interfaces that integrate with JSONEditor.
function createCustomTransformUI(editor) {
const transformButton = document.createElement('button');
transformButton.textContent = 'Custom Transform';
transformButton.onclick = () => {
const data = editor.get();
// Show custom transform dialog
showCustomTransformDialog(data, (transformedData) => {
editor.set(transformedData);
});
};
// Add button to custom toolbar
document.getElementById('custom-toolbar').appendChild(transformButton);
}
function showCustomTransformDialog(data, onApply) {
// Create modal with custom transformation options
const modal = document.createElement('div');
modal.className = 'transform-modal';
// Add transformation controls
const controls = createTransformControls(data);
modal.appendChild(controls);
// Apply button
const applyButton = document.createElement('button');
applyButton.textContent = 'Apply Transform';
applyButton.onclick = () => {
const transformedData = applyCustomTransform(data, getTransformSettings());
onApply(transformedData);
document.body.removeChild(modal);
};
modal.appendChild(applyButton);
document.body.appendChild(modal);
}Analyze and validate transformation results.
function analyzeTransformResult(originalData, transformedData) {
const analysis = {
originalSize: JSON.stringify(originalData).length,
transformedSize: JSON.stringify(transformedData).length,
compressionRatio: 0,
itemsChanged: 0,
itemsRemoved: 0,
itemsAdded: 0
};
analysis.compressionRatio = analysis.transformedSize / analysis.originalSize;
// Count changes (simplified)
if (Array.isArray(originalData) && Array.isArray(transformedData)) {
analysis.itemsRemoved = Math.max(0, originalData.length - transformedData.length);
analysis.itemsAdded = Math.max(0, transformedData.length - originalData.length);
}
return analysis;
}
// Usage
const original = editor.get();
const transformed = executeTransform(original, query);
const analysis = analyzeTransformResult(original, transformed);
console.log(`Transform reduced size by ${((1 - analysis.compressionRatio) * 100).toFixed(1)}%`);const options = {
mode: "tree",
enableTransform: true,
queryDescription: `
<h4>Custom JMESPath Guide</h4>
<p>Use JMESPath syntax to filter and transform your data:</p>
<ul>
<li><code>items[?price < 100]</code> - Filter by price</li>
<li><code>sort_by(users, &name)</code> - Sort by name</li>
<li><code>users[].{name: name, email: email}</code> - Project fields</li>
</ul>
<p><a href="https://jmespath.org" target="_blank">Full JMESPath documentation</a></p>
`
};const graphQLQueryConfig = {
createQuery: (json, queryOptions) => {
let query = "{\n";
if (queryOptions.projection) {
queryOptions.projection.fields.forEach(field => {
query += ` ${field}\n`;
});
}
query += "}";
if (queryOptions.filter) {
query += `\nwhere: { ${queryOptions.filter.field}: { ${queryOptions.filter.relation}: "${queryOptions.filter.value}" } }`;
}
return query;
},
executeQuery: (json, graphQLQuery) => {
// Custom GraphQL-style execution
return executeGraphQLStyleQuery(json, graphQLQuery);
},
queryDescription: "GraphQL-style query syntax for data selection and filtering."
};const mongoQueryConfig = {
createQuery: (json, queryOptions) => {
const pipeline = [];
// Match stage (filter)
if (queryOptions.filter) {
const matchStage = { $match: {} };
const field = queryOptions.filter.field === "@" ? "_value" : queryOptions.filter.field;
switch (queryOptions.filter.relation) {
case "==":
matchStage.$match[field] = queryOptions.filter.value;
break;
case ">=":
matchStage.$match[field] = { $gte: parseFloat(queryOptions.filter.value) };
break;
// ... other operators
}
pipeline.push(matchStage);
}
// Sort stage
if (queryOptions.sort) {
const sortStage = { $sort: {} };
const field = queryOptions.sort.field === "@" ? "_value" : queryOptions.sort.field;
sortStage.$sort[field] = queryOptions.sort.direction === "asc" ? 1 : -1;
pipeline.push(sortStage);
}
// Project stage
if (queryOptions.projection) {
const projectStage = { $project: {} };
queryOptions.projection.fields.forEach(field => {
projectStage.$project[field] = 1;
});
pipeline.push(projectStage);
}
return JSON.stringify(pipeline, null, 2);
},
executeQuery: (json, mongoQuery) => {
// Execute MongoDB-style aggregation pipeline
return executeMongoStyleQuery(json, JSON.parse(mongoQuery));
},
queryDescription: "MongoDB aggregation pipeline syntax for data transformation."
};