Add fn:jsonpath to evaluate a JSONPath expression on a value JSONPath: https://github.com/jayway/JsonPath
Project: http://git-wip-us.apache.org/repos/asf/marmotta/repo Commit: http://git-wip-us.apache.org/repos/asf/marmotta/commit/ac782081 Tree: http://git-wip-us.apache.org/repos/asf/marmotta/tree/ac782081 Diff: http://git-wip-us.apache.org/repos/asf/marmotta/diff/ac782081 Branch: refs/heads/ldp Commit: ac782081f8c5733b91a76d0d79895f07678e2b8d Parents: fa98d10 Author: Chris Beer <[email protected]> Authored: Wed Jun 4 13:46:32 2014 -0700 Committer: Chris Beer <[email protected]> Committed: Thu Jun 5 07:35:43 2014 -0700 ---------------------------------------------------------------------- libraries/ldpath/ldpath-core-bundle/pom.xml | 10 +- libraries/ldpath/ldpath-functions-json/pom.xml | 107 +++++++++++++++++++ .../model/functions/json/JsonPathFunction.java | 84 +++++++++++++++ ...rmotta.ldpath.api.functions.SelectorFunction | 1 + .../functions/json/JsonPathFunctionTest.java | 61 +++++++++++ .../src/test/resources/logback.xml | 27 +++++ .../ldpath/model/functions/json/data.n3 | 31 ++++++ libraries/ldpath/ldpath-ldquery-cli/pom.xml | 4 + .../ldpath/ldpath-template-linkeddata/pom.xml | 4 + libraries/ldpath/pom.xml | 1 + parent/pom.xml | 10 ++ 11 files changed, 339 insertions(+), 1 deletion(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/marmotta/blob/ac782081/libraries/ldpath/ldpath-core-bundle/pom.xml ---------------------------------------------------------------------- diff --git a/libraries/ldpath/ldpath-core-bundle/pom.xml b/libraries/ldpath/ldpath-core-bundle/pom.xml index fdf351f..893f1cd 100644 --- a/libraries/ldpath/ldpath-core-bundle/pom.xml +++ b/libraries/ldpath/ldpath-core-bundle/pom.xml @@ -75,6 +75,11 @@ <artifactId>ldpath-functions-xml</artifactId> <version>${project.version}</version> </dependency> + <dependency> + <groupId>org.apache.marmotta</groupId> + <artifactId>ldpath-functions-json</artifactId> + <version>${project.version}</version> + </dependency> </dependencies> @@ -94,6 +99,7 @@ NOTES: * jdom2 is required for using the ldpath-functions-xml * jsoup is required for using the ldpath-functions-html + * jsonpath is required for using the ldpath-functions-json --> <Import-Package> org.slf4j.*;version="[1.6,2)", @@ -101,6 +107,7 @@ ch.qos.logback.classic;resolution:=optional, org.jdom2.*;resolution:=optional, org.jsoup.*;resolution:=optional, + com.jayway.jsonpath.*;resolution:=optional, * </Import-Package> <_exportcontents> @@ -114,7 +121,8 @@ ldpath-core, ldpath-functions-collections, ldpath-functions-date, ldpath-functions-html, ldpath-functions-math, - ldpath-functions-text, ldpath-functions-xml + ldpath-functions-text, ldpath-functions-xml, + ldpath-functions-json </Embed-Dependency> </instructions> </configuration> http://git-wip-us.apache.org/repos/asf/marmotta/blob/ac782081/libraries/ldpath/ldpath-functions-json/pom.xml ---------------------------------------------------------------------- diff --git a/libraries/ldpath/ldpath-functions-json/pom.xml b/libraries/ldpath/ldpath-functions-json/pom.xml new file mode 100644 index 0000000..3c6ae66 --- /dev/null +++ b/libraries/ldpath/ldpath-functions-json/pom.xml @@ -0,0 +1,107 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <parent> + <groupId>org.apache.marmotta</groupId> + <artifactId>marmotta-parent</artifactId> + <version>3.3.0-SNAPSHOT</version> + <relativePath>../../../parent</relativePath> + </parent> + <modelVersion>4.0.0</modelVersion> + + <name>LDPath Functions: JSON</name> + <artifactId>ldpath-functions-json</artifactId> + <packaging>jar</packaging> + + <description>LDPath Functions for JSON content.</description> + + <dependencies> + <dependency> + <groupId>org.apache.marmotta</groupId> + <artifactId>ldpath-api</artifactId> + </dependency> + <dependency> + <groupId>org.apache.marmotta</groupId> + <artifactId>ldpath-core</artifactId> + </dependency> + <dependency> + <groupId>com.jayway.jsonpath</groupId> + <artifactId>json-path</artifactId> + </dependency> + + <dependency> + <groupId>org.apache.marmotta</groupId> + <artifactId>ldpath-core</artifactId> + <version>${project.version}</version> + <type>test-jar</type> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.apache.marmotta</groupId> + <artifactId>ldpath-backend-sesame</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.openrdf.sesame</groupId> + <artifactId>sesame-repository-sail</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.openrdf.sesame</groupId> + <artifactId>sesame-sail-memory</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.openrdf.sesame</groupId> + <artifactId>sesame-rio-n3</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>ch.qos.logback</groupId> + <artifactId>logback-classic</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.apache.commons</groupId> + <artifactId>commons-lang3</artifactId> + </dependency> + </dependencies> + + <build> + <pluginManagement> + <plugins> + <plugin> <!-- generate JRebel Configuration --> + <groupId>org.zeroturnaround</groupId> + <artifactId>jrebel-maven-plugin</artifactId> + <executions> + <execution> + <id>generate-rebel-xml</id> + <phase>process-resources</phase> + <goals> + <goal>generate</goal> + </goals> + </execution> + </executions> + <configuration> + <relativePath>../../../</relativePath> + <rootPath>$${rebel.root}</rootPath> + </configuration> + </plugin> + </plugins> + </pluginManagement> + <plugins> + <plugin> + <groupId>org.apache.rat</groupId> + <artifactId>apache-rat-plugin</artifactId> + <configuration> + <excludes> + <!-- No License-Header in META-INF/services --> + <exclude>src/main/resources/META-INF/services/*</exclude> + </excludes> + </configuration> + </plugin> + </plugins> + + </build> +</project> http://git-wip-us.apache.org/repos/asf/marmotta/blob/ac782081/libraries/ldpath/ldpath-functions-json/src/main/java/org/apache/marmotta/ldpath/model/functions/json/JsonPathFunction.java ---------------------------------------------------------------------- diff --git a/libraries/ldpath/ldpath-functions-json/src/main/java/org/apache/marmotta/ldpath/model/functions/json/JsonPathFunction.java b/libraries/ldpath/ldpath-functions-json/src/main/java/org/apache/marmotta/ldpath/model/functions/json/JsonPathFunction.java new file mode 100644 index 0000000..4e80ec8 --- /dev/null +++ b/libraries/ldpath/ldpath-functions-json/src/main/java/org/apache/marmotta/ldpath/model/functions/json/JsonPathFunction.java @@ -0,0 +1,84 @@ +package org.apache.marmotta.ldpath.model.functions.json; + +import com.jayway.jsonpath.JsonPath; +import org.apache.marmotta.ldpath.api.backend.RDFBackend; +import org.apache.marmotta.ldpath.api.functions.SelectorFunction; +import org.apache.marmotta.ldpath.model.transformers.StringTransformer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +public class JsonPathFunction<Node> extends SelectorFunction<Node> { + + private static final Logger log = LoggerFactory.getLogger(JsonPathFunction.class); + private final StringTransformer<Node> transformer = new StringTransformer<Node>(); + + @Override + protected String getLocalName() { + return "jsonpath"; + } + + @Override + public Collection<Node> apply(RDFBackend<Node> rdfBackend, Node context, @SuppressWarnings("unchecked") Collection<Node>... args) throws IllegalArgumentException { + + Set<String> jsonpaths = new HashSet<String>(); + for (Node jsonpath : args[0]) { + try { + jsonpaths.add(transformer.transform(rdfBackend,jsonpath, null)); + } catch (IllegalArgumentException iae) { + throw new IllegalArgumentException("First argument must not contain anything else than String-Literals!"); + } + } + + Iterator<Node> it; + if(args.length < 2){ + log.debug("Use context {} to execute jsonpaths {}",context,jsonpaths); + it = Collections.singleton(context).iterator(); + } else { + log.debug("execute jsonpaths {} on parsed parameters",jsonpaths); + it = org.apache.marmotta.ldpath.util.Collections.iterator(1,args); + } + + List<Node> result = new ArrayList<Node>(); + while (it.hasNext()) { + Node n = it.next(); + try { + for (String r : doFilter(transformer.transform(rdfBackend,n, null), jsonpaths)) { + result.add(rdfBackend.createLiteral(r)); + } + } catch (IOException e) { + // This should never happen, since validation is turned off. + } + } + + return result; + } + + private List<String> doFilter(String in, Set<String> jsonpaths) throws IOException { + List<String> result = new ArrayList<String>(); + + for (String jsonpath : jsonpaths) { + result.add(String.valueOf(JsonPath.read(in, jsonpath))); + } + + return result; + } + + @Override + public String getSignature() { + return "fn:json(json: String [, nodes: JsonPathList]) : LiteralList"; + } + + @Override + public String getDescription() { + return "Evaluate a JSONPath expression on either the value of the context node or the values of the nodes passed as arguments."; + } +} http://git-wip-us.apache.org/repos/asf/marmotta/blob/ac782081/libraries/ldpath/ldpath-functions-json/src/main/resources/META-INF/services/org.apache.marmotta.ldpath.api.functions.SelectorFunction ---------------------------------------------------------------------- diff --git a/libraries/ldpath/ldpath-functions-json/src/main/resources/META-INF/services/org.apache.marmotta.ldpath.api.functions.SelectorFunction b/libraries/ldpath/ldpath-functions-json/src/main/resources/META-INF/services/org.apache.marmotta.ldpath.api.functions.SelectorFunction new file mode 100644 index 0000000..64c8f37 --- /dev/null +++ b/libraries/ldpath/ldpath-functions-json/src/main/resources/META-INF/services/org.apache.marmotta.ldpath.api.functions.SelectorFunction @@ -0,0 +1 @@ +org.apache.marmotta.ldpath.model.functions.json.JsonPathFunction \ No newline at end of file http://git-wip-us.apache.org/repos/asf/marmotta/blob/ac782081/libraries/ldpath/ldpath-functions-json/src/test/java/org/apache/marmotta/ldpath/model/functions/json/JsonPathFunctionTest.java ---------------------------------------------------------------------- diff --git a/libraries/ldpath/ldpath-functions-json/src/test/java/org/apache/marmotta/ldpath/model/functions/json/JsonPathFunctionTest.java b/libraries/ldpath/ldpath-functions-json/src/test/java/org/apache/marmotta/ldpath/model/functions/json/JsonPathFunctionTest.java new file mode 100644 index 0000000..923e944 --- /dev/null +++ b/libraries/ldpath/ldpath-functions-json/src/test/java/org/apache/marmotta/ldpath/model/functions/json/JsonPathFunctionTest.java @@ -0,0 +1,61 @@ +package org.apache.marmotta.ldpath.model.functions.json; + +import com.google.common.collect.Lists; +import org.apache.marmotta.ldpath.model.fields.FieldMapping; +import org.apache.marmotta.ldpath.parser.LdPathParser; +import org.apache.marmotta.ldpath.parser.ParseException; +import org.apache.marmotta.ldpath.test.AbstractTestBase; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.openrdf.model.URI; +import org.openrdf.model.Value; +import org.openrdf.repository.RepositoryException; +import org.openrdf.rio.RDFFormat; +import org.openrdf.rio.RDFParseException; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + + +@RunWith(Parameterized.class) +public class JsonPathFunctionTest extends AbstractTestBase { + + @Parameterized.Parameters(name = "{1}") + public static List<String[]> data() { + ArrayList<String[]> data = new ArrayList<String[]>(); + data.add(new String[] { "$.string", "stringValue" }); + data.add(new String[] { "$.int", "0" }); + data.add(new String[] { "$..child[0]", "a" }); + data.add(new String[] { "$.array", "[{\"child\":\"a\"},{\"child\":\"b\"}]" }); + data.add(new String[] { "$..child", "[\"a\",\"b\"]" }); + return data; + } + + @Parameterized.Parameter + public String path; + @Parameterized.Parameter(1) + public String answer; + + @Before + public void loadData() throws RepositoryException, RDFParseException, IOException { + super.loadData("data.n3", RDFFormat.N3); + } + + @Test + public void testJsonPathFunction() throws ParseException { + + final URI ctx = repository.getValueFactory().createURI(NSS.get("ex") + "Quiz"); + + final LdPathParser<Value> parser = createParserFromString("fn:jsonpath(\"" + path + "\", <http://www.w3.org/2011/content#chars>) :: xsd:string"); + final FieldMapping<Object, Value> rule = parser.parseRule(NSS); + final Collection<Object> values = rule.getValues(backend, ctx); + + Assert.assertEquals(1, values.size()); + Assert.assertEquals(answer, values.iterator().next()); + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/marmotta/blob/ac782081/libraries/ldpath/ldpath-functions-json/src/test/resources/logback.xml ---------------------------------------------------------------------- diff --git a/libraries/ldpath/ldpath-functions-json/src/test/resources/logback.xml b/libraries/ldpath/ldpath-functions-json/src/test/resources/logback.xml new file mode 100644 index 0000000..1bfecff --- /dev/null +++ b/libraries/ldpath/ldpath-functions-json/src/test/resources/logback.xml @@ -0,0 +1,27 @@ +<!-- + ~ 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. + --> + +<configuration> + <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"> + <encoder> + <pattern>%d{HH:mm:ss.SSS} %highlight(%level) %cyan(%logger{15}) - %m%n</pattern> + </encoder> + </appender> + <root level="${root-level:-INFO}"> + <appender-ref ref="CONSOLE"/> + </root> +</configuration> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/marmotta/blob/ac782081/libraries/ldpath/ldpath-functions-json/src/test/resources/org/apache/marmotta/ldpath/model/functions/json/data.n3 ---------------------------------------------------------------------- diff --git a/libraries/ldpath/ldpath-functions-json/src/test/resources/org/apache/marmotta/ldpath/model/functions/json/data.n3 b/libraries/ldpath/ldpath-functions-json/src/test/resources/org/apache/marmotta/ldpath/model/functions/json/data.n3 new file mode 100644 index 0000000..bfeec91 --- /dev/null +++ b/libraries/ldpath/ldpath-functions-json/src/test/resources/org/apache/marmotta/ldpath/model/functions/json/data.n3 @@ -0,0 +1,31 @@ +# +# 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. +# +@prefix ex: <http://www.example.com/> . +@prefix cnt: <http://www.w3.org/2011/content#> . + +ex:Quiz a ex:Test, cnt:ContentAsText; + cnt:chars """ + { + "string": "stringValue", + "int": 0, + "array": [ + { "child": "a" }, + { "child": "b" } + ] + } + """ . http://git-wip-us.apache.org/repos/asf/marmotta/blob/ac782081/libraries/ldpath/ldpath-ldquery-cli/pom.xml ---------------------------------------------------------------------- diff --git a/libraries/ldpath/ldpath-ldquery-cli/pom.xml b/libraries/ldpath/ldpath-ldquery-cli/pom.xml index a81d56a..63358d7 100644 --- a/libraries/ldpath/ldpath-ldquery-cli/pom.xml +++ b/libraries/ldpath/ldpath-ldquery-cli/pom.xml @@ -176,6 +176,10 @@ <artifactId>ldpath-functions-xml</artifactId> </dependency> <dependency> + <groupId>org.apache.marmotta</groupId> + <artifactId>ldpath-functions-json</artifactId> + </dependency> + <dependency> <groupId>org.apache.marmotta</groupId> <artifactId>ldpath-functions-math</artifactId> </dependency> http://git-wip-us.apache.org/repos/asf/marmotta/blob/ac782081/libraries/ldpath/ldpath-template-linkeddata/pom.xml ---------------------------------------------------------------------- diff --git a/libraries/ldpath/ldpath-template-linkeddata/pom.xml b/libraries/ldpath/ldpath-template-linkeddata/pom.xml index bef5b39..1e8845f 100644 --- a/libraries/ldpath/ldpath-template-linkeddata/pom.xml +++ b/libraries/ldpath/ldpath-template-linkeddata/pom.xml @@ -118,6 +118,10 @@ </dependency> <dependency> <groupId>org.apache.marmotta</groupId> + <artifactId>ldpath-functions-json</artifactId> + </dependency> + <dependency> + <groupId>org.apache.marmotta</groupId> <artifactId>ldpath-functions-math</artifactId> </dependency> <dependency> http://git-wip-us.apache.org/repos/asf/marmotta/blob/ac782081/libraries/ldpath/pom.xml ---------------------------------------------------------------------- diff --git a/libraries/ldpath/pom.xml b/libraries/ldpath/pom.xml index cb6a5c1..0e6b4a6 100644 --- a/libraries/ldpath/pom.xml +++ b/libraries/ldpath/pom.xml @@ -100,6 +100,7 @@ <module>ldpath-functions-text</module> <module>ldpath-functions-math</module> <module>ldpath-functions-date</module> + <module>ldpath-functions-json</module> <!-- <module>ldpath-backend-sparql</module> --> http://git-wip-us.apache.org/repos/asf/marmotta/blob/ac782081/parent/pom.xml ---------------------------------------------------------------------- diff --git a/parent/pom.xml b/parent/pom.xml index 2096480..b5196eb 100644 --- a/parent/pom.xml +++ b/parent/pom.xml @@ -1639,6 +1639,11 @@ <version>${project.version}</version> </dependency> <dependency> + <groupId>org.apache.marmotta</groupId> + <artifactId>ldpath-functions-json</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> <groupId>org.apache.marmotta</groupId> <artifactId>ldpath-functions-math</artifactId> <version>${project.version}</version> @@ -1663,6 +1668,11 @@ <artifactId>jsoup</artifactId> <version>1.7.2</version> </dependency> + <dependency> + <groupId>com.jayway.jsonpath</groupId> + <artifactId>json-path</artifactId> + <version>0.9.1</version> + </dependency> <dependency> <groupId>junit</groupId>
