All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.konig.rio.turtle.SeaTurtleParser Maven / Gradle / Ivy

There is a newer version: 2.11.0
Show newest version
package io.konig.rio.turtle;

/*
 * #%L
 * Konig Core
 * %%
 * Copyright (C) 2015 - 2017 Gregory McFall
 * %%
 * 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.
 * #L%
 */


import java.io.IOException;
import java.io.Reader;

import org.openrdf.model.Literal;
import org.openrdf.model.Resource;
import org.openrdf.model.URI;
import org.openrdf.model.Value;
import org.openrdf.model.ValueFactory;
import org.openrdf.model.impl.ValueFactoryImpl;
import org.openrdf.model.vocabulary.XMLSchema;
import org.openrdf.rio.RDFHandlerException;
import org.openrdf.rio.RDFParseException;

import io.konig.core.Context;
import io.konig.core.NameMap;
import io.konig.core.Term;
import io.konig.core.Term.Kind;
import io.konig.core.impl.BasicContext;
import io.konig.core.impl.ChainedContext;

public class SeaTurtleParser extends TurtleParser {
	
	private Context defaultContext;
	private Context currentContext;
	private ContextHandler contextHandler;
	
	private Term lastTerm = null;
	private Term predicateTerm = null;
	
	protected NameMap nameMap;
	
	private NamespaceMap defaultNamespaceMap;
	
	public SeaTurtleParser() {
		this(null);
	}
	
	public SeaTurtleParser(NamespaceMap map) {
		super(null, ValueFactoryImpl.getInstance());
		defaultNamespaceMap = map;
		currentContext = defaultContext = new ChainedContext(null, new BasicContext(null));
		namespaceMap = new ContextNamespaceMap();
		setValueFactory(new CoercingValueFactory());
	}
	
	


	public NamespaceMap getDefaultNamespaceMap() {
		return defaultNamespaceMap;
	}

	public void setDefaultNamespaceMap(NamespaceMap defaultNamespaceMap) {
		this.defaultNamespaceMap = defaultNamespaceMap;
	}

	public NameMap getNameMap() {
		return nameMap;
	}

	public void setNameMap(NameMap nameMap) {
		this.nameMap = nameMap;
	}
	
	@Override
	public void parse(Reader reader, String baseURI) throws IOException, RDFParseException, RDFHandlerException {
		super.parse(reader, baseURI);
	}

	@Override
	protected void initParse(Reader reader, String baseURI) {
		super.initParse(reader, baseURI);
		currentContext = defaultContext;
	}

	public ContextHandler getContextHandler() {
		return contextHandler;
	}

	public void setContextHandler(ContextHandler contextHandler) {
		this.contextHandler = contextHandler;
	}


	protected void prologue() throws IOException, RDFParseException, RDFHandlerException {
		
		int c = next();
		while (c == '@') {
			directive(c);
			c = next();
		}
		unread(c);
		
	}

	/**
	 * 
	 *  prefixID | base | sparqlPrefix | sparqlBase | context
	 * 
*/ protected void directive(int c) throws IOException, RDFParseException, RDFHandlerException { if (tryWord("prefix")) { prefixID(); } else if (tryWord("context")) { contextTermList(); } else if (tryWord("base")) { base(); } else if (tryWord("term")) { termDirective(); } } /** * termDirective ::= '@term' * @throws IOException * @throws RDFParseException * @throws RDFHandlerException */ private void termDirective() throws RDFParseException, IOException, RDFHandlerException { skipSpace(); String termName = pn_local(); String idValue = null; int c = next(); if (c == '<') { idValue = iriRef(c); } else { unread(c); String prefix = pn_prefix(); c = read(); if (c == ':') { String local = pn_local(); idValue = prefix + ':' + local; } else { fail("Expected fully-qualified IRI or CURIE"); } } Context context = getContext(); context.add(new Term(termName, idValue)); } /** *
	 * contextTermList ::= '{' contextElement (',' contextElement)* '}' 
	 *                 ::= '{' term ( ',' term)* '}'
	 * 
*/ protected void contextTermList() throws IOException, RDFParseException { assertNext('{'); Context parentContext = currentContext; Context context = new BasicContext(null); currentContext = new ChainedContext(parentContext, context); Term term = term(); context.add(term); int c = next(); while (c == ',') { term = term(); context.add(term); c = next(); } assertEquals('}', c); currentContext.compile(); if (contextHandler != null) { contextHandler.addContext((ChainedContext) currentContext); } } /** * Here's the official Turtle 1.1 Syntax *
	 * PrefixedName	::=	PNAME_LN | PNAME_NS
	 *              ::= (PNAME_NS PN_LOCAL) | PNAME_NS
	 *              ::= PNAME_NS PN_LOCAL?
	 *              ::= PN_PREFIX? ':' PN_LOCAL?      
	 * 
* * We customize the Turtle syntax by redefining PrefixedName as follows. *
	 * PrefixedName	::=	(PN_PREFIX? ':' PN_LOCAL?) | bareLocalName 
	 * bareLocalName ::= PN_PREFIX
	 * 
* Notice that this customization requires that a bareLocalName is allowed only if it matches * the syntax of a namespace prefix. */ protected URI prefixedName(int c) throws IOException, RDFParseException { unread(c); String prefix = pn_prefix(); c = read(); if (c != ':') { unread(c); // Treat the prefix as a bare local name. defaultContext.compile(); Term term = lastTerm = currentContext.getTerm(prefix); if (term == null) { if (nameMap!=null) { URI result = nameMap.get(prefix); if (result != null) { return result; } } StringBuilder err = err(); err.append("Term not defined: "); err.append(prefix); fail(err); } return term.getExpandedId(); } String localName = pn_local(); String namespace = namespaceMap.get(prefix); if (namespace == null) { Term term = currentContext.getTerm(prefix); if (term != null) { defaultContext.compile(); namespace = term.getExpandedIdValue(); } } if (namespace == null) { fail("Namespace not defined for prefix '" + prefix + "'"); } return valueFactory.createURI(namespace + localName); } /** *
	 * term ::= termName ':' termDefinition
	 * 
*/ private Term term() throws IOException, RDFParseException { String termName = termName(); assertNext(':'); readSpace(); return termDefinition(termName); } /** *
	 * termName ::= jsonString
	 * 
* @throws IOException * @throws RDFParseException */ private String termName() throws RDFParseException, IOException { return jsonString(); } /** *
	 *	jsonString ::= '"' jsonChar* '"'
	 *
*/ private String jsonString() throws RDFParseException, IOException { assertNext('"'); buffer(); while (jsonChar()); String result = buffer.toString(); assertNext('"'); return result; } /** *
	 * jsonChar ::= unescapedJsonChar | escapedJsonChar
	 * 
*/ private boolean jsonChar() throws IOException, RDFParseException { int c = read(); boolean ok = unescapedJsonChar(c) || escapedJsonChar(c); if (!ok) { unread(c); } return ok; } /** *
	 *
	 * escapedJsonChar ::= escape (
	 *	  [#x22] 
	 *	| [#x5C] 
	 *	| [#x2F]
	 *	| [#x62]
	 *	| [#x66]
	 *	| [#x6E]
	 *	| [#x72]
	 *	| [#x74]
	 *	| 'u' hex hex hex hex)
	 *
	 * escape := [#xx5C]
	 * 
*/ private boolean escapedJsonChar(int c) throws IOException, RDFParseException { if (c=='\\') { c=read(); switch (c) { case 0x5C : case 0x2F : case 0x62 : case 0x66 : case 0x6E : case 0x72 : case 0x74 : buffer.appendCodePoint(c); break; case 'u' : String hexString = new String(new char[]{hex(), hex(), hex(), hex()}); buffer.appendCodePoint(Integer.parseInt(hexString, 16)); break; default : fail("Invalid escape character. Expected '\\\"', '\\\\', '\\/', '\\b', '\\f', '\\n', '\\r', '\\t' or '\\u' hex hex hex ."); } return true; } return false; } /** *
	 * unescapedJsonChar ::= [#x20-#x21] | [#x23-#x5B] | [#x4D-#x10FFF]
	 * 
*/ private boolean unescapedJsonChar(int c) { if ( inRange(c, 0x20, 0x21) || inRange(c, 0x23, 0x5B) || inRange(c, 0x5D, 0x10FFFF) ) { buffer.appendCodePoint(c); return true; } return false; } /** *
	 * termDefinition ::= jsonString | expandedTermDefinition
	 * 
* @throws IOException * @throws RDFParseException */ private Term termDefinition(String termName) throws IOException, RDFParseException { Term term = null; int c = peek(); if (c == '"') { String idValue = jsonString(); term = new Term(termName, idValue, Kind.ANY); } else if (c == '{') { term = expandedTermDefinition(termName); } return term; } protected Context getContext() { return currentContext; } /** *
	 * expandedTermDefinition ::= '{' termElement (',' termElement)* '}'
	 * termElement ::= 
  	 *    idProperty
	 *	| typeProperty
	 *  | languageProperty
	 *
	 * idProperty ::=  '"@id"'  ':' jsonString	
	 * typeProperty ::=  '"@type"' ':' jsonString
	 * languageProperty ::= '"@language"' ':' jsonString
	 * 
*/ private Term expandedTermDefinition(String termName) throws RDFParseException, IOException { String id=null; String type=null; String language=null; assertNext('{'); for (;;) { String keyword = jsonString(); switch (keyword) { case "@id" : assertNext(':'); id = jsonString(); break; case "@type" : assertNext(':'); type = jsonString(); break; case "@language" : assertNext(':'); language = jsonString(); break; default : StringBuilder err = err(); err.append("JSON-LD keyword not supported: "); err.append(keyword); fail(err); } int c = next(); if (c == '}') { break; } if (c!=',') { fail("Expected ',' or '}'"); } } return new Term(termName, id, language, type); } /** *
	 * iri	::=	IRIREF | PrefixedName | BareLocalName | IriTemplate | IriPropertyList
	 * 
* @throws RDFHandlerException */ protected URI iri(int c) throws RDFParseException, IOException, RDFHandlerException { if (c == '<') { String text = iriRef(c); return valueFactory.createURI(text); } else if (c=='{') { return iriPropertyList(c); } else { return prefixedName(c); } } protected URI iriPropertyList() throws RDFParseException, RDFHandlerException, IOException { read('{'); return iriPropertyList('{'); } protected Value object(int c) throws RDFParseException, IOException, RDFHandlerException { if (c == '{') { unread(c); return iriPropertyList(); } return super.object(c); } /** *
	 * IriPropertyList ::= '{' context? idProperty predicateObjectList '}'
	 * 
* @throws IOException * @throws RDFHandlerException */ private URI iriPropertyList(int c) throws RDFParseException, IOException, RDFHandlerException { assertEquals('{', c); Context initialContext = currentContext; URI id = null; c = next(); while (c=='@') { if (tryWord("context")) { if (id != null) { fail("@context must come before @id"); } contextTermList(); } else if (tryWord("id")) { id = iri(next()); } else { fail("Expected '@context' or '@id'"); } c = next(); } if (id == null) { fail("@id property must be defined."); } if (c == ';') { predicateObjectList(id); assertNext('}'); } else { assertEquals('}', c); } if (currentContext != initialContext) { ChainedContext chain = (ChainedContext) currentContext; currentContext = chain.getParent(); if (contextHandler != null) { contextHandler.removeContext(chain); } } return id; } protected URI verb() throws IOException, RDFParseException, RDFHandlerException { // We capture the lastTerm as a side-effect of invoking the verb() rule. // And we save the lastTerm as the predicateTerm, so that we can use it later // for type coercion lastTerm = null; URI result = super.verb(); predicateTerm = lastTerm; return result; } protected void triples(int c) throws RDFParseException, IOException, RDFHandlerException { Resource subject = null; if (c == '[') { subject = tryBlankNodePropertyList(c); if (subject != null) { c = next(); unread(c); if (c != '.') { predicateObjectList(subject); } return; } } else if (c== '{') { subject = iriPropertyList(c); c = next(); unread(c); if (c != '.') { predicateObjectList(subject); } return; } subject = subject(c); predicateObjectList(subject); } private class ContextNamespaceMap implements NamespaceMap { @Override public String get(String prefix) { defaultContext.compile(); Term term = currentContext.getTerm(prefix); return term!=null ? term.getExpandedIdValue() : defaultNamespaceMap!=null ? defaultNamespaceMap.get(prefix) : null; } @Override public void put(String prefix, String name) { defaultContext.addTerm(prefix, name).setKind(Kind.NAMESPACE); } } private class CoercingValueFactory extends ValueFactoryImpl { @Override public Literal createLiteral(String value, URI datatype) { if (predicateTerm != null) { currentContext.compile(); String lang = predicateTerm.getLanguage(); if (lang != null) { return super.createLiteral(value, lang); } URI type = predicateTerm.getExpandedType(); if (type != null) { datatype = type; } } String lang = currentContext.getLanguage(); if (lang != null && XMLSchema.STRING.equals(datatype)) { return super.createLiteral(value, lang); } return super.createLiteral(value, datatype); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy