package org.gbif.occurrence.ws.provider;
import org.gbif.dwc.terms.DcTerm;
import org.gbif.dwc.terms.DwcTerm;
import org.gbif.dwc.terms.GbifTerm;
import org.gbif.dwc.terms.Term;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import com.google.common.base.Optional;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
/**
* Simple wrapper around {@link Document} to generate DarwinCore XML file.
* This class is a candidate to be moved to the dwca-io project.
*
*/
public class DwcXMLDocument {
private static final String NS_URI = "http://www.w3.org/2000/xmlns/";
private static final String NS_PREFIX = "xmlns:";
/**
* Currently private but could be exposed if needed elsewhere.
* Could also be refactor if the Term interface expose a getPrefix and getNamespace methods.
*/
private enum DwcXmlNamespace {
DWC(DwcTerm.class, DwcTerm.PREFIX, DwcTerm.NS),
DC(DcTerm.class, DcTerm.PREFIX, DcTerm.NS),
GBIF(GbifTerm.class, GbifTerm.PREFIX, GbifTerm.NS);
private final Class<? extends Term> termClass;
private final String prefix;
private final String namespace;
DwcXmlNamespace(Class<? extends Term> termClass, String prefix, String namespace) {
this.termClass = termClass;
this.prefix = prefix;
this.namespace = namespace;
}
/**
* Get a DwcXmlNamespace from {@Term}.
*
* @param term
* @return corresponding DwcXmlNamespace of Optional.empty() if the provided term is not supported
*/
public static Optional<DwcXmlNamespace> fromTerm(Term term) {
for (DwcXmlNamespace dwcXmlNamespace : DwcXmlNamespace.values()) {
if (dwcXmlNamespace.termClass.equals(term.getClass())) {
return Optional.of(dwcXmlNamespace);
}
}
return Optional.absent();
}
}
private final Document doc;
private final Element currentElement;
/**
* Private constructor, newInstance method should be used to get an instance.
*
* @param doc
* @param rootElementTerm
*/
private DwcXMLDocument(Document doc, DwcTerm rootElementTerm) {
this.doc = doc;
currentElement = createDwcXMLRootElement(rootElementTerm);
}
/**
* Creates a new DwcXMLDocument using the specified Term as root element.
*
* @param rootElementTerm
* @return
* @throws ParserConfigurationException
*/
public static DwcXMLDocument newInstance(DwcTerm rootElementTerm) throws ParserConfigurationException {
DocumentBuilderFactory icFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder icBuilder = icFactory.newDocumentBuilder();
return new DwcXMLDocument(icBuilder.newDocument(), rootElementTerm);
}
/**
*
* @return newly created root Element
*/
private Element createDwcXMLRootElement(DwcTerm rootElementTerm) {
Element rootElement = doc.createElement(DwcXmlNamespace.DWC.prefix + ":" + rootElementTerm.simpleName());
for (DwcXmlNamespace dwcXmlNS : DwcXmlNamespace.values()) {
rootElement.setAttributeNS(NS_URI, NS_PREFIX + dwcXmlNS.prefix, dwcXmlNS.namespace);
}
doc.appendChild(rootElement);
return rootElement;
}
public void append(DcTerm term, String value) {
append(currentElement, DwcXmlNamespace.DC, term, value);
}
public void append(DwcTerm term, String value) {
append(currentElement, DwcXmlNamespace.DWC, term, value);
}
public void append(GbifTerm term, String value) {
append(currentElement, DwcXmlNamespace.GBIF, term, value);
}
/**
* Get the underlying {@link Document}.
*
* @return
*/
public Document getDocument() {
return doc;
}
/**
* Try to append the provided {@Term term} if it can be matched to a supported namespace.
*
* @param term
* @param value
* @return appended to the document or not
*/
public boolean tryAppend(Term term, String value) {
Optional<DwcXmlNamespace> dwcXmlNamespace = DwcXmlNamespace.fromTerm(term);
if (dwcXmlNamespace.isPresent()) {
append(currentElement, dwcXmlNamespace.get(), term, value);
} else {
return false;
}
return true;
}
/**
* Appends the term,value to the document under the parentElement with dwcXmlNamespace. null values are simply ignored.
*
* @param parentElement
* @param dwcXmlNamespace
* @param term
* @param value the value to add or null
*/
private void append(Element parentElement, DwcXmlNamespace dwcXmlNamespace, Term term, String value) {
if (value == null) {
return;
}
Element node = doc.createElement(dwcXmlNamespace.prefix + ":" + term.simpleName());
node.appendChild(doc.createTextNode(value));
parentElement.appendChild(node);
}
}