Chuyển đổi Mảng YAML thành Danh sách Java với SnakeYAML

Giới thiệu

YAML là một trong những ngôn ngữ tuần tự hóa dữ liệu phổ biến nhất sau JSON. Do đó, đôi khi nó được gọi là khắt khe bộ siêu tập của JSON. Nó đã được thiết kế để con người tương tác và dễ đọc ngay từ đầu, do đó, nó được biết đến với sự đơn giản của nó. Nó được thiết kế với tính linh hoạt và khả năng truy cập, vì vậy nó hoạt động với tất cả các ngôn ngữ lập trình hiện đại và một định dạng mạnh mẽ để viết các tệp cấu hình. Nó cũng được sử dụng để duy trì dữ liệu, nhắn tin qua internet, chia sẻ dữ liệu đa ngôn ngữ và nhiều tùy chọn khác.

YAML được bắt đầu vào năm 2001 và được gọi là “Tuy nhiên, một ngôn ngữ đánh dấu khác" tại thời điểm đó. Nhưng sau đó nó đã được đăng ký nhãn hiệu là “YAML không phải là ngôn ngữ đánh dấu“. Cấu trúc cơ bản của tệp YAML là một bản đồ. Nó còn được gọi là từ điển, băm (bản đồ) hoặc đơn giản là dựa trên đối tượng dựa trên ngôn ngữ lập trình mà chúng ta chọn sử dụng.

Khoảng trắng và thụt lề được sử dụng trong các tệp YAML để biểu thị lồng nhau.

Chú thích: Chỉ có thể sử dụng khoảng trắng để thụt lề trong tệp YAML; ký tự tab không được phép. Miễn là việc thụt đầu dòng được thực hiện một cách nhất quán thì việc sử dụng bao nhiêu khoảng trắng không quan trọng.

Cú pháp YAML

Định dạng YAML chủ yếu sử dụng 3 loại nút:

  • Bản đồ / Từ điển: A bản đồ nội dung của nút là một tập hợp không có thứ tự giá trị cốt lõi nút cặp, với yêu cầu mỗi khóa phải khác biệt. Không có giới hạn nào khác được áp đặt cho các nút bởi YAML.
  • Mảng / Danh sách: An mảng nội dung của nút là tập hợp có thứ tự gồm 0 hoặc nhiều nút. Đặc biệt, một chuỗi có thể bao gồm cùng một nút nhiều lần. Nó có thể chứa cả chính nó.
  • Chữ viết (Chuỗi, số, boolean, v.v.): Một chuỗi từ XNUMX trở lên Ký tự Unicode có thể được sử dụng để đại diện cho dữ liệu không rõ ràng tạo nên một vô hướng nội dung của nút.

Trong bài viết này, chúng ta sẽ đặc biệt xem xét cách chuyển đổi nội dung mảng YAML thành Danh sách trong Java. Có rất nhiều thư viện mã nguồn mở có sẵn nhưng phổ biến nhất trong số đó là Jacksoncon rắnYAML. Trong hướng dẫn này, chúng tôi sẽ sử dụng SnakeYaml làm thư viện để phân tích cú pháp nội dung YAML.

con rắnYaml

con rắnYAML là một gói phân tích cú pháp YAML cung cấp API cấp cao để tuần tự hóa và giải mã tài liệu YAML. Điểm vào SnakeYAML là Yaml lớp. Các tài liệu hoặc tệp YAML có thể được tải bằng load() phương pháp hoặc hàng loạt thông qua loadAll() phương pháp. Các phương thức lấy dữ liệu YAML chính hãng ở dạng đối tượng Chuỗi cũng như InputStreams, đây là loại tệp điển hình mà bạn gặp phải.

Cho : cấu trúc bẩm sinh cho các tệp YAML, SnakeYAML tự nhiên hoạt động tốt với Bản đồ Java, nhưng chúng tôi cũng có thể sử dụng Đối tượng Java.

Để đưa thư viện vào dự án của chúng tôi, hãy thêm phần phụ thuộc sau vào pom.xml tập tin:

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

Hoặc, nếu bạn đang sử dụng Gradle:

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

Đọc một mảng YAML đơn giản

Hãy nhanh chóng bắt đầu bằng cách đọc một mảng đơn giản từ tệp YAML. Hãy xem xét rằng chúng tôi có một tệp yaml với dữ liệu sau trong thư mục tài nguyên của dự án Java của chúng tôi:

- One
- Two
- Three
- Four

Sau đó, chúng tôi có thể tải nội dung tệp dưới dạng InputStream. Tiếp theo, chúng tôi sẽ xây dựng Yaml thể hiện này sau đó sẽ hoạt động như một điểm vào để truy cập thư viện và đối tượng để đại diện cho nội dung tệp YAML theo chương trình. Các load() phương thức cho phép chúng tôi đọc và phân tích cú pháp bất kỳ InputStream với dữ liệu YAML hợp lệ:

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

Phương thức sẽ trả về một Java List dữ liệu chuỗi. Nếu chúng tôi in data thì nó sẽ cho kết quả như sau:

[One, Two, Three, Four]

Đọc một mảng được nhóm YAML

Đôi khi chúng ta muốn xác định một mảng nội dung dựa trên một khóa nhất định. Điều này được gọi là nhóm các mảng thành một nút bản đồ YAML. Một YAML mẫu của loại như vậy trông giống như dưới đây:

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

Đây có thể coi là Java Map chứa một : trong đó giá trị là một mảng. Vì vậy, dữ liệu sẽ vẫn được tải dưới dạng InputStream như chúng tôi đã xác định ở trên. Nhưng data phải được định nghĩa là 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);
}

Bây giờ nếu chúng ta đọc data, nó sẽ trông giống như thế này:

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

Đọc một mảng mảng nhiều dòng YAML

Đôi khi chúng ta bắt gặp một tệp YAML có dữ liệu chứa nhiều mảng. Ví dụ: chúng tôi nhóm các khóa học và biểu diễn chúng dưới dạng mảng các mảng như bên dưới:

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

Điều này có thể được phân tích cú pháp như Java Map of List of List of String. Chúng tôi có thể tải lại InputStream như chúng tôi đã làm trước đó. Nhưng dữ liệu sẽ được tải như bên dưới:

Xem hướng dẫn thực hành, thực tế của chúng tôi để học Git, với các phương pháp hay nhất, các tiêu chuẩn được ngành công nghiệp chấp nhận và bảng lừa đảo đi kèm. Dừng lệnh Googling Git và thực sự học nó!

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);
}

Vì vậy, nếu chúng tôi in data, nó sẽ trông giống như bên dưới:

{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

Đọc nội dung YAML lồng nhau phức tạp dưới dạng Java Bean

Chúng tôi đã thấy cách chúng tôi có thể xử lý nội dung loại mảng một cách riêng biệt, nhưng với các tệp YAML lồng nhau phức tạp – việc có bản đồ bản đồ với danh sách các danh sách khó phân tích cú pháp một cách trực quan và khó xử lý. Ngay cả trong ví dụ trước, chúng ta chỉ có hai danh sách lồng nhau – việc xử lý chúng dưới dạng danh sách khá dài dòng.

Trong những trường hợp này, tốt nhất là tạo một POJO có thể ánh xạ tới dữ liệu YAML lồng nhau. Trước tiên, hãy tạo một YAML mẫu chứa nội dung lồng nhau của một trang web:

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

Chúng ta cần xác định một lớp Java cha WebsiteContent điều đó sẽ bao gồm List kỹ năng và một List of Map trong số các hướng dẫn sẽ lại chứa danh sách các thẻ và cộng tác viên:

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 + ''' +
                '}';
    }
}

Bây giờ chúng ta có thể tải lại dữ liệu từ tệp dưới dạng InputStream như chúng tôi đã làm trước đó. Tiếp theo khi chúng tôi tạo Yaml đối tượng lớp, chúng ta cần chỉ định kiểu dữ liệu mà chúng ta muốn truyền dữ liệu vào. Các new Constructor(WebsiteContent.class) yêu cầu SnakeYAML đọc dữ liệu từ tệp YAML ánh xạ nó vào WebsiteContent vật.

Ánh xạ là đơn giản và tên của các thuộc tính đối tượng của chúng ta phải khớp với tên của các thuộc tính 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);
}

Cuối cùng, khi chúng tôi in data, nó sẽ trông giống như bên dưới:

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}}

Như chúng ta có thể thấy, SnakeYaml đã phân tích cú pháp và chuyển đổi thành công WebsiteContent phản đối và giữ sự kế thừa và liên kết với Tutorial đối tượng còn nguyên vẹn.

Kết luận

Vì tệp YAML được sử dụng rộng rãi cho DevOps và dữ liệu liên quan đến cấu hình, nó khá hữu ích để phân tích cú pháp và thao tác dữ liệu bằng cách sử dụng mã.

SnakeYAML cho phép chúng tôi quản lý các tệp YAML trong dự án Java của mình một cách dễ dàng và nó chỉ yêu cầu một chút mã để tải tệp YAML vào dự án của chúng tôi hoặc ghi dữ liệu vào tệp YAML. Ngoài ra, SnakeYAML cung cấp các lựa chọn định dạng để bạn có thể điều chỉnh và cá nhân hóa nó cho phù hợp với nhu cầu của chúng tôi.

Dấu thời gian:

Thêm từ xếp chồng lên nhau