【问题标题】:Java FastXML JSON library: How to parse a nested JSON structureJava FasterXML JSON 库:如何解析嵌套的 JSON 结构
【发布时间】:2015-05-17 15:54:38
【问题描述】:

下面是我正在尝试使用 org.fasterxml.jackson.core 和 jackson-databind 库以流方式测试 JSON 处理的 Java 程序。

目标是学习如何处理 JSON 并捕获我想要的信息。目前,我想要完成的是:
1)我在这里发布的 JSON 有很多数据。这个 JSON 之后的 Java 程序是我处理这个 JSON 的尝试,特别是在“part1/myAnalysis/matches.”和 ”下捕获 "name": US SSN" 元素name": MasterCard Credit Card number",这两个元素都在“part1/myAnalysis/matches”的范围内。 仅限

好的,现在,我的目标是:我只想让我的程序编译并至少打印出我感兴趣的这两个元素(上述元素)

我的编译尝试产生了以下结果:

Unprocessed property: type
Unprocessed property: incidentTimestamp
Unprocessed property: numOfMatches
Unprocessed property: myReport
Unprocessed property: whatSetItOffEntry
Unprocessed property: seeRestrictedIds
Unprocessed property: status
Unprocessed property: timeStamps
Unprocessed property: count

所以程序试图处理的JSON如下。如果有人能指出如何使这个程序编译然后打印出我想要的元素。这将是一个很棒的两步流程任务。

{
    "type": "ImportantIncidentInfo",
    "incidentTimestamp": "2014-05-15T10:09:27.989-05:00",
    "numOfMatches": 4,
    "myReport": {
        "docReports": {
            "part1/.": {
                "path": [
                    "unknown"
                ],
                "myAnalysis": {
                    "matches": [
                        {
                            "id": {
                                "major": 1,
                                "minor": 0
                            },
                            "name": "US SSN",
                            "position": 13,
                            "string": " 636-12-4567 "
                        },
                        {
                            "id": {
                                "major": 3,
                                "minor": 0
                            },
                            "name": "MasterCard Credit Card Number",
                            "position": 35,
                            "string": " 5424-1813-6924-3685 "
                        }
                    ]
                },
                "cleanedUpData": [
                    {
                        "startPosition": 0,
                        "endPosition": 65,
                        "frameContent": ""
                    }
                ],
                "minedMetadata": {
                    "Content-Encoding": "ISO-8859-1",
                    "Content-Type": "text/html; charset=iso-8859-1"
                },
                "deducedMetadata": {
                    "Content-Type": "text/html; iso-8859-1"
                }
            },
            "part2/.": {
                "path": [
                    "unknown"
                ],
                "patternAnalysis": {
                    "matches": [
                        {
                            "id": {
                                "major": 1,
                                "minor": 0
                            },
                            "name": "SSN",
                            "position": 3,
                            "string": " 636-12-4567\r"
                        },
                        {
                            "id": {
                                "major": 3,
                                "minor": 0
                            },
                            "name": "MasterCard Credit Card Number",
                            "position": 18,
                            "string": "\n5424-1813-6924-3685\r"
                        }
                    ]
                },
                "cleanedUpData": [
                    {
                        "startPosition": 0,
                        "endPosition": 44,
                        "frameContent": ""
                    }
                ],
                "minedMetadata": {
                    "Content-Encoding": "windows-1252",
                    "Content-Type": "text/plain; charset=windows-1252"
                },
                "deducedMetadata": {
                    "Content-Type": "text/plain; iso-8859-1"
                }
            }
        }
    },
    "whatSetItOffEntry": {
        "action": "Log",
        "component": {
            "type": "aComponent",
            "components": [
                {
                    "type": "PatternComponent",
                    "patterns": [
                        1
                    ],
                    "not": false
                }
            ],
            "not": false
        },
        "ticketInfo": {
            "createIncident": true,
            "tags": [],
            "seeRestrictedIds": [
                {
                    "type": "userGroup",
                    "name": "SiteMasters",
                    "description": "Group for SiteMasters",
                    "masters": [
                        "04fb02a2bc0fba"
                    ],
                    "members": [],
                    "id": "04fade"
                }
            ]
        },
        "letmeknowInfo": {
            "createNotification": true,
            "contactNames": [
                "someguy@gmail.com"
            ]
        }
    },
    "seeRestrictedIds": [
        "04fade66c0"
    ],
    "status": "New",
    "timeStamps": [
        "2014-03-15T10:09:27.989-05:00"
    ],
    "count": 1
}

任务 #2
2)为了处理这个JSON,我写了下面的Java程序。

import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.core.*;

import java.io.*;

public class ParseJson {

    public static void main(String[] args) {

        try{

                // TODO Auto-generated method stub
                JsonFactory f = new MappingJsonFactory();
                //JsonParser jp = f.createJsonParser(new File(args[0]));
                JsonParser jp = f.createParser(new File("C:/somepath /in/my/eclipse/project/jsonFormattedModified.json"));


                JsonToken current;

                current = jp.nextToken();
                if (current != JsonToken.START_OBJECT) {
                  System.out.println("Error: root should be object: quiting.");
                  return;
                }

                while (jp.nextToken() != JsonToken.END_OBJECT) {
                  String fieldName = jp.getCurrentName();
                  // move from field name to field value
                  current = jp.nextToken();
                  if (fieldName.equals("matches")) {
                    if (current == JsonToken.START_ARRAY) {
                      // For each of the records in the array
                      while (jp.nextToken() != JsonToken.END_ARRAY) {
                        // read the record into a tree model,
                        // this moves the parsing position to the end of it
                        JsonNode node = jp.readValueAsTree();
                        // And now we have random access to everything in the object
                        System.out.println("Name: " + node.get("name").asText());
                        System.out.println("POS: " + node.get("pos").asText());
                      }
                    } else {
                      System.out.println("Error: records should be an array: skipping.");
                      jp.skipChildren();
                    }
                  } else {
                    System.out.println("Unprocessed property: " + fieldName);
                    jp.skipChildren();
                  }
                }                
              } catch(IOException ie) {
                  ie.printStackTrace();

              } 

        }
}

感谢大家的帮助。

【问题讨论】:

    标签: java json jackson


    【解决方案1】:

    我建议您使用非常有用的 Google API Gson 来轻松处理序列化和反序列化。因此,首先,创建与您的 json 结构匹配的所有以下类。

    助手类:

    class Helper {
        String type;
        String incidentTimestamp;
        int numOfMatches;
        Report myReport;
        WhatSetItOffEntry whatSetItOffEntry;
        List<String> seeRestrictedIds;
        String status;
        List<String> timeStamps;
        int count;
        //getters and setters
    }
    

    报告类:

    class Report {
        DocsReport docReports;
        //getters and setters
    }
    

    DocsReport 类:

    class DocsReport {
        @SerializedName("part1/.")
        Part1 part1;
        Part2 part2;
        //getters and setters
    }
    

    Part1 类:

    class Part1 {
        List<String> path;
        Analysis myAnalysis;
        List<CleanedUpData> cleanedUpData;
        MinedMetadata minedMetadata;
        DeducedMetadata deducedMetadata;
        //getters and setters
    }
    

    分析类:

    class Analysis {
        List<Information> matches;
        //getters and setters
    }
    

    信息类:

    class Information {
        Identifying id;
        String name;
        int position;
        String string;
        //getters and setters
    }
    

    识别类:

    class Identifying {
        int major;
        int minor;
        //getters and setters
    }
    

    CleanedUpData 类:

    class CleanedUpData {
        int startPosition;
        int endPosition;
        String frameContent;
        //getters and setters
    }
    

    MinedMetadata 类:

    class MinedMetadata {
        @SerializedName("Content-Encoding")
        String contentEncoding;
        @SerializedName("Content-Type")
        String contentType;
        //getters and setters
    }
    

    DeducedMetadata 类:

    class DeducedMetadata {
        @SerializedName("Content-Type")
        String contentType;
        //getters and setters
    }
    

    Part2 类:

    class Part2 {
        List<String> path;
        Analysis patternAnalysis;
        CleanedUpData cleanedUpData;
        MinedMetadata minedMetadata;
        DeducedMetadata deducedMetadata;
        //getters and setters
    }
    

    WhatSetItOffEntry 类:

    class WhatSetItOffEntry {
        String action;
        Component component;
        TicketInfo ticketInfo;
        LetmeknowInfo letmeknowInfo;
        //getters and setters
    }
    

    组件类:

    class Component {
        String type;
        List<ComponentData> components;
        Boolean not;
        //getters and setters
    }
    

    ComponentData 类:

    class ComponentData {
        String type;
        List<Integer> patterns;
        Boolean not;
        //getters and setters
    }
    

    TicketInfo 类:

    class TicketInfo {
        Boolean createIncident;
        List<Object> tags;
        List<RestrictedIds> seeRestrictedIds;
        //getters and setters
    }
    

    RestrictedIds 类:

    class RestrictedIds {
        String type;
        String name;
        String description;
        List<String> masters;
        List<Object> members;
        String id;
        //getters and setters
    }
    

    LetmeknowInfo 类:

    class LetmeknowInfo {
        Boolean createNotification;
        List<String> contactNames;
        //getters and setters
    }
    

    然后得到你的两个名字如下

    Gson gson = new Gson();
    Helper data = gson
            .fromJson(
                   new BufferedReader(
                            new FileReader(
                                    "C:/somepath/in/my/eclipse/project/jsonFormattedModified.json")),
                    new TypeToken<Helper>() {
                    }.getType());
    
    String name1 = data.getMyReport().getDocReports().getPart1()
            .getMyAnalysis().getMatches().get(0).getName();
    String name2 = data.getMyReport().getDocReports().getPart1()
            .getMyAnalysis().getMatches().get(1).getName();
    
    System.out.println(name1+"\n"+name2);
    

    输出:

    US SSN
    MasterCard Credit Card Number
    

    【讨论】:

    • 非常感谢。我会尝试一下,然后告诉你进展如何。
    • 我已经在我的 IDE 上对其进行了测试,它运行良好。只是不要忘记从我在答案中提供给您的链接下载后添加 gson jar。
    • 我只是想在我的 IDE 中测试它。只需几分钟,我就会看到您的努力和付出的结果。
    • 我还需要 30 分钟才能完成这堂课。我会马上带着我的测试结果回来。
    • 您使用的是哪个 Gson 库?对于这段代码:它在这一行抱怨 getJson 方法不适用于参数 BufferedWriter 和 Type。我正在使用 gson-2.2.4.jar Helper data = gson.fromJson( new BufferedWriter( new FileReader("C:/somepath/in/my/eclipse/project/jsonFormattedModified.json")), new TypeToken( ) { }.getType());
    【解决方案2】:

    需要考虑的两件事:

    • 如果您想继续流式传输,调用jp.readValueAsTree() 不是一个好主意,因为这将分配内存来创建包含当前节点下所有数据的树(在您的代码中,所有内容都在“匹配”下),除非您知道这肯定是一棵小树。
    • 要获取数组中的值,无需先创建数组。流式处理 API 可让您找到所需数组中的值。

    正如@MChaker 在他的回答中显示的那样,如果您需要 JSON 文件中提供的大部分数据,那么创建一个模型来保存数据将是有益的。但如果你只需要几个值,Jackson 会让你这样做。尽管如此,我必须承认,以真正的流媒体方式获取数据需要一些创造力才能找到跟踪您所在位置和期望数据的方法。

    下面的代码展示了简单的方式和流的方式:

    import java.io.*;
    import java.util.*;
    
    import com.fasterxml.jackson.core.*;
    import com.fasterxml.jackson.databind.*;
    
    /**
     * http://stackoverflow.com/q/30288878/3080094
     * Using jackson-databind-2.5.3 which uses
     * jackson-annotations-2.5.0 and
     * jackson-core-2.5.3
     * @author vanOekel
     */
    public class JsonTest {
    
        public static void main(String[] args) {
    
            try {
                new JsonTest().getNames();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        ObjectMapper jsonMapper = new ObjectMapper();
        JsonFactory jsonFactory = new JsonFactory();
    
        void getNames() throws Exception {
    
            final String resourceName = "some.json";
            JsonNode jn;
            try (InputStream in = 
                    Thread.currentThread().getContextClassLoader().getResourceAsStream(resourceName)
                    ) {
                if (in == null) {
                    throw new FileNotFoundException("File not found: " + resourceName);
                }
                jn = jsonMapper.readTree(in);
            } 
            findByPath(jn);
    
            try (InputStream in = 
                    Thread.currentThread().getContextClassLoader().getResourceAsStream(resourceName)
                    ) {
                if (in == null) {
                    throw new FileNotFoundException("File not found: " + resourceName);
                }
                JsonParser jsonParser = jsonFactory.createParser(in);
                findInStream(jsonParser);
            } 
        }
    
        final String[] path = new String[] {"myReport", "docReports", "part1/.", "myAnalysis", "matches", "name"};
    
        void findByPath(JsonNode jn) {
    
            JsonNode matchesNamesNode = jn;
            for (int i = 0; i < path.length - 1; i++) {
                matchesNamesNode = matchesNamesNode.path(path[i]);
            }
            if (matchesNamesNode.isMissingNode()) {
                throw new RuntimeException("No node with names found.");
            }
            System.out.println("Tree names: " + matchesNamesNode.findValuesAsText(path[path.length - 1]));
        }
    
        void findInStream(JsonParser jp) throws Exception {
    
            int pathIndex = 0;
            List<String> names = new ArrayList<String>();
            boolean breakOnClose = false;
    
            while (jp.nextToken() != null) {
                final String fieldName = jp.getCurrentName();
                if (fieldName == null) {
                    continue;
                }
                if (breakOnClose && fieldName.equals(path[path.length - 2])) {
                    System.out.println("Stopping search at end of node " + fieldName);
                    break;
                }
                if (jp.getCurrentToken() != JsonToken.FIELD_NAME) {
                    continue;
                }
                // System.out.println("Field " + fieldName);
                if (pathIndex >= path.length - 1) {
                    if (fieldName.equals(path[path.length - 1])) {
                        // move from field name to field value.
                        jp.nextToken(); 
                        String name = jp.getValueAsString();
                        if (name == null) {
                            throw new RuntimeException("No value exists for field " + fieldName);
                        }
                        names.add(name);
                        System.out.println("Found " + fieldName + " value: " + name);
                    }
                } else if (fieldName.equals(path[pathIndex])) {
                    System.out.println("Found node " + path[pathIndex]);
                    pathIndex++;
                    if (pathIndex >= path.length - 1) {
                        System.out.println("Looking for names ...");
                        breakOnClose = true;
                        // prevent breaking on "matches" value json-token.
                        jp.nextFieldName(); 
                    }
                }
            }
            System.out.println("Streaming names: " + names);
        }
    
    }
    

    【讨论】:

    • 对不起,我现在才看你的回答。是的。我喜欢 Chaker 的解决方案,但我更喜欢流式处理方法,因为我试图在 json 中找到几条数据。让我试试这个然后回复你。
    • 所以,你正在做的是给我两种方法来获取我想要的数据。 1)findInStream 2)findInPath
    • 确实,一个“在内存中”,另一个流式传输。只要文件小于(比如说)32kB,我就会选择“findByPath”(“内存中”)选项。与流式传输选项相比,它更容易使用(和维护),我怀疑你会用完内存。如果您需要同时处理多个超过 1MB 的文件,则可能需要为流式传输选项付出额外的努力。但我只会在确定需要它以防止内存不足时才使用流式传输选项。
    • 感谢您的详细解释。
    【解决方案3】:
      String jsonRecord = "[
                     {
                       a:a,
                       b:
                         {
                          c:
                            [{d:d,e:e},{d:d1,e:e1}]
                         }
                      }
                    ]";
     String value ="$.b.c[1].d";
     String str = JsonPath.read(jsonRecord, value);
     system.out.println(str);
    

    它将打印 d1

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-01-15
      • 1970-01-01
      • 1970-01-01
      • 2019-06-28
      • 2018-04-10
      • 2020-04-29
      • 2020-02-22
      • 1970-01-01
      相关资源
      最近更新 更多