最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Deriving the list of JSON Paths from a JSON Schema model - Stack Overflow

programmeradmin5浏览0评论

I am looking for a Javascript library to list the possible Json Paths based on a Json Schema.

For a json schema like below, I want to list the possible json paths.

{
  "$id": ".schema.json",
  "$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",
        }
    }
  }
}

Possible Json Paths: firstName, lastName, age, address.city, and address.country

I am looking for a Javascript library to list the possible Json Paths based on a Json Schema.

For a json schema like below, I want to list the possible json paths.

{
  "$id": "https://example./person.schema.json",
  "$schema": "http://json-schema/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",
        }
    }
  }
}

Possible Json Paths: firstName, lastName, age, address.city, and address.country

Share Improve this question edited Jan 14, 2019 at 11:33 Mani asked Jan 14, 2019 at 10:34 ManiMani 1251 gold badge2 silver badges9 bronze badges 1
  • 1 I don't think your schema is valid. The schema for address should be having a properties keyword holding city and country. – custommander Commented Jan 14, 2019 at 22:32
Add a ment  | 

2 Answers 2

Reset to default 5

Based on @custommander's answer

  • Add support for $ref (prevent recursion)
  • Add hierarchy parents paths too (i.e. a.b.c -> a + a.b + a.b.c)
  • Add support for array items (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/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" }
      }
    }
  }
}));

You don't necessarily need a library for that. You can use a simple recursive function:

var schema = {
  "$id": "https://example./person.schema.json",
  "$schema": "http://json-schema/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",
      "properties": {
        "city": {
          "type": "string",
        },
        "country": {
          "type": "string",
        }
      }
    }
  }
};

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

console.log(

  path(schema)

);

发布评论

评论列表(0)

  1. 暂无评论