You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java中如何从com.networknt.schema.JsonSchema获取指定层级属性及可选值

问题前提

给定JSON Schema

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://example.com/product.schema.json",
  "title": "Draft JSON Schema",
  "type": "object",
  "properties": {
      "person": {
          "type": "object",
          "properties": {
              "details": {
                  "type": "object",
                  "properties": {
                      "first_name": {
                          "type": "string"
                      },
                      "last_name": {
                          "type": "string"
                      },
                      "groups": {
                          "type": "array",
                          "items": { "$ref": "#/$defs/existing_groups"
                      }
                  }

              }
          }
      },
      "$defs": {
          "existing_groups": [ "Teachers", "Students" ]
      },
      "book": {
          "type": "object",
          "properties": {
              "title": {
                  "type": "string"
              },
              "author": {
                  "type": "string"
              }
          }
      }
  }
}

需求描述

需要从上述schema中获取指定层级的可用属性及对应可选值,规则如下:

  • 输入person.details时,返回first_name、last_name、groups
  • 输入person.details.groups时,返回其可选值Teachers、Students
  • 输入book.title时,返回空数组或空集合

已知可通过JsonPath从JSON对象中提取属性值,现在需要从com.networknt.schema.JsonSchema实例中获取可选属性,有可选值定义时同时返回可选值,以下是Java最简单的实现方式。


实现方案

networknt的JsonSchema库没有直接提供层级属性遍历的工具,最简单的实现思路是直接操作Schema对应的JsonNode结构,逐层遍历路径并处理$ref引用即可。

第一步:引入依赖

Maven依赖示例:

<dependency>
    <groupId>com.networknt</groupId>
    <artifactId>json-schema-validator</artifactId>
    <version>1.2.0</version>
</dependency>

第二步:核心实现代码

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.networknt.schema.JsonSchema;
import com.networknt.schema.JsonSchemaFactory;
import com.networknt.schema.SpecVersion;

import java.util.*;

public class SchemaPropertyExtractor {
    private static final ObjectMapper objectMapper = new ObjectMapper();
    private static final JsonSchemaFactory schemaFactory = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V202012);
    
    public static List<String> extract(JsonSchema schema, String path) {
        JsonNode rootNode = schema.getSchemaNode();
        String[] pathSegs = path.split("\\.");
        JsonNode currentNode = rootNode.get("properties");
        
        // 逐层遍历路径
        for (int i = 0; i < pathSegs.length; i++) {
            String seg = pathSegs[i];
            currentNode = currentNode.get(seg);
            if (currentNode == null) return Collections.emptyList();
            
            if (i != pathSegs.length - 1) {
                // 中间节点如果是数组类型,取items节点继续遍历
                if (currentNode.has("type") && "array".equals(currentNode.get("type").asText())) {
                    currentNode = resolveRef(currentNode.get("items"), rootNode);
                }
                currentNode = currentNode.get("properties");
                if (currentNode == null) return Collections.emptyList();
            }
        }
        
        // 处理最终节点
        if (currentNode.has("type") && "object".equals(currentNode.get("type").asText())) {
            // 对象类型返回所有属性名
            List<String> props = new ArrayList<>();
            currentNode.get("properties").fieldNames().forEachRemaining(props::add);
            return props;
        } else if (currentNode.has("type") && "array".equals(currentNode.get("type").asText())) {
            // 数组类型解析items的引用,返回可选值
            JsonNode itemsNode = resolveRef(currentNode.get("items"), rootNode);
            List<String> enums = new ArrayList<>();
            itemsNode.forEach(item -> enums.add(item.asText()));
            return enums;
        } else {
            // 其他类型返回空集合
            return Collections.emptyList();
        }
    }
    
    // 处理$ref引用
    private static JsonNode resolveRef(JsonNode node, JsonNode rootNode) {
        if (node.has("$ref")) {
            String refPath = node.get("$ref").asText().substring(2); // 去除前缀#/
            String[] refSegs = refPath.split("/");
            JsonNode refNode = rootNode;
            for (String seg : refSegs) {
                refNode = refNode.get(seg);
            }
            return refNode;
        }
        return node;
    }

    // 测试用例
    public static void main(String[] args) throws Exception {
        // 加载Schema文件
        JsonNode schemaNode = objectMapper.readTree(SchemaPropertyExtractor.class.getResourceAsStream("/product.schema.json"));
        JsonSchema schema = schemaFactory.getSchema(schemaNode);
        
        // 测试三个场景
        System.out.println(extract(schema, "person.details")); // 输出 [first_name, last_name, groups]
        System.out.println(extract(schema, "person.details.groups")); // 输出 [Teachers, Students]
        System.out.println(extract(schema, "book.title")); // 输出 []
    }
}

说明

上述代码仅适配了示例中的简单场景,如果你有跨文件引用、嵌套引用、枚举类型等更复杂的Schema结构,扩展resolveRef方法和最终节点的判断逻辑即可。


内容的提问来源于stack exchange,提问作者AnjaM

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.07 15:39:04