有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

获取给定Java中JSON路径/JSON指针的JSON文件的行号

我正在寻找一种方法来解析特定节点的JSON文件,并在文件中获取该节点的行号。我想使用Jayway JSONPath库来支持扩展的JSONPath查询

例如(来自jsonpath.com),这里有一些JSON:

{
  "firstName": "John",
  "lastName" : "doe",
  "age"      : 26,
  "address"  : {
    "streetAddress": "naist street",
    "city"         : "Nara",
    "postalCode"   : "630-0192"
  },
  "phoneNumbers": [
    {
      "type"  : "iPhone",
      "number": "0123-4567-8888"
    },
    {
      "type"  : "home",
      "number": "0123-4567-8910"
    }
  ]
}

这里有一个jsonPath: $.phoneNumbers.[?(@.type=='iPhone')]

我想用一种方式说这个节点在json文件的第11行。我不知道json内容可能是什么,也不知道jsonPath是什么。两者都是动态的

到目前为止,我已经尝试将json解析为一棵树,并将其遍历到节点以获取解析器的当前位置,但是解析器必须始终在jsonPath执行之前运行到文件的末尾。还有其他想法吗


共 (2) 个答案

  1. # 1 楼答案

    我想您可以使用漂亮的json打印版本,它应该返回带有换行符的json格式,然后从那里开始工作

  2. # 2 楼答案

    我最终找到了一个使用Jackson的JsonFactory和JsonParser的解决方案。至少可以这么说,这是一个kludge-y,但它使用JsonParser对其解析器行号的了解来获取JsonNode的位置,并且工作得非常好

    我将把代码粘贴到这里,但是代码也可以在watchtower github上找到

    主叫班级:

    void findLineNumber() throws Exception{
        CustomParserFactory customParserFactory = new CustomParserFactory();
        ObjectMapper om = new ObjectMapper(customParserFactory);
        factory = new CustomJsonNodeFactory(om.getDeserializationConfig().getNodeFactory(),
                customParserFactory);
        om.setConfig(om.getDeserializationConfig().with(factory));
        config = Configuration.builder()
                .mappingProvider(new JacksonMappingProvider(om))
                .jsonProvider(new JacksonJsonNodeJsonProvider(om))
                .options(Option.ALWAYS_RETURN_LIST)
                .build();
    
        File filePath = ...;
        JsonPath jsonPath = ...;
        DocumentContext parsedDocument = JsonPath.parse(filePath, config);
        ArrayNode findings = parsedDocument.read(jsonPath);
        for (JsonNode finding : findings) {
            JsonLocation location = factory.getLocationForNode(finding);
            int lineNum = location.getLineNr();
            //Do something with lineNum
        }
    }
    

    CustomJsonNodeFactory。爪哇

    public class CustomJsonNodeFactory extends JsonNodeFactory {
    
        private static final long serialVersionUID = 8807395553661461181L;
    
        private final JsonNodeFactory delegate;
        private final CustomParserFactory parserFactory;
    
        /*
         * "Why isn't this a map?" you might be wondering. Well, when the nodes are created, they're all
         * empty and a node's hashCode is based on its children. So if you use a map and put the node
         * in, then the node's hashCode is based on no children, then when you lookup your node, it is
         * *with* children, so the hashcodes are different. Instead of all of this, you have to iterate
         * through a listing and find their matches once the objects have been populated, which is only
         * after the document has been completely parsed
         */
        private List<Entry<JsonNode, JsonLocation>> locationMapping;
    
        public CustomJsonNodeFactory(JsonNodeFactory nodeFactory,
            CustomParserFactory parserFactory) {
            delegate = nodeFactory;
            this.parserFactory = parserFactory;
            locationMapping = new ArrayList<>();
        }
    
        /**
         * Given a node, find its location, or null if it wasn't found
         * 
         * @param jsonNode the node to search for
         * @return the location of the node or null if not found
         */
        public JsonLocation getLocationForNode(JsonNode jsonNode) {
            return this.locationMapping.stream().filter(e -> e.getKey().equals(jsonNode))
                    .map(e -> e.getValue()).findAny().orElse(null);
        }
    
        /**
         * Simple interceptor to mark the node in the lookup list and return it back
         * 
         * @param <T>  the type of the JsonNode
         * @param node the node itself
         * @return the node itself, having marked its location
         */
        private <T extends JsonNode> T markNode(T node) {
            JsonLocation loc = parserFactory.getParser().getCurrentLocation();
            locationMapping.add(new SimpleEntry<>(node, loc));
            return node;
        }
    
        @Override
        public BooleanNode booleanNode(boolean v) {
            return markNode(delegate.booleanNode(v));
        }
    
        @Override
        public NullNode nullNode() {
            return markNode(delegate.nullNode());
        }
    
        @Override
        public NumericNode numberNode(byte v) {
            return markNode(delegate.numberNode(v));
        }
    
        @Override
        public ValueNode numberNode(Byte value) {
            return markNode(delegate.numberNode(value));
        }
    
        @Override
        public NumericNode numberNode(short v) {
            return markNode(delegate.numberNode(v));
        }
    
        @Override
        public ValueNode numberNode(Short value) {
            return markNode(delegate.numberNode(value));
        }
    
        @Override
        public NumericNode numberNode(int v) {
            return markNode(delegate.numberNode(v));
        }
    
        @Override
        public ValueNode numberNode(Integer value) {
            return markNode(delegate.numberNode(value));
        }
    
        @Override
        public NumericNode numberNode(long v) {
            return markNode(delegate.numberNode(v));
        }
    
        @Override
        public ValueNode numberNode(Long value) {
            return markNode(delegate.numberNode(value));
        }
    
        @Override
        public ValueNode numberNode(BigInteger v) {
            return markNode(delegate.numberNode(v));
        }
    
        @Override
        public NumericNode numberNode(float v) {
            return markNode(delegate.numberNode(v));
        }
    
        @Override
        public ValueNode numberNode(Float value) {
            return markNode(delegate.numberNode(value));
        }
    
        @Override
        public NumericNode numberNode(double v) {
            return markNode(delegate.numberNode(v));
        }
    
        @Override
        public ValueNode numberNode(Double value) {
            return markNode(delegate.numberNode(value));
        }
    
        @Override
        public ValueNode numberNode(BigDecimal v) {
            return markNode(delegate.numberNode(v));
        }
    
        @Override
        public TextNode textNode(String text) {
            return markNode(delegate.textNode(text));
        }
    
        @Override
        public BinaryNode binaryNode(byte[] data) {
            return markNode(delegate.binaryNode(data));
        }
    
        @Override
        public BinaryNode binaryNode(byte[] data, int offset, int length) {
            return markNode(delegate.binaryNode(data, offset, length));
        }
    
        @Override
        public ValueNode pojoNode(Object pojo) {
            return markNode(delegate.pojoNode(pojo));
        }
    
        @Override
        public ValueNode rawValueNode(RawValue value) {
            return markNode(delegate.rawValueNode(value));
        }
    
        @Override
        public ArrayNode arrayNode() {
            return markNode(delegate.arrayNode());
        }
    
        @Override
        public ArrayNode arrayNode(int capacity) {
            return markNode(delegate.arrayNode(capacity));
        }
    
        @Override
        public ObjectNode objectNode() {
            return markNode(delegate.objectNode());
        }
    
    }
    

    CustomParserFactory。java(请注意,这会消除线程安全性,这可能是一件大事):

    public class CustomParserFactory extends JsonFactory {
    
        private static final long serialVersionUID = -7523974986510864179L;
        private JsonParser parser;
    
        public JsonParser getParser() {
            return this.parser;
        }
    
        @Override
        public JsonParser createParser(Reader r) throws IOException, JsonParseException {
            parser = super.createParser(r);
            return parser;
        }
    
        @Override
        public JsonParser createParser(String content) throws IOException, JsonParseException {
            parser = super.createParser(content);
            return parser;
        }    
    }