Преобразование массива YAML в список Java с помощью SnakeYAML

Введение

YAML является одним из самых популярных языков сериализации данных после JSON. Поэтому его иногда называют строгий надстройка JSON. Он с самого начала был разработан для человеческого взаимодействия и удобочитаемости, поэтому он известен своей простотой. Он разработан с учетом гибкости и доступности, поэтому он работает со всеми современными языками программирования и мощным форматом для записи файлов конфигурации. Он также используется для сохранения данных, обмена сообщениями в Интернете, обмена данными на разных языках и многих других опций.

YAML был запущен в 2001 году и назывался «Еще один язык разметки" в то время. Но позже он был зарегистрирован как «YAML - это не язык разметки“. Базовая структура файла YAML представляет собой карта. Он также известен как словарь, хэш (карта) или просто объект на основе языка программирования, который мы решили использовать.

Пробелы и отступы используются в файлах YAML для обозначения вложенности.

Внимание: для отступов в файлах YAML можно использовать только пробелы; символы табуляции не допускаются. Пока отступ выполняется последовательно, не имеет значения, сколько пробелов используется.

Синтаксис YAML

Формат YAML в основном использует 3 типа узлов:

  • Карты/Словари: карта содержимое узла представляет собой неупорядоченный набор ключ / значение узел пар, с требованием, чтобы каждый ключ был различен. Никаких дополнительных ограничений на узлы YAML не накладывает.
  • Массивы / Списки: массив содержимое узла представляет собой упорядоченный набор из нуля или более узлов. В частности, последовательность может включать один и тот же узел более одного раза. Он может содержать даже самого себя.
  • литералы (Строки, числа, логические значения и т. д.): последовательность из нуля или более Символы Юникод может использоваться для представления непрозрачных данных, составляющих скаляр содержимое узла.

В этой статье мы специально рассмотрим преобразование содержимого массива YAML в список в Java. Существует множество библиотек с открытым исходным кодом, но наиболее популярными из них являются Джексон и ЗмеяЯМЛ. В этом руководстве мы будем использовать SnakeYaml в качестве нашей библиотеки для анализа содержимого YAML.

ЗмеяЯмл

ЗмеяЯМЛ — это пакет синтаксического анализа YAML, который предлагает высокоуровневый API для сериализации и десериализации документов YAML. Точкой входа для SnakeYAML является Yaml учебный класс. Документы или файлы YAML можно загрузить с помощью load() метод или в пакетном режиме через loadAll() метод. Методы принимают подлинные данные YAML в виде объектов String, а также InputStreams, который является типичным типом файла, с которым можно столкнуться.

Учитывая : структура, присущая файлам YAML, SnakeYAML, естественно, хорошо работает с Карты Явы, но мы также можем использовать уникальные Объекты 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. Учтите, что у нас есть файл yaml со следующими данными в папке ресурсов нашего проекта Java:

- 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 — имея карту карт со списками списков, сложно интуитивно анализировать и с ней трудно иметь дело. Даже в последнем примере, где у нас было только два вложенных списка, обработка их как списков становится довольно многословной.

В этих случаях лучше всего создать POJO, который можно сопоставить с вложенными данными YAML. Давайте сначала создадим образец 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 class, нам нужно указать тип данных, в который мы хотим преобразовать данные. 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 позволяет нам с легкостью управлять файлами YAML в нашем проекте Java, и для загрузки файлов YAML в наш проект или записи данных в файлы YAML требуется лишь немного кода. Кроме того, SnakeYAML предлагает варианты форматирования, поэтому вы можете настроить и персонализировать его в соответствии со своими потребностями.

Отметка времени:

Больше от Стекабьюс