从JSON模式模型派生JSON路径列表

时间:2019-01-14 10:34:48

标签: javascript json jsonschema jsonpath

我正在寻找一个Javascript库,以基于Json Schema列出可能的Json路径。

对于如下所示的json模式,我想列出可能的json路径。

{
  "$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",
        }
    }
  }
}

可能的Json路径:名字,姓氏,年龄,地址城市和地址国家/地区

2 个答案:

答案 0 :(得分:1)

您不一定为此需要一个库。您可以使用一个简单的递归函数:

var schema = {
  "$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",
      "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)

);

答案 1 :(得分:0)

基于@customcommander的答案

  • 添加对$ ref(防止递归)的支持
  • 也添加层次结构的父路径(即a.b.c-> a + a.b + a.b.c)
  • 添加对数组项的支持(使用[]作为通用索引器)

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" }
      }
    }
  }
}));