【问题标题】:How to select fields in different levels of a jsonfile with jsonPath?如何使用jsonPath选择jsonfile不同级别的字段?
【发布时间】:2020-05-12 13:47:19
【问题描述】:

我想将 jsonobjcts 转换为 csv 文件。到目前为止,Wy(工作)尝试是将 json 文件加载为 JSONObject(来自 googlecode.josn-simple 库),然后使用 jsonPath 将它们转换为字符串数组,然后用于构建 csv 行。但是我遇到了 jsonPath 的问题。从给定的示例 json...

{
"issues": [
    {
        "key": "abc",
        "fields": {
            "issuetype": {
                "name": "Bug",
                "id": "1",
                "subtask": false
            },
            "priority": {
                "name": "Major",
                "id": "3"
            },
            "created": "2020-5-11",
            "status": {
                "name": "OPEN"
            }
        }
    },
    {
        "key": "def",
        "fields": {
            "issuetype": {
                "name": "Info",
                "id": "5",
                "subtask": false
            },
            "priority": {
                "name": "Minor",
                "id": "2"
            },
            "created": "2020-5-8",
            "status": {
                "name": "DONE"
            }
        }
    }
]}

我想选择以下:

[
    "abc",
    "Bug",
    "Major",
    "2020-5-11",
    "OPEN",
    "def",
    "Info",
    "Minor",
    "2020-5-8",
    "DONE"
]

csv 应该是这样的:

abc,Bug,Major,2020-5-11,OPEN
def,Info,Minor,2020-5-8,DONE

我试过$.issues.[*].[key,fields],我得到了

  "abc",
  {
    "issuetype": {
      "name": "Bug",
      "id": "1",
      "subtask": false
    },
    "priority": {
      "name": "Major",
      "id": "3"
    },
    "created": "2020-5-11",
    "status": {
      "name": "OPEN"
    }
  },
  "def",
  {
    "issuetype": {
      "name": "Info",
      "id": "5",
      "subtask": false
    },
    "priority": {
      "name": "Minor",
      "id": "2"
    },
    "created": "2020-5-8",
    "status": {
      "name": "DONE"
    }
  }
]

但是当我想选择例如仅“创建”$.issues.[*].[key,fields.[created]

[
  "2020-5-11",
  "2020-5-8"
]

这是结果。

但我只是不知道如何选择“键”,例如字段问题类型中的“名称”。 我该如何使用 jsonPath 来做到这一点,还是有更好的方法来过滤 jsonfile 然后将其转换为 csv?

【问题讨论】:

    标签: java json csv jsonpath


    【解决方案1】:

    我推荐一种我认为更好的方法——即创建一组代表 JSON 数据结构的 Java 类。当您将 JSON 读入这些类时,您可以使用标准 Java 操作数据。

    我还推荐一个不同的 JSON 解析器 - 在这个例子中是杰克逊,但还有其他的。为什么?主要是熟悉度 - 请参阅稍后了解更多说明。

    从最终结果开始:假设我有一个名为 Container 的类,其中包含 JSON 文件中列出的所有问题,然后我可以使用以下内容填充它:

    //import com.fasterxml.jackson.databind.ObjectMapper;
    
    String jsonString = "{...}" // your JSON data as a string, for this demo.
    ObjectMapper objectMapper = new ObjectMapper();
    Container container = objectMapper.readValue(jsonString, Container.class);
    

    现在我可以打印出你想要的 CSV 格式的所有问题,如下所示:

    container.getIssues().forEach((issue) -> {
        printCsvRow(issue);
    });
    

    这里,printCsvRow() 方法如下所示:

    private void printCsvRow(Issue issue) {
        String key = issue.getKey();
        Fields fields = issue.getFields();
        String type = fields.getIssuetype().getName();
        String priority = fields.getPriority().getName();
        String created = fields.getCreated();
        String status = fields.getStatus().getName();
        System.out.println(String.join(",", key, type, priority, created, status));
    }
    

    实际上,我会使用 CSV 库来确保记录的格式正确 - 以上只是为了说明,展示如何访问 JSON 数据。

    打印如下:

    abc,Bug,Major,2020-5-11,OPEN
    def,Info,Minor,2020-5-8,DONE
    

    为了只过滤 OPEN 记录,我可以这样做:

    container.getIssues()
            .stream()
            .filter(issue -> issue.getFields().getStatus().getName().equals("OPEN"))
            .forEach((issue) -> {
        printCsvRow(issue);
    });
    

    打印如下:

    abc,Bug,Major,2020-5-11,OPEN
    

    为了启用 Jackson,我使用具有以下依赖项的 Maven:

    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.10.3</version>
    </dependency>
    

    如果您不使用 Maven,这会给我 3 个 JAR:jackson-databindjackson-annotationsjackson-core

    为了创建我需要的嵌套 Java 类(以反映 JSON 的结构),我使用了一个工具,该工具使用您的示例 JSON 为我生成它们。

    在我的例子中,我使用了this tool,但还有其他的。

    我选择“Container”作为根 Java 类的名称; JSON 的源类型;并选择了 Jackson 2.x 注释。我还请求了 getter 和 setter。

    我将生成的类(字段、问题、问题类型、优先级、状态和容器)添加到我的项目中。

    警告:这些 Java 类的完整性仅与示例 JSON 一样好。但是您当然可以增强这些类以更准确地反映您需要处理的实际 JSON。

    Jackson ObjectMapper 负责将 JSON 加载到类结构中。

    我选择使用 Jackson 而不是 JsonPath,只是因为熟悉。 JsonPath 似乎具有非常相似的对象映射功能 - 但我从未使用过 JsonPath 的这些功能。

    最后说明:您可以在 JsonPath 中使用 xpath 样式谓词来访问单个数据项和项组 - 正如您在问题中所描述的那样。但是(根据我的经验)如果您想以更灵活的方式处理所有数据,那么创建 Java 类几乎总是值得付出额外努力——尤其是当这涉及将 JSON 输入转换为不同的输出结构时。

    【讨论】:

    • 哇,谢谢!现在我要睡觉了,但明天我会试一试。一个问题。在处理许多不同的 json 时,这也是首选方式吗?在我的应用程序中,我通过其他 API 从各种来源收集信息,将它们转换为 csv,以便我可以处理数据。
    • 可能取决于“多少?”和“有什么不同?” (结构上)。您可以将任意 JSON 加载到“通用”Java 结构中。有关一些可能的线索,请参阅 herehere。就个人而言,我会为每个 JSON 有效负载创建特定的 Java 对象;而且我不会尝试构建复杂的解析器。
    猜你喜欢
    • 2014-09-21
    • 2021-03-24
    • 1970-01-01
    • 1970-01-01
    • 2022-11-18
    • 2021-01-10
    • 2011-02-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多