package net.enilink.komma.parser.manchester;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import net.enilink.vocab.owl.DataRange;
import net.enilink.vocab.owl.Restriction;
import net.enilink.vocab.rdf.RDF;
import net.enilink.vocab.rdfs.Class;
import net.enilink.vocab.rdfs.Datatype;
import net.enilink.vocab.xmlschema.XMLSCHEMA;
import net.enilink.komma.core.IBindings;
import net.enilink.komma.core.IEntity;
import net.enilink.komma.core.ILiteral;
import net.enilink.komma.core.IReference;
import net.enilink.komma.core.URI;
/**
* Generator for the
* <a href="http://www.w3.org/2007/OWL/wiki/ManchesterSyntax">Manchester OWL
* Syntax</a>.
*/
public class ManchesterSyntaxGenerator {
static final String FACET_QUERY = createFacetQuery();
private static String createFacetQuery() {
StringBuilder sb = new StringBuilder("PREFIX xsd: <" + XMLSCHEMA.NAMESPACE + ">\n");
sb.append("select ?facet ?value where {\n");
Iterator<String> facets = Arrays.asList("length", "minLength", "maxLength", "pattern", "langPattern",
"minInclusive", "minExclusive", "maxInclusive", "maxExclusive").iterator();
while (facets.hasNext()) {
String facet = "xsd:" + facets.next();
sb.append("\t{ ?s ").append(facet).append(" ?value\n");
sb.append("\tbind ( ").append(facet).append(" as ?facet ) }\n");
if (facets.hasNext()) {
sb.append("\tunion\n");
}
}
sb.append("} limit 1");
return sb.toString();
}
// maps XSD facets to shorthand notations
static final Map<String, String> FACET_SHORTHANDS = new HashMap<String, String>();
static {
FACET_SHORTHANDS.put("minInclusive", "<=");
FACET_SHORTHANDS.put("minExclusive", "<");
FACET_SHORTHANDS.put("maxInclusive", ">=");
FACET_SHORTHANDS.put("maxExclusive", ">");
}
public String generateText(Object object) {
if (object instanceof Class) {
return clazz((Class) object, 0).toString();
}
return value(object).toString();
}
protected ManchesterSyntaxGenerator append(Object token) {
sb.append(token);
return this;
}
private StringBuilder sb = new StringBuilder();
private ManchesterSyntaxGenerator clazz(Class clazz, int prio) {
if (clazz.getURI() == null) {
if (clazz instanceof Restriction) {
return restriction((Restriction) clazz, prio);
} else if (clazz instanceof Datatype && ((Datatype) clazz).getOwlOnDatatype() != null) {
append(toString(((Datatype) clazz).getOwlOnDatatype()));
return datatypeRestrictions(((Datatype) clazz).getOwlWithRestrictions());
} else if (clazz instanceof net.enilink.vocab.owl.Class) {
net.enilink.vocab.owl.Class owlClass = (net.enilink.vocab.owl.Class) clazz;
if (owlClass.getOwlUnionOf() != null) {
return setOfClasses(owlClass.getOwlUnionOf(), "or", 1, prio);
} else if (owlClass.getOwlIntersectionOf() != null) {
return setOfClasses(owlClass.getOwlIntersectionOf(), "and", 2, prio);
} else if (owlClass.getOwlComplementOf() != null) {
append("not ");
return clazz(owlClass.getOwlComplementOf(), 3);
} else if (owlClass.getOwlOneOf() != null) {
return list(owlClass.getOwlOneOf());
}
}
}
return value(clazz);
}
/**
* Converts a list of datatype restrictions to a Manchester expression in
* the form [facet1 value1, facet2 value2, ...]
*
* Example: xsd:int[>=18]
*
* @param list
* The list of datatype restrictions which are expressed using
* XML Schmema facets.
*
* @return The generator instance.
*/
private ManchesterSyntaxGenerator datatypeRestrictions(List<?> list) {
if (list != null) {
append("[");
Iterator<? extends Object> it = list.iterator();
while (it.hasNext()) {
IEntity dtRestriction = (IEntity) it.next();
for (IBindings<?> bindings : dtRestriction.getEntityManager().createQuery(FACET_QUERY)
.setParameter("s", dtRestriction).evaluate(IBindings.class)) {
IReference facet = (IReference) bindings.get("facet");
String facetShortHand = FACET_SHORTHANDS.get(facet.getURI().localPart());
if (facetShortHand == null) {
facetShortHand = facet.getURI().localPart();
}
append(facetShortHand).append(toString(bindings.get("value")));
if (it.hasNext()) {
append(", ");
}
}
}
append("]");
}
return this;
}
private ManchesterSyntaxGenerator dataRange(DataRange dataRange) {
return clazz(dataRange, 0);
}
private ManchesterSyntaxGenerator list(List<? extends Object> list) {
append("{");
Iterator<? extends Object> it = list.iterator();
while (it.hasNext()) {
value(it.next());
if (it.hasNext()) {
append(", ").append(" ");
}
}
append("}");
return this;
}
private ManchesterSyntaxGenerator onClassOrDataRange(Restriction restriction) {
if (restriction.getOwlOnClass() != null) {
return clazz(restriction.getOwlOnClass(), 0);
} else if (restriction.getOwlOnDataRange() != null) {
return dataRange(restriction.getOwlOnDataRange());
}
return this;
}
public ManchesterSyntaxGenerator restriction(Restriction restriction, int prio) {
if (restriction.getURI() == null) {
int operatorPrio = 4;
if (restriction.getOwlOnProperty() != null) {
if (prio >= operatorPrio) {
append("(");
}
value(restriction.getOwlOnProperty());
} else if (restriction.getOwlOnProperties() != null) {
if (prio >= operatorPrio) {
append("(");
}
// TODO How is this correctly represented as manchester syntax?
list(restriction.getOwlOnProperties());
} else {
// this is an invalid restriction, since target properties are
// missing, so just return the name of this restriction
return value(restriction);
}
append(" ");
if (restriction.getOwlAllValuesFrom() != null) {
append("only").append(" ");
clazz(restriction.getOwlAllValuesFrom(), operatorPrio);
} else if (restriction.getOwlSomeValuesFrom() != null) {
append("some").append(" ");
clazz(restriction.getOwlSomeValuesFrom(), operatorPrio);
} else if (restriction.getOwlMaxCardinality() != null) {
append("max").append(" ");
append(restriction.getOwlMaxCardinality());
} else if (restriction.getOwlMinCardinality() != null) {
append("min").append(" ");
append(restriction.getOwlMinCardinality());
} else if (restriction.getOwlCardinality() != null) {
append("exactly").append(" ");
append(restriction.getOwlCardinality());
} else if (restriction.getOwlMaxQualifiedCardinality() != null) {
append("max").append(" ");
append(restriction.getOwlMaxQualifiedCardinality()).append(" ");
onClassOrDataRange(restriction);
} else if (restriction.getOwlMinQualifiedCardinality() != null) {
append("min").append(" ");
append(restriction.getOwlMinQualifiedCardinality()).append(" ");
onClassOrDataRange(restriction);
} else if (restriction.getOwlQualifiedCardinality() != null) {
append("exactly").append(" ");
append(restriction.getOwlQualifiedCardinality()).append(" ");
onClassOrDataRange(restriction);
} else if (restriction.getOwlHasValue() != null) {
append("value").append(" ");
value(restriction.getOwlHasValue());
}
if (prio >= operatorPrio) {
append(")");
}
return this;
}
return value(restriction);
}
private ManchesterSyntaxGenerator setOfClasses(List<? extends Class> set, String operator, int operatorPrio,
int prio) {
Iterator<? extends Class> it = set.iterator();
if (operatorPrio < prio && set.size() > 1) {
append("(");
}
while (it.hasNext()) {
clazz(it.next(), operatorPrio);
if (it.hasNext()) {
append(" ").append(operator).append(" ");
}
}
if (operatorPrio < prio && set.size() > 1) {
append(")");
}
return this;
}
@Override
public String toString() {
return sb.toString();
}
protected String escapeLiteral(String label) {
return label.replace("\\", "\\\\").replace("\t", "\\t").replace("\n", "\\n").replace("\r", "\\r").replace("\"",
"\\\"");
}
protected ManchesterSyntaxGenerator value(Object value) {
if (value instanceof ILiteral) {
ILiteral literal = (ILiteral) value;
boolean quoted = XMLSCHEMA.TYPE_STRING.equals(literal.getDatatype())
|| RDF.TYPE_LANGSTRING.equals(literal.getDatatype()) || literal.getDatatype() == null;
if (quoted) {
append("\"");
}
append(escapeLiteral(literal.getLabel()));
if (quoted) {
append("\"");
}
if (literal.getLanguage() != null) {
append("@").append(toString(literal.getLanguage()));
} else if (literal.getDatatype() != null) {
append("^^").append(toString(literal.getDatatype()));
}
} else {
append(toString(value));
}
return this;
}
protected String getPrefix(IReference reference) {
if (reference instanceof IEntity) {
return ((IEntity) reference).getEntityManager().getPrefix(reference.getURI().namespace());
}
return null;
}
protected String toString(Object value) {
if (value instanceof IReference) {
URI uri = ((IReference) value).getURI();
if (uri != null) {
String prefix = getPrefix((IReference) value);
String localPart = uri.localPart();
boolean hasLocalPart = localPart != null && localPart.length() > 0;
StringBuilder text = new StringBuilder();
if (prefix != null && prefix.length() > 0 && hasLocalPart) {
text.append(prefix).append(":");
}
if (hasLocalPart && prefix != null) {
text.append(localPart);
} else {
text.append("<").append(uri.toString()).append(">");
}
return text.toString();
}
}
return String.valueOf(value);
}
}