使用 SnakeYAML 将 YAML 数组转换为 Java 列表

介绍

Yaml 是之后最流行的数据序列化语言之一 JSON. 因此,它有时被称为 严格 超集 的 JSON。 它从一开始就是为人类交互和可读性而设计的,因此,它以其简单而闻名。 它的设计考虑了灵活性和可访问性,因此它适用于所有现代编程语言和用于编写配置文件的强大格式。 它还用于数据持久性、互联网消息传递、跨语言数据共享以及更多选项。

YAML 始于 2001 年,被称为“另一种标记语言“ 当时。 但后来它被注册为“YAML 不是标记语言“。 YAML 文件的基本结构是 地图. 它也被称为字典、散列(映射)或简单的基于我们选择使用的编程语言的对象。

YAML 文件中使用空格和缩进来表示嵌套。

备注: YAML 文件的缩进只能使用空格; 不允许使用制表符。 只要缩进始终如一,使用多少空格都没有关系。

YAML 语法

YAML 格式主要使用 3 种节点类型:

  • 地图/字典:一个 地图 节点的内容是一个无序的集合 核心价值 节点 , 要求每个键必须是不同的。 YAML 没有对节点施加进一步的限制。
  • 数组/列表:安 排列 节点的内容是零个或多个节点的有序集合。 特别是,一个序列可能不止一次地包含同一个节点。 它甚至可能包含它自己。
  • 文字 (字符串、数字、布尔值等):零个或多个的序列 Unicode字符 可以用来表示组成一个不透明数据 纯量 节点的内容。

在本文中,我们将专门研究如何将 YAML 数组内容转换为 Java 中的 List。 有很多可用的开源库,但其中最受欢迎的是 杰克逊蛇YAML. 在本指南中,我们将使用 SnakeYaml 作为我们的库来解析 YAML 内容。

蛇药

蛇YAML 是一个 YAML 解析包,它为 YAML 文档序列化和反序列化提供高级 API。 SnakeYAML 的入口点是 Yaml 班级。 可以使用加载文档或 YAML 文件 load() 方法或批量通过 loadAll() 方法。 这些方法以字符串对象的形式获取真正的 YAML 数据以及 InputStreams,这是遇到的典型文件类型。

鉴于 : YAML 文件固有的结构,SnakeYAML 自然适用于 Java 地图,但我们也可以使用唯一的 Java 对象.

要将库包含在我们的项目中,请将以下依赖项添加到您的 pom.xml 文件:

<dependencies>
    <dependency>
        <groupId>org.yaml</groupId>
        <artifactId>snakeyaml</artifactId>
        <version>1.33</version>
    </dependency>
</dependencies>

或者,如果您使用的是Gradle:

compile group: 'org.yaml', name: 'snakeyaml', version: '1.33'

读取一个简单的 YAML 数组

让我们从 YAML 文件中读取一个简单的数组快速开始。 假设我们的 Java 项目的资源文件夹中有一个包含以下数据的 yaml 文件:

- One
- Two
- Three
- Four

然后我们可以将文件内容加载为 InputStream. 接下来,我们将构建 Yaml 然后将充当访问库的入口点和以编程方式表示 YAML 文件内容的对象的实例。 这 load() 方法允许我们读取和解析任何 InputStream 使用有效的 YAML 数据:

public void readYamlWithArray() {
    InputStream inputStream = this.getClass()
            .getClassLoader()
            .getResourceAsStream("number.yml");
    Yaml yaml = new Yaml();
    List data = yaml.load(inputStream);
    System.out.println(data);
 }

该方法将返回一个 Java List 字符串数据。 如果我们打印 data 那么它将给出以下结果:

[One, Two, Three, Four]

读取 YAML 分组数组

有时我们想针对给定的键定义一个内容数组。 这称为将数组分组到 YAML 映射节点中。 此类 YAML 示例如下所示:

languages:
  - Java
  - JavaScript
  - Python
  - Golang
  - Perl
  - Shell
  - Scala

这可以被认为是Java Map 包含一个 : 其中值为 排列. 所以数据仍将被加载为 InputStream 正如我们上面定义的。 但是 data 必须定义为 Map of List of Strings:

public void readYamlWithArrayGroup() {
    InputStream inputStream = this.getClass()
            .getClassLoader()
            .getResourceAsStream("language.yml");
    Yaml yaml = new Yaml();
    Map<String, List> data = yaml.load(inputStream);
    System.out.println(data);
    
    data.values()
            .stream()
            .collect(Collectors.toList())
            .get(0)
            .forEach(System.out::println);
}

现在,如果我们阅读我们的 data,它看起来像这样:

{languages=[Java, JavaScript, Python, Golang, Perl, Shell, Scala]}
Java
JavaScript
Python
Golang
Perl
Shell
Scala

读取 YAML 多行数组

有时我们会遇到包含数组数组的数据的 YAML 文件。 例如,我们将课程分组并将它们表示为如下数组:

courses:
  - - C
    - Java
    - Data Structures
    - Algorithms
  - - Big Data
    - Spark
    - Kafka
    - Machine Learning

这可以解析为Java Map of List of List of String. 我们可以再次加载 InputStream 正如我们之前所做的那样。 但数据将按如下方式加载:

查看我们的 Git 学习实践指南,其中包含最佳实践、行业认可的标准以及随附的备忘单。 停止谷歌搜索 Git 命令,实际上 学习 它!

public void readYamlWithMultiLineArrayGroup() {
    InputStream inputStream = this.getClass()
            .getClassLoader()
            .getResourceAsStream("courses.yml");
    Yaml yaml = new Yaml();
    
    Map<String, List<List>> data = yaml.load(inputStream);
    System.out.println(data);
    
    System.out.println("First Array Group:");
    data.values()
            .stream()
            .collect(Collectors.toList())
            .get(0)
            .get(0)
            .forEach(System.out::println);
    
    System.out.println("nSecond Array Group:");
    data.values()
            .stream()
            .collect(Collectors.toList())
            .get(0)
            .get(1)
            .forEach(System.out::println);
}

所以如果我们打印 data,它看起来像下面这样:

{courses=[[C, Java, Data Structures, Algorithms], [Big Data, Spark, Kafka, Machine Learning]]}

First Array Group:
C
Java
Data Structures
Algorithms

Second Array Group:
Big Data
Spark
Kafka
Machine Learning

将复杂的嵌套 YAML 内容读取为 Java Bean

我们看到了如何单独处理数组类型的内容,但是对于复杂的嵌套 YAML 文件 - 使用带有列表列表的映射映射很难直观地解析并且难以处理。 即使在最后一个我们只有两个嵌套列表的示例中——将它们作为列表处理也会变得相当冗长。

在这些情况下,最好创建一个可以映射到嵌套 YAML 数据的 POJO。让我们首先创建一个包含网站嵌套内容的示例 YAML:

website: stackabuse
skills:
  - python
  - javascript
  - java
  - unix
  - machine learning
  - web development
tutorials:
  - graphs:
      name: Graphs in Python - Theory and Implementation
      tags:
        - python
        - data structures
        - algorithm
      contributors:
        - David Landup
        - Dimitrije Stamenic
        - Jovana Ninkovic
      last_updated: June 2022
  - git:
      name: Git Essentials - Developer's Guide to Git
      tags:
        - git
      contributors:
        - David Landup
        - François Dupire
        - Jovana Ninkovic
      last_updated: April 2022
  - deep learning:
      name: Practical Deep Learning for Computer Vision with Python
      tags:
        - python
        - machine learning
        - tensorflow
        - computer vision
      contributors:
        - David Landup
        - Jovana Ninkovic
      last_updated: October 2022
published: true

我们需要定义一个父 Java 类 WebsiteContent 这将包括 List 的技能和 List of Map 教程将再次包含标签和贡献者列表:

public class WebsiteContent {
    private String website;
    private List skills;
    private List<Map> tutorials;
    private Boolean published;

    

    @Override
    public String toString() {
        return "WebsiteContent{" +
                "website='" + website + ''' +
                ", skills=" + skills +
                ", tutorials=" + tutorials +
                ", published=" + published +
                '}';
    }
}
public class Tutorial {

    private String name;
    private List tags;
    private List contributors;
    private String lastUpdated;

    

    @Override
    public String toString() {
        return "Tutorial{" +
                "name='" + name + ''' +
                ", tags=" + tags +
                ", contributors=" + contributors +
                ", lastUpdated='" + lastUpdated + ''' +
                '}';
    }
}

现在我们可以再次从文件中加载数据 InputStream 正如我们之前所做的那样。 接下来当我们创建我们的 Yaml 类对象,我们需要指定我们要将数据转换成的数据类型。 这 new Constructor(WebsiteContent.class) 告诉 SnakeYAML 从 YAML 文件中读取数据并将其映射到我们的 WebsiteContent 目的。

映射很简单,我们的对象属性的名称必须与 YAML 属性的名称匹配。

public void readYamlAsBeanWithNestedArrays(){
    
    InputStream inputStream = this.getClass()
            .getClassLoader()
            .getResourceAsStream("website_content.yml");
            
    
    Yaml yaml = new Yaml(new Constructor(WebsiteContent.class));
    WebsiteContent data = yaml.load(inputStream);
    
    
    System.out.println(data);
    System.out.println("nList of Skills: ");
    data.getSkills().stream().forEach(System.out::println);
    System.out.println("nList of Tutorials: ");
    data.getTutorials().stream().forEach(System.out::println);
}

最后,当我们打印 data,它看起来像下面这样:

WebsiteContent{website='stackabuse', skills=[python, javascript, java, unix, machine learning, web development], tutorials=[{graphs={name=Graphs in Python - Theory and Implementation, tags=[python, data structures, algorithm], contributors=[David Landup, Dimitrije Stamenic, Jovana Ninkovic], last_updated=June 2022}}, {git={name=Git Essentials - Developer's Guide to Git, tags=[git], contributors=[David Landup, François Dupire, Jovana Ninkovic], last_updated=April 2022}}, {deep learning={name=Practical Deep Learning for Computer Vision with Python, tags=[python, machine learning, tensorflow, computer vision], contributors=[David Landup, Jovana Ninkovic], last_updated=October 2022}}], published=true}

List of Skills: 
python
javascript
java
unix
machine learning
web development

List of Tutorials: 
{graphs={name=Graphs in Python - Theory and Implementation, tags=[python, data structures, algorithm], contributors=[David Landup, Dimitrije Stamenic, Jovana Ninkovic], last_updated=June 2022}}
{git={name=Git Essentials - Developer's Guide to Git, tags=[git], contributors=[David Landup, François Dupire, Jovana Ninkovic], last_updated=April 2022}}
{deep learning={name=Practical Deep Learning for Computer Vision with Python, tags=[python, machine learning, tensorflow, computer vision], contributors=[David Landup, Jovana Ninkovic], last_updated=October 2022}}

可以看到,SnakeYaml 已经成功解析并转换了 WebsiteContent 对象并保持继承和关联 Tutorial 对象完好无损。

结论

由于 YAML 文件广泛用于 DevOps 和配置相关数据,因此使用代码解析和操作数据非常有用。

SnakeYAML 让我们可以轻松地管理 Java 项目中的 YAML 文件,并且只需要一点代码即可将 YAML 文件加载到我们的项目中或将数据写入 YAML 文件中。 此外,SnakeYAML 提供格式选择,因此您可以调整和个性化它以满足我们的需求。

时间戳记:

更多来自 堆栈滥用