Flexibel einsetzbare Markupsprache

15. Apr. 2022

Die Idee, dass Daten wertvoll sind und das strukturierte Speichern dieser sinnvoll ist, wurde schon in den 60er Jahren im Konzept des Generic Coding erkannt. Diese Versuche, eine vereinheitlichte Sprache zur Beschreibung von Daten zu entwickeln, mündeten 1986 in die Entstehung der Standard Generalized Markup Language (SGML), welche sich durch die Verwendung von sogenannten Tags auszeichnet.

Die Ähnlichkeit zu modernen Markup-Sprachen wie HTML oder XML ist kein Zufall, da diese SGML-konform entstanden sind, sich aber mittlerweile davon gelöst haben, um ihre Struktur weniger eingeschränkt anpassen zu können.

Datenformate zum strukturierten Speichern von Daten

Mittlerweile gibt es eine ganze Reihe an verschiedenen Datenformaten, die aus der Idee Daten strukturiert zu speichern entstanden sind. Dazu zählen zum einen die Nachfolger von SGML wie die Hypertext Markup Language (HTML) zur Auszeichnung von Internetseiten oder die Extensible Markup Language (XML) zum Auszeichnen beliebiger Dokumentstrukturen. Zum anderen gibt es die JavaScript Object Notation (JSON), YAML Ain’t Markup Language (YAML) oder Tom’s Obvious, Minimal Language (TOML), welche sich durch ihre deutlich schmalere Syntax zum Abbilden von Datenstrukturen auszeichnen.

Darüber hinaus sind Formate entstanden, die das strukturierte Festhalten von Daten etwas in den Hintergrund stellen. Formate wie AsciiDoc, Markdown oder Creole zeichnen sich dadurch aus, dass sie wenig Struktur vorgeben und das Markieren von zum Beispiel einer Überschrift durch wenige Zeichen ermöglichen und so das Schreiben von Fließtext einfacher gestalten.

Grundsätzlich lassen sich diese Formate in drei verschiedene Kategorien einteilen:

  1. Markup-Sprachen wie XML: Markup-Sprachen zeichnen sich dadurch aus, dass sie das Festhalten von Text gemischt mit Elementen zum Auszeichnen (markup) von bestimmten Textstellen ermöglichen.
  2. Datenaustauschformate wie JSON: Datenaustauschformate können in den meisten Programmiersprachen Datenstrukturen eindeutig abbilden und sind sowohl für Rechner als auch für Menschen leicht zu verstehen.
  3. Lightweight-Markup-Sprachen wie AsciiDoc: Dokumente in AsciiDoc werden in Freitext geschrieben und durch Formatierungszeichen, die zum Beispiel eine Überschrift oder eine Liste kennzeichnen, ergänzt.

Dabei hat jede Kategorie ihre eigenen Vor- und Nachteile und ist für unterschiedliche Anwendungszwecke geeignet. Wir wollen uns nun JSON, XML und AsciiDoc weiter anschauen, um genauer auf diese Unterschiede einzugehen.

JavaScript Object Notation (JSON)

Die JavaScript Object Notation (JSON) ist ein Datenaustauschformat, das sich durch eine sehr einfache Syntax auszeichnet und deshalb zum Speichern und Verarbeiten von Daten geeignet ist. Ein einfaches JSON-Dokument könnte beispielhaft wie in der nebenstehenden Abbildung aussehen.

Hierbei fällt auf, dass JSON sehr strukturiert ist und verschiedenartige Typen von Daten unterstützt. JSON kann auch verschachtelt werden, sodass sich beliebige Datenstrukturen in JSON abbilden lassen.

Die schmale Syntax ermöglicht ein robustes Programm zu schreiben, welches die Daten verarbeiten kann. Texte lassen sich in JSON jedoch nur in Strings speichern. Möchte man in JSON Freitext mit Absätzen abbilden, so müssen sich entweder komplizierte Datenstrukturen überlegt oder der gesamte Text mit impliziten Steuerzeichen in eine einzige Zeile geschrieben werden, da JSON keine Zeilenumbrüche in Strings erlaubt.

Extensible Markup Language (XML)

Die Extensible Markup Language (XML) ist eine Auszeichnungssprache, die ähnlich wie JSON das strukturierte Aufführen von Dokumenten ermöglicht.

Es wird sichtbar, dass XML sogenannte Tags zum Auszeichnen von Teilen des Dokumentes nutzt, welche, wie beispielsweise chapter, auch Attribute haben können. Das Dokument kann damit in beliebiger Tiefe durchsetzt werden, was die Lesbarkeit allein durch die Menge an zusätzlichen Zeichen entsprechend erschweren kann. Der Vorteil bei XML ist, dass Text frei geschrieben und sogar frei definierbare Formatierungs-Tags verwendet werden können.

Als Nachteil ist jedoch die Herausforderung anzuführen, ein Programm zu schreiben, das alle Eigenschaften des XML-Standards abdeckt. XML besteht nämlich nicht nur aus der im Beispiel angeführten Auszeichnungssprache.

Durch den Versuch, XML als Lösung aller Probleme zu verwenden, wurden über Jahrzehnte immer mehr Erweiterungen hinzugefügt. So gibt es die Document Type Definition (DTD), mit welcher die Struktur eines XML-Dokuments XML-artig beschrieben wird, wodurch eine weitere Sprache erkannt werden muss. Dabei wird sogar das Aufteilen in mehrere Dateien unterstützt, da solche Dateien mitunter mehrere tausend Zeilen groß werden können. Aufgrund der mangelnden Validierungsmöglichkeiten in DTD wurde die XML-konforme XML Schema Definition (XSD) ergänzt, später dann die Extensible Stylesheet Language (XSL), welche die XSL Transformation (XSLT), XSL Formatting Objects (XSL-FO) und XML Path Language (XPath) beinhaltet, die alle mit XML beschrieben werden. XSLT beschreibt, wie XML verändert werden soll, XML-FO beschreibt, wie XML dargestellt werden soll und mit XPath kann ein XML-Dokument durchsucht sowie ausgewertet werden.

Um gleiche Tags in unterschiedlichen Kontexten unterscheiden zu können, helfen die XML Namespaces, welche einerseits genutzt werden können, um Präfixe für Tags zu definieren, sodass diese unterschieden werden können. Andererseits aber auch um eine ganze Hierarchie mit einem Namespace zu versehen, sodass alle Elemente in dieser implizit mit dem Präfix interpretiert werden. Darüber hinaus muss ein Programm, um XML vollständig zu unterstützen, nicht nur UTF-8 (die de-facto-Standardkodierung), sondern auch UTF-16 verarbeiten können, bei welcher ein Byte Order Mark erkannt werden muss, um die Reihenfolge der Bytes in der Datei richtig zu interpretieren.

Wenn Processing Instructions in das Dokument eingebettet werden, können in XML zusätzlich Informationen an das verarbeitende Programm gereicht werden. So kann beispielsweise ein Stylesheet zur graphischen Aufbereitung eingefügt werden. Eine Vielzahl der Programme zum Verarbeiten von XML-Dokumenten beschränken sich aufgrund dieser Komplexität darauf nur einen Teil des Standards zu verarbeiten.

AsciiDoc

AsciiDoc ist eine vereinfachte Auszeichnungssprache, die in ein einfaches Textdokument geschrieben wird, welches Steuerzeichen zum Markieren von zum Beispiel Überschriften erlaubt:

Dies ist von allen drei Beispielen, die wir bis jetzt betrachtet haben, das am einfachsten lesbare. Der Titel des Dokuments wird durch = markiert, weitere Abschnitte durch mehrere =. Text, der hervorgehoben werden soll, wird mit * markiert. AsciiDoc bietet eine große Auswahl an Steuerzeichen an, mit welchen Überschriften, Bilder, Videos, Listen, Tabellen und noch viel mehr im Dokument markiert werden können. Der Hintergedanke AsciiDoc zu verwenden ist meist, dass das geschriebene Dokument von einem Programm in eine besser lesbare Internetseite oder ein Buch übersetzt wird.

Obwohl das Schreiben von AsciiDoc für einen Menschen sehr angenehm ist, ist das Verarbeiten mit einem Programm deutlich aufwendiger. Die fehlende Struktur macht es bis auf die Auswertung der Überschriften und einigen Attributen schwierig, die im Dokument festgehaltenen Daten weiter zu verarbeiten. Weiter erschwert wird dies durch die stetige Erweiterung von AsciiDoctor, des offiziellen Programms zum Verarbeiten von AsciiDoc. Potenziell dutzende verschieden rekursiv arbeitende Programmteile müssten nachgebildet werden, um standardkonform zu arbeiten. AsciiDoctor selber arbeitet nicht konsistent und hat besonders im Bereich des Escapings ernsthafte Probleme, welche bereits seit 2014 bestehen und bis jetzt - 2021 - nicht gelöst wurden.

Das Dilemma bestehender Markupsprachen

Zu Beginn eines neuen Projekts muss entschieden werden, welche Technologien oder Formate zum Festhalten von Daten zur Umsetzung genutzt werden sollen. Einige Entscheidungen können dabei schnell getroffen werden: Sollen beispielweise Daten übertragen werden, ist JSON meist eine gute Wahl. Konfigurationsdateien wiederum lassen sich gut in YAML oder TOML beschreiben. Aber was ist mit Textinhalten?

Aus Nutzersicht ist AsciiDoc angenehmer, da es hier einfach ist, auch ausführliche Texte zu schreiben und nur wenige Steuerzeichen ergänzt werden müssen. Jedoch ist AsciiDoc schwer zu verarbeiten und die fehlende Struktur macht das Auslesen von Informationen aus dem Dokument aufwendiger. Aus Entwicklersicht ist eine strukturierte Sprache wie XML (auch wenn dies nun sehr komplex ist) oder JSON wünschenswerter, da hier Informationen gezielt markiert und somit einfach ausgelesen werden können. Das manuelle Schreiben einer solchen Datei ist jedoch mühselig und fehleranfällig.

Insgesamt gesehen existiert hierbei also immer ein Konflikt zwischen dem einfachen Schreiben und dem strukturierten Verarbeiten. Um dem entgegenzuwirken haben wir unsere eigene Sprache entworden - die Double Yielding Markup Language.

DYML: Unsere eigene Markupsprache

Die Double Yielding Markup Language (DYML) verfolgt ein klares Ziel: Das strukturierte Festhalten von Informationen, die angenehm geschrieben und eindeutig verarbeitet werden können, um so die Vorteile von XML und leichtgewichtigen Markdown zu vereinen.

DYML ist ein einfaches Format mit einer einfachen Struktur und wenig vorgegebenen Steuerzeichen und wird erst durch die verarbeitende Anwendung sinnvoll. DYML hat, dem Namen entsprechend, zwei Modi, welche je nach Anwendungsfall gewechselt werden können: Der Textmodus und der Node-Modus.

Schauen wir uns zunächst den Textmodus genauer an. Im einfachsten Fall ist eine DYML-Datei einfach eine Textdatei, in die ein wenig Text geschrieben wurde. Spannender wird es allerdings im folgenden Beispiel, das viele Features von DYML zeigt.

Eine ähnliche Darstellung davon in XML wäre:

Es fällt auf, dass Tags, welche mit # eingeleitet werden, ihren Inhalt durch geschweifte Klammern markieren und nicht das erneute Aufführen des Tags zum Abschließen erfordern. Dabei werden auch Attribute unterstützt. Sie werden durch @ angezeigt und können dem Tag folgen oder mit einem @@ vor das Tag gestellt werden, was in einigen Situationen für eine bessere Lesbarkeit sorgt. In der aufgeführten Beispieldatei ist nur ein book beschrieben; es können aber auch mehrere, verschiedenartige Elemente in der Datei liegen, ohne wie in XML ein gemeinsames Root-Element zu fordern.verschiedenartige Elemente in der Datei liegen, ohne wie in XML ein gemeinsames Root-Element zu fordern.

Soll weniger Text aber dafür mehr Struktur beschrieben werden, kann der Node-Modus von DYML genutzt werden:

Der Beginn der Datei mit #! ist hier entscheidend, um DYML mitzuteilen, dass nun Inhalt im Node-Modus folgt. Im Gegensatz zum Textmodus wird freistehender Text nun als Elemente interpretiert, wodurch sich verschachtelte Strukturen sehr einfach darstellen lassen. Müsste im Textmodus #var{#Volume{#float}} verwendet werden, wird dies zu var Volume float im Node-Modus, da hier aufeinanderfolgende Elemente als verschachtelt interpretiert werden. Die Verschachtelung kann durch ein Komma oder einen Block verhindert werden. A B würde bedeuten, dass B in A ist. A, B oder A{} B wären zwei nicht verschachtelte Elemente.

Auch hierbei werden Attribute unterstützt. Ähnlich wie im Textmodus können diese auch dem Element folgen oder vor das Element geschrieben werden. Eine Zeile frei formulierten Text zu verfassen ist durch # möglich, wodurch der Rest der Zeile als Text interpretiert wird. Hier kann ## verwendet werden, um den Text der aktuellen Zeile in das nächste Element zu setzen.

Hier ist die Struktur aus dem Beispiel noch einmal als XML aufgeführt:

Fairerweise sei an dieser Stelle im Vergleich zu XML gesagt, dass dieses Beispiel bewusst zu Gunsten von DYML gewählt wurde. Besonders das in DYML auftauchende Zeichen -> wurde speziell zum Markieren von Rückgabewerten eingeführt und muss in XML in eine größere Struktur (ret) übersetzt werden. Im ersten Beispiel war der Unterschied zwischen den Formaten noch relativ klein, aber besonders im zweiten Beispiel wird deutlich, dass sich DYML durch die kompaktere und weniger redundante Notation angenehmer Schreiben lässt als XML - und das ganze ohne dabei an Bedeutung zu verlieren.

Die Entwicklung eines Parsers für DYML

Ein Parser ist ein Programm, welches Daten aus einem Format in ein anderes Format umwandelt. Meist ist damit die Umwandlung von Textdaten in Datenstrukturen gemeint, die dann weiterverarbeitet werden können. So gibt es XML-Parser, die eine XML-Datei in eine Baumstruktur im Speicher übersetzen, welche dann weiterverarbeitet werden kann, ohne die Eigenarten des XML-Formats zu beachten.

Damit DYML-Dateien auch verarbeitet werden können, benötigt es einen Parser. Vorab sollte man sich darüber Gedanken machen, was überhaupt geparst werden soll.

Mit den Beispielen und der kurzen Beschreibungen von DYML aus diesem Artikel ist vielleicht eine grundlegende Idee davon entstanden, was DYML ist und wie es funktioniert. Computer aber brauchen aber eine lückenlose Beschreibung, um Daten verarbeiten zu können. Dazu sollte zunächst eine EBNF aufgestellt werden, welche die Syntax einer Sprache festhält.

Mit einer formalen Definition der Grammatik kann dann ein Parser entwickelt werden, der eine DYML-Datei als Eingabe bekommt und eine Baumstruktur ausgeben soll. Die einzelnen Zeichen aus der Datei direkt zu verarbeiten könnte jedoch schwierig werden, da gleiche Zeichen an verschiedenen Stellen verschiedene Bedeutungen haben. DYML hat somit keine kontextfreie Grammatik, bei welcher jedes Zeichen gleich interpretiert wird, sondern eine kontextsensitive Grammatik.

In einem ersten Schritt wird also die Datei in kleine Bruchstücke, den sogenannten Tokens, aufgeteilt. Dies ist nicht direkt die Aufgabe des Parsers, sondern vielmehr des Tokenizers, auch Lexer genannt. Der Tokenizer sorgt für eine starke Vereinfachung des Parsers, da dieser nun nicht mehr einzelne Zeichen, sondern kleine Bausteine zum Zusammensetzen erhält. Der Tokenizer würde die Zeichen # a b c zu zwei Tokens wie ElementAnfang(#) und ElementName(abc) verarbeiten.

Mit diesen kleinen Bausteinen kann nun der richtige Parser geschrieben werden. Der Parser versucht aus den Tokens die Baumstruktur, die in DYML abgebildet ist, zu erstellen. Dabei können Tokens in einer Reihenfolge erscheinen, die der Parser so nicht erwartet - was bestimmt jeder beim Programmieren in Form eines Syntaxfehlers schon einmal erlebt hat. Deshalb ist die Fehlermeldung in einigen Programmiersprachen in diesem Fall auch unexpected token.

Das Parsen einer Baumstruktur – geht das?

In einem Baum, im Sinne der Informatik, hat jeder Knoten einen Wert und mehrere Kinder. In folgendem Beispiel hat der Baum als Wurzel das Element A mit zwei Kindern B und E. B hat dabei wieder zwei Kinder, C und D. Wie häufig beim Verarbeiten von Baumstrukturen ist hier Rekursion eine große Hilfe. Wir benötigen somit lediglich eine Funktion, die den Namen eines Elements erkennt und dann rekursiv die Kinder des Elements verarbeitet.

In Schritt 0, bevor der Parser anfängt zu arbeiten, liegen ihm nur die einzelnen Tokens vor. Auf diese wird nun die Funktion zum Parsen angewandt, wodurch in Schritt 1 der Knoten A erkannt wird. Die Kinder davon werden auf genau dieselbe Art verarbeitet, wodurch dann in Schritt 2 B und in Schritt 3 C erkannt wird. Werden in einem Knoten keine weiteren Kinder erkannt, wird wieder in die höhere Ebene gewechselt. So wird nach und nach der gesamte Baum geparst. Da dieser Parser rekursiv den Baum absteigt, spricht man auch von einem Recursive Descent Parser.

Das Einlesen von Attributen oder Zeichenketten kann dann in diesen prototypischen Parser nach und nach ergänzt werden, um schließlich die gesamte Spezifikation von DYML erkennen zu können.

Was schließlich mit den geparsten Informationen aus DYML passiert, ist der Anwendung überlassen. Bei uns soll DYML im Bereich der Softwarearchitektur und der damit einhergehenden Dokumentation eingesetzt werden. Das Codebeispiel aus dem vorherigen Abschnitt gibt schon einen kleinen Einblick darauf, wie dies aussehen könnte. Mit dieser Markup Language möchten wir Programmierern, Testern und Projektmanagern eine Möglichkeit bieten, Umfang und Verhalten von Software eindeutig festzuhalten und so die Qualität der Software nachhaltig zu sichern.

Unser Language-Experte

Torben Schinke

ist für Sie da!

+49 441 559 770 0

Haben Sie Fragen?

Weitere Blogartikel

08. Jan. 2024

Persönlich nachgefragt bei Adrian Macha und Torben Schinke von worldiety

Blog

Wie schauen Adrian Macha und Torben Schinke heute auf das Projekt „worldiety Zentrum Oldenburg“? mehr

10. Jan. 2023

Generator für Softwarearchitekturen

Blog

Bei der Entwicklung von Software treten bei fortlaufender Dauer, entsprechender Größe, Komplexität und bei häufig auftretenden Änderungen Herausforderungen hinsichtlich der Architektur des zu entwickelnden Softwaresystems auf. Diese bestehen zumeist darin, den immer größer werdenden Quellcode und die zunehmende Anzahl von Softwarekomponenten passend zu organisieren. Die Architektur des Softwaresystems ist dabei maßgeblich für die Wartung und Anpassungsfähigkeit der Software als auch für die Einarbeitungszeit neuer Entwickler. mehr

01. Mai. 2022

Benutzerdokumentation automatisiert generieren

Blog

Die agile Softwareentwicklung hat sich in den letzten Jahren zu einem wichtigen Ansatz der technischen Umsetzbarkeit entfaltet. Neben den Vorteilen, wie z. B. Flexibilität, Fehlererkennung und erhöhte Performanz durch eine stetige Kommunikation, bringt eine agile Softwareentwicklung jedoch auch Einschränkungen mit sich. So wird die Dokumentation - zu welcher auch die Benutzerdokumentation zählt - eher relativiert betrachtet und zugunsten der engen Zusammenarbeit zwischen Entwickler:innen, Tester:innen, Kund:innen und Nutzer:innen auf ein Minimum beschränkt. Bedingt durch Covid-19 musste der persönliche Kontakt mit Kunden, welcher in einer agilen Entwicklungsumgebung einen hohen Stellenwert besitzt, auf ein Minimum reduziert werden. Dabei gewann Software allgemein in den letzten Jahren immer mehr an Komplexität, welches auch eine zunehmende Rolle in der Organisation von Informationen innerhalb der Benutzerdokumentation zur Folge hat. mehr

28. Apr. 2022

Empathy Maps als UX-Tool

Headerbild Empathy Maps
Blog

In Entwicklungs-, Design- oder Marketing-Teams bestehen oftmals unterschiedliche Vorstellungen von Zielgruppen, bzw. dem Endnutzer einer Applikation. Dies kann dann problematisch werden, wenn bspw. neue Features geplant oder versucht wird, den Endnutzer in Texten sowie Bildern direkt anzusprechen. Vor allem aber führt dies oftmals zu langwierigen Prozessen sowie Entscheidungen über die Nutzer und deren Bedürfnisse. Um dieser Herausforderung entgegenzuwirken, lassen sich unterschiedliche Ansätze sowie Methoden nutzen. Eine besonders effiziente und in der Umsetzung einfache Methode ist die „Empathy Map“. Empathy Maps sind ein agiles Tool im Bereich des User Experience Designs, das dabei hilft, die Nutzer sowie deren Bedürfnisse besser zu verstehen und ein einheitliches Mindset im Projekt-Team zu etablieren. Die Nielsen Norman Group, eine Erfolgreiche UX Beratungsfirma aus Amerika, welche von den User Experience Pionieren, Don Norman und Jakob Nielsen gegründet wurde, definiert Empathy Maps wie folgt: mehr