package models.database.importers;
import java.util.HashMap;
import java.util.Map;
/**
* Definition of a (XML) syntax. Gives a fluent interface to create a
* <ul>
* <li>simple,
* <li>non-recursing,
* <li>unordered
* </ul>
* xml reader.<br/>
*
* Refer to {@link XMLParser#getSyntax} for an example.
*
* @author aaron
*
*/
public class Syntax {
private final String name;
private final Syntax parent;
private final Map<String, Syntax> subsyntax;
private Action callback;
public Syntax(String name) {
this(name, null);
}
private Syntax(String name, Syntax parent) {
this.name = name;
this.parent = parent;
this.subsyntax = new HashMap<String, Syntax>();
}
/**
* Tries to accept the tag. That means, it checks, whether such a tag is
* allowed and throws a <code>SemanticError()</code> if it's not. The fluent
* interface works with return values: <br/>
* <code>syntax.get("user").get("name")</code>
*
* @param tag
* @return
*/
public Syntax get(String tag) {
Syntax syntax = this.subsyntax.get(tag);
if (syntax == null)
throw new SemanticError();
return this.subsyntax.get(tag);
}
@Override
public String toString() {
return "S[" + this.name + "](" + this.subsyntax.toString() + ")";
}
/**
* Defines a subsyntax. In here, there can be further subsyntaxes and/or
* reads nested.
*
* @param tag
* @return
*/
public Syntax by(String tag) {
Syntax sub = new Syntax(tag, this);
this.subsyntax.put(tag, sub);
return sub;
}
/**
* Defines a simple shallow field. There are no subfields and just a text
* read.
*
* @param tag
* @return
*/
public Syntax read(String tag) {
Syntax sub = new Syntax(tag, this);
this.subsyntax.put(tag, sub);
return this;
}
/**
* Ends the current subsyntax. It is not necessary to close all of them in
* the very end.
*
* @return
*/
public Syntax end() {
return this.parent;
}
/**
* Gives a Parser that implements this syntax.
*
* @return
*/
public ElementParser done() {
return new ElementParser(this);
}
/**
* returns the supersyntax of this one.
*
* @return
*/
public Syntax getParent() {
return this.parent;
}
/**
* Defines an Action to be executed, once this syntax (ie this tag) is
* closed.
*
* @param action
* @return
*/
public Syntax call(Action action) {
this.callback = action;
return this;
}
/**
*
* @return true iff an Action is to be executed on the end of this tag.
*/
public boolean hasCallback() {
return this.callback != null;
}
/**
* Performs the callback, after the tag is closed, taking the produced
* Element as input.
*
* @param elt
*/
public void callback(Element elt) {
if (hasCallback()) {
this.callback.call(elt);
}
}
}