[an error occurred while processing this directive]

An introduction to Unotal. [] (Junotal JSON YAML S-expression XML), Tutorial, page 722194
https://www.purl.org/stefan_ram/pub/junotal_tutorial (permalink) is the canonical URI of this page.
Stefan Ram

Junotal  Tutorial

Junotal  is the Java  implementation of Unotal. Unotal  is a general purpose syntax that can be used for structured data and programs, ranging from configuration files to programming languages. It can be compared to S-expressions, JSON, YAML, or XML. General information about Unotal  and Junotal  can be found elsewhere (see search engines). This tutorial focuses on the use of Junotal  in Java  programs.

Junotal  is an alpha-release: Not all details of the API are fixed yet, and some details might be changed in the future. However, it is currently being used in several projects of its author and has been designed and implemented for years, so it is not expected to suddenly vanish. The original plans for Unotal  were inspired by S-expressions and predate XML.

The first part of this tutorial contains basic uses of Junotal. It ends with the section „Strings “. The rest of the tutorial deals with details or advance topics.

It is expected that one can read this tutorial without preceding Unotal -knowledge, because the most of structure of Unotal  can be guessed from this tutorial and some parts are repeated here.

Installing Junotal

To use Junotal  in Java, the library ram.jar  needs to be in the classpath. It is available under the GPL license. The library should include JavaDoc -comments for all operations mentioned in this tutorial, but this documentation is still incomplete or missing. Insofar, this tutorial is  the documentation for now.

ram.jar
https://www.purl.org/stefan_ram/pub/ram-jar

The Documentation

Although often there are no natural-language descriptions in the documentation yet, the documentation of ram.jar  already comes handy to get an overview of the methods of a class mentioned in this tutorial or to see the signature of a method mentioned in this tutorial. Therefore, a reference is given here.

ram.jar documentation
https://www.purl.org/stefan_ram/html/ram.jar/index.html

Building a Room From a String

A room can be build from a text by a single call. Access to the information of the room will be shown later.

The room »< &t a=b c=d e f g >« as used in this example has the type »t«, two attributes and three entries (values).

Main.java
import de.dclj.ram.notation.unotal.Room;
import static de.dclj.ram.notation.unotal.RoomFromModule.room; public final class Main
{ public static void main( final java.lang.String argv[] )
{ final Room room = room( "< &t a=b c=d e f g >" ); }}

Building a Room From a Text File

A room can just be built from a text file using the same call as above with a file instead of a string.

source.uno
< &t a=b c=d e f g >
Main.java
import java.io.File;
import de.dclj.ram.notation.unotal.Room;
import static de.dclj.ram.notation.unotal.RoomFromModule.room; public final class Main
{ public static void main( final java.lang.String argv[] )
{ final Room room = room( new File( "source.uno" )); }}

Converting a Room to a String

The »toString()« method yields a string representation of a room, which can be used to display the room or serialize it to a file.

Main.java
import java.lang.String;
import java.lang.System;
import de.dclj.ram.notation.unotal.Room;
import static de.dclj.ram.notation.unotal.RoomFromModule.room; public final class Main
{ public static void main( final String argv[] )
{ final Room room = room( "< &t a=b c=d e f g >" );
System.out.println( room ); }}
System.out
< &t a =b c =d e f g >

(The space in front of »=«, but not after it, looks ugly. This will be improved later, yet it is not significant regarding the semantics.)

The formatted room can be read in again to give the same room.

The order of attributes and types does not matter in Unotal, so the text representation might contain them in another order than the order used in the source.

Getting Information From a Room

The contents of a room is available by a »get(int)« method.

The attributes of a room are available by a »get(java.lang.Object)« method.

When one only wants to read from a room, the interface »RoomSource« (a room used as a source of information, that is, in read-only mode) is recommended.

Main.java
import java.lang.String;
import java.lang.System;
import de.dclj.ram.notation.unotal.RoomSource;
import static de.dclj.ram.notation.unotal.RoomFromModule.room;

public final class Main
{ public static void main( final String argv[] )
{ final RoomSource room = room( "< &t a=b c=d e f g >" );
System.out.println( room.get( 0 ));
System.out.println( room.get( 1 ));
System.out.println( room.get( "a" ));
System.out.println( room.get( "c" )); }}
System.out
e
f
b
d

Strings and String Values

The right hand side of an assignment sometimes is considered to be a “value”. If it looks like a string, its type still is not »java.lang.String«, but »de.dclj.ram.notation.unotal.StringValue«. In many cases, a string value is as good as a string, because it can be constructed from a string and be converted to a string using »toString()«.

When analyzing a room and testing for the type of a part of the room, however, one needs to be aware of the types one could possibly encounter.

Main.java
import java.lang.String;
import java.lang.System;
import de.dclj.ram.notation.unotal.RoomSource;
import static de.dclj.ram.notation.unotal.RoomFromModule.room;

public final class Main
{ public static void main( final String argv[] )
{ final RoomSource room = room( "< &t a=b c=d e f g >" );
System.out.println( room.get( 0 ).getClass() );
System.out.println( room.get( 1 ).getClass() );
System.out.println( room.get( "a" ).getClass() );
System.out.println( room.get( "c" ).getClass() ); }}
System.out
class java.lang.String
class java.lang.String
class de.dclj.ram.notation.unotal.StringValue
class de.dclj.ram.notation.unotal.StringValue

Building a Room at Runtime

Because the class »Room« extends the class »java.util.Map« all Map operations should be available (this was not yet tested for all operations). Usually values are added to a room by the operation »add«.

One can create a new room and add types, attributes and values to it. A type needs to be added as an attribute with the key »:unotal:type«.

Main.java
import java.lang.String;
import java.lang.System;
import de.dclj.ram.notation.unotal.Room;
import de.dclj.ram.notation.unotal.RoomSink; public final class Main
{ public static void main( final String argv[] )
{ final RoomSink room = new Room();
room.add( ":unotal:type", "t" );
room.add( "a", "b" );
room.add( "c", "d" );
room.add( "e" );
room.add( "f" );
room.add( "g" );
System.out.println( room ); }}
System.out
< &t a =b c =d e f g >

Nested Rooms

Rooms can be nested. Not only can rooms be entries of other rooms, but they can also be values of attributes.

Main.java
import java.lang.String;
import java.lang.System;
import de.dclj.ram.notation.unotal.RoomSource;
import static de.dclj.ram.notation.unotal.RoomFromModule.room;

public final class Main
{ public static void main( final String argv[] )
{ System.out.println( room( "<< a b >< c d >>" ).get( 0 ));
System.out.println( room( "<< a b >< c d >>" ).getRoom( 0 ).get( 0 ));
System.out.println( room( "< a=< b c >>" ).get( "a" ));
System.out.println( room( "< a=< b c >>" ).getRoom( "a" ).get( 0 )); }}
System.out
< a b >
a
< b c >
b

The utility »getRoom« has the static return type »de.dclj.ram.notation.unotal.RoomInterface«, while »get« returns »java.lang.Object«. Thus, »getRoom« can be used to avoid a cast, when the result is known to be a room.

Strings

When a string is a single word, made only of Unicode letters or digits (of a Unicode category starting with »L«, »M« or »N«) or the “free string” characters »_+-:/.,«, it is called a “free string” and can be used in a room as it is, separated by white space. For example, the room "< alpha 0123 +:+ >" contains the three strings »alpha«, »0123«, and »+:+«. Many simple numbers and URIs thus can directly be used in a room. For example, the room »< -2,000.00 http://www.example.com >« contains the number »-2,000.00« and the string »http://www.example.com«.

Certain „single“ characters »!#%&()<=>{}~;|« always stand for themselves and can never be part of a free string, when used directly in a room. These characters and all other characters that may not be part of a free string are usually reserved and should not be used directly in a room.

To write a general string, it has to be put into brackets. This is called a “bracketed string ”. Even though an application might choose to make a difference, usually a free string should be treated as the same text in brackets. Thus, the room »< alpha >« and the room »< [alpha] >« usually are considered to be the same room. Bracketed strings can contain properly nested brackets and multiple lines. For example, the room »< [a<b>c[d]e] >« is a room with a single string, the text of which are the 9 characters »a<b>c[d]e«.

The Junotal   implementation can scan all those strings and decide how to write out a string, usually choosing a free string if possible.

Main.java
import java.lang.String;
import java.lang.System;
import de.dclj.ram.notation.unotal.Room;
import static de.dclj.ram.notation.unotal.RoomFromModule.room;

public final class Main
{ public static void main( final String argv[] )
{ System.out.println( room( "< alpha 0123 +:+ >" ));
System.out.println( room( "< -2,000.00 http://www.example.com >" ));
System.out.println( room( "< alpha >" ));
System.out.println( room( "< [alpha] >" ));
System.out.println( room( "< [a<b>c[d]e] >" )); }}
System.out
< alpha 0123 +:+ >
< -2,000.00 http://www.example.com >
< alpha >
< alpha >
< [a<b>c[d]e] >

Some rarely needed details, such as how to write strings with unpaired brackets will be described in later sections. However, to see how a string needs to be written, it always can be added to a room as a Java  string using the method »add« as described above and then written out using the room's method »toString()«.

This is the end of the basic tutorial with the most-simple features of Junotal. Additional sections will describe more advanced features and finer details.

The Concatenation Operator »~«

The concatenation operator »~« concatenates the bracketed strings to its left and its right.

To insert a tilde string between two bracketed strings, the tilde also has to bracketed.

The output of the following program shows a room expression followed by the string representation of the room constructed from the string literal. Only in one case (at the end of the first string) the preconditions for the application of the concatenation operator apply and two bracketed strings are concatenated indeed.

Main.java
public class Main
{ public static void d( final java.lang.String string )
{ java.lang.System.out.println( string );
java.lang.System.out.println
( " " + de.dclj.ram.notation.unotal.RoomFromModule.room( string ));
java.lang.System.out.println(); } public static void main( final java.lang.String[] args )
{ d( "< c ~ d e ~ [f] g ~ [h] [i] ~ [j] >" );
d( "< c [~] d e [~] [f] g [~] [h] [i] [~] [j] >" ); }}
System.out
< c ~ d e ~ [f] g ~ [h] [i] ~ [j] >
< c [~] d e [~] f g [~] h ij > < c [~] d e [~] [f] g [~] [h] [i] [~] [j] >
< c [~] d e [~] f g [~] h i [~] j >

The Compartment Separator »;«

The compartment operator »;« splits a room into several “compartments”, which are actually subrooms.

It can be used in cases when "<a b; c d>" is deemed more readable than "<< a b >< c d >>". Both expressions denote the same room.

If there is no entry following the compartment separator in a room, then no subroom will be created following the semicolon, but if there is no entry preceding the compartment separator in a room, then an empty subroom will be created in front of the semicolon (see examples below).

To denote a single semicolon as a text, a semicolon in brackets has to be used.

The following program shows some room expressions and the string representation of the room they denote.

Main.java
public class Main
{ public static void d( final java.lang.String string )
{ java.lang.System.out.println( string );
java.lang.System.out.println
( " " + de.dclj.ram.notation.unotal.RoomFromModule.room( string ));
java.lang.System.out.println(); } public static void main( final java.lang.String[] args )
{ d( "< a b; c d; e f >" );
d( "< a [;] b >" );
d( "< a ; b >" );
d( "< ; >" );
d( "< a; >" );
d( "< ; a >" ); }}
System.out
< a b; c d; e f >
< < a b >< c d >< e f >> < a [;] b >
< a [;] b > < a ; b >
< < a >< b >> < ; >
< < >> < a; >
< < a >> < ; a >
< < >< a >>

The Header Separator »:«

The header separator »:« might be used at most once within a room. It might be followed, but not preceded by one or multiple compartment separators. It separates entries of the room on its left from entries of an implicit subroom on its right. So, like the compartment separator, it creates a subroom, but only for the entries following it. (Like the compartment separator, it does not create an empty subroom if there are no entries following it.)

Multiple uses of the header separator, or uses of the header separator following a compartment separator are not allowed. The behavior of implementations is not defined for such use. (It might become defined in the future.)

Main.java
public class Main
{ public static void d( final java.lang.String string )
{ java.lang.System.out.println( string );
java.lang.System.out.println
( " " + de.dclj.ram.notation.unotal.RoomFromModule.room( string ));
java.lang.System.out.println(); } public static void main( final java.lang.String[] args )
{ d( "< a : b >" );
d( "< a [:] b >" );
d( "< a : b ; c >" );
d( "< a : >" );
d( "< : a >" );
d( "< : >" ); }}
System.out
< a : b >
< a < b >> < a [:] b >
< a [:] b > < a : b ; c >
< a < b >< c >> < a : >
< a > < : a >
< < a >> < : >
< >

Namespaces

In order to separate names, names might be put into namespaces. The colon »:« is reserved for names appearing as an attribute key or a type. In other attribute values or room entries, it can be used freely or as a reference to the former uses. For example, the name »:a:b« is considered to be the name »b« within the namespace »:a«. To abbreviate namespaces, a namespace can be declared for a room and all subrooms by an exclamation mark. It applies to all types and attribute keys without an explicit namespace, but not to attribute values and entries. The Junotal  writer is aware of this namespace notation and will try to use it, when writing such a room.

Main.java
import java.lang.String;
import java.lang.System;
import de.dclj.ram.notation.unotal.Room;
import static de.dclj.ram.notation.unotal.RoomFromModule.room;

public final class Main
{ public static void main( final String argv[] )
{ System.out.println( room( "< :a:b=c >" ).get( ":a:b" ));
System.out.println( room( "< !a b=c >" ).get( ":a:b" ));
System.out.println( room( "< !a &b >" ).get( ":unotal:type" ));
System.out.println( room( "< &:a:b :a:c=d >" ));
System.out.println( room( "< !a &:a:b :a:c =d >" ));
System.out.println( room( "< !a &b c=d >" )); }}
System.out
c
c
:a:b
< &:a:b :a:c =d >
< !a &:a:b :a:c =d >
< !a &:a:b :a:c =d >

The output of the last room is a slight bug, because the namespace prefixes are not stripped from the type and attribute key. But since an explicit namespace will suppress the declared prefix, this does no harm. The line before the last line shows that the output of the last room will be read as the same structure as the last room is.

Multiple Values of a Key

Generalizing properties of other data languages, a Unotal attribute might have several different values. They are represented as a set, which is called a spray  in this case. For example, in the room »< a=b a=c >«, the key »a« has two values, namely, »b« and »c«. One might also say in this case that the key »a« has the spray »{ b, c }« as its value.

It might seem irregular that the value of a key sometimes is a single value and sometimes a set. Technically, it might even become difficult to tell between a single value, which happens to be a set, and multiple values, given as a set. Therefore, the operation »getValues« is available, which uniformly will always return a set of all values of a given attribute key, even if this key just has one value.

Main.java
import java.lang.String;
import java.lang.System;
import de.dclj.ram.notation.unotal.Room;
import static de.dclj.ram.notation.unotal.RoomFromModule.room; public final class Main
{ public static void main( final String argv[] )
{ System.out.println( room( "< a=b >" ).get( "a" ));
System.out.println( room( "< a=b >" ).get( "a" ).getClass() ); System.out.println( room( "< a=b a=c >" ).get( "a" ));
System.out.println( room( "< a=b a=c >" ).get( "a" ).getClass() ); System.out.println( room( "< >" ).getValues( "a" ));
System.out.println( room( "< >" ).getValues( "a" ).getClass() ); System.out.println( room( "< a=b >" ).getValues( "a" ));
System.out.println( room( "< a=b >" ).getValues( "a" ).getClass() ); System.out.println( room( "< a=b a=b >" ).getValues( "a" ));
System.out.println( room( "< a=b a=b >" ).getValues( "a" ).getClass() ); System.out.println( room( "< a=b a=c >" ).getValues( "a" ));
System.out.println( room( "< a=b a=c >" ).getValues( "a" ).getClass() ); }}
System.out
b
class de.dclj.ram.notation.unotal.StringValue [b, c]
class de.dclj.ram.notation.unotal.SprayValue []
class de.dclj.ram.notation.unotal.SprayValue [b]
class java.util.HashSet [b]
class java.util.HashSet [b, c]
class java.util.HashSet

Both, »SprayValue« and »HashSet« implement »java.util.Set«, so the caller always can rely on getting a set from »getValues«. Still, later versions of »getValues« should always return an object of the class »SprayValue« more uniformly (not sometimes »java.util.HashSet«).

Uniformly Multiple Values

Generalizing properties of other data languages, a Unotal attribute might have several different values. They are represented as a set, which is called a spray  in this case. For example, in the room »< a=b a=c >«, the key »a« has two values »b« and »c«, in other words: the key »a« has the spray »{ b, c }« as its value.

It might seem irregular that the value of a key sometimes is a single value and sometimes a spray. Technically, it might even become difficult to tell between a single value, which happens to be a spray, and multiple values, given as a spray. Therefore, the operation »getValues« is available, which uniformly will always return a set of all values of a given attribute key, even if this key just has no value or just one value.

Main.java
import java.lang.String;
import java.lang.System;
import de.dclj.ram.notation.unotal.Room;
import static de.dclj.ram.notation.unotal.RoomFromModule.room; public final class Main
{ public static void main( final String argv[] )
{ System.out.println( room( "< a=b >" ).get( "a" ));
System.out.println( room( "< a=b >" ).get( "a" ).getClass() ); System.out.println( room( "< a=b a=c >" ).get( "a" ));
System.out.println( room( "< a=b a=c >" ).get( "a" ).getClass() ); System.out.println( room( "< >" ).getValues( "a" ));
System.out.println( room( "< >" ).getValues( "a" ).getClass() ); System.out.println( room( "< a=b >" ).getValues( "a" ));
System.out.println( room( "< a=b >" ).getValues( "a" ).getClass() ); System.out.println( room( "< a=b a=b >" ).getValues( "a" ));
System.out.println( room( "< a=b a=b >" ).getValues( "a" ).getClass() ); System.out.println( room( "< a=b a=c >" ).getValues( "a" ));
System.out.println( room( "< a=b a=c >" ).getValues( "a" ).getClass() ); }}
System.out
b
class de.dclj.ram.notation.unotal.StringValue [b, c]
class de.dclj.ram.notation.unotal.SprayValue []
class de.dclj.ram.notation.unotal.SprayValue [b]
class java.util.HashSet [b]
class java.util.HashSet [b, c]
class java.util.HashSet

Both, »SprayValue« and »HashSet« implement »java.util.Set«, so the caller always can rely on getting a set from »getValues«. Still, later versions of »getValues« should always return an object of the class »SprayValue« more uniformly (not sometimes »java.util.HashSet«).

Reddit   |   About this page, Impressum  |   Form for messages to the publisher regarding this page  |   "ram@zedat.fu-berlin.de" (without the quotation marks) is the email-address of Stefan Ram.   |   Beginning at the start page often more information about the topics of this page can be found. (A link to the start page appears at the very top of this page.)  |   Copyright 2004 Stefan Ram, Berlin. All rights reserved. This page is a publication by Stefan Ram. slrprd, PbclevtugFgrsnaEnz