├── .gitignore ├── .travis.yml ├── README.md ├── pom.xml └── src ├── main └── java │ └── solutions │ └── linked │ └── jarql │ ├── JarqlExecutor.java │ ├── JarqlParser.java │ └── TripleSink.java └── test ├── java └── solutions │ └── linked │ └── jarql │ └── ParserTest.java └── resources └── solutions └── linked └── jarql ├── array.json ├── array.query ├── array.ttl ├── boolean.json ├── boolean_raw.ttl ├── contratto.json ├── contratto.query ├── contratto.ttl ├── contratto_raw.ttl ├── null.json ├── null_raw.ttl ├── number-array.json ├── number-array_raw.ttl ├── number.json ├── number.query ├── number.ttl ├── paperino.json ├── paperino.query ├── paperino.ttl └── paperino_raw.ttl /.gitignore: -------------------------------------------------------------------------------- 1 | /nbproject/ 2 | /target/ 3 | /target2/ 4 | /target3/ -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: java 2 | dist: trusty 3 | jdk: 4 | - oraclejdk8 5 | sudo: false 6 | script: mvn clean install -Pexecutable -DfinalName=jarql-$TRAVIS_TAG 7 | deploy: 8 | skip_cleanup: true 9 | provider: releases 10 | api_key: 11 | secure: B/Liuhjat1yA5K+nCEKdrfQbotRyprQwQao5/Zk1mGIzuZ3qWtX+Z3etgunNxcoLW5AAO4rT3wgvdS1jNhAd5KpIbHTLNflmcUSd6F6+9IPTCxITLxikee1jqSw8BwXXmPOkxrkLkJ+2B2hJ+pil2HM34OiEPpqTwej2t3tj5rJ3XsOzvyZ0fy5IFe/e4oiLKjf9AX2exJPqHvUI+BKKHsQ9Q4nihsrERz+cJaKgbedC0VpIQXKbX4ndVs6Ez8sNrR7ntW2YhjYcL8DcLM4CPBVoR4yFEjTcDvNBakeJ7T4WPK4wtyiuzbDzMnktOLH9zQdvZvWXqpCKv1ykclGvh6/ulZP+K9BbMbcQYmoOOzmCBlhsJ78V00jWf2jPb0pmCbDBmxsATskR7iLhybAwWXU9VFy15SME0LtpV4HR1q9XL80BkMtHzfk/dH+nKtJ88jOkl1TVqIwm+ofrDsfUEqBZQQdRm6PArXfejhSl7BXtxJPXfVK0cYtZHWk7TSARtNP4EVjFEhpk6DXVFr+0BFR6JsjcxshKnIu9YH68ck9bn4pvbA4HPnaqhFBfiXzL+ge0YlGkqd5PAdtcOuhoyBozVU2fFRErjXG/YwOI96dkgRXhmP+PZIa/PrVnK4NG3aurxdkwDhWjv4mvHhO6Fc5RIK+maC/IFwie9WLg+j0= 12 | file: target/jarql-$TRAVIS_TAG.jar 13 | on: 14 | repo: linked-solutions/jarql 15 | tags: true 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.org/linked-solutions/jarql.svg?branch=master)](https://travis-ci.org/linked-solutions/jarql) 2 | 3 | 4 | # JARQL 5 | SPARQL construct queries on JSON files 6 | 7 | JARQL allows to execute SPARQL Construct Queries against JSON files. The project was inspired by [Tarql](https://github.com/tarql/tarql) which provides similar functionality for CSV files. With JARQL you can easily transform JSON Documents to RDF. 8 | 9 | ## Build 10 | Instead of building yourself you can download it from the release page. 11 | 12 | In order to create an executable .jar containing all the dependencies just run: 13 | 14 | mvn package -Pexecutable 15 | 16 | ## Usage 17 | 18 | java -jar jarql-.jar 19 | 20 | For example if you have a file called `paperino.json` with the following content: 21 | 22 | ```json 23 | { 24 | "parent": [{ 25 | "name": "Paperino", 26 | "children": ["Qui", "Quo", "Qua"], 27 | "fiance": {"name": "Paperina"} 28 | }, { 29 | "name": "Topolino", 30 | "children": ["Tip", "Tap", "Top"], 31 | "fiance": {"name": "Minnie"} 32 | }] 33 | } 34 | ``` 35 | 36 | And a file called `paperino.query` with the following content: 37 | 38 | ```sparql 39 | PREFIX : 40 | PREFIX jarql: 41 | 42 | CONSTRUCT { 43 | ?p :name ?n; 44 | :child [:name ?cn]. 45 | } 46 | WHERE { 47 | jarql:root jarql:parent ?p. 48 | ?p jarql:name ?n. 49 | ?p jarql:children ?cn. 50 | } 51 | ``` 52 | 53 | Invoking `jarql-1.0-pre1.jar` as follows: 54 | 55 | java -jar jarql-1.0-pre1.jar paperino.json paperino.query 56 | 57 | will output the following RDF: 58 | 59 | ```turtle 60 | [ [ 61 | "Qui"^^ ] ; 62 | [ 63 | "Qua"^^ ] ; 64 | [ 65 | "Quo"^^ ] ; 66 | "Paperino"^^ 67 | ] . 68 | 69 | [ [ 70 | "Top"^^ ] ; 71 | [ 72 | "Tap"^^ ] ; 73 | [ 74 | "Tip"^^ ] ; 75 | "Topolino"^^ 76 | ] . 77 | 78 | ``` 79 | ### Advanced usage 80 | Add all metadata you want using ```BIND``` combined with [SPARQL 1.1 functions](https://www.w3.org/TR/sparql11-query/#SparqlOps)! 81 | 82 | Create URI... 83 | ``` 84 | BIND (URI(CONCAT('http://example.com/ns#', ?var)) AS ?uri) 85 | ``` 86 | ...add language tags... 87 | ``` 88 | BIND (STRLANG(?string, 'en') AS ?with_language_tag) 89 | ``` 90 | ...or datatypes! 91 | ``` 92 | BIND (STRDT(?num, xsd:integer) AS ?int) 93 | ``` 94 | 95 | ## Current limitations 96 | 97 | * Nested arrays in JSON are not supported 98 | * The order of JSon Arrays is irrelevant 99 | 100 | ## Similar Projects 101 | 102 | * [JSON2RDF](https://github.com/AtomGraph/JSON2RDF) provides streaming conversion from JSON to RDF. 103 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | solutions.linked 6 | parent 7 | 1 8 | 9 | 10 | jarql 11 | 2.0.0-SNAPSHOT 12 | jar 13 | Jarql 14 | SPARQL for JSON: Turn JSON into RDF using SPARQL syntax. 15 | http://jarql.linked.solutions 16 | 17 | https://github.com/linked-solutions/jarql 18 | scm:git:git://github.com/linked-solutions/jarql.git 19 | scm:git:git@github.com:linked-solutions/jarql.git 20 | HEAD 21 | 22 | 23 | 24 | org.glassfish 25 | javax.json 26 | 1.0.4 27 | 28 | 29 | org.apache.clerezza.commons-rdf 30 | commons-rdf-api 31 | 0.2 32 | 33 | 34 | junit 35 | junit 36 | 4.12 37 | test 38 | 39 | 40 | org.apache.clerezza.commons-rdf 41 | commons-rdf-impl-utils 42 | 0.2 43 | jar 44 | 45 | 46 | org.apache.clerezza 47 | rdf.jena.parser 48 | 1.1.0 49 | test 50 | 51 | 52 | org.apache.clerezza 53 | rdf.core 54 | 1.0.0 55 | jar 56 | 57 | 58 | org.slf4j 59 | slf4j-simple 60 | 1.5.8 61 | runtime 62 | 63 | 64 | org.apache.clerezza 65 | rdf.ontologies 66 | 1.0.0 67 | jar 68 | 69 | 70 | org.apache.clerezza 71 | rdf.jena.commons 72 | 1.1.1 73 | 74 | 75 | org.apache.clerezza 76 | rdf.jena.sparql 77 | 1.1.1 78 | 79 | 80 | org.apache.clerezza 81 | rdf.jena.serializer 82 | 1.1.1 83 | 84 | 85 | 86 | 87 | executable 88 | 89 | false 90 | 91 | 92 | 93 | 94 | org.apache.maven.plugins 95 | maven-shade-plugin 96 | 1.6 97 | 98 | true 99 | 100 | 101 | *:* 102 | 103 | META-INF/*.SF 104 | META-INF/*.DSA 105 | META-INF/*.RSA 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | package 114 | 115 | shade 116 | 117 | 118 | 119 | 120 | 121 | 122 | io.synapta.jarql.JarqlExecutor 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | -------------------------------------------------------------------------------- /src/main/java/solutions/linked/jarql/JarqlExecutor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright 2017 user. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | package solutions.linked.jarql; 25 | 26 | import com.hp.hpl.jena.rdf.model.Model; 27 | import com.hp.hpl.jena.rdf.model.ModelFactory; 28 | import java.io.InputStream; 29 | import org.apache.clerezza.commons.rdf.Graph; 30 | import org.apache.clerezza.commons.rdf.impl.utils.simple.SimpleGraph; 31 | import org.apache.clerezza.rdf.jena.facade.JenaGraph; 32 | import com.hp.hpl.jena.query.Query; 33 | import com.hp.hpl.jena.query.QueryExecution; 34 | import com.hp.hpl.jena.query.QueryExecutionFactory; 35 | import com.hp.hpl.jena.query.QueryFactory; 36 | import static solutions.linked.jarql.JarqlParser.parse; 37 | import java.io.BufferedReader; 38 | import java.io.File; 39 | import java.io.FileInputStream; 40 | import java.io.FileNotFoundException; 41 | import java.io.InputStreamReader; 42 | import java.util.stream.Collectors; 43 | import org.apache.clerezza.rdf.core.serializedform.Serializer; 44 | import org.apache.clerezza.rdf.jena.storage.JenaGraphAdaptor; 45 | 46 | /** 47 | * 48 | * @author user 49 | */ 50 | public class JarqlExecutor { 51 | 52 | /** 53 | * @param args the command line arguments 54 | */ 55 | 56 | public static void main(String[] args) throws FileNotFoundException { 57 | final String jsonFileName = args[0]; 58 | final File jsonFile = new File(jsonFileName); 59 | if (!jsonFile.exists()) { 60 | System.err.println("File " + jsonFileName + " does not exist"); 61 | System.exit(-1); 62 | } 63 | final FileInputStream jsonIn = new FileInputStream(jsonFile); 64 | final String queryFileName = args[1]; 65 | final File queryFile = new File(queryFileName); 66 | if (!queryFile.exists()) { 67 | System.err.println("File " + queryFileName + " does not exist"); 68 | System.exit(-1); 69 | } 70 | final FileInputStream queryIn = new FileInputStream(queryFile); 71 | String queryString = new BufferedReader(new InputStreamReader(queryIn)).lines().collect(Collectors.joining("\n")); 72 | Graph graph = execute(jsonIn, queryString); 73 | Serializer.getInstance().serialize(System.out, graph, "text/turtle"); 74 | } 75 | 76 | 77 | static public Graph execute(final InputStream in, final String queryString) { 78 | Graph JsonGraph = new SimpleGraph(); 79 | JarqlParser.parse(in, JsonGraph); 80 | JenaGraph jg = new JenaGraph(JsonGraph); 81 | Model model = ModelFactory.createModelForGraph(jg); 82 | Query query = QueryFactory.create(queryString); 83 | try (QueryExecution qexec = QueryExecutionFactory.create(query, model)) { 84 | Model results = qexec.execConstruct(); 85 | return new JenaGraphAdaptor(results.getGraph()); 86 | } 87 | 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/main/java/solutions/linked/jarql/JarqlParser.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright 2016 Zazuko GmbH. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | package solutions.linked.jarql; 25 | 26 | import java.io.InputStream; 27 | import java.io.OutputStream; 28 | import java.io.OutputStreamWriter; 29 | import java.io.PrintWriter; 30 | import java.io.UnsupportedEncodingException; 31 | import java.nio.charset.Charset; 32 | import java.util.HashMap; 33 | import java.util.Map; 34 | import java.util.WeakHashMap; 35 | import java.util.function.Consumer; 36 | import javax.json.Json; 37 | import javax.json.stream.JsonParser; 38 | import javax.json.stream.JsonParser.Event; 39 | import javax.json.stream.JsonParserFactory; 40 | import org.apache.clerezza.commons.rdf.BlankNode; 41 | import org.apache.clerezza.commons.rdf.BlankNodeOrIRI; 42 | import org.apache.clerezza.commons.rdf.Graph; 43 | import org.apache.clerezza.commons.rdf.IRI; 44 | import org.apache.clerezza.commons.rdf.Literal; 45 | import org.apache.clerezza.commons.rdf.RDFTerm; 46 | import org.apache.clerezza.commons.rdf.Triple; 47 | import org.apache.clerezza.commons.rdf.impl.utils.PlainLiteralImpl; 48 | import org.apache.clerezza.commons.rdf.impl.utils.TripleImpl; 49 | import org.apache.clerezza.commons.rdf.impl.utils.TypedLiteralImpl; 50 | import org.apache.clerezza.rdf.ontologies.RDF; 51 | import org.apache.clerezza.rdf.ontologies.XSD; 52 | 53 | /** 54 | * 55 | * @author user 56 | */ 57 | public class JarqlParser { 58 | 59 | final String prefix = "http://jarql.com/"; 60 | final IRI ROOT = new IRI(prefix+"root"); 61 | final IRI ROOT_TYPE = new IRI(prefix+"Root"); 62 | 63 | 64 | 65 | static void parse(final InputStream in, final OutputStream out) { 66 | final PrintWriter printWriter; 67 | try { 68 | printWriter = new PrintWriter(new OutputStreamWriter(out, "utf-8"), true); 69 | } catch (UnsupportedEncodingException ex) { 70 | throw new RuntimeException(ex); 71 | } 72 | parse(in, new TripleSink() { 73 | 74 | final WeakHashMap node2IdMap = new WeakHashMap<>(); 75 | int idCounter = 1; 76 | 77 | @Override 78 | public void add(Triple triple) { 79 | printWriter.println(toNT(triple)); 80 | } 81 | 82 | private String toNT(Triple triple) { 83 | return toNT(triple.getSubject()) + " " + toNT(triple.getPredicate()) + " " + toNT(triple.getObject()) + "."; 84 | } 85 | 86 | private String toNT(Literal literal) { 87 | //TODO real impl 88 | return literal.toString(); 89 | } 90 | 91 | private String toNT(IRI iri) { 92 | //TODO real impl 93 | return iri.toString(); 94 | } 95 | 96 | private String toNT(BlankNode node) { 97 | String id = node2IdMap.get(node); 98 | if (id == null) { 99 | id = Integer.toString(idCounter); 100 | idCounter++; 101 | node2IdMap.put(node, id); 102 | } 103 | return "_:" + id; 104 | } 105 | 106 | private String toNT(RDFTerm node) { 107 | if (node instanceof Literal) { 108 | return toNT((Literal) node); 109 | } else { 110 | return toNT((BlankNodeOrIRI) node); 111 | } 112 | } 113 | 114 | private String toNT(BlankNodeOrIRI node) { 115 | if (node instanceof IRI) { 116 | return toNT((IRI) node); 117 | } else { 118 | return toNT((BlankNode) node); 119 | } 120 | } 121 | }); 122 | } 123 | 124 | static void parse(final InputStream in, final Graph graph) { 125 | parse(in, new TripleSink() { 126 | @Override 127 | public void add(Triple triple) { 128 | graph.add(triple); 129 | } 130 | 131 | }); 132 | } 133 | 134 | static void parse(InputStream in, TripleSink sink) { 135 | final JsonParserFactory factory = Json.createParserFactory(null); 136 | final JsonParser jsonParser = factory.createParser(in, Charset.forName("utf-8")); 137 | JarqlParser jsonLdParser = new JarqlParser(jsonParser, sink); 138 | jsonLdParser.parse(); 139 | } 140 | 141 | private final JsonParser jsonParser; 142 | private final TripleSink sink; 143 | private final Map label2bnodeMap = new HashMap<>(); 144 | 145 | private JarqlParser(JsonParser jsonParser, TripleSink sink) { 146 | this.jsonParser = jsonParser; 147 | this.sink = sink; 148 | } 149 | 150 | private void parse() { 151 | final Event firstEvent = jsonParser.next(); 152 | switch (firstEvent) { 153 | case START_OBJECT: { 154 | parseRootJsonObject(); 155 | break; 156 | } 157 | case START_ARRAY: { 158 | parseRootJsonArray(); 159 | break; 160 | } 161 | default: { 162 | throw new RuntimeException("Document should start with object: " + firstEvent); 163 | } 164 | } 165 | } 166 | 167 | private void parseRootJsonObject() { 168 | parseJsonObject(ROOT); 169 | sink.add(new TripleImpl(ROOT, RDF.type, ROOT_TYPE)); 170 | } 171 | 172 | private void parseRootJsonArray() { 173 | parseJsonArray(object -> { 174 | if (object instanceof Literal) { 175 | throw new RuntimeException("Elements of root array must not be literal"); 176 | } 177 | sink.add(new TripleImpl((BlankNodeOrIRI) object, RDF.type, ROOT_TYPE)); 178 | }); 179 | } 180 | 181 | 182 | 183 | 184 | public void parseJsonObject(BlankNodeOrIRI subject) { 185 | ALLKEYS: while(true) { 186 | JsonParser.Event event = jsonParser.next(); 187 | if (event == Event.END_OBJECT) { 188 | break ALLKEYS; 189 | } 190 | if (!event.equals(JsonParser.Event.KEY_NAME)) { 191 | throw new RuntimeException("Sorry: " + event+ jsonParser.getString()); 192 | } 193 | String key = jsonParser.getString(); 194 | final IRI predicate = new IRI(prefix + key); 195 | final Event next = jsonParser.next(); 196 | switch (next) { 197 | case VALUE_STRING: 198 | case VALUE_NUMBER: { 199 | final String value = jsonParser.getString(); 200 | final Literal literal = new PlainLiteralImpl(value); 201 | sink.add(new TripleImpl(subject, predicate, literal)); 202 | break; 203 | } 204 | case VALUE_TRUE: { 205 | final Literal literal = new TypedLiteralImpl("true", XSD.boolean_); 206 | sink.add(new TripleImpl(subject, predicate, literal)); 207 | break; 208 | } 209 | case VALUE_FALSE: { 210 | final Literal literal = new TypedLiteralImpl("false", XSD.boolean_); 211 | sink.add(new TripleImpl(subject, predicate, literal)); 212 | break; 213 | } 214 | case START_ARRAY: { 215 | //new JsonArrayParser(subject, predicate); 216 | parseJsonArray(object -> sink.add(new TripleImpl(subject, predicate, object))); 217 | break; 218 | } 219 | case START_OBJECT: { 220 | final BlankNode object = new BlankNode(); 221 | sink.add(new TripleImpl(subject, predicate, object)); 222 | parseJsonObject(object); 223 | break; 224 | } 225 | case VALUE_NULL: { 226 | break; 227 | } 228 | default: { 229 | throw new RuntimeException("Not supported here: " + next); 230 | } 231 | } 232 | } 233 | } 234 | 235 | 236 | 237 | private void parseJsonArray(Consumer elementProcessor) { 238 | ARRAY: while (true) { 239 | JsonParser.Event element = jsonParser.next(); 240 | switch (element) { 241 | case VALUE_STRING: 242 | case VALUE_NUMBER: { 243 | final String value = jsonParser.getString(); 244 | final Literal literal = new PlainLiteralImpl(value); 245 | elementProcessor.accept(literal); 246 | break; 247 | } 248 | case START_ARRAY: { 249 | throw new RuntimeException("We don't know what to do with nested arrays"); 250 | } 251 | case START_OBJECT: { 252 | final BlankNode object = new BlankNode(); 253 | elementProcessor.accept(object); 254 | parseJsonObject(object); 255 | break; 256 | } 257 | case END_ARRAY: { 258 | break ARRAY; 259 | } 260 | default: { 261 | throw new RuntimeException("Not supported here: " + element); 262 | } 263 | } 264 | } 265 | } 266 | } 267 | -------------------------------------------------------------------------------- /src/main/java/solutions/linked/jarql/TripleSink.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright 2016 Zazuko GmbH. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | package solutions.linked.jarql; 25 | 26 | import org.apache.clerezza.commons.rdf.Triple; 27 | 28 | /** 29 | * 30 | * @author user 31 | */ 32 | public interface TripleSink { 33 | void add(Triple triple); 34 | } 35 | -------------------------------------------------------------------------------- /src/test/java/solutions/linked/jarql/ParserTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright 2016 user. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | package solutions.linked.jarql; 25 | 26 | 27 | import solutions.linked.jarql.JarqlExecutor; 28 | import solutions.linked.jarql.JarqlParser; 29 | import java.io.BufferedReader; 30 | import java.io.ByteArrayInputStream; 31 | import java.io.ByteArrayOutputStream; 32 | import java.io.IOException; 33 | import java.io.InputStream; 34 | import java.io.InputStreamReader; 35 | import java.util.stream.Collectors; 36 | import org.apache.clerezza.commons.rdf.Graph; 37 | import org.apache.clerezza.commons.rdf.IRI; 38 | import org.apache.clerezza.commons.rdf.ImmutableGraph; 39 | import org.apache.clerezza.commons.rdf.impl.utils.simple.SimpleGraph; 40 | import org.apache.clerezza.rdf.core.serializedform.Parser; 41 | import org.apache.clerezza.rdf.core.serializedform.SupportedFormat; 42 | import org.junit.After; 43 | import org.junit.AfterClass; 44 | import org.junit.Assert; 45 | import org.junit.Before; 46 | import org.junit.BeforeClass; 47 | import org.junit.Test; 48 | import static org.junit.Assert.*; 49 | 50 | /** 51 | * 52 | * @author user 53 | */ 54 | public class ParserTest { 55 | 56 | public ParserTest() { 57 | } 58 | 59 | @BeforeClass 60 | public static void setUpClass() { 61 | } 62 | 63 | @AfterClass 64 | public static void tearDownClass() { 65 | } 66 | 67 | @Before 68 | public void setUp() { 69 | } 70 | 71 | @After 72 | public void tearDown() { 73 | } 74 | static void testFromResource(String baseName, boolean checkRaw) throws Exception { 75 | testFromResource(baseName, checkRaw, true); 76 | } 77 | static void testFromResource(String baseName, boolean checkRaw, boolean checkFinal) throws Exception { 78 | final Parser parser = Parser.getInstance(); 79 | final ImmutableGraph expectedJsonGraph; 80 | if (checkRaw) { 81 | final InputStream jsonGraphTurtle = ParserTest.class.getResourceAsStream(baseName+"_raw.ttl"); 82 | expectedJsonGraph = parser.parse(jsonGraphTurtle, SupportedFormat.TURTLE); 83 | } else { 84 | expectedJsonGraph = null; 85 | } 86 | 87 | 88 | 89 | final ImmutableGraph expectedFinalGraph; 90 | final String queryString; 91 | if (checkFinal) { 92 | final InputStream queryStream = ParserTest.class.getResourceAsStream(baseName+".query"); 93 | queryString = new BufferedReader(new InputStreamReader(queryStream)).lines().collect(Collectors.joining("\n")); 94 | final InputStream finalGraphTurtle = ParserTest.class.getResourceAsStream(baseName+".ttl"); 95 | expectedFinalGraph = parser.parse(finalGraphTurtle, SupportedFormat.TURTLE); 96 | } else { 97 | queryString = null; 98 | expectedFinalGraph = null; 99 | } 100 | 101 | testFromResource(baseName+".json", expectedJsonGraph, expectedFinalGraph, queryString); 102 | } 103 | static void testFromResource(String fileName, ImmutableGraph expectedJsonGRaph, ImmutableGraph expectedFinalGraph, String queryString ) throws Exception { 104 | final InputStream inJson = ParserTest.class.getResourceAsStream(fileName); 105 | final Graph graph = new SimpleGraph(); 106 | JarqlParser.parse(inJson, graph); 107 | final ImmutableGraph result = graph.getImmutableGraph(); 108 | if (expectedJsonGRaph != null) { 109 | Assert.assertEquals("JsonGraph wrong", expectedJsonGRaph, result); 110 | } 111 | if (queryString != null) { 112 | final InputStream inJsonAgain = ParserTest.class.getResourceAsStream(fileName); 113 | Graph executorResultGraph = JarqlExecutor.execute(inJsonAgain, queryString); 114 | final ImmutableGraph resultExecutor = executorResultGraph.getImmutableGraph(); 115 | Assert.assertEquals("ResultGraph wrong", expectedFinalGraph, resultExecutor); 116 | } 117 | } 118 | 119 | @Test 120 | public void paperino() throws Exception { 121 | testFromResource("paperino", true); 122 | } 123 | @Test 124 | public void contratto() throws Exception { 125 | testFromResource("contratto", true); 126 | } 127 | 128 | @Test 129 | public void array() throws Exception { 130 | testFromResource("array", false); 131 | } 132 | 133 | @Test 134 | public void number() throws Exception { 135 | testFromResource("number", false); 136 | } 137 | 138 | @Test 139 | public void booleanValue() throws Exception { 140 | testFromResource("boolean", true, false); 141 | } 142 | 143 | @Test 144 | public void jsonNull() throws Exception { 145 | testFromResource("null", true, false); 146 | } 147 | 148 | @Test 149 | public void numberArray() throws Exception { 150 | testFromResource("number-array", true, false); 151 | } 152 | 153 | } 154 | -------------------------------------------------------------------------------- /src/test/resources/solutions/linked/jarql/array.json: -------------------------------------------------------------------------------- 1 | [{"name":"alessio"}, {"name":"davide"}] -------------------------------------------------------------------------------- /src/test/resources/solutions/linked/jarql/array.query: -------------------------------------------------------------------------------- 1 | prefix : 2 | prefix jarql: 3 | 4 | construct { [] :name ?n} 5 | where { 6 | ?root a jarql:Root. 7 | ?root jarql:name ?n. 8 | } 9 | 10 | -------------------------------------------------------------------------------- /src/test/resources/solutions/linked/jarql/array.ttl: -------------------------------------------------------------------------------- 1 | [] "alessio" . 2 | [] "davide" . 3 | -------------------------------------------------------------------------------- /src/test/resources/solutions/linked/jarql/boolean.json: -------------------------------------------------------------------------------- 1 | { 2 | "cool": false, 3 | "hot": true 4 | } 5 | -------------------------------------------------------------------------------- /src/test/resources/solutions/linked/jarql/boolean_raw.ttl: -------------------------------------------------------------------------------- 1 | @prefix jarql: . 2 | jarql:root a jarql:Root; 3 | jarql:cool false; 4 | jarql:hot true. 5 | -------------------------------------------------------------------------------- /src/test/resources/solutions/linked/jarql/contratto.json: -------------------------------------------------------------------------------- 1 | { 2 | "cig": "XXXX4A36A7", 3 | "strutturaProponente": { 4 | "codiceFiscaleProp": "01111111111", 5 | "denominazione": "Comune di Paperopoli" 6 | }, 7 | "oggetto": "Costruzione di un grande deposito su una collina.", 8 | "partecipanti": [ 9 | { 10 | "ragioneSociale": "OCOPOLI COSTRUZIONI S.R.L.", 11 | "vatID": "42424242424" 12 | }, 13 | { 14 | "ragioneSociale": "DE PAPERONI S.P.A.", 15 | "vatID": "23232323232" 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /src/test/resources/solutions/linked/jarql/contratto.query: -------------------------------------------------------------------------------- 1 | prefix rdfs: 2 | prefix dcterm: 3 | prefix pc: 4 | prefix jarql: 5 | 6 | CONSTRUCT { 7 | ?URI a "Contract"; 8 | dcterm:identifier ?cig; 9 | pc:contractingAuth ?URIpa; 10 | rdfs:label ?oggetto. 11 | ?URIpa a "PubAdmin"; 12 | rdfs:label ?denominazione; 13 | dcterm:identifier ?codiceFiscaleProp. 14 | ?URIpart a "Participant"; 15 | rdfs:label ?ragioneSocialePart; 16 | dcterm:identifier ?vatIDPart. 17 | } 18 | WHERE { 19 | jarql:root jarql:cig ?cig. 20 | BIND(URI(CONCAT("http://test.yo/", MD5(?cig))) as ?URI). 21 | jarql:root jarql:strutturaProponente ?proponente. 22 | ?proponente jarql:codiceFiscaleProp ?codiceFiscaleProp. 23 | ?proponente jarql:denominazione ?denominazione. 24 | BIND(URI(CONCAT("http://test.yo/", MD5(?codiceFiscaleProp))) as ?URIpa). 25 | jarql:root jarql:oggetto ?oggetto. 26 | jarql:root jarql:partecipanti ?partecipanti. 27 | ?partecipanti jarql:ragioneSociale ?ragioneSocialePart. 28 | ?partecipanti jarql:vatID ?vatIDPart. 29 | BIND(URI(CONCAT("http://test.yo/", MD5(?vatIDPart))) as ?URIpart). 30 | } 31 | -------------------------------------------------------------------------------- /src/test/resources/solutions/linked/jarql/contratto.ttl: -------------------------------------------------------------------------------- 1 | 2 | a "Participant"^^ ; 3 | 4 | "DE PAPERONI S.P.A."^^ ; 5 | 6 | "23232323232"^^ . 7 | 8 | 9 | a "PubAdmin"^^ ; 10 | 11 | "Comune di Paperopoli"^^ ; 12 | 13 | "01111111111"^^ . 14 | 15 | 16 | a "Participant"^^ ; 17 | 18 | "OCOPOLI COSTRUZIONI S.R.L."^^ ; 19 | 20 | "42424242424"^^ . 21 | 22 | 23 | a "Contract"^^ ; 24 | 25 | "Costruzione di un grande deposito su una collina."^^ ; 26 | 27 | ; 28 | 29 | "XXXX4A36A7"^^ . 30 | -------------------------------------------------------------------------------- /src/test/resources/solutions/linked/jarql/contratto_raw.ttl: -------------------------------------------------------------------------------- 1 | @prefix jarql: . 2 | jarql:root a jarql:Root; 3 | jarql:cig "XXXX4A36A7"; 4 | jarql:strutturaProponente [ 5 | jarql:codiceFiscaleProp "01111111111"; 6 | jarql:denominazione "Comune di Paperopoli" 7 | ]; 8 | jarql:oggetto "Costruzione di un grande deposito su una collina."; 9 | jarql:partecipanti [ 10 | jarql:ragioneSociale "OCOPOLI COSTRUZIONI S.R.L."; 11 | jarql:vatID "42424242424" 12 | ]; 13 | jarql:partecipanti [ 14 | jarql:ragioneSociale "DE PAPERONI S.P.A."; 15 | jarql:vatID "23232323232" 16 | ]. 17 | -------------------------------------------------------------------------------- /src/test/resources/solutions/linked/jarql/null.json: -------------------------------------------------------------------------------- 1 | { 2 | "EntityCod": "TRS-IT-SIC-07856", 3 | "Tel": null, 4 | "GeogAreaCod": "PA" 5 | } -------------------------------------------------------------------------------- /src/test/resources/solutions/linked/jarql/null_raw.ttl: -------------------------------------------------------------------------------- 1 | @prefix jarql: . 2 | jarql:root a jarql:Root; 3 | jarql:GeogAreaCod "PA"; 4 | jarql:EntityCod "TRS-IT-SIC-07856". -------------------------------------------------------------------------------- /src/test/resources/solutions/linked/jarql/number-array.json: -------------------------------------------------------------------------------- 1 | { 2 | "number":[ 3 | 219412 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /src/test/resources/solutions/linked/jarql/number-array_raw.ttl: -------------------------------------------------------------------------------- 1 | @prefix jarql: . 2 | jarql:root a jarql:Root; 3 | jarql:number "219412". 4 | -------------------------------------------------------------------------------- /src/test/resources/solutions/linked/jarql/number.json: -------------------------------------------------------------------------------- 1 | { 2 | "offset": 100 3 | } 4 | -------------------------------------------------------------------------------- /src/test/resources/solutions/linked/jarql/number.query: -------------------------------------------------------------------------------- 1 | prefix : 2 | prefix jarql: 3 | prefix xsd: 4 | 5 | construct { [] :value ?n} 6 | where { 7 | ?root a jarql:Root. 8 | ?root jarql:offset ?o. 9 | BIND(xsd:integer(?o) AS ?n) 10 | } -------------------------------------------------------------------------------- /src/test/resources/solutions/linked/jarql/number.ttl: -------------------------------------------------------------------------------- 1 | [] 100 . 2 | -------------------------------------------------------------------------------- /src/test/resources/solutions/linked/jarql/paperino.json: -------------------------------------------------------------------------------- 1 | 2 | { 3 | "parent": [{ 4 | "name": "Paperino", 5 | "children": ["Qui", "Quo", "Qua"], 6 | "fiance": {"name": "Paperina"} 7 | }, { 8 | "name": "Topolino", 9 | "children": ["Tip", "Tap", "Top"], 10 | "fiance": {"name": "Minnie"} 11 | }] 12 | } 13 | -------------------------------------------------------------------------------- /src/test/resources/solutions/linked/jarql/paperino.query: -------------------------------------------------------------------------------- 1 | prefix : 2 | prefix jarql: 3 | 4 | construct { ?p :name ?n; :child [:name ?cn].} 5 | where { 6 | jarql:root jarql:parent ?p. 7 | ?p jarql:name ?n. 8 | ?p jarql:children ?cn. 9 | } 10 | -------------------------------------------------------------------------------- /src/test/resources/solutions/linked/jarql/paperino.ttl: -------------------------------------------------------------------------------- 1 | _:AX2dX60d6858cX3aX159d0c9ace6X3aXX2dX7ffa _:AX2dX60d6858cX3aX159d0c9ace6X3aXX2dX7ff9 . 2 | _:AX2dX60d6858cX3aX159d0c9ace6X3aXX2dX7ffa _:AX2dX60d6858cX3aX159d0c9ace6X3aXX2dX7ff8 . 3 | _:AX2dX60d6858cX3aX159d0c9ace6X3aXX2dX7ffa _:AX2dX60d6858cX3aX159d0c9ace6X3aXX2dX7ff7 . 4 | _:AX2dX60d6858cX3aX159d0c9ace6X3aXX2dX7ffa "Paperino" . 5 | _:AX2dX60d6858cX3aX159d0c9ace6X3aXX2dX7ff9 "Qui" . 6 | _:AX2dX60d6858cX3aX159d0c9ace6X3aXX2dX7ff8 "Quo" . 7 | _:AX2dX60d6858cX3aX159d0c9ace6X3aXX2dX7ff7 "Qua" . 8 | _:AX2dX60d6858cX3aX159d0c9ace6X3aXX2dX7ff6 _:AX2dX60d6858cX3aX159d0c9ace6X3aXX2dX7ff5 . 9 | _:AX2dX60d6858cX3aX159d0c9ace6X3aXX2dX7ff6 _:AX2dX60d6858cX3aX159d0c9ace6X3aXX2dX7ff4 . 10 | _:AX2dX60d6858cX3aX159d0c9ace6X3aXX2dX7ff6 _:AX2dX60d6858cX3aX159d0c9ace6X3aXX2dX7ff3 . 11 | _:AX2dX60d6858cX3aX159d0c9ace6X3aXX2dX7ff6 "Topolino" . 12 | _:AX2dX60d6858cX3aX159d0c9ace6X3aXX2dX7ff5 "Tip" . 13 | _:AX2dX60d6858cX3aX159d0c9ace6X3aXX2dX7ff4 "Tap" . 14 | _:AX2dX60d6858cX3aX159d0c9ace6X3aXX2dX7ff3 "Top" . -------------------------------------------------------------------------------- /src/test/resources/solutions/linked/jarql/paperino_raw.ttl: -------------------------------------------------------------------------------- 1 | @prefix jarql: . 2 | jarql:root a jarql:Root; 3 | jarql:parent [ 4 | jarql:name "Paperino"; 5 | jarql:children "Qui", "Quo", "Qua"; 6 | jarql:fiance [jarql:name "Paperina"] 7 | ]; 8 | jarql:parent [ 9 | jarql:name "Topolino"; 10 | jarql:children "Tip", "Tap", "Top"; 11 | jarql:fiance [jarql:name "Minnie"] 12 | ]. 13 | 14 | --------------------------------------------------------------------------------