Wiki

Clone wiki

snakeyaml-engine / Documentation

SnakeYAML Engine Documentation

This documentation is very brief and incomplete. Feel free to fix or improve it.

Installation

If you use Maven just add a dependency as described here.

Tutorial

Loading YAML

The Builder pattern is used to create immutable instance of org.snakeyaml.engine.v2.api.LoadSettings

LoadSettings settings = LoadSettings.builder().setLabel("Custom user configuration").build();

Create the org.snakeyaml.engine.v2.api.Load instance:

Load load = new Load(settings);

The org.snakeyaml.engine.v2.api.Load instance can load 3 types of sources:

  • InputStream
  • Reader
  • String

The InputStream does not contain the encoding information and to detect the encoding the BOM (byte order mark) sequence at the beginning of the stream can be used. If no BOM is present, the UTF-8 encoding is assumed.

The Reader and String define the encoding and the BOM must not be present (it will be interpreted as data).

These methods convert a YAML document to a Java object:

  • loadFromInputStream
  • loadFromReader
  • loadFromString

Load load = new Load(settings);
String document = "\n- Hesperiidae\n- Papilionidae\n- Apatelodidae\n- Epiplemidae";
List<String> list = (List<String>) yaml.loadFromString(document);
System.out.println(list);

['Hesperiidae', 'Papilionidae', 'Apatelodidae', 'Epiplemidae']
You can find examples here

Implicit types

When a tag for a scalar node is not explicitly defined, SnakeYAML Engine tries to detect the type applying regular expressions to the content of the scalar node.

1.0 -> Double
42 -> Integer
null -> null
false -> boolean
Only the JSON Schema is supported now.

The Core Schema requires to write a custom implementation
of the ScalarResolver (it might be added in the next versions).

Dumping YAML

The Builder pattern is used to create immutable instance of org.snakeyaml.engine.v2.api.DumpSettings

DumpSettings settings = DumpSettings.builder().setDefaultScalarStyle(ScalarStyle.DOUBLE_QUOTED).build();

Create the org.snakeyaml.engine.v2.api.Dump instance:

Dump dump = new Dump(settings);

The method Dump.dumpToString() takes an instance and returns its YAML document. The method Dump.dumpAllToString() takes an java.util.Iterator and returns a YAML stream with all the documents included. The documents are separated as defined in the DumpSettings.

To support output to streams Dump has dump() and dumpAll(). They take an instance of StreamDataWriter as a parameter. The interface is identical to java.io.Writer but without throwing IOExceptions. It means that the user has to create the implementation of the interface and take care of catching the I/O exceptions.

Working examples can be found in the tests

Dumping a custom YAML document

TODO

Constructors, representers, resolvers

TODO

Enum

TODO

Threading

The implementation is not thread-safe. Different threads may not call the same instance. Threads must have separate Load or Dump instances.

Low Level API

It is possible to parse or compose the incoming stream of characters. Examples can be found here for parsing or here for composing.

Tags

Explicit tags can be local (begin with single exclamation mark '!car') and global (begin with 2 exclamation marks '!!com.Car'). Global tags work well within a single programming language, because they can be parsed without extra configuration. Local tags require additional context. Since every parser must provide more information at runtime to create instances, local tags help a YAML document to be exchanged with other languages (every parser is free to define what to do with !car)

Implicit tags are assigned to every scalar and they are determined from the regular expressions. It is possible to add custom implicit tags. When a scalar is created the following order is used:

  1. explicit tag - when it is present.

  2. implicit tag - when the runtime class of the instance is unknown

It means that the implicit tag is ignored as soon as any other information about a scalar is available.

YAML syntax

A good introduction to the YAML syntax is Chapter 2 of the YAML specification.

Here we present most common YAML constructs together with the corresponding Java objects.

Documents

YAML stream is a collection of zero or more documents. An empty stream contains no documents. Documents are separated with ---. Documents may optionally end with .... A single document may or may not be marked with ---.

Example of an implicit document:

- Multimedia
- Internet
- Education

Example of an explicit document:

---
- Afterstep
- CTWM
- Oroborus
...

Example of several documents in the same stream:

---
- Ada
- APL
- ASP

- Assembly
- Awk
---
- Basic
---
- C
- C#    # Note that comments are denoted with ' #' (space and #).
- C++
- Cold Fusion

Block sequences

In the block context, sequence entries are denoted by - (dash and space):

# YAML
- The Dagger 'Narthanc'
- The Dagger 'Nimthanc'
- The Dagger 'Dethanc'
# Java
["The Dagger 'Narthanc'", "The Dagger 'Nimthanc'", "The Dagger 'Dethanc'"]

Block sequences can be nested:

# YAML
-
  - HTML
  - LaTeX
  - SGML
  - VRML
  - XML
  - YAML
-
  - BSD
  - GNU Hurd
  - Linux
# Java
[['HTML', 'LaTeX', 'SGML', 'VRML', 'XML', 'YAML'], ['BSD', 'GNU Hurd', 'Linux']]

It's not necessary to start a nested sequence with a new line:

# YAML
- 1.1
- - 2.1
  - 2.2
- - - 3.1
    - 3.2
    - 3.3
# Java
[1.1, [2.1, 2.2], [[3.1, 3.2, 3.3]]]

A block sequence may be nested to a block mapping. Note that in this case it is not necessary to indent the sequence.

# YAML
left hand:
- Ring of Teleportation
- Ring of Speed

right hand:
- Ring of Resist Fire
- Ring of Resist Cold
- Ring of Resist Poison
# Java
{'right hand': ['Ring of Resist Fire', 'Ring of Resist Cold', 'Ring of Resist Poison'],
'left hand': ['Ring of Teleportation', 'Ring of Speed']}

Block mappings

In the block context, keys and values of mappings are separated by : (colon and space):

# YAML
base armor class: 0
base damage: [4,4]
plus to-hit: 12
plus to-dam: 16
plus to-ac: 0
# Java
{'plus to-hit': 12, 'base damage': [4, 4], 'base armor class': 0, 'plus to-ac': 0, 'plus to-dam': 16}

Complex keys are denoted with ? (question mark and space):

# YAML
? !!python/tuple [0,0]
: The Hero
? !!python/tuple [0,1]
: Treasure
? !!python/tuple [1,0]
: Treasure
? !!python/tuple [1,1]
: The Dragon
# Java
{(0, 1): 'Treasure', (1, 0): 'Treasure', (0, 0): 'The Hero', (1, 1): 'The Dragon'}

Block mapping can be nested:

# YAML
hero:
  hp: 34
  sp: 8
  level: 4
orc:
  hp: 12
  sp: 0
  level: 2
# Java
{'hero': {'hp': 34, 'sp': 8, 'level': 4}, 'orc': {'hp': 12, 'sp': 0, 'level': 2}}

A block mapping may be nested in a block sequence:

# YAML
- name: PyYAML
  status: 4
  license: MIT
  language: Python
- name: PySyck
  status: 5
  license: BSD
  language: Python
# Java
[{'status': 4, 'language': 'Python', 'name': 'PyYAML', 'license': 'MIT'},
{'status': 5, 'license': 'BSD', 'name': 'PySyck', 'language': 'Python'}]

Flow collections

The syntax of flow collections in YAML is very close to the syntax of list and dictionary constructors in Python:

# YAML
{ str: [15, 17], con: [16, 16], dex: [17, 18], wis: [16, 16], int: [10, 13], chr: [5, 8] }
# Java
{'dex': [17, 18], 'int': [10, 13], 'chr': [5, 8], 'wis': [16, 16], 'str': [15, 17], 'con': [16, 16]}

Scalars

There are 5 styles of scalars in YAML: plain, single-quoted, double-quoted, literal, and folded:

# YAML
plain: Scroll of Remove Curse
single-quoted: 'EASY_KNOW'
double-quoted: "?"
literal: |    # Borrowed from http://www.kersbergen.com/flump/religion.html
  by hjw              ___
     __              /.-.\
    /  )_____________\\  Y
   /_ /=== == === === =\ _\_
  ( /)=== == === === == Y   \
   `-------------------(  o  )
                        \___/
folded: >
  It removes all ordinary curses from all equipped items.
  Heavy or permanent curses are unaffected.
# Java
{'plain': 'Scroll of Remove Curse',
'literal':
    'by hjw              ___\n'
    '   __              /.-.\\\n'
    '  /  )_____________\\\\  Y\n'
    ' /_ /=== == === === =\\ _\\_\n'
    '( /)=== == === === == Y   \\\n'
    ' `-------------------(  o  )\n'
    '                      \\___/\n',
'single-quoted': 'EASY_KNOW',
'double-quoted': '?',
'folded': 'It removes all ordinary curses from all equipped items. Heavy or permanent curses are unaffected.\n'}

Each style has its own quirks. A plain scalar does not use indicators to denote its start and end, therefore it's the most restricted style. Its natural applications are names of attributes and parameters.

Using single-quoted scalars, you may express any value that does not contain special characters. No escaping occurs for single quoted scalars except that duplicate quotes '' are replaced with a single quote '.

Double-quoted is the most powerful style and the only style that can express any scalar value. Double-quoted scalars allow escaping. Using escaping sequences \x** and \u****, you may express any ASCII or Unicode character.

There are two kind of block scalar styles: literal and folded. The literal style is the most suitable style for large block of text such as source code. The folded style is similar to the literal style, but two consequent non-empty lines are joined to a single line separated by a space character.

Aliases

Using YAML you may represent objects of arbitrary graph-like structures. If you want to refer to the same object from different parts of a document, you need to use anchors and aliases.

Anchors are denoted by the & indicator while aliases are denoted by *. For instance, the document

left hand: &A
  name: The Bastard Sword of Eowyn
  weight: 30
right hand: *A
expresses the idea of a hero holding a heavy sword in both hands.

SnakeYAML now fully supports recursive objects. For instance, the document

&A [ *A ]
will produce a list object containing a reference to itself.

Tags

Tags are used to denote the type of a YAML node. Standard YAML tags are defined at http://yaml.org/type/index.html.

Tags may be implicit:

boolean: true
integer: 3
float: 3.14
#!python
{'boolean': True, 'integer': 3, 'float': 3.14}

or explicit:

boolean: !!bool "true"
integer: !!int "3"
float: !!float "3.14"
#!python
{'boolean': True, 'integer': 3, 'float': 3.14}

Plain scalars without explicitly defined tag are subject to implicit tag resolution. The scalar value is checked against a set of regular expressions and if one of them matches, the corresponding tag is assigned to the scalar. SnakeYAML allows an application to add custom implicit tag resolvers.

YAML tags and Java types

The following table describes how nodes with different tags are converted to Java objects.

YAML tag Java type
Standard YAML tags
!!null null
!!bool Boolean
!!int Integer, Long, BigInteger
!!float Double
!!binary byte[], String
!!omap, !!pairs List of Object[]
!!set Set
!!str String
!!seq List
!!map Map

Collections

Default implementations of collections are:

  • List: ArrayList

  • Map: LinkedHashMap (the order is implicitly defined)

It is possible to define other default implementations. It must be specified as a function from init size to the collection implementation. An example can be found here for List and for Map

ENV Variable substitution

SnakeYAML Engine provides a way to make ENV Variable substitution similar to how it works for Docker compose

Only ${VARIABLE} syntax is supported.

it is possible to provide inline default values using typical shell syntax (exactly as for docker-compose):

  • ${VARIABLE:-default} evaluates to default if VARIABLE is unset or empty in the environment.
  • ${VARIABLE-default} evaluates to default only if VARIABLE is unset in the environment.
  • ${VARIABLE:?err} exits with an error message containing err if VARIABLE is unset or empty in the environment.
  • ${VARIABLE?err} exits with an error message containing err if VARIABLE is unset in the environment.

If variable is not set, the empty value is used. Except when it is explicitly instructed to fail.

Since SnakeYAML is no template engine, it does not substitute parts of scalar, only the whole scalar. For instance this stays as it is because template is just a part of the scalar:

    environment:
      - DEBUG=${DEBUG}
      - "DIR=${DATA_DIR}"
This is substituted:
    environment:
      DEBUG: ${DEBUG}
      DIR: ${DATA_DIR}

An example can be found it tests.

Merge

YAML has a "merge" specification: http://yaml.org/type/merge.html

This tag is no more supported in YAML 1.2 and its implementation has been removed from SnakeYAML Engine.

Deviations from the specification

to be found...

Updated