/*******************************************************************************
* Copyright 2012 Pearson Education
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
package org.semantictools.jsonld.io.impl;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map.Entry;
import java.util.regex.Pattern;
import org.codehaus.jackson.JsonFactory;
import org.codehaus.jackson.JsonNode;
import org.codehaus.jackson.JsonParseException;
import org.codehaus.jackson.JsonParser;
import org.codehaus.jackson.JsonToken;
import org.codehaus.jackson.node.ArrayNode;
import org.codehaus.jackson.node.ObjectNode;
import org.semantictools.jsonld.LdClass;
import org.semantictools.jsonld.LdContainerType;
import org.semantictools.jsonld.LdContext;
import org.semantictools.jsonld.LdContextManager;
import org.semantictools.jsonld.LdContextParseException;
import org.semantictools.jsonld.LdDatatype;
import org.semantictools.jsonld.LdDatatypeManager;
import org.semantictools.jsonld.LdProperty;
import org.semantictools.jsonld.LdQualifiedRestriction;
import org.semantictools.jsonld.LdRestriction;
import org.semantictools.jsonld.LdTerm;
import org.semantictools.jsonld.Whitespace;
import org.semantictools.jsonld.io.ErrorHandler;
import org.semantictools.jsonld.io.LdContextReader;
public class LdContextReaderImpl implements LdContextReader {
private LdContextManager manager;
private ErrorHandler errorHandler;
public LdContextReaderImpl(LdContextManager manager) {
this.manager = manager;
}
/**
* Returns the LdContextManager that is used to resolve external contexts.
*/
public LdContextManager getManager() {
return manager;
}
/**
* Sets the LdContextManager that is used to resolve external contexts.
*/
public void setManager(LdContextManager manager) {
this.manager = manager;
}
private LdContext parseContext(JsonParser parser) throws JsonParseException, IOException {
LdContext context = new LdContext();
parseContext(parser, context);
return context;
}
/**
* Perform the work of parsing a JSON stream into the given LdContext.
*/
private void parseContext(JsonParser parser, LdContext context) throws JsonParseException, IOException {
JsonToken token = null;
while ( (token=parser.nextToken()) != null) {
if (token == JsonToken.END_OBJECT) break;
if (token != JsonToken.FIELD_NAME) {
throw new JsonParseException("Expected a field name", parser.getCurrentLocation());
}
String fieldName = parser.getCurrentName();
parseField(parser, context, fieldName);
}
}
/**
* For the given fieldName, parse an LdTerm and add it to the given context.
*/
private void parseField(JsonParser parser, LdContext context, String fieldName) throws JsonParseException, IOException {
LdTerm term = new LdTerm();
term.setShortName(fieldName);
context.add(term);
JsonToken token = parser.nextToken();
switch (token) {
case VALUE_STRING :
term.setRawIRI(parser.getText());
break;
case START_OBJECT:
parseTermFields(parser, term);
break;
default:
throw new JsonParseException("Expected IRI value or object definition of term", parser.getCurrentLocation());
}
}
/**
* Parse the fields within a JSON-LD term from the given parser into the given LdTerm object.
*/
private void parseTermFields(JsonParser parser, LdTerm term) throws JsonParseException, IOException {
JsonToken token = null;
while ( (token=parser.nextToken()) != JsonToken.END_OBJECT) {
switch (token) {
case FIELD_NAME :
String fieldName = parser.getCurrentName();
if ("@id".equals(fieldName)) {
term.setRawIRI(readString(parser));
} else if ("@type".equals(fieldName)) {
term.setRawTypeIRI(readString(parser));
} else if ("@language".equals(fieldName)) {
term.setLanguage(readString(parser));
} else if ("@container".equals(fieldName)) {
term.setContainerType(readContainerType(parser));
} else if ("@minCardinality".equals(fieldName)) {
term.setMinCardinality(Integer.parseInt(readString(parser)));
} else if ("datatype".equals(fieldName)) {
parseDatatype(parser, term);
} else if ("class".equals(fieldName)) {
parseClass(parser, term);
} else if("property".equals(fieldName)) {
parseProperty(parser, term);
} else {
skipValue(parser);
}
break;
default:
throw new JsonParseException("Expected field name", parser.getCurrentLocation());
}
}
}
private void parseProperty(JsonParser parser, LdTerm term) throws JsonParseException, IOException {
LdProperty property = new LdProperty();
term.setProperty(property);
assertToken(parser, JsonToken.START_OBJECT);
while ( parser.nextToken() == JsonToken.FIELD_NAME) {
String fieldName = parser.getCurrentName();
if ("domain".equals(fieldName)) {
parseDomain(parser, property);
}
}
assertCurrentToken(parser, JsonToken.END_OBJECT);
}
private void parseDomain(JsonParser parser, LdProperty property) throws JsonParseException, IOException {
assertToken(parser, JsonToken.START_ARRAY);
while ( parser.nextToken() == JsonToken.VALUE_STRING) {
String domainValue = parser.getText();
property.addDomain(domainValue);
}
assertCurrentToken(parser, JsonToken.END_ARRAY);
}
private void assertCurrentToken(JsonParser parser, JsonToken expected) throws JsonParseException {
JsonToken actual = parser.getCurrentToken();
if (expected != actual) {
throw new JsonParseException("Expected " + expected + ", but found " + actual, parser.getCurrentLocation());
}
}
private void parseClass(JsonParser parser, LdTerm term) throws JsonParseException, IOException {
LdClass rdfClass = new LdClass(null);
term.setRdfClass(rdfClass);
assertToken(parser, JsonToken.START_OBJECT);
while ( parser.nextToken() == JsonToken.FIELD_NAME) {
String fieldName = parser.getCurrentName();
if ("supertype".equals(fieldName)) {
parserSupertype(parser, rdfClass);
} else if ("restriction".equals(fieldName)) {
parseRestrictionArray(parser, rdfClass);
} else {
skipValue(parser);
}
}
}
private void parseRestrictionArray(JsonParser parser, LdClass rdfClass) throws JsonParseException, IOException {
assertToken(parser, JsonToken.START_ARRAY);
while (parser.nextToken() == JsonToken.START_OBJECT) {
parseRestriction(parser, rdfClass);
}
assertCurrentToken(parser, JsonToken.END_ARRAY);
}
private void parseRestriction(JsonParser parser, LdClass rdfClass) throws JsonParseException, IOException {
LdRestriction restriction = new LdRestriction();
while (parser.nextToken() == JsonToken.FIELD_NAME) {
String fieldName = parser.getCurrentName();
if ("onProperty".equals(fieldName)) {
restriction.setPropertyURI(readString(parser));
} else if ("maxCardinality".equals(fieldName)) {
restriction.setMaxCardinality(readInt(parser));
} else if ("minCardinality".equals(fieldName)) {
restriction.setMinCardinality(readInt(parser));
} else if ("qualifiedRestriction".equals(fieldName)) {
parseQualifiedRestrictionArray(parser, restriction);
} else if ("allValuesFrom".equals(fieldName)) {
restriction.setAllValuesFrom(readString(parser));
} else {
skipValue(parser);
}
}
assertCurrentToken(parser, JsonToken.END_OBJECT);
rdfClass.add(restriction);
}
private void parseQualifiedRestrictionArray(
JsonParser parser, LdRestriction restriction) throws JsonParseException, IOException {
assertToken(parser, JsonToken.START_ARRAY);
while (parser.nextToken() == JsonToken.START_OBJECT) {
parseQualifiedRestriction(parser, restriction);
}
assertCurrentToken(parser, JsonToken.END_ARRAY);
}
private void parseQualifiedRestriction(JsonParser parser,
LdRestriction restriction) throws JsonParseException, IOException {
LdQualifiedRestriction qr = new LdQualifiedRestriction();
restriction.add(qr);
while (parser.nextToken() == JsonToken.FIELD_NAME) {
String fieldName = parser.getCurrentName();
if ("onClass".equals(fieldName)) {
qr.setRangeURI(readString(parser));
} else if ("maxCardinality".equals(fieldName)) {
qr.setMaxCardinality(readInt(parser));
} else if ("minCardinality".equals(fieldName)) {
qr.setMinCardinality(readInt(parser));
}
}
assertCurrentToken(parser, JsonToken.END_OBJECT);
}
private void parserSupertype(JsonParser parser, LdClass rdfClass) throws JsonParseException, IOException {
assertToken(parser, JsonToken.START_ARRAY);
while ( parser.nextToken() == JsonToken.VALUE_STRING) {
String supertypeURI = parser.getText();
LdClass superClass = new LdClass(supertypeURI);
rdfClass.addSupertype(superClass);
}
}
private void parseDatatype(JsonParser parser, LdTerm term) throws JsonParseException, IOException {
LdDatatype datatype = new LdDatatype();
term.setDatatype(datatype);
assertToken(parser, JsonToken.START_OBJECT);
while ( parser.nextToken() == JsonToken.FIELD_NAME) {
String fieldName = parser.getCurrentName();
if (fieldName.equals("base")) {
String baseURI = readString(parser);
LdDatatype base = new LdDatatype();
base.setURI(baseURI);
datatype.setBase(base);
} else if ("length".equals(fieldName)) {
datatype.setLength(readInt(parser));
} else if ("minLength".equals(fieldName)) {
datatype.setMinLength(readInt(parser));
} else if ("maxLength".equals(fieldName)) {
datatype.setMaxLength(readInt(parser));
} else if ("pattern".equals(fieldName)) {
datatype.setPattern(Pattern.compile(readString(parser)));
} else if ("whitespace".equals(fieldName)) {
String name = readString(parser);
Whitespace ws =
"collapse".equals(name) ? Whitespace.COLLAPSE :
"replace".equals(name) ? Whitespace.REPLACE :
"preserve".equals(name) ? Whitespace.PRESERVE :
null;
if (ws == null) {
throw new JsonParseException("Unrecognized whitespace: " + name, parser.getCurrentLocation());
}
datatype.setWhitespace(ws);
} else if ("maxInclusive".equals(fieldName)) {
datatype.setMaxInclusive(readNumber(parser));
} else if ("minInclusive".equals(fieldName)) {
datatype.setMinInclusive(readNumber(parser));
} else if ("maxExclusive".equals(fieldName)) {
datatype.setMaxExclusive(readNumber(parser));
} else if ("minExclusive".equals(fieldName)) {
datatype.setMinExclusive(readNumber(parser));
} else if ("totalDigits".equals(fieldName)) {
datatype.setTotalDigits(readInt(parser));
} else if ("fractionDigits".equals(fieldName)) {
datatype.setFractionDigits(readInt(parser));
} else {
skipValue(parser);
}
}
}
private Number readNumber(JsonParser parser) throws JsonParseException, IOException {
JsonToken token = parser.nextToken();
switch (token) {
case VALUE_NUMBER_INT:
return new Long(parser.getLongValue());
case VALUE_NUMBER_FLOAT:
return new Double(parser.getDoubleValue());
default:
throw new JsonParseException(
"Expected int or float value, but found " + parser.getCurrentToken(), parser.getCurrentLocation());
}
}
private Integer readInt(JsonParser parser) throws JsonParseException, IOException {
assertToken(parser, JsonToken.VALUE_NUMBER_INT);
return new Integer(parser.getIntValue());
}
private void assertToken(JsonParser parser, JsonToken expected) throws JsonParseException, IOException {
if (parser.nextToken() != expected) {
throw new JsonParseException("Expected " + expected, parser.getCurrentLocation());
}
}
private void skipValue(JsonParser parser) throws JsonParseException, IOException {
int objectDepth=0;
int arrayDepth=0;
JsonToken token = null;
while ( (token = parser.nextToken()) != null) {
switch (token) {
case END_ARRAY :
arrayDepth--;
break;
case END_OBJECT :
objectDepth--;
break;
case FIELD_NAME :
continue;
case START_ARRAY :
arrayDepth++;
break;
case START_OBJECT :
objectDepth++;
break;
case VALUE_FALSE :
case VALUE_NULL :
case VALUE_NUMBER_FLOAT :
case VALUE_NUMBER_INT :
case VALUE_STRING :
case VALUE_TRUE :
// Do nothing
break;
}
if (objectDepth == 0 && arrayDepth==0) {
break;
}
}
}
private LdContainerType readContainerType(JsonParser parser) throws JsonParseException, IOException {
String text = readString(parser);
return
"@set".equals(text) ? LdContainerType.SET :
"@list".equals(text) ? LdContainerType.LIST :
LdContainerType.UNDEFINED;
}
private String readString(JsonParser parser) throws JsonParseException, IOException {
JsonToken token = parser.nextToken();
if (token != JsonToken.VALUE_STRING) {
throw new JsonParseException("Expected string value", parser.getCurrentLocation());
}
return parser.getText();
}
/**
* Parse the JSON-LD context from the given stream, associate it with the given contextURI,
* and store the result in the internal LdContextManager.
* @throws LdContextParseException
*/
public LdContext parseExternalContext(String contextURI, InputStream stream) throws
IOException, LdContextParseException {
LdContext context = parseExternalContext(stream);
context.setContextURI(contextURI);
return context;
}
@Override
public LdContext parserExternalContext(Reader reader)
throws IOException, LdContextParseException {
LdContext context = null;
JsonFactory factory = new JsonFactory();
factory.enable(JsonParser.Feature.ALLOW_COMMENTS);
JsonParser jsonParser = factory.createJsonParser(reader);
JsonToken token=null;
while ( (token = jsonParser.nextToken()) != null) {
if (token == JsonToken.FIELD_NAME) {
String fieldName = jsonParser.getCurrentName();
if ("@context".equals(fieldName)) {
context = parseContextField(jsonParser);
}
}
}
return context;
}
@Override
public LdContext parseExternalContext(InputStream stream) throws JsonParseException,
IOException, LdContextParseException {
LdContext context = null;
JsonFactory factory = new JsonFactory();
factory.enable(JsonParser.Feature.ALLOW_COMMENTS);
JsonParser jsonParser = factory.createJsonParser(stream);
JsonToken token=null;
while ( (token = jsonParser.nextToken()) != null) {
if (token == JsonToken.FIELD_NAME) {
String fieldName = jsonParser.getCurrentName();
if ("@context".equals(fieldName)) {
context = parseContextField(jsonParser);
}
}
}
return context;
}
@Override
public LdContext parseContextField(JsonParser jsonParser) throws IOException, LdContextParseException {
LdContext context = null;
JsonToken token = jsonParser.nextToken();
boolean external = false;
switch (token) {
case VALUE_STRING:
context = loadExternalContext(jsonParser.getText());
external = true;
break;
case START_ARRAY:
context = new LdContext();
parseContextArray(jsonParser, context);
break;
case START_OBJECT:
context = parseContext(jsonParser);
break;
}
if (context != null) {
context.close();
prepareOwlClasses(context);
// We don't need to resolve references if the context is external
// and obtained from the LdContextManager.
//
if (!external && context.isEnhanced()) {
resolveRefereces(context);
}
}
return context;
}
/** Add RDF class for owl:Thing if it is referenced explicitly.
* This method is a bit of a hack.
* TODO: Find a more elegant solution.
* @param context
*/
private void prepareOwlClasses(LdContext context) {
LdTerm term = context.getTerm("http://www.w3.org/2002/07/owl#Thing");
if (term == null) return;
LdClass type = term.getRdfClass();
if (type == null) {
type = new LdClass(term.getIRI());
term.setRdfClass(type);
}
}
private void resolveRefereces(LdContext context) {
List<LdTerm> termList = context.listTerms();
if (termList == null) return;
for (LdTerm term : termList) {
resolve(context, term);
}
}
private void resolve(LdContext context, LdTerm term) {
resolveDatatype(context, term);
resolveClass(context, term);
}
private void resolveClass(LdContext context, LdTerm term) {
LdClass rdfClass = term.getRdfClass();
if (rdfClass != null) {
String uri = term.getIRI();
rdfClass.setURI(uri);
resolveSupertypes(context, rdfClass);
}
}
private void resolveSupertypes(LdContext context, LdClass rdfClass) {
List<LdClass> superList = rdfClass.listSupertypes();
if (superList != null && !superList.isEmpty()) {
List<LdClass> newList = new ArrayList<LdClass>();
for (LdClass original : superList) {
LdClass newClass = context.getClass(original.getURI());
if (newClass == null) {
newClass = original;
}
newList.add(newClass);
}
rdfClass.setSupertypes(newList);
}
}
private void resolveDatatype(LdContext context, LdTerm term) {
LdDatatype datatype = term.getDatatype();
if (datatype != null) {
String uri = term.getIRI();
int mark = uri.lastIndexOf('#');
if (mark < 0) {
mark = uri.lastIndexOf('/');
}
String localName = uri.substring(mark+1);
datatype.setLocalName(localName);
datatype.setNamespace(uri.substring(0, mark));
datatype.setURI(uri);
LdDatatype base = datatype.getBase();
if (base != null) {
String baseURI = base.getURI();
LdDatatype newBase = LdDatatypeManager.getXsdTypeByURI(baseURI);
if (newBase == null) {
LdTerm baseTerm = context.getTerm(baseURI);
newBase = baseTerm == null ? null : baseTerm.getDatatype();
}
if (newBase != null) {
datatype.setBase(newBase);
}
}
}
}
private void parseContextArray(JsonParser jsonParser, LdContext context) throws IOException, LdContextParseException {
JsonToken token = null;
LdContext child = null;
while ( (token=jsonParser.nextToken()) != null) {
switch (token) {
case END_ARRAY: return;
case VALUE_STRING:
try {
child = loadExternalContext(jsonParser.getText());
context.add(child);
} catch (IOException e) {
if (errorHandler == null) {
throw e;
} else {
errorHandler.handleError(e);
}
} catch (LdContextParseException e) {
if (errorHandler == null) {
throw e;
} else {
errorHandler.handleError(e);
}
}
break;
case START_OBJECT :
child = parseContext(jsonParser);
context.add(child);
break;
}
}
}
private LdContext loadExternalContext(String contextURI) throws IOException, LdContextParseException {
if (manager == null) {
String msg = "Cannot load external contexts";
handleError( new LdContextParseException(msg) );
}
LdContext context = manager.findContext(contextURI);
if (context == null) {
handleError( new LdContextParseException("JSON-LD context not found: " + contextURI));
}
return context;
}
protected void handleError(Throwable oops) throws IOException, LdContextParseException {
if (errorHandler==null) {
if (oops instanceof IOException) throw (IOException) oops;
if (oops instanceof LdContextParseException) throw (LdContextParseException) oops;
throw new LdContextParseException(oops);
} else {
errorHandler.handleError(oops);
}
}
@Override
public void setErrorHandler(ErrorHandler handler) {
errorHandler = handler;
}
@Override
public ErrorHandler getErrorHandler() {
return errorHandler;
}
@Override
public LdContext parseContext(JsonNode node) throws LdContextParseException, IOException {
LdContext context = null;
boolean external = false;
if (node.isTextual()) {
context = loadExternalContext(node.asText());
external = true;
} else if (node instanceof ObjectNode) {
context = new LdContext();
parseContextObject((ObjectNode) node, context);
} else if (node instanceof ArrayNode) {
context = new LdContext();
parseContextArray((ArrayNode)node, context);
}
if (context != null) {
context.close();
prepareOwlClasses(context);
// We don't need to resolve references if the context is external
// and obtained from the LdContextManager.
//
if (!external && context.isEnhanced()) {
resolveRefereces(context);
}
}
return context;
}
private void parseContextArray(ArrayNode array, LdContext context) throws LdContextParseException, IOException {
for (int i=0; i<array.size(); i++) {
JsonNode node = array.get(i);
if (node.isTextual()) {
LdContext child;
try {
child = loadExternalContext(node.getTextValue());
if (child != null) {
context.add(child);
}
} catch (LdContextParseException e) {
if (errorHandler != null) {
errorHandler.handleError(e);
} else {
throw e;
}
} catch (IOException e) {
if (errorHandler != null) {
errorHandler.handleError(e);
} else {
throw e;
}
}
} else if (node instanceof ObjectNode) {
LdContext child = new LdContext();
try {
parseContextObject((ObjectNode)node, child);
context.add(child);
} catch (JsonParseException e) {
if (errorHandler != null) {
errorHandler.handleError(e);
} else {
throw e;
}
}
}
}
}
private void parseContextObject(ObjectNode node, LdContext context) throws JsonParseException, LdContextParseException {
Iterator<Entry<String, JsonNode>> sequence = node.getFields();
while (sequence.hasNext()) {
Entry<String, JsonNode> entry = sequence.next();
parseField(context, entry.getKey(), entry.getValue());
}
}
private void parseField(LdContext context, String fieldName, JsonNode value) throws JsonParseException, LdContextParseException {
LdTerm term = new LdTerm();
term.setShortName(fieldName);
context.add(term);
if (value.isTextual()) {
term.setRawIRI(value.getTextValue());
} else if (value instanceof ObjectNode) {
parseTermFields((ObjectNode)value, term);
} else {
throw new JsonParseException("Expected IRI value or object definition of term " + fieldName, null);
}
}
private void parseTermFields(ObjectNode json, LdTerm term) throws LdContextParseException {
JsonToken token = null;
Iterator<Entry<String,JsonNode>> sequence = json.getFields();
while (sequence.hasNext()) {
Entry<String,JsonNode> entry = sequence.next();
String fieldName = entry.getKey();
JsonNode value = entry.getValue();
if ("@id".equals(fieldName)) {
term.setRawIRI(value.getTextValue());
} else if ("@type".equals(fieldName)) {
term.setRawTypeIRI(value.getTextValue());
} else if ("@language".equals(fieldName)) {
term.setLanguage(value.getTextValue());
} else if ("@container".equals(fieldName)) {
term.setContainerType(readContainerType(value));
} else if ("@minCardinality".equals(fieldName)) {
term.setMinCardinality(value.getIntValue());
} else if ("datatype".equals(fieldName)) {
parseDatatype(value, term);
} else if ("class".equals(fieldName)) {
parseClass(value, term);
} else if("property".equals(fieldName)) {
parseProperty(value, term);
}
}
}
private void parseProperty(JsonNode value, LdTerm term) {
// TODO Auto-generated method stub
}
private void parseClass(JsonNode value, LdTerm term) throws LdContextParseException {
if ( ! (value instanceof ObjectNode)) {
throw new LdContextParseException("Expected class definition to be an object in term " + term.getRawIRI());
}
ObjectNode object = (ObjectNode) value;
LdClass rdfClass = new LdClass(null);
term.setRdfClass(rdfClass);
Iterator<Entry<String,JsonNode>> sequence = object.getFields();
while ( sequence.hasNext() ) {
Entry<String,JsonNode> entry = sequence.next();
String fieldName = entry.getKey();
value = entry.getValue();
if ("supertype".equals(fieldName)) {
parserSupertype(value, rdfClass);
} else if ("restriction".equals(fieldName)) {
parseRestrictionArray(value, rdfClass);
}
}
}
private void parseRestrictionArray(JsonNode value, LdClass rdfClass) throws LdContextParseException {
if (! (value instanceof ArrayNode)) {
throw new LdContextParseException("Expected restriction definition to be an array");
}
ArrayNode array = (ArrayNode) value;
for (int i=0; i<array.size(); i++) {
value = array.get(i);
parseRestriction(value, rdfClass);
}
}
private void parseRestriction(JsonNode value, LdClass rdfClass) throws LdContextParseException {
if (!(value instanceof ObjectNode)) {
throw new LdContextParseException("Expected restriction definition to be an object");
}
LdRestriction restriction = new LdRestriction();
rdfClass.add(restriction);
ObjectNode object = (ObjectNode) value;
Iterator<Entry<String,JsonNode>> sequence = object.getFields();
while (sequence.hasNext()) {
Entry<String,JsonNode> entry = sequence.next();
String fieldName = entry.getKey();
value = entry.getValue();
if ("onProperty".equals(fieldName)) {
restriction.setPropertyURI(value.getTextValue());
} else if ("maxCardinality".equals(fieldName)) {
restriction.setMaxCardinality(value.getIntValue());
} else if ("minCardinality".equals(fieldName)) {
restriction.setMinCardinality(value.getIntValue());
} else if ("qualifiedRestriction".equals(fieldName)) {
parseQualifiedRestrictionArray(value, restriction);
}
}
}
private void parseQualifiedRestrictionArray(JsonNode value,
LdRestriction restriction) throws LdContextParseException {
if (!(value instanceof ArrayNode)) {
throw new LdContextParseException("Expected qualified restriction definition to be an array");
}
ArrayNode array = (ArrayNode) value;
for (int i=0; i<array.size(); i++) {
parseQualifiedRestriction(value, restriction);
}
}
private void parseQualifiedRestriction(JsonNode value, LdRestriction restriction) throws LdContextParseException {
if (! (value instanceof ObjectNode)) {
throw new LdContextParseException("Expected qualified restriction definition to be an object");
}
ObjectNode object = (ObjectNode) value;
LdQualifiedRestriction qr = new LdQualifiedRestriction();
restriction.add(qr);
Iterator<Entry<String,JsonNode>> sequence = object.getFields();
while (sequence.hasNext()) {
Entry<String,JsonNode> entry = sequence.next();
value = entry.getValue();
String fieldName = entry.getKey();
if ("onClass".equals(fieldName)) {
qr.setRangeURI(value.getTextValue());
} else if ("maxCardinality".equals(fieldName)) {
qr.setMaxCardinality(value.getIntValue());
} else if ("minCardinality".equals(fieldName)) {
qr.setMinCardinality(value.getIntValue());
}
}
}
private void parserSupertype(JsonNode value, LdClass rdfClass) throws LdContextParseException {
if (! (value instanceof ArrayNode)) {
throw new LdContextParseException("Expected supertype value to be an array");
}
ArrayNode array = (ArrayNode) value;
for (int i=0; i<array.size(); i++) {
value = array.get(i);
String supertypeURI = value.getTextValue();
LdClass superClass = new LdClass(supertypeURI);
rdfClass.addSupertype(superClass);
}
}
private void parseDatatype(JsonNode value, LdTerm term) throws LdContextParseException {
LdDatatype datatype = new LdDatatype();
term.setDatatype(datatype);
if ( !(value instanceof ObjectNode)) {
throw new LdContextParseException("Expected object for datatype description " + term.getRawIRI());
}
ObjectNode object = (ObjectNode) value;
Iterator<Entry<String,JsonNode>> sequence = object.getFields();
while (sequence.hasNext()) {
Entry<String,JsonNode> entry = sequence.next();
String fieldName = entry.getKey();
value = entry.getValue();
if (fieldName.equals("base")) {
String baseURI = value.getTextValue();
LdDatatype base = new LdDatatype();
base.setURI(baseURI);
datatype.setBase(base);
} else if ("length".equals(fieldName)) {
datatype.setLength(value.getIntValue());
} else if ("minLength".equals(fieldName)) {
datatype.setMinLength(value.getIntValue());
} else if ("maxLength".equals(fieldName)) {
datatype.setMaxLength(value.getIntValue());
} else if ("pattern".equals(fieldName)) {
datatype.setPattern(Pattern.compile(value.getTextValue()));
} else if ("whitespace".equals(fieldName)) {
String name = value.getTextValue();
Whitespace ws =
"collapse".equals(name) ? Whitespace.COLLAPSE :
"replace".equals(name) ? Whitespace.REPLACE :
"preserve".equals(name) ? Whitespace.PRESERVE :
null;
if (ws == null) {
throw new LdContextParseException("Unrecognized whitespace '" + name + "' in term " + term.getIRI());
}
datatype.setWhitespace(ws);
} else if ("maxInclusive".equals(fieldName)) {
datatype.setMaxInclusive(readNumber(value));
} else if ("minInclusive".equals(fieldName)) {
datatype.setMinInclusive(readNumber(value));
} else if ("maxExclusive".equals(fieldName)) {
datatype.setMaxExclusive(readNumber(value));
} else if ("minExclusive".equals(fieldName)) {
datatype.setMinExclusive(readNumber(value));
} else if ("totalDigits".equals(fieldName)) {
datatype.setTotalDigits(value.getIntValue());
} else if ("fractionDigits".equals(fieldName)) {
datatype.setFractionDigits(value.getIntValue());
}
}
}
private Number readNumber(JsonNode value) throws LdContextParseException {
if (value.isInt()) {
return new Integer(value.getIntValue());
}
if (value.isLong()) {
return new Long(value.getLongValue());
}
if (value.isDouble()) {
return new Double(value.getDoubleValue());
}
throw new LdContextParseException("Expected a numeric value");
}
private LdContainerType readContainerType(JsonNode value) {
String text = value.getTextValue();
return
"@set".equals(text) ? LdContainerType.SET :
"@list".equals(text) ? LdContainerType.LIST :
LdContainerType.UNDEFINED;
}
}