YAML Ain't Markup Language (YAML)

Eintrag zuletzt aktualisiert am: 12.06.2019
 siehe auch https://yaml.org

YAML ist ein textbasiertes Datenformat in Form einer Auszeichnungssprache. Eine Auszeichnungssprache (englisch Markup Language) ist laut [https://de.wikipedia.org/wiki/Auszeichnungssprache] eine maschinenlesbare Sprache für die Gliederung und Formatierung von Texten und anderen Daten. Bekanntere Auszeichnungssprachen sind HTML, XML und JSON. YAML zeichnet sich gegenüber HTML, XML und JSON dadurch aus, dass es kompakter und übersichtlicher ist; daher ist es nicht nur für Maschinen, sondern auch für Menschen gut lesbar.

Einsatzgebiete von YAML

YAML wird inzwischen an einigen Stellen als Konfigurationsformat eingesetzt, z.B. in Docker, Kubernetes und seit 2019 auch in Azure DevOps-Pipelines zur Definition von Continous Integration- und Continous Delivery-Prozessen. Grundsätzlich kann YAML aber nicht nur für Konfigurationsdateien, sondern als beliebiges Datenformat eingesetzt werden, auch als Ersatz für XML und JSON.

Es gibt zahlreiche Softwarekomponenten zur Serialisierung von Objektmodellen in YAML bzw. der Deserialisierung von YAML in Objektmodellen in zahlreichen Programmiersprachen und Frameworks, z.B. C, C++, Ruby, Python, Java, Perl, .NET, PHP, Dart, JavaScript (siehe [https://yaml.org/]).

Name YAML

Die Abkürzung YAML stand ursprünglich für "Yet Another Markup Language". Mittlerweile verwendet man YAML als rekursive Abkürzung für "YAML Ain’t Markup Language".

Versionen

Die erste Version der YAML-Sepzifikation von Oren Ben-Kiki, Clark Evans und Brian Ingerson stammt bereits vom 29.2.2004 [https://yaml.org/spec/1.0/]
Version 1.1: 18.1.2005 [https://yaml.org/spec/1.1/]
Version 1.2: 10.1.2009 [https://yaml.org/spec/1.2/spec.html]

Website

https://yaml.org

YAML-Parser für .NET

https://github.com/aaubry/YamlDotNet

Microsoft selbst liefert in .NET Framework und .NET Core noch keine YAML-Bibliothek mit. Diese Lücke füllt das Github-Projekt YamlDotNet [https://github.com/aaubry/YamlDotNet]. Die kompilierte Bibliothek gibt es auf Nuget [https://www.nuget.org/packages/YamlDotNet/]. Die erste dort veröffentlichte Version war 2013, seitdem sind zahlreiche Versionen erschienen. Die aktuelle Version zum Zeitpunkt der Erstellung des Beitrags ist 6.1.1 vom 4.6.2019. YamlDotNet basiert auf .NET Standard 1.3, läuft daher in .NET Core ab Version 1.0 und .NET Framework ab Version 4.5 sowie Mono und Unity. Die Installation in einem Projekt erfolgt mit Install-Package YamlDotNet.

Bestandteile

Die wichtigsten Elemente in YAML sind:
 Leerzeichen zur Einrückung als Strukturierungselement
 Einfachen Listen (alias Arrays); Listenelemente beginnen mit einem Minuszeichen
 Assoziativen Listen (alias Hashes, Maps, Dictionary) in der Form Name : Wert
 Einzelwerten (Skalare): diese können, müssen aber nicht in einfachen oder doppelten Anführungszeichen stehen
 Sprungmarken (Anker) und Verweise (Referenzen): die Sprungmarke beginnt mit dem kaufmännischen &, der Verweis darauf mit einem Stern *
 Kommentaren (beginnen mit #)
 Abschnitten (---), die ein Datei in mehrere Dokumente teilen können

Einsatzgebiete

YAML hat erst Mitte der 2010er-Jahre größere Bedeutung erhalten als es von Docker als Konfigurationsformat für Deployment und Debugging-Einstellungenverwendet wurde.
Microsoft verwendet YAML seit 2019 in Azure DevOps.

Beispiel

Listing 1 zeigt ein Objektmodell mit verschiedenen Datentypen (inkl. Nullable Value Types), Listen, einem Aufzählungstyp und einer zirkulären Referenzen. Der Programmcode ist eine komplexere Form eines Beispiels auf Github [https://github.com/aaubry/YamlDotNet/blob/master/YamlDotNet.Samples/SerializeObjectGraph.cs]. Listing 2 zeigt die Serialisierung und Deserialisierung mit YamlDotNet. Listing 3 zeigt das Ergebnisdokument.

Listing 1: Ein Objektmodell in C# mit zirkulären Referenzen

using System;
using System.Collections.Generic;

namespace ITVisions.Demo.BO
{
public enum Title
{
None, Dr, Prof, ProfDr
}
public class Address
{
public string Street { get; set; }
public string City { get; set; }
public string State { get; set; }
}

public class Order
{
public Guid ReceiptGUID { get; set; }
public DateTime Date { get; set; }
public Customer Customer { get; set; }
public List<Item> Items { get; set; }
public Address Bill_To { get; set; }
public Address Ship_To { get; set; }
public string SpecialDelivery { get; set; }
}

public class Customer
{
public string Name { get; set; }
public Employee Employee { get; set; }
}

public class Employee
{
public Title Title { get; set; }
public string Givenname { get; set; }
public string Surname { get; set; }
public DateTime? Birthday { get; set; }
public List<Receipt> Receipts { get; set; } = new List<Receipt>();
}

public class Item
{
public short Part_No { get; set; }
public string Description { get; set; }
public decimal Price { get; set; }
public int Quantity { get; set; }
public int? Weight { get; set; }
}
}

Listing 2: Erzeugen eines Objektmodells und Serialisierung sowie Deserialisierung in YAML

using ITVisions.Demo.BO;
using System;
using System.Linq;
using YamlDotNet.Serialization;
using YamlDotNet.Serialization.NamingConventions;

namespace ITVisions
{

public class YAMLDemo
{

public void Run()
{
Console.WriteLine("--- Creating Business Objects...");
var receipt = CreateBusinessObjects();

Console.WriteLine("--- Serializing...");
var serializer = new SerializerBuilder()
.WithNamingConvention(new PascalCaseNamingConvention())
.Build();
var yaml = serializer.Serialize(receipt);

Console.WriteLine("--- Result:");
Console.WriteLine(yaml);


Console.WriteLine("--- Deserializing...");

var deserializer = new DeserializerBuilder()
.WithNamingConvention(new PascalCaseNamingConvention())
.Build();

var receipt2 = deserializer.Deserialize<Order>(yaml);
Console.WriteLine("--- Result:");
ObjectDumper.Write(receipt2);

}

private static Order CreateBusinessObjects()
{
var address = new Address
{
Street = "De-La-Chevallerie-Straße 42,\nEtage 2",
City = "45894 Gelsenkirchen",
State = "NRW"
};

var receipt = new Order
{
ReceiptGUID = Guid.NewGuid(),
Date = DateTime.Now,
Customer = new Customer
{
Name = "5Minds IT Solutions Gmbh & Co KG",
Employee = new Employee
{
Title = Title.Dr,
Givenname = "Dr. Holger",
Surname = "Schwichtenberg"
}
},
Items = (new Item[]
{
new Item
{
Part_No = 123,
Description = "C# 7.3 Crashkurs",
Price = 14.99M,
Quantity = 40
},
new Item
{
Part_No = 456,
Description = "Moderne Datenzugriffslösungen mit \"Entity ramework Core 2.1/2.2 Ruby\"",
Price = 49.00M,
Quantity = 1
}
}).ToList(),
Bill_To = address,
Ship_To = address,
SpecialDelivery = "Bitte zusammen anliefern\n" +
"Wareneingang 2. Etage.\n" +
"Bitte am Empfang melden"
};

// recursion
receipt.Customer.Employee.Receipts.Add(receipt);

return receipt;
}
}
}

Listing 3: YAML-Dokument für das Objektmodell in Listing 1

&o0
ReceiptGUID: d5549070-102a-4768-8b65-03501b76af24
Date: 2019-06-12T20:16:55.2529275+02:00
Customer:
Name: 5Minds IT-Solutions Gmbh & Co KG
Employee:
Title: Dr
Givenname: Dr. Holger
Surname: Schwichtenberg
Receipts:
  • *o0

Items:
  • PartNo: 123

Description: C# 7.3 Crashkurs
Price: 14.99
Quantity: 40
  • PartNo: 456

Description: Moderne Datenzugriffslösungen mit "Entity Framework Core 2.1/2.2 Ruby"
Price: 49.00
Quantity: 1
BillTo: &o1
Street: >-
De-La-Chevallerie-Straße 42,

Etage 2
City: 45894 Gelsenkirchen
State: NRW
ShipTo: *o1
SpecialDelivery: >-
Bitte zusammen anliefern

Wareneingang 2. Etage.

Bitte am Empfang melden