jt-oddl
is an Open Data Description Language parser written in Java.
Add the following to the <dependencies>
element in your pom.xml
:
<dependency>
<groupId>com.github.mdzhb</groupId>
<artifactId>jt-oddl</artifactId>
<version>1.0.1</version>
</dependency>
To parse an OpenDDL file, you need an ODDLReader
and an implementation of the ODDLListener
interface. The ODDLReader
parses text read from a Reader
or InputStream
. Every time the ODDLReader
encounters a valid language construct in the input, it calls the appropriate method in its ODDLListener
.
Consider the following example listener. For brevity, it only implements three of the methods specified in the ODDLListener
interface.
// this class generates a list of Structure objects; imagine the Structure class is defined elsewhere in your code
class StructureListener implements ODDLListener<List<Structure>> {
/** this is the collection of structures our listener will return */
private final List<Structure> structures = new ArrayList<>();
/** a stack helps us handle nested structures */
private final Deque<Structure> stack = new ArrayDeque<>();
// this method is called when the reader encounters the beginning of a custom structure
@Override
public void beginCustomStructure(IdentifierToken identifier, NameToken name, PropertyMap properties) {
stack.push(new Structure(identifier, name, properties));
}
// this method is called when the reader reaches the end of a custom structure (i.e. the closing brace)
@Override
public void endCustomStructure(IdentifierToken identifier, NameToken name, PropertyMap properties) {
Structure struct = stack.pop();
if (stack.isEmpty()) { // this is a top-level structure
structures.add(struct);
} else { // this is a child structure
stack.peek().addChildStructure(struct);
}
}
// this method is called when the reader reaches end of file
@Override
public List<Structure> end(int row, int col) {
return structures; // this return value is the object returned by ODDLReader.read()
}
}
You would use the StructureListener
like this:
try (InputStream in = Files.newInputStream(Paths.get("myfile.oddl"))) {
List<Structure> structures = new ODDLReader(in).read(new StructureListener());
// operate on your list of Structures...
}
ODDLToken
defines methods that convert tokens to more specific types without casting. This is useful when handling structure properties in your listener implementation, for example.
@Override
public void beginCustomStructure(IdentifierToken identifier, NameToken name, PropertyMap properties) {
PropertyValueToken token = properties.get("propertyName");
if (token.isFloat()) { // is this a float literal?
FloatToken ft = token.asFloat(); // it is, so this line is valid
}
}
If handling a large number of token types, it may be wiser to use a switch statement:
switch (token.getType()) {
case BOOL:
boolean bt = token.asBool().getValue();
break;
case FLOAT:
float ft = token.asFloat().getValue();
break;
// etc.
}
These "downcasting" methods throw an IllegalArgumentException
when the token is not an instance of the desired class.