Skip to content

Commit 51ee600

Browse files
author
Mark Hale
committed
Add JsonPath tuple function.
1 parent 284ecb7 commit 51ee600

9 files changed

Lines changed: 118 additions & 14 deletions

File tree

model/src/main/java/com/msd/gin/halyard/model/XMLLiteral.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,15 @@ protected DocumentBuilderFactory initialValue() {
5050
}
5151
};
5252

53+
public static Document asDocument(Literal l) throws ParserConfigurationException, SAXException, IOException {
54+
if (l instanceof XMLLiteral) {
55+
return ((XMLLiteral) l).objectValue();
56+
} else {
57+
String xml = l.getLabel();
58+
return parseXml(xml);
59+
}
60+
}
61+
5362
public static byte[] writeInfoset(Literal l) throws TransformerException {
5463
l = Wrapper.unwrap(l);
5564
if (l instanceof XMLLiteral) {

model/src/main/java/com/msd/gin/halyard/model/vocabulary/HALYARD.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,8 @@ public final class HALYARD implements Vocabulary {
138138

139139
public final static IRI XPATH_PROPERTY = SVF.createIRI(NAMESPACE, "xpath");
140140

141+
public final static IRI JSON_PATH_PROPERTY = SVF.createIRI(NAMESPACE, "jsonPath");
142+
141143
public final static IRI NON_STRING_TYPE = SVF.createIRI(NAMESPACE, "nonString");
142144

143145
public final static IRI ANY_NUMERIC_TYPE = SVF.createIRI(NAMESPACE, "anyNumeric");

pom.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
<logback.version>1.2.12</logback.version>
5252
<lz4.version>1.8.0</lz4.version>
5353
<icu4j.version>71.1</icu4j.version>
54+
<jsonpath.version>2.10.0</jsonpath.version>
5455
<junit4.version>4.13.2</junit4.version>
5556
<junit5.version>5.8.2</junit5.version>
5657
<assertj.version>3.24.2</assertj.version>

spin/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,11 @@
6161
<artifactId>rdf4j-rio-turtle</artifactId>
6262
<version>${rdf4j.version}</version>
6363
</dependency>
64+
<dependency>
65+
<groupId>com.jayway.jsonpath</groupId>
66+
<artifactId>json-path</artifactId>
67+
<version>${jsonpath.version}</version>
68+
</dependency>
6469

6570
<dependency>
6671
<groupId>junit</groupId>
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package com.msd.gin.halyard.spin.function.halyard;
2+
3+
import java.util.Collections;
4+
import java.util.List;
5+
6+
import org.eclipse.rdf4j.common.iteration.CloseableIteration;
7+
import org.eclipse.rdf4j.common.iteration.CloseableIteratorIteration;
8+
import org.eclipse.rdf4j.common.iteration.ConvertingIteration;
9+
import org.eclipse.rdf4j.model.Literal;
10+
import org.eclipse.rdf4j.model.Value;
11+
import org.eclipse.rdf4j.model.ValueFactory;
12+
import org.eclipse.rdf4j.query.QueryEvaluationException;
13+
import org.eclipse.rdf4j.query.algebra.evaluation.ValueExprEvaluationException;
14+
import org.eclipse.rdf4j.query.algebra.evaluation.function.TupleFunction;
15+
16+
import com.jayway.jsonpath.Configuration;
17+
import com.jayway.jsonpath.JsonPath;
18+
import com.jayway.jsonpath.Option;
19+
import com.msd.gin.halyard.model.MapLiteral;
20+
import com.msd.gin.halyard.model.vocabulary.HALYARD;
21+
import com.msd.gin.halyard.spin.function.InverseMagicProperty;
22+
23+
public class JsonPathTupleFunction implements TupleFunction, InverseMagicProperty {
24+
@Override
25+
public String getURI() {
26+
return HALYARD.JSON_PATH_PROPERTY.stringValue();
27+
}
28+
29+
@Override
30+
public CloseableIteration<? extends List<? extends Value>> evaluate(ValueFactory vf, Value... args) throws ValueExprEvaluationException {
31+
if (args.length != 2) {
32+
throw new ValueExprEvaluationException(String.format("%s requires 2 arguments, got %d", getURI(), args.length));
33+
}
34+
35+
if (!(args[0] instanceof Literal)) {
36+
throw new ValueExprEvaluationException("First argument must be a JsonPath string");
37+
}
38+
if (!MapLiteral.isMapLiteral(args[1])) {
39+
throw new ValueExprEvaluationException("Second argument must be a JSON literal");
40+
}
41+
42+
String path = args[0].stringValue();
43+
String json = args[1].stringValue();
44+
Configuration conf = Configuration.defaultConfiguration().addOptions(Option.DEFAULT_PATH_LEAF_TO_NULL, Option.ALWAYS_RETURN_LIST);
45+
46+
try {
47+
List<Object> result = JsonPath.using(conf).parse(json).read(path);
48+
return new ConvertingIteration<>(new CloseableIteratorIteration<>(result.iterator())) {
49+
@Override
50+
protected List<? extends Value> convert(Object s) {
51+
return Collections.singletonList(vf.createLiteral(result.toString()));
52+
}
53+
};
54+
} catch (Exception e) {
55+
throw new QueryEvaluationException(e);
56+
}
57+
}
58+
}

spin/src/main/java/com/msd/gin/halyard/spin/function/halyard/XPathTupleFunction.java

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -65,15 +65,9 @@ public CloseableIteration<? extends List<? extends Value>> evaluate(ValueFactory
6565
returnType = XPathConstants.STRING;
6666
}
6767

68-
String query = ((Literal) args[0]).stringValue();
68+
String query = args[0].stringValue();
6969
try {
70-
Document doc;
71-
if (args[1] instanceof XMLLiteral) {
72-
doc = ((XMLLiteral) args[1]).objectValue();
73-
} else {
74-
String xml = ((Literal) args[1]).getLabel();
75-
doc = XMLLiteral.parseXml(xml);
76-
}
70+
Document doc = XMLLiteral.asDocument((Literal) args[1]);
7771
XPathExpression xpe = XPATH_CACHE.get(query);
7872
Object result = xpe.evaluate(doc, returnType);
7973
LSSerializer serializer;
@@ -90,7 +84,7 @@ public CloseableIteration<? extends List<? extends Value>> evaluate(ValueFactory
9084
return new SingletonIteration<>(Collections.singletonList(vf.createLiteral(s)));
9185
} else if (result instanceof NodeList) {
9286
NodeList nl = (NodeList) result;
93-
return new CloseableIteration<List<? extends Value>>() {
87+
return new CloseableIteration<>() {
9488
int pos = 0;
9589

9690
@Override
@@ -125,7 +119,7 @@ public void close() throws QueryEvaluationException {
125119

126120
private static String serializeNode(Node n, LSSerializer serializer) {
127121
if (n instanceof Attr) {
128-
return ((Attr) n).getNodeValue();
122+
return n.getNodeValue();
129123
} else {
130124
return serializer.writeToString(n);
131125
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package com.msd.gin.halyard.spin.function.halyard;
2+
3+
import static org.junit.Assert.assertEquals;
4+
import static org.junit.Assert.assertFalse;
5+
import static org.junit.Assert.assertTrue;
6+
7+
import java.util.List;
8+
9+
import org.eclipse.rdf4j.common.iteration.CloseableIteration;
10+
import org.eclipse.rdf4j.model.Literal;
11+
import org.eclipse.rdf4j.model.Value;
12+
import org.eclipse.rdf4j.model.ValueFactory;
13+
import org.eclipse.rdf4j.model.impl.SimpleValueFactory;
14+
import org.junit.Test;
15+
16+
import com.msd.gin.halyard.model.MapLiteral;
17+
18+
public class JsonPathTupleFunctionTest {
19+
@Test
20+
public void testSimplePath() {
21+
ValueFactory vf = SimpleValueFactory.getInstance();
22+
String json = "{\"foo\":\"bar\"}";
23+
Literal l = new MapLiteral(json);
24+
String jsonPath = "$.foo";
25+
CloseableIteration<? extends List<? extends Value>> iter = new JsonPathTupleFunction().evaluate(vf, vf.createLiteral(jsonPath), l);
26+
assertTrue(iter.hasNext());
27+
assertEquals("[\"bar\"]", iter.next().get(0).stringValue());
28+
assertFalse(iter.hasNext());
29+
}
30+
}

spin/src/test/java/com/msd/gin/halyard/spin/function/halyard/XPathTupleFunctionTest.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
package com.msd.gin.halyard.spin.function.halyard;
22

3-
import com.msd.gin.halyard.model.XMLLiteral;
4-
import com.msd.gin.halyard.spin.function.halyard.XPathTupleFunction;
3+
import static org.junit.Assert.assertEquals;
4+
import static org.junit.Assert.assertFalse;
5+
import static org.junit.Assert.assertTrue;
56

67
import java.util.List;
78

@@ -12,10 +13,9 @@
1213
import org.eclipse.rdf4j.model.Value;
1314
import org.eclipse.rdf4j.model.ValueFactory;
1415
import org.eclipse.rdf4j.model.impl.SimpleValueFactory;
15-
import org.eclipse.rdf4j.query.QueryEvaluationException;
1616
import org.junit.Test;
1717

18-
import static org.junit.Assert.*;
18+
import com.msd.gin.halyard.model.XMLLiteral;
1919

2020
public class XPathTupleFunctionTest {
2121
@Test

webapps/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,11 @@
122122
<artifactId>icu4j</artifactId>
123123
<version>${icu4j.version}</version>
124124
</artifactItem>
125+
<artifactItem>
126+
<groupId>com.jayway.jsonpath</groupId>
127+
<artifactId>json-path</artifactId>
128+
<version>${jsonpath.version}</version>
129+
</artifactItem>
125130

126131
<!-- lang chain -->
127132
<artifactItem>

0 commit comments

Comments
 (0)