Converter matriz YAML em lista Java com SnakeYAML

Introdução

Yaml é uma das linguagens de serialização de dados mais populares depois JSON. Portanto, às vezes é chamado de rigoroso superconjunto de JSON. Ele foi projetado para interação humana e legibilidade desde o início, portanto, é conhecido por sua simplicidade. Ele foi projetado com flexibilidade e acessibilidade em mente, por isso funciona com todas as linguagens de programação modernas e um formato poderoso para gravar arquivos de configuração. Também é usado para persistência de dados, mensagens na Internet, compartilhamento de dados entre idiomas e muitas outras opções.

O YAML foi iniciado em 2001 e foi denominado como “Mais uma linguagem de marcação" naquela hora. Mas depois foi registrado como “YAML não é linguagem de marcação“. A estrutura básica de um arquivo YAML é uma mapa,. Também é conhecido como dicionário, hash(mapa) ou simplesmente baseado em objetos na linguagem de programação que optamos por usar.

Espaço em branco e recuo são usados ​​em arquivos YAML para denotar aninhamento.

Note: Somente espaços podem ser usados ​​para recuo em arquivos YAML; caracteres de tabulação não são permitidos. Desde que o recuo seja feito de forma consistente, não importa quantos espaços sejam utilizados.

Sintaxe YAML

Um formato YAML usa principalmente 3 tipos de nós:

  • Mapas/Dicionários: UMA mapa, o conteúdo do nó é uma coleção não ordenada de valor chavepares, com o requisito de que cada chave deve ser distinta. Nenhuma outra limitação é imposta aos nós pelo YAML.
  • Matrizes/Listas: A ordem o conteúdo do nó é uma coleção ordenada de zero ou mais nós. Uma sequência pode incluir o mesmo nó mais de uma vez, em particular. Pode conter até a si mesmo.
  • Literais (Strings, números, boolean, etc.): Uma sequência de zero ou mais Caracteres Unicode pode ser usado para representar os dados opacos que compõem um escalar conteúdo do nó.

Neste artigo, analisaremos especificamente a conversão de conteúdo de matriz YAML em uma lista em Java. Existem muitas bibliotecas de código aberto disponíveis, mas as mais populares delas são Jackson e CobraYAML. Neste guia, usaremos SnakeYaml como nossa biblioteca para analisar o conteúdo YAML.

SnakeYamlGenericName

CobraYAML é um pacote de análise YAML que oferece uma API de alto nível para serialização e desserialização de documentos YAML. O ponto de entrada para SnakeYAML é o Yaml classe. Os documentos ou os arquivos YAML podem ser carregados usando load() método ou em lote através do loadAll() método. Os métodos pegam dados YAML genuínos na forma de objetos String, bem como InputStreams, que é um tipo de arquivo típico para encontrar.

Considerando a : estrutura inata para arquivos YAML, SnakeYAML naturalmente funciona bem com Mapas Java, mas também podemos usar objetos Java.

Para incluir a biblioteca em nosso projeto, adicione a seguinte dependência ao seu pom.xml arquivo:

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

Ou, se você estiver usando o Gradle:

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

Lendo uma matriz YAML simples

Vamos começar rapidamente lendo uma matriz simples de um arquivo YAML. Considere que temos um arquivo yaml com os seguintes dados na pasta de recursos do nosso projeto Java:

- One
- Two
- Three
- Four

Então podemos carregar o conteúdo do arquivo como um InputStream. A seguir, vamos construir o Yaml instância que atuará como um ponto de entrada para acessar a biblioteca e o objeto para representar o conteúdo do arquivo YAML programaticamente. o load() método nos permite ler e analisar qualquer InputStream com dados YAML válidos:

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

O método retornará um Java List de dados String. Se imprimirmos o data então dará o seguinte resultado:

[One, Two, Three, Four]

Lendo uma matriz agrupada YAML

Às vezes, gostaríamos de definir uma matriz de conteúdo em relação a uma determinada chave. Isso é chamado de agrupamento de matrizes em um nó de mapa YAML. Um exemplo de YAML desse tipo se parece com o seguinte:

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

Isso pode ser considerado como Java Map contendo um : onde o valor é um ordem. Assim, os dados ainda serão carregados como InputStream como definimos acima. Mas o data deve ser definido como 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);
}

Agora, se lermos nosso data, seria mais ou menos assim:

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

Lendo uma matriz de várias linhas YAML de matrizes

Às vezes nos deparamos com um arquivo YAML com dados contendo array de arrays. Por exemplo, agrupamos os cursos e os representamos como array de arrays como abaixo:

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

Isso pode ser analisado como Java Map of List of List of String. Podemos carregar novamente o InputStream como fizemos anteriormente. Mas os dados serão carregados conforme abaixo:

Confira nosso guia prático e prático para aprender Git, com práticas recomendadas, padrões aceitos pelo setor e folha de dicas incluída. Pare de pesquisar comandos Git no Google e realmente aprender -lo!

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

Então, se imprimirmos o data, ficaria algo como abaixo:

{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

Lendo um conteúdo YAML aninhado complexo como Java Bean

Vimos como podemos lidar com o conteúdo do tipo array separadamente, mas com arquivos YAML aninhados complexos – ter um mapa de mapas com listas de listas é difícil de analisar intuitivamente e difícil de lidar. Mesmo no último exemplo, onde tínhamos apenas duas listas aninhadas – lidar com elas como listas fica bastante detalhado.

Nesses casos, é melhor criar um POJO que possa ser mapeado para os dados YAML aninhados. Vamos primeiro criar um YAML de amostra contendo o conteúdo aninhado de um site:

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

Precisamos definir uma classe Java pai WebsiteContent que consistirá em List de habilidades e um List of Map de tutoriais que novamente conterão listas de tags e contribuidores:

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

Agora podemos carregar novamente os dados do arquivo como InputStream como fizemos anteriormente. Em seguida, quando criamos nosso Yaml objeto de classe, precisamos especificar o tipo de dados em que queremos converter os dados. o new Constructor(WebsiteContent.class) diz ao SnakeYAML para ler os dados do arquivo YAML mapeá-lo para o nosso WebsiteContent objeto.

O mapeamento é direto e os nomes de nossos atributos de objeto devem corresponder aos nomes dos atributos 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);
}

Por fim, quando imprimimos o data, ficaria algo como abaixo:

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

Como podemos ver, o SnakeYaml analisou e converteu com sucesso o WebsiteContent objeto e manteve a herança e associação com Tutorial objeto intacto.

Conclusão

Como os arquivos YAML são amplamente usados ​​para DevOps e dados relacionados à configuração, é bastante útil analisar e manipular os dados usando código.

SnakeYAML nos permite gerenciar arquivos YAML em nosso projeto Java com facilidade, e requer apenas um pouco de código para carregar arquivos YAML em nosso projeto ou gravar dados em arquivos YAML. Além disso, o SnakeYAML oferece opções de formatação para que você possa ajustá-lo e personalizá-lo para atender às nossas necessidades.

Carimbo de hora:

Mais de Abuso de pilha