package org.gbif.checklistbank.neo.printer;
import org.gbif.api.service.checklistbank.NameParser;
import org.gbif.api.vocabulary.Rank;
import org.gbif.checklistbank.neo.Labels;
import org.gbif.checklistbank.neo.NeoProperties;
import org.gbif.nameparser.GBIFNameParser;
import java.io.IOException;
import java.io.Writer;
import java.util.LinkedList;
import java.util.Optional;
import com.google.common.base.Strings;
import com.google.common.base.Throwables;
import com.google.common.collect.Lists;
import com.google.common.xml.XmlEscapers;
import org.neo4j.graphdb.Node;
import org.parboiled.common.StringUtils;
/**
* A handler that can be used with the TaxonWalker to print a neo4j taxonomy in a simple nested text structure.
*/
public class XmlPrinter implements TreePrinter {
private final Writer writer;
private final NameParser parser;
private LinkedList<String> parents = Lists.newLinkedList();
public XmlPrinter(Writer writer) {
this.writer = writer;
parser = new GBIFNameParser(250);
}
@Override
public void start(Node n) {
open(n, n.hasLabel(Labels.SYNONYM));
}
@Override
public void end(Node n) {
if (!n.hasLabel(Labels.SYNONYM)){
close(n);
}
}
private void open(Node n, boolean close) {
try {
String sname = NeoProperties.getScientificName(n);
String cname = NeoProperties.getCanonicalName(n);
Rank rank = Rank.values()[(Integer) n.getProperty(NeoProperties.RANK, Rank.UNRANKED.ordinal())];
if (Strings.isNullOrEmpty(cname)) {
cname = Optional.ofNullable(parser.parseToCanonical(sname, rank)).orElse(sname);
}
cname = escapeTag(cname);
writer.write(StringUtils.repeat(' ', parents.size() * 2));
writer.write("<");
writer.write(cname);
printAttr("name", sname);
printAttr("rank", rank.name().toLowerCase());
if (n.hasLabel(Labels.BASIONYM)) {
printAttr("basionym", "true");
}
if (n.hasLabel(Labels.SYNONYM)) {
printAttr("synonym", "true");
}
if (close) {
writer.write(" /");
} else {
parents.add(cname);
}
writer.write(">");
writer.write("\n");
} catch (IOException e) {
Throwables.propagate(e);
}
}
private void close(Node n) {
try {
writer.write("</");
writer.write(parents.removeLast());
writer.write(">");
writer.write("\n");
} catch (IOException e) {
Throwables.propagate(e);
}
}
private void printAttr(String attr, String value) throws IOException {
if (!Strings.isNullOrEmpty(value)) {
writer.write(" ");
writer.write(attr);
writer.write("=\"");
writer.write(XmlEscapers.xmlAttributeEscaper().escape(value));
writer.write("\"");
}
}
private String escapeTag(String x) {
return x.replaceAll("[^a-zA-Z0-9_.-]", "_");
}
@Override
public void close() {
}
}