/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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.apache.jena.n3.turtle; import org.apache.jena.datatypes.RDFDatatype ; import org.apache.jena.datatypes.TypeMapper ; import org.apache.jena.datatypes.xsd.XSDDatatype ; import org.apache.jena.graph.Node ; import org.apache.jena.graph.NodeFactory ; import org.apache.jena.graph.Triple ; import org.apache.jena.n3.N3IRIResolver ; import org.apache.jena.n3.JenaURIException ; import org.apache.jena.shared.PrefixMapping ; import org.apache.jena.shared.impl.PrefixMappingImpl ; import org.apache.jena.vocabulary.RDF ; @SuppressWarnings("deprecation") public class ParserBase { // Should be the same as ARQ ParserBase and Prologues. protected final Node XSD_TRUE = NodeFactory.createLiteral("true", null, XSDDatatype.XSDboolean) ; protected final Node XSD_FALSE = NodeFactory.createLiteral("false", null, XSDDatatype.XSDboolean) ; protected final Node nRDFtype = RDF.type.asNode() ; protected final Node nRDFnil = RDF.nil.asNode() ; protected final Node nRDFfirst = RDF.first.asNode() ; protected final Node nRDFrest = RDF.rest.asNode() ; protected final Node nRDFsubject = RDF.subject.asNode() ; protected final Node nRDFpredicate = RDF.predicate.asNode() ; protected final Node nRDFobject = RDF.object.asNode() ; protected final String SWAP_NS = "http://www.w3.org/2000/10/swap/" ; protected final String SWAP_LOG_NS = "http://www.w3.org/2000/10/swap/log#" ; protected final Node nLogImplies = NodeFactory.createURI(SWAP_LOG_NS+"implies") ; protected final Node nOwlSameAs = NodeFactory.createURI("http://www.w3.org/2002/07/owl#sameAs") ; protected boolean strictTurtle = true ; protected boolean skolomizedBNodes = true ; public ParserBase() {} PrefixMapping prefixMapping = new PrefixMappingImpl() ; N3IRIResolver resolver = new N3IRIResolver() ; protected String getBaseURI() { return resolver.getBaseIRI() ; } public void setBaseURI(String u) { resolver = new N3IRIResolver(u) ; } protected void setBase(String iriStr , int line, int column) { // Already resolved. setBaseURI(iriStr) ; } public PrefixMapping getPrefixMapping() { return prefixMapping ; } // label => bNode for construct templates patterns LabelToNodeMap bNodeLabels = new LabelToNodeMap() ; TurtleEventHandler handler = null ; public void setEventHandler(TurtleEventHandler h) { handler = h ; } protected void emitTriple(int line, int col, Triple triple) { handler.triple(line, col, triple) ; } protected void startFormula(int line, int col) { handler.startFormula(line, col) ; } protected void endFormula(int line, int col) {handler.endFormula(line, col) ; } protected void setPrefix(int line, int col, String prefix, String uri) { prefixMapping.setNsPrefix(prefix, uri) ; handler.prefix(line, col, prefix, uri) ; } protected int makePositiveInteger(String lexicalForm) { if ( lexicalForm == null ) return -1 ; return Integer.parseInt(lexicalForm) ; } protected Node createLiteralInteger(String lexicalForm) { return NodeFactory.createLiteral(lexicalForm, null, XSDDatatype.XSDinteger) ; } protected Node createLiteralDouble(String lexicalForm) { return NodeFactory.createLiteral(lexicalForm, null, XSDDatatype.XSDdouble) ; } protected Node createLiteralDecimal(String lexicalForm) { return NodeFactory.createLiteral(lexicalForm, null, XSDDatatype.XSDdecimal) ; } protected Node createLiteral(String lexicalForm, String langTag, Node datatype) { String uri = (datatype==null) ? null : datatype.getURI() ; return createLiteral(lexicalForm, langTag, uri) ; } protected Node createLiteral(String lexicalForm, String langTag, String datatypeURI) { Node n = null ; // Can't have type and lang tag. if ( datatypeURI != null) { RDFDatatype dType = TypeMapper.getInstance().getSafeTypeByName(datatypeURI) ; n = NodeFactory.createLiteral(lexicalForm, null, dType) ; } else n = NodeFactory.createLiteral(lexicalForm, langTag, null) ; return n ; } protected long integerValue(String s) { if ( s.startsWith("+") ) s = s.substring(1) ; if ( s.startsWith("0x") ) { // Hex s = s.substring(2) ; return Long.parseLong(s, 16) ; } return Long.parseLong(s) ; } protected double doubleValue(String s) { if ( s.startsWith("+") ) s = s.substring(1) ; double valDouble = Double.parseDouble(s) ; return valDouble ; } protected String stripQuotes(String s) { return s.substring(1,s.length()-1) ; } protected String stripQuotes3(String s) { return s.substring(3,s.length()-3) ; } protected String stripChars(String s, int n) { return s.substring(n, s.length()) ; } protected String resolveQuotedIRI(String iriStr ,int line, int column) { iriStr = stripQuotes(iriStr) ; return resolveIRI(iriStr, line, column) ; } protected String resolveIRI(String iriStr , int line, int column) { if ( isBNodeIRI(iriStr) ) return iriStr ; if ( resolver != null ) iriStr = _resolveIRI(iriStr, line, column) ; return iriStr ; } private String _resolveIRI(String iriStr , int line, int column) { try { iriStr = resolver.resolve(iriStr) ; } catch (JenaURIException ex) { throwParseException(ex.getMessage(), line, column) ; } return iriStr ; } protected String resolvePName(String qname, int line, int column) { String s = myExpandPrefix(prefixMapping, qname) ; if ( s == null ) throwParseException("Unresolved prefixed name: "+qname, line, column) ; return s ; } private static String myExpandPrefix(PrefixMapping prefixMapping, String qname) { String s = prefixMapping.expandPrefix(qname) ; if ( s == null ) return null ; if ( s.equals(qname) ) { // The contract of expandPrefix is to return the original name if // there is no prefix but what s the expanded and original form are // actually the same character string ? int colon = qname.indexOf( ':' ); if (colon < 0) return null ; String prefix = qname.substring( 0, colon ) ; if ( prefixMapping.getNsPrefixURI(prefix) != null ) // The original and resolved forms are the same. return s ; return null ; } return s ; } final static String bNodeLabelStart = "_:" ; protected Node createListNode() { return createBNode() ; } // Unlabelled bNode. protected Node createBNode() { return bNodeLabels.allocNode() ; } // Labelled bNode. protected Node createBNode(String label, int line, int column) { return bNodeLabels.asNode(label) ; } protected Node createVariable(String s, int line, int column) { s = s.substring(1) ; // Drop the marker return NodeFactory.createVariable(s) ; } protected Node createNode(String iri) { // Is it a bNode label? i.e. <_:xyz> if ( isBNodeIRI(iri) ) { String s = iri.substring(bNodeLabelStart.length()) ; Node n = NodeFactory.createBlankNode(s) ; return n ; } return NodeFactory.createURI(iri) ; } protected boolean isBNodeIRI(String iri) { return skolomizedBNodes && iri.startsWith(bNodeLabelStart) ; } // protected Node createNodeFromURI(String s, int line, int column) // { // s = stripQuotes(s) ; // String uriStr = s ; // Mutated // // try { // uriStr = resolver.resolve(uriStr) ; // } catch (JenaURIException ex) // { // throw new TurtleParseException(exMsg(ex.getMessage(), line, column)) ; // } // return Node.createURI(uriStr) ; // } protected void throwParseException(String s , int line, int column) { throw new TurtleParseException(exMsg(s, line, column)) ; } protected String fixupPrefix(String prefix, int line, int column) { if ( prefix.endsWith(":") ) prefix = prefix.substring(0, prefix.length()-1) ; return prefix ; } // Utilities to remove escapes // Testing interface public static String unescapeStr(String s) { return unescape(s, '\\', false, 1, 1) ; } // public static String unescapeCodePoint(String s) // { return unescape(s, '\\', true, 1, 1) ; } // // protected String unescapeCodePoint(String s, int line, int column) // { return unescape(s, '\\', true, line, column) ; } protected String unescapeStr(String s, int line, int column) { return unescape(s, '\\', false, line, column) ; } // Worker function private static String unescape(String s, char escape, boolean pointCodeOnly, int line, int column) { int i = s.indexOf(escape) ; if ( i == -1 ) return s ; // Dump the initial part straight into the string buffer StringBuilder sb = new StringBuilder(s.substring(0,i)) ; int len = s.length() ; for ( ; i < len ; i++ ) { char ch = s.charAt(i) ; // Keep line and column numbers. switch (ch) { case '\n': case '\r': line++ ; column = 1 ; break ; default: column++ ; break ; } if ( ch != escape ) { sb.append(ch) ; continue ; } // Escape if ( i >= len-1 ) throw new TurtleParseException(exMsg("Illegal escape at end of string", line, column)) ; char ch2 = s.charAt(i+1) ; column = column+1 ; i = i + 1 ; // \\u and \\U if ( ch2 == 'u' ) { // i points to the \ so i+6 is next character if ( i+4 >= len ) throw new TurtleParseException(exMsg("\\u escape too short", line, column)) ; int x = hex(s, i+1, 4, line, column) ; sb.append((char)x) ; // Jump 1 2 3 4 -- already skipped \ and u i = i+4 ; column = column+4 ; continue ; } if ( ch2 == 'U' ) { // i points to the \ so i+6 is next character if ( i+8 >= len ) throw new TurtleParseException(exMsg("\\U escape too short", line, column)) ; int x = hex(s, i+1, 8, line, column) ; sb.append((char)x) ; // Jump 1 2 3 4 5 6 7 8 -- already skipped \ and u i = i+8 ; column = column+8 ; continue ; } // Are we doing just point code escapes? // If so, \X-anything else is legal as a literal "\" and "X" if ( pointCodeOnly ) { sb.append('\\') ; sb.append(ch2) ; i = i + 1 ; continue ; } // Not just codepoints. Must be a legal escape. char ch3 = 0 ; switch (ch2) { case 'n': ch3 = '\n' ; break ; case 't': ch3 = '\t' ; break ; case 'r': ch3 = '\r' ; break ; case 'b': ch3 = '\b' ; break ; case 'f': ch3 = '\f' ; break ; case '\'': ch3 = '\'' ; break ; case '\"': ch3 = '\"' ; break ; case '\\': ch3 = '\\' ; break ; default: throw new TurtleParseException(exMsg("Unknown escape: \\"+ch2, line, column)) ; } sb.append(ch3) ; } return sb.toString() ; } // Line and column that started the escape static private int hex(String s, int i, int len, int line, int column) { // if ( i+len >= s.length() ) // { // // } int x = 0 ; for ( int j = i ; j < i+len ; j++ ) { char ch = s.charAt(j) ; column++ ; int k = 0 ; switch (ch) { case '0': k = 0 ; break ; case '1': k = 1 ; break ; case '2': k = 2 ; break ; case '3': k = 3 ; break ; case '4': k = 4 ; break ; case '5': k = 5 ; break ; case '6': k = 6 ; break ; case '7': k = 7 ; break ; case '8': k = 8 ; break ; case '9': k = 9 ; break ; case 'A': case 'a': k = 10 ; break ; case 'B': case 'b': k = 11 ; break ; case 'C': case 'c': k = 12 ; break ; case 'D': case 'd': k = 13 ; break ; case 'E': case 'e': k = 14 ; break ; case 'F': case 'f': k = 15 ; break ; default: throw new TurtleParseException(exMsg("Illegal hex escape: "+ch, line, column)) ; } x = (x<<4)+k ; } return x ; } protected static String exMsg(String msg, int line, int column) { return "Line " + line + ", column " + column + ": " + msg ; } }