Generating JSON Paths from a JSON Schema structure

Can anyone recommend a Javascript library that can generate a list of possible Json Paths based on a given Json Schema?

Imagine having a json schema structured like the one below, I am interested in a tool that can provide me with all potential json paths.

{
  "$id": "https://example.com/person.schema.json",
  "$schema": "http://json-schema.org/draft-07/schema#",
  "title": "Customer",
  "type": "object",
  "properties": {
    "firstName": {
      "type": "string",
      "description": "The person's first name."
    },
    "lastName": {
      "type": "string",
      "description": "The person's last name."
    },
    "age": {
      "description": "Age in years which must be equal to or greater than zero.",
      "type": "integer",
      "minimum": 0
    },
    "address": {
        "type": "object",
        "city": {
            "type": "string",
        },
        "country": {
            "type": "string",
        }
    }
  }
}

The expected Json Paths would include: firstName, lastName, age, address.city, and address.country

Answer №1

Referencing @customcommander's response

  • Integrate $ref support to avoid recursion
  • Include hierarchy parent paths (e.g. a.b.c -> a + a.b + a.b.c)
  • Incorporate array items support (using [] as a generic indexer)

const _derivePathsFromSchema = (schema, properties, defined) => {
  let paths = [];
  if (!properties) return paths;
  return Object.keys(properties).reduce((paths, childKey) => {
    let child = properties[childKey];
    const { $ref, ...childProperties } = child;
    if ($ref?.startsWith('#/definitions/')) {
      const definition = $ref.substr($ref.lastIndexOf('/') + 1);
      if (!defined.includes(definition)) // prevent recursion of definitions
      {
        defined.push(definition);
        child = {
          ...schema.definitions[definition], // load $ref properties
          ...childProperties, // child properties override those of the $ref
        };
      }
    }
    if (child.type === 'object') {
      return paths.concat(childKey, _derivePathsFromSchema(schema, child.properties, defined.slice()).map(p => `${childKey}.${p}`));
    }
    if (child.type === 'array' && child.items?.properties) {
      return paths.concat(childKey, `${childKey}[]`, _derivePathsFromSchema(schema, child.items.properties, defined.slice()).map(p => `${childKey}[].${p}`));
    }

    return paths.concat(childKey);
  }, paths);
};
const derivePathsFromSchema = schema => _derivePathsFromSchema(schema, schema.properties, []);


console.log(derivePathsFromSchema({
  "$schema": "http://json-schema.org/draft-07/schema#",
  "definitions": {
    "BType": {
      "type": "object",
      "properties": {
        "a": {
          "$ref": "#/definitions/AType"
        }
      }
    },
    "AType": {
      "type": "object",
      "properties": {
        "b": {
          "$ref": "#/definitions/BType"
        }    
      }
    }
  },
  "type": "object",
  "properties": {
    "a": {
      "$ref": "#/definitions/AType"
    },
    "b": {
      "$ref": "#/definitions/BType"
    },
    "id": {
      "type": "string"
    },
    "array": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "item": { "type": "string" }
        }
      }
    },
    "obj": {
      "type": "object",
      "properties": {
        "nested": { "type": "string" }
      }
    }
  }
}));

Answer №2

You don't have to rely on a library for this task. A simple recursive function can get the job done:

var data = {
  "name": "John",
  "age": 30,
  "pets": {
    "dog": {
      "name": "Buddy",
      "breed": "Golden Retriever"
    },
    "cat": {
      "name": "Whiskers",
      "breed": "Siamese"
    }
  }
};

var extractKeys = ({}) =>
  Object.keys(data).reduce((acc, key) =>
    acc.concat(typeof data[key] !== 'object' ? key :
      extractKeys(data[key]).map(p => `${key}.${p}`)), []);

console.log(
  extractKeys(data)
);

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Why do my messages from BehaviorSubject get duplicated every time a new message is received?

Currently, I am using BehaviorSubject to receive data and also utilizing websockets, although the websocket functionality is not relevant at this moment. The main issue I am facing is why I keep receiving duplicated messages from BehaviorSubject. When exa ...

The error message "Failed to load the default credentials in Firebase" occurs sporadically. Approximately 50% of the time, the app functions properly, while the other 50% of the time, this specific

Occasionally in my firebase functions log, I encounter an error message stating: "Error: Could not load the default credentials. Browse to https://cloud.google.com/docs/authentication/getting-started for more information." This error appears randomly withi ...

Converting milliseconds to a valid date object using Angular form validation

I am facing an issue with form validation and milliseconds in my Angular application. It seems that Angular does not consider time in milliseconds as a valid date format, causing the angular.isDate(1418645071000) function to return false. How can I modify ...

Utilizing Javascript / jQuery to eliminate specific CSS styles

I am facing an issue with the CSS code for a table positioned at the bottom of the screen. The current code includes a filter specifically for IE 8, but I need to make it compatible with IE 10 as well by removing the filter and adding a background color. ...

Decoding JSON data retrieved from the Pokeapi

Looking for help on how to effectively call an API known as Pokeapi and then parse the received data into an object using an external library called PokeApi.NET in C#. I am able to get a response from the API in my C# code, but struggle with parsing it int ...

Sweetalert fails to display following a successful execution of the function

Everything seems to be working fine with the Sweetalert warning after clicking the delete button, but I'm having trouble getting the confirmation alert in the ajax success function to display on the page. As a beginner in coding, I was following a tu ...

Dealing with React Native: Navigating App Store Rejections and Embracing IPv6

In my react-native client for a website, the login page offers two options: manually enter the login code or scan it using a barcode scanner. I have extensively tested the app on real devices and emulators, and it's functioning correctly. However, all ...

Saving a .JSON file with Java ME

After successfully converting java to json using toJSON(), I'm now wondering how I can save that json data as a .json file. Any suggestions or tips on how to accomplish this? I am currently utilizing Blackberry and Java ME for my project. If anyone h ...

Why does the text in a div display in Safari 8.2 and Chrome 39, but not in Firefox 34?

In my HTML document, I have a div tag located within the body like so: <div id="content_text"></div>​ Using javascript, I later set the contents of the div like this: var content_text = document.getElementById("content_text") c ...

Struggling with passing custom headers in Rails, jQuery, and Ajax interactions

I'm having trouble sending custom headers to a Rails API, and I keep encountering this frustrating issue! ActionController::RoutingError (No route matches [OPTIONS] "/api/v1/surveys") In my application_controller.rb, I've added the code below ...

NextJS 13 causes tailwind to malfunction when route group is utilized

I've encountered an issue in my NextJS 13 application where Tailwind classes are no longer being applied after moving page.tsx/layout.tsx from the root directory to a (main) directory within the root. I suspect that there may be a configuration that i ...

Utilize middleware in a separate controller file to handle specific tasks within an Express application

Currently, I have implemented a code snippet that utilizes the express-fileupload middleware for file uploads: const fileUpload = require('express-fileupload'); app.use(fileUpload({useTempFiles: true})); app.post('/upload', (req, re ...

Issue with MUI Data Grid sorting: Data Grid sortComparator function returning undefined

I'm attempting to organize data with nested values in a data grid, but I keep receiving 'undefined' on the sortComparator of Data Grid Columns. Code: Column Data Setup: { headerName: 'Title', field: `${this.props.type} ...

The worth of the scope is evident, yet it remains undefined when trying to access it

Currently, I am in the process of developing an AngularJS directive. However, I have encountered an issue where a scope variable appears to be undefined when attempting to access it. Interestingly, upon printing out the scope, it is evident that the variab ...

How can I automatically add a specific word that I've highlighted within a <text area> situated within an iframe?

This chrome plugin automatically inserts a designated word into the content of an iframe. Specifically designed for Chrome users. <html> <iframe id="iframe" frameborder="0" src="http://www.maozakor.co.il/demo/default.aspx"> </if ...

When attempting to process a JSON file within my application, everything appears to be error-free. However, upon trying to run the app on the emulator, it fails to execute

It seems like the issue lies in the app's inability to access the JSON file for parsing. Despite no errors during runtime or build, it halts at "11/23 23:14:38: Launching 'app' on Device 4.Install successfully finished in 325 ms." ...

whenever I execute my `node file.js 1 23 44` command, nothing is displayed on the screen

When I execute node file.js 1 23 45, the expected output is supposed to be One TwoThree FourFive. However, for some unknown reason, nothing is being printed out. The script appears to run without any errors, but the desired output is just not appearing. ...

Seeking assistance in understanding how to validate images in Javascript code with the use of Selenium WebDriver. Any t

I am looking to implement the following code to verify if the images on the webpage have loaded successfully. Would anyone be able to clarify how this javascript code actually confirms whether the images are loaded or not? ArrayList<WebElement> imgE ...

Adding fewer components to your current Angular 5 project

I have a JS Fiddle showcasing a CSS chart. How can I integrate LESS into my current Angular 5 project to make use of this chart? Also, where should I place the JavaScript and references to the LESS file from this example within my Angular component? The li ...

Extract the year from a string formatted as 1880-01-01T00:00:00.000

Looking to extract the year from an array of dates with format 1880-01-01T00:00:00.000. What's the most efficient method to accomplish this using JavaScript? ...