diff --git a/assembly-descriptors/pom.xml b/assembly-descriptors/pom.xml index 25b0b093889..9e0bf066314 100644 --- a/assembly-descriptors/pom.xml +++ b/assembly-descriptors/pom.xml @@ -4,7 +4,7 @@ org.eclipse.rdf4j rdf4j - 5.1.0-SNAPSHOT + 6.0.0 rdf4j-assembly-descriptors RDF4J: Assembly Descriptors diff --git a/assembly/pom.xml b/assembly/pom.xml index a88d567f0e5..45207243131 100644 --- a/assembly/pom.xml +++ b/assembly/pom.xml @@ -4,7 +4,7 @@ org.eclipse.rdf4j rdf4j - 5.1.0-SNAPSHOT + 6.0.0 rdf4j-assembly pom diff --git a/bom/pom.xml b/bom/pom.xml index 8056082ccc1..54634082b60 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -4,7 +4,7 @@ org.eclipse.rdf4j rdf4j - 5.1.0-SNAPSHOT + 6.0.0 rdf4j-bom pom diff --git a/compliance/elasticsearch/pom.xml b/compliance/elasticsearch/pom.xml index 794dacb7bd7..6e722a166ac 100644 --- a/compliance/elasticsearch/pom.xml +++ b/compliance/elasticsearch/pom.xml @@ -4,7 +4,7 @@ org.eclipse.rdf4j rdf4j-compliance - 5.1.0-SNAPSHOT + 6.0.0 rdf4j-elasticsearch-compliance RDF4J: Elasticsearch Sail Tests diff --git a/compliance/geosparql/pom.xml b/compliance/geosparql/pom.xml index 41e8785595b..9cf2d3b14a5 100644 --- a/compliance/geosparql/pom.xml +++ b/compliance/geosparql/pom.xml @@ -4,7 +4,7 @@ org.eclipse.rdf4j rdf4j-compliance - 5.1.0-SNAPSHOT + 6.0.0 rdf4j-geosparql-compliance RDF4J: GeoSPARQL compliance tests diff --git a/compliance/lucene/pom.xml b/compliance/lucene/pom.xml index dcf84054c6d..a34bab2b9d3 100644 --- a/compliance/lucene/pom.xml +++ b/compliance/lucene/pom.xml @@ -4,7 +4,7 @@ org.eclipse.rdf4j rdf4j-compliance - 5.1.0-SNAPSHOT + 6.0.0 rdf4j-lucene-compliance RDF4J: Lucene Sail Tests diff --git a/compliance/model/pom.xml b/compliance/model/pom.xml index 3d3ac105fa9..1b4cb28bac4 100644 --- a/compliance/model/pom.xml +++ b/compliance/model/pom.xml @@ -3,7 +3,7 @@ rdf4j-compliance org.eclipse.rdf4j - 5.1.0-SNAPSHOT + 6.0.0 4.0.0 rdf4j-model-compliance diff --git a/compliance/pom.xml b/compliance/pom.xml index 7a3f7a3e7ff..bb1ebf89a07 100644 --- a/compliance/pom.xml +++ b/compliance/pom.xml @@ -4,7 +4,7 @@ org.eclipse.rdf4j rdf4j - 5.1.0-SNAPSHOT + 6.0.0 rdf4j-compliance pom diff --git a/compliance/repository/pom.xml b/compliance/repository/pom.xml index 069ade53eec..363d69fcfb9 100644 --- a/compliance/repository/pom.xml +++ b/compliance/repository/pom.xml @@ -4,7 +4,7 @@ org.eclipse.rdf4j rdf4j-compliance - 5.1.0-SNAPSHOT + 6.0.0 rdf4j-repository-compliance war diff --git a/compliance/rio/pom.xml b/compliance/rio/pom.xml index 850062bf2f4..a2ec281a5a9 100644 --- a/compliance/rio/pom.xml +++ b/compliance/rio/pom.xml @@ -4,7 +4,7 @@ org.eclipse.rdf4j rdf4j-compliance - 5.1.0-SNAPSHOT + 6.0.0 rdf4j-rio-compliance RDF4J: Rio compliance tests diff --git a/compliance/solr/pom.xml b/compliance/solr/pom.xml index 454f5295ca6..e543a37c08f 100644 --- a/compliance/solr/pom.xml +++ b/compliance/solr/pom.xml @@ -4,7 +4,7 @@ org.eclipse.rdf4j rdf4j-compliance - 5.1.0-SNAPSHOT + 6.0.0 rdf4j-solr-compliance RDF4J: Solr Sail Tests diff --git a/compliance/sparql/pom.xml b/compliance/sparql/pom.xml index 3340661c18d..b4cb38040c5 100644 --- a/compliance/sparql/pom.xml +++ b/compliance/sparql/pom.xml @@ -4,7 +4,7 @@ org.eclipse.rdf4j rdf4j-compliance - 5.1.0-SNAPSHOT + 6.0.0 rdf4j-sparql-compliance war diff --git a/core/client/pom.xml b/core/client/pom.xml index 845360a26cc..069b2b7d02a 100644 --- a/core/client/pom.xml +++ b/core/client/pom.xml @@ -4,7 +4,7 @@ org.eclipse.rdf4j rdf4j-core - 5.1.0-SNAPSHOT + 6.0.0 rdf4j-client RDF4J: Client Libraries diff --git a/core/collection-factory/api/pom.xml b/core/collection-factory/api/pom.xml index 5ba6df646b7..686b4e35a8f 100644 --- a/core/collection-factory/api/pom.xml +++ b/core/collection-factory/api/pom.xml @@ -4,7 +4,7 @@ org.eclipse.rdf4j rdf4j-collection-factory - 5.1.0-SNAPSHOT + 6.0.0 rdf4j-collection-factory-api RDF4J: Collection Factory - API diff --git a/core/collection-factory/mapdb/pom.xml b/core/collection-factory/mapdb/pom.xml index c8e843b984e..950a7e0565c 100644 --- a/core/collection-factory/mapdb/pom.xml +++ b/core/collection-factory/mapdb/pom.xml @@ -4,7 +4,7 @@ org.eclipse.rdf4j rdf4j-collection-factory - 5.1.0-SNAPSHOT + 6.0.0 rdf4j-collection-factory-mapdb RDF4J: Collection Factory - Map DB backed diff --git a/core/collection-factory/mapdb3/pom.xml b/core/collection-factory/mapdb3/pom.xml index a00d4c8e811..948eda647db 100644 --- a/core/collection-factory/mapdb3/pom.xml +++ b/core/collection-factory/mapdb3/pom.xml @@ -4,7 +4,7 @@ org.eclipse.rdf4j rdf4j-collection-factory - 5.1.0-SNAPSHOT + 6.0.0 rdf4j-collection-factory-mapdb3 RDF4J: Collection Factory - Map DB v3 backed diff --git a/core/collection-factory/pom.xml b/core/collection-factory/pom.xml index bb1df7bb226..06e1189ccdd 100644 --- a/core/collection-factory/pom.xml +++ b/core/collection-factory/pom.xml @@ -4,7 +4,7 @@ org.eclipse.rdf4j rdf4j-core - 5.1.0-SNAPSHOT + 6.0.0 rdf4j-collection-factory pom diff --git a/core/common/annotation/pom.xml b/core/common/annotation/pom.xml index f5f53a65e21..323c0c765f4 100644 --- a/core/common/annotation/pom.xml +++ b/core/common/annotation/pom.xml @@ -4,7 +4,7 @@ org.eclipse.rdf4j rdf4j-common - 5.1.0-SNAPSHOT + 6.0.0 rdf4j-common-annotation RDF4J: common annotation diff --git a/core/common/exception/pom.xml b/core/common/exception/pom.xml index bbd533f1adf..4d0c1e766cb 100644 --- a/core/common/exception/pom.xml +++ b/core/common/exception/pom.xml @@ -4,7 +4,7 @@ org.eclipse.rdf4j rdf4j-common - 5.1.0-SNAPSHOT + 6.0.0 rdf4j-common-exception RDF4J: common exception diff --git a/core/common/io/pom.xml b/core/common/io/pom.xml index f99f7f2af4e..86bbfc4e6d7 100644 --- a/core/common/io/pom.xml +++ b/core/common/io/pom.xml @@ -4,7 +4,7 @@ org.eclipse.rdf4j rdf4j-common - 5.1.0-SNAPSHOT + 6.0.0 rdf4j-common-io RDF4J: common IO diff --git a/core/common/iterator/pom.xml b/core/common/iterator/pom.xml index c8b62012574..ab50ca506c7 100644 --- a/core/common/iterator/pom.xml +++ b/core/common/iterator/pom.xml @@ -4,7 +4,7 @@ org.eclipse.rdf4j rdf4j-common - 5.1.0-SNAPSHOT + 6.0.0 rdf4j-common-iterator RDF4J: common iterators diff --git a/core/common/order/pom.xml b/core/common/order/pom.xml index 5228081fc0e..4238bd7a1d5 100644 --- a/core/common/order/pom.xml +++ b/core/common/order/pom.xml @@ -4,7 +4,7 @@ org.eclipse.rdf4j rdf4j-common - 5.1.0-SNAPSHOT + 6.0.0 rdf4j-common-order RDF4J: common order diff --git a/core/common/pom.xml b/core/common/pom.xml index fc821867500..9be4c51f5ea 100644 --- a/core/common/pom.xml +++ b/core/common/pom.xml @@ -4,7 +4,7 @@ org.eclipse.rdf4j rdf4j-core - 5.1.0-SNAPSHOT + 6.0.0 rdf4j-common pom diff --git a/core/common/text/pom.xml b/core/common/text/pom.xml index f26391a3d11..3139efffa1a 100644 --- a/core/common/text/pom.xml +++ b/core/common/text/pom.xml @@ -4,7 +4,7 @@ org.eclipse.rdf4j rdf4j-common - 5.1.0-SNAPSHOT + 6.0.0 rdf4j-common-text RDF4J: common text diff --git a/core/common/transaction/pom.xml b/core/common/transaction/pom.xml index 2a327eba54c..ae85f069067 100644 --- a/core/common/transaction/pom.xml +++ b/core/common/transaction/pom.xml @@ -4,7 +4,7 @@ org.eclipse.rdf4j rdf4j-common - 5.1.0-SNAPSHOT + 6.0.0 rdf4j-common-transaction RDF4J: common transaction diff --git a/core/common/xml/pom.xml b/core/common/xml/pom.xml index 76184d6e127..d553cef99ae 100644 --- a/core/common/xml/pom.xml +++ b/core/common/xml/pom.xml @@ -4,7 +4,7 @@ org.eclipse.rdf4j rdf4j-common - 5.1.0-SNAPSHOT + 6.0.0 rdf4j-common-xml RDF4J: common XML diff --git a/core/http/client/pom.xml b/core/http/client/pom.xml index 8e26e6c8d3f..88b31cd6842 100644 --- a/core/http/client/pom.xml +++ b/core/http/client/pom.xml @@ -4,7 +4,7 @@ org.eclipse.rdf4j rdf4j-http - 5.1.0-SNAPSHOT + 6.0.0 rdf4j-http-client RDF4J: HTTP client diff --git a/core/http/pom.xml b/core/http/pom.xml index ee3e0261ad0..e9e452c4bc8 100644 --- a/core/http/pom.xml +++ b/core/http/pom.xml @@ -4,7 +4,7 @@ org.eclipse.rdf4j rdf4j-core - 5.1.0-SNAPSHOT + 6.0.0 rdf4j-http pom diff --git a/core/http/protocol/pom.xml b/core/http/protocol/pom.xml index a5d66a693e0..2c3d2393b54 100644 --- a/core/http/protocol/pom.xml +++ b/core/http/protocol/pom.xml @@ -4,7 +4,7 @@ org.eclipse.rdf4j rdf4j-http - 5.1.0-SNAPSHOT + 6.0.0 rdf4j-http-protocol RDF4J: HTTP protocol diff --git a/core/http/protocol/src/main/java/org/eclipse/rdf4j/http/protocol/transaction/TransactionSAXParser.java b/core/http/protocol/src/main/java/org/eclipse/rdf4j/http/protocol/transaction/TransactionSAXParser.java index db28082223c..a93d19b9ce6 100644 --- a/core/http/protocol/src/main/java/org/eclipse/rdf4j/http/protocol/transaction/TransactionSAXParser.java +++ b/core/http/protocol/src/main/java/org/eclipse/rdf4j/http/protocol/transaction/TransactionSAXParser.java @@ -34,7 +34,7 @@ import org.eclipse.rdf4j.query.Binding; import org.eclipse.rdf4j.query.impl.SimpleBinding; import org.eclipse.rdf4j.query.impl.SimpleDataset; -import org.eclipse.rdf4j.rio.helpers.RDFStarUtil; +import org.eclipse.rdf4j.rio.helpers.TripleTermUtil; import org.xml.sax.SAXException; /** @@ -83,7 +83,7 @@ public void startDocument() throws SAXException { public void startTag(String tagName, Map atts, String text) throws SAXException { if (TransactionXMLConstants.TRIPLE_TAG.equals(tagName)) { // fixes GH-3048 - parsedValues.add(RDFStarUtil.fromRDFEncodedValue(valueFactory.createIRI(text))); + parsedValues.add(TripleTermUtil.fromRDFEncodedValue(valueFactory.createIRI(text))); } else if (TransactionXMLConstants.URI_TAG.equals(tagName)) { parsedValues.add(valueFactory.createIRI(text)); } else if (TransactionXMLConstants.BNODE_TAG.equals(tagName)) { diff --git a/core/http/protocol/src/main/java/org/eclipse/rdf4j/http/protocol/transaction/TransactionWriter.java b/core/http/protocol/src/main/java/org/eclipse/rdf4j/http/protocol/transaction/TransactionWriter.java index 763b01fcc3c..1d97f331596 100644 --- a/core/http/protocol/src/main/java/org/eclipse/rdf4j/http/protocol/transaction/TransactionWriter.java +++ b/core/http/protocol/src/main/java/org/eclipse/rdf4j/http/protocol/transaction/TransactionWriter.java @@ -35,7 +35,7 @@ import org.eclipse.rdf4j.model.util.Literals; import org.eclipse.rdf4j.query.Binding; import org.eclipse.rdf4j.query.Dataset; -import org.eclipse.rdf4j.rio.helpers.RDFStarUtil; +import org.eclipse.rdf4j.rio.helpers.TripleTermUtil; /** * Serializes of an RDF transaction. @@ -242,6 +242,8 @@ protected void serialize(Value value, XMLWriter xmlWriter) throws IOException { serialize((Resource) value, xmlWriter); } else if (value instanceof Literal) { serialize((Literal) value, xmlWriter); + } else if (value instanceof Triple) { + serialize((Triple) value, xmlWriter); } else if (value == null) { serializeNull(xmlWriter); } else { @@ -254,8 +256,6 @@ protected void serialize(Resource resource, XMLWriter xmlWriter) throws IOExcept serialize((IRI) resource, xmlWriter); } else if (resource instanceof BNode) { serialize((BNode) resource, xmlWriter); - } else if (resource instanceof Triple) { - serialize((Triple) resource, xmlWriter); } else if (resource == null) { serializeNull(xmlWriter); } else { @@ -313,7 +313,7 @@ protected void serializeNull(XMLWriter xmlWriter) throws IOException { protected void serialize(Triple triple, XMLWriter xmlWriter) throws IOException { if (triple != null) { - Value convertBase64 = RDFStarUtil.toRDFEncodedValue(triple); + Value convertBase64 = TripleTermUtil.toRDFEncodedValue(triple); xmlWriter.textElement(TransactionXMLConstants.TRIPLE_TAG, convertBase64.stringValue()); } else { serializeNull(xmlWriter); diff --git a/core/http/protocol/src/test/java/org/eclipse/rdf4j/http/protocol/ProtocolTest.java b/core/http/protocol/src/test/java/org/eclipse/rdf4j/http/protocol/ProtocolTest.java index 88c695ce5ae..3b60d4d44c7 100644 --- a/core/http/protocol/src/test/java/org/eclipse/rdf4j/http/protocol/ProtocolTest.java +++ b/core/http/protocol/src/test/java/org/eclipse/rdf4j/http/protocol/ProtocolTest.java @@ -136,7 +136,7 @@ public void testDecodeContext() { assertEquals(vf.createBNode("bnode1"), Protocol.decodeContext("_:bnode1", vf)); assertEquals(vf.createIRI("urn:test"), Protocol.decodeContext("", vf)); - // RDF-star triples are resources but they can't be used as context values + // triples can't be used as context values try { Protocol.decodeContext("<< >>", SimpleValueFactory.getInstance()); fail("Must fail with exception"); diff --git a/core/model-api/pom.xml b/core/model-api/pom.xml index cf07e38798c..6cd60a61fbf 100644 --- a/core/model-api/pom.xml +++ b/core/model-api/pom.xml @@ -4,7 +4,7 @@ org.eclipse.rdf4j rdf4j-core - 5.1.0-SNAPSHOT + 6.0.0 rdf4j-model-api RDF4J: Model API diff --git a/core/model-api/src/main/java/org/eclipse/rdf4j/model/Literal.java b/core/model-api/src/main/java/org/eclipse/rdf4j/model/Literal.java index b261e76061c..a51c634327b 100644 --- a/core/model-api/src/main/java/org/eclipse/rdf4j/model/Literal.java +++ b/core/model-api/src/main/java/org/eclipse/rdf4j/model/Literal.java @@ -41,6 +41,36 @@ * @see XML Schema Definition Language (XSD) 1.1 Part 2: Datatypes */ public interface Literal extends Value { + String LTR_SUFFIX = "--ltr"; + String RTL_SUFFIX = "--rtl"; + String BASE_DIR_SEPARATOR = "--"; + + enum BaseDirection { + NONE(""), + LTR(LTR_SUFFIX), + RTL(RTL_SUFFIX); + + private final String suffix; + + BaseDirection(final String suffix) { + this.suffix = suffix; + } + + @Override + public String toString() { + return suffix; + } + + public static BaseDirection fromString(final String dir) { + if (dir == null || dir.isEmpty()) + return NONE; + if (dir.equals(LTR_SUFFIX)) + return LTR; + if (dir.equals(RTL_SUFFIX)) + return RTL; + throw new IllegalArgumentException("Unknown BaseDirection: " + dir); + } + } @Override default boolean isLiteral() { @@ -61,6 +91,10 @@ default boolean isLiteral() { */ Optional getLanguage(); + default BaseDirection getBaseDirection() { + return BaseDirection.NONE; + } + /** * Gets the datatype for this literal. *

diff --git a/core/model-api/src/main/java/org/eclipse/rdf4j/model/Triple.java b/core/model-api/src/main/java/org/eclipse/rdf4j/model/Triple.java index 29ad625bae7..5593d787306 100644 --- a/core/model-api/src/main/java/org/eclipse/rdf4j/model/Triple.java +++ b/core/model-api/src/main/java/org/eclipse/rdf4j/model/Triple.java @@ -13,8 +13,8 @@ import org.eclipse.rdf4j.common.annotation.Experimental; /** - * An RDF-star embedded triple. Embedded triples have a subject, predicate and object. Unlike {@link Statement}, a - * triple never has an associated context. + * An embedded triple. Embedded triples have a subject, predicate and object. Unlike {@link Statement}, a triple never + * has an associated context. *

* Additional utility functionality for working with {@code Triple} objects is available in the * {@link org.eclipse.rdf4j.model.util.Statements} and {@link org.eclipse.rdf4j.model.util.Values} utility classes. @@ -23,10 +23,9 @@ * @implNote In order to ensure interoperability of concrete classes implementing this interface, * {@link #equals(Object)} and {@link #hashCode()} methods must be implemented exactly as described in their * specs. - * @see RDF-star and SPARQL-star Draft Community Group Report */ @Experimental -public interface Triple extends Resource { +public interface Triple extends Value { @Override default boolean isTriple() { diff --git a/core/model-api/src/main/java/org/eclipse/rdf4j/model/ValueFactory.java b/core/model-api/src/main/java/org/eclipse/rdf4j/model/ValueFactory.java index 00441731e57..774433b0ce2 100644 --- a/core/model-api/src/main/java/org/eclipse/rdf4j/model/ValueFactory.java +++ b/core/model-api/src/main/java/org/eclipse/rdf4j/model/ValueFactory.java @@ -86,6 +86,18 @@ public interface ValueFactory { */ Literal createLiteral(String label, String language); + /** + * Creates a new literal with the supplied label and language attribute. The return value of + * {@link Literal#getDatatype()} for the returned object must be + * {@code rdf:langString}. + * + * @param label The literal's label, must not be null. + * @param language The literal's language attribute, must not be null. + * @param baseDirection The literal's base direction, either "", "--ltr", or "--rtl". + * @return A literal for the specified value and language attribute. + */ + Literal createLiteral(String label, String language, Literal.BaseDirection baseDirection); + /** * Creates a new literal with the supplied label and datatype. * @@ -265,11 +277,11 @@ default Literal createLiteral(TemporalAmount value) { Statement createStatement(Resource subject, IRI predicate, Value object, Resource context); /** - * Creates a new RDF-star triple with the supplied subject, predicate and object. + * Creates a new triple term with the supplied subject, predicate and object. * - * @param subject The statement's subject. - * @param predicate The statement's predicate. - * @param object The statement's object. + * @param subject The triple's subject. + * @param predicate The triple's predicate. + * @param object The triple's object. * @return The created triple. * @implNote This temporary default method is only supplied as a stop-gap for backward compatibility, but throws an * {@link UnsupportedOperationException}. Concrete implementations are expected to override. diff --git a/core/model-api/src/main/java/org/eclipse/rdf4j/model/base/AbstractLiteral.java b/core/model-api/src/main/java/org/eclipse/rdf4j/model/base/AbstractLiteral.java index 635c12a8847..d64ae697c1f 100644 --- a/core/model-api/src/main/java/org/eclipse/rdf4j/model/base/AbstractLiteral.java +++ b/core/model-api/src/main/java/org/eclipse/rdf4j/model/base/AbstractLiteral.java @@ -77,11 +77,12 @@ public abstract class AbstractLiteral implements Literal { private static final long serialVersionUID = -1286527360744086451L; static boolean reserved(IRI datatype) { - return CoreDatatype.RDF.LANGSTRING.getIri().equals(datatype); + return CoreDatatype.RDF.LANGSTRING.getIri().equals(datatype) + || CoreDatatype.RDF.DIRLANGSTRING.getIri().equals(datatype); } static boolean reserved(CoreDatatype datatype) { - return CoreDatatype.RDF.LANGSTRING == datatype; + return CoreDatatype.RDF.LANGSTRING == datatype || CoreDatatype.RDF.DIRLANGSTRING == datatype; } /** @@ -186,7 +187,7 @@ public String toString() { return getLanguage() - .map(language -> label + '@' + language) + .map(language -> label + '@' + language + getBaseDirection()) .orElseGet(() -> CoreDatatype.XSD.STRING == getCoreDatatype() ? label : label + "^^<" + getDatatype().stringValue() + ">"); @@ -268,10 +269,16 @@ static class TaggedLiteral extends AbstractLiteral { private final String label; private final String language; + private final BaseDirection baseDirection; TaggedLiteral(String label, String language) { + this(label, language, BaseDirection.NONE); + } + + TaggedLiteral(String label, String language, BaseDirection baseDirection) { this.label = label; this.language = language; + this.baseDirection = baseDirection; } @Override @@ -284,14 +291,20 @@ public Optional getLanguage() { return Optional.of(language); } + @Override + public BaseDirection getBaseDirection() { + return baseDirection; + } + @Override public IRI getDatatype() { - return CoreDatatype.RDF.LANGSTRING.getIri(); + return baseDirection == BaseDirection.NONE ? CoreDatatype.RDF.LANGSTRING.getIri() + : CoreDatatype.RDF.DIRLANGSTRING.getIri(); } @Override public CoreDatatype.RDF getCoreDatatype() { - return CoreDatatype.RDF.LANGSTRING; + return baseDirection == BaseDirection.NONE ? CoreDatatype.RDF.LANGSTRING : CoreDatatype.RDF.DIRLANGSTRING; } } diff --git a/core/model-api/src/main/java/org/eclipse/rdf4j/model/base/AbstractTriple.java b/core/model-api/src/main/java/org/eclipse/rdf4j/model/base/AbstractTriple.java index d4508225dc1..0a8d4497168 100644 --- a/core/model-api/src/main/java/org/eclipse/rdf4j/model/base/AbstractTriple.java +++ b/core/model-api/src/main/java/org/eclipse/rdf4j/model/base/AbstractTriple.java @@ -30,7 +30,7 @@ public abstract class AbstractTriple implements Triple { @Override public String stringValue() { - return "<<" + getSubject() + " " + getPredicate() + " " + getObject() + ">>"; + return "<<(" + getSubject() + " " + getPredicate() + " " + getObject() + ")>>"; } @Override diff --git a/core/model-api/src/main/java/org/eclipse/rdf4j/model/base/AbstractValueFactory.java b/core/model-api/src/main/java/org/eclipse/rdf4j/model/base/AbstractValueFactory.java index e88070a5af3..4d5ba3f39a3 100644 --- a/core/model-api/src/main/java/org/eclipse/rdf4j/model/base/AbstractValueFactory.java +++ b/core/model-api/src/main/java/org/eclipse/rdf4j/model/base/AbstractValueFactory.java @@ -146,15 +146,21 @@ public Literal createLiteral(String label, IRI datatype, CoreDatatype coreDataty @Override public Literal createLiteral(String label, String language) { + return createLiteral(label, language, Literal.BaseDirection.NONE); + } + + @Override + public Literal createLiteral(String label, String language, Literal.BaseDirection baseDirection) { Objects.requireNonNull(label, "null label"); Objects.requireNonNull(language, "null language"); + Objects.requireNonNull(baseDirection, "null baseDirection"); if (language.isEmpty()) { throw new IllegalArgumentException("empty language tag"); } - return new TaggedLiteral(label, language); + return new TaggedLiteral(label, language, baseDirection); } @Override diff --git a/core/model-api/src/main/java/org/eclipse/rdf4j/model/base/CoreDatatype.java b/core/model-api/src/main/java/org/eclipse/rdf4j/model/base/CoreDatatype.java index 50af84d1df3..c48be81ccfd 100644 --- a/core/model-api/src/main/java/org/eclipse/rdf4j/model/base/CoreDatatype.java +++ b/core/model-api/src/main/java/org/eclipse/rdf4j/model/base/CoreDatatype.java @@ -283,7 +283,9 @@ public String toString() { enum RDF implements CoreDatatype { HTML(iri("HTML")), + JSON(iri("JSON")), XMLLITERAL(iri("XMLLiteral")), + DIRLANGSTRING(iri("dirLangString")), LANGSTRING(iri("langString")); public static final String NAMESPACE = "http://www.w3.org/1999/02/22-rdf-syntax-ns#"; diff --git a/core/model-api/src/test/java/org/eclipse/rdf4j/model/LiteralTest.java b/core/model-api/src/test/java/org/eclipse/rdf4j/model/LiteralTest.java index be492efbef6..d7ddc088be3 100644 --- a/core/model-api/src/test/java/org/eclipse/rdf4j/model/LiteralTest.java +++ b/core/model-api/src/test/java/org/eclipse/rdf4j/model/LiteralTest.java @@ -85,6 +85,7 @@ public abstract class LiteralTest { static final String XSD_DURATION_YEARMONTH = XSD + "yearMonthDuration"; static final String RDF_LANG_STRING = RDF + "langString"; + static final String RDF_DIR_LANG_STRING = RDF + "dirLangString"; /** * Creates a test literal instance. @@ -103,6 +104,16 @@ public abstract class LiteralTest { */ protected abstract Literal literal(String label, String language); + /** + * Creates a test literal instance. + * + * @param label the label of the literal + * @param language the language of the literal + * @param dir the language direction of the literal + * @return a new instance of the concrete literal class under test + */ + protected abstract Literal literal(String label, String language, Literal.BaseDirection dir); + /** * Creates a test literal instance. * @@ -168,14 +179,24 @@ public final void testTaggedConstructor() { final String label = "label"; final String language = "en"; - final Literal literal = literal(label, language); + final Literal languageLiteral = literal(label, language); - assertThat(literal.getLabel()).isEqualTo(label); - assertThat(literal.getLanguage()).contains(language); - assertThat(literal.getDatatype().stringValue()).isEqualTo(RDF_LANG_STRING); + assertThat(languageLiteral.getLabel()).isEqualTo(label); + assertThat(languageLiteral.getLanguage()).contains(language); + assertEquals(Literal.BaseDirection.NONE, languageLiteral.getBaseDirection()); + assertThat(languageLiteral.getDatatype().stringValue()).isEqualTo(RDF_LANG_STRING); + + final Literal directedLanguageLiteral = literal(label, language, Literal.BaseDirection.LTR); + + assertThat(directedLanguageLiteral.getLabel()).isEqualTo(label); + assertThat(directedLanguageLiteral.getLanguage()).contains(language); + assertThat(directedLanguageLiteral.getBaseDirection().toString()).isEqualTo(Literal.LTR_SUFFIX); + assertThat(directedLanguageLiteral.getDatatype().stringValue()).isEqualTo(RDF_DIR_LANG_STRING); assertThatNullPointerException().isThrownBy(() -> literal(null, (String) null)); assertThatNullPointerException().isThrownBy(() -> literal("", (String) null)); + assertThatNullPointerException().isThrownBy(() -> literal("", (String) null, Literal.BaseDirection.NONE)); + assertThatNullPointerException().isThrownBy(() -> literal("", (String) null, Literal.BaseDirection.LTR)); assertThatNullPointerException().isThrownBy(() -> literal(null, "")); assertThatNullPointerException().isThrownBy(() -> literal(null, (IRI) null)); @@ -198,8 +219,10 @@ public final void testTypedConstructor() { assertThatNullPointerException().isThrownBy(() -> literal(null, (IRI) null)); assertThatNullPointerException().isThrownBy(() -> literal(null, datatype(XSD_STRING))); assertThatNullPointerException().isThrownBy(() -> literal(null, datatype(RDF_LANG_STRING))); + assertThatNullPointerException().isThrownBy(() -> literal(null, datatype(RDF_DIR_LANG_STRING))); assertThatIllegalArgumentException().isThrownBy(() -> literal("", datatype(RDF_LANG_STRING))); + assertThatIllegalArgumentException().isThrownBy(() -> literal("", datatype(RDF_DIR_LANG_STRING))); } @@ -763,10 +786,13 @@ public void testEqualsAndHashCode() { final Literal plain = literal("plain"); final Literal tagged = literal("tagged", "en"); + final Literal tagged_with_direction = literal("tagged", "en--ltr"); final Literal typed = literal("typed", datatype("http://example.org/datatype")); final Literal _plain = literal(plain.getLabel()); final Literal _tagged = literal(tagged.getLabel(), tagged.getLanguage().orElse("")); + final Literal _tagged_with_direction = literal(tagged_with_direction.getLabel(), + tagged_with_direction.getLanguage().orElse("")); final Literal _typed = literal(typed.getLabel(), typed.getDatatype()); assertThat(plain).isEqualTo(plain); @@ -775,6 +801,9 @@ public void testEqualsAndHashCode() { assertThat(tagged).isEqualTo(tagged); assertThat(tagged).isEqualTo(_tagged); + assertThat(tagged_with_direction).isEqualTo(tagged_with_direction); + assertThat(tagged_with_direction).isEqualTo(_tagged_with_direction); + assertThat(typed).isEqualTo(typed); assertThat(typed).isEqualTo(_typed); @@ -784,16 +813,21 @@ public void testEqualsAndHashCode() { assertThat(plain).isNotEqualTo(tagged); assertThat(plain).isNotEqualTo(typed); assertThat(tagged).isNotEqualTo(typed); + assertThat(tagged_with_direction).isNotEqualTo(plain); + assertThat(tagged_with_direction).isNotEqualTo(tagged); + assertThat(tagged_with_direction).isNotEqualTo(typed); assertThat(plain).isNotEqualTo(literal("other")); assertThat(tagged).isNotEqualTo(literal(tagged.getLabel(), "other")); assertThat(typed).isNotEqualTo(literal(typed.getLabel(), datatype("http://example.org/other"))); + assertThat(_tagged_with_direction).isNotEqualTo(literal(tagged_with_direction.getLabel(), "en--rtl")); // hashCode() should return identical values for literals for which equals() is true - assertThat(plain.hashCode()).isEqualTo(_plain.hashCode()); - assertThat(tagged.hashCode()).isEqualTo(_tagged.hashCode()); - assertThat(typed.hashCode()).isEqualTo(_typed.hashCode()); + assertThat(plain).hasSameHashCodeAs(_plain); + assertThat(tagged).hasSameHashCodeAs(_tagged); + assertThat(tagged_with_direction).hasSameHashCodeAs(_tagged_with_direction); + assertThat(typed).hasSameHashCodeAs(_typed); assertThat(tagged.hashCode()) .as("computed according to contract") @@ -860,11 +894,20 @@ public final void testCoreDatatypeTaggedConstructor() { String label = "label"; String language = "en"; - Literal literal = literal(label, language); + Literal languageLiteral = literal(label, language); + Literal directedLanguageLiteral = literal(label, language, Literal.BaseDirection.LTR); - assertThat(literal.getLabel()).isEqualTo(label); - assertThat(literal.getLanguage()).contains(language); - assertThat(literal.getCoreDatatype()).isEqualTo(CoreDatatype.RDF.LANGSTRING); + assertThat(languageLiteral.getLabel()).isEqualTo(label); + assertThat(languageLiteral.getLanguage()).contains(language); + assertEquals(Literal.BaseDirection.NONE, languageLiteral.getBaseDirection()); + assertThat(languageLiteral.getCoreDatatype()).isEqualTo(CoreDatatype.RDF.LANGSTRING); + assertEquals("\"label\"@en", languageLiteral.toString()); + + assertThat(directedLanguageLiteral.getLabel()).isEqualTo(label); + assertThat(directedLanguageLiteral.getLanguage()).contains(language); + assertEquals(Literal.BaseDirection.LTR, directedLanguageLiteral.getBaseDirection()); + assertThat(directedLanguageLiteral.getCoreDatatype()).isEqualTo(CoreDatatype.RDF.DIRLANGSTRING); + assertEquals("\"label\"@en--ltr", directedLanguageLiteral.toString()); assertThatNullPointerException().isThrownBy(() -> literal(null, (String) null)); assertThatNullPointerException().isThrownBy(() -> literal("", (String) null)); @@ -890,8 +933,10 @@ public final void testCoreDatatypeTypedConstructor() { assertThatNullPointerException().isThrownBy(() -> literal(null, (CoreDatatype) null)); assertThatNullPointerException().isThrownBy(() -> literal(null, CoreDatatype.XSD.STRING)); assertThatNullPointerException().isThrownBy(() -> literal(null, CoreDatatype.RDF.LANGSTRING)); + assertThatNullPointerException().isThrownBy(() -> literal(null, CoreDatatype.RDF.DIRLANGSTRING)); assertThatIllegalArgumentException().isThrownBy(() -> literal("", CoreDatatype.RDF.LANGSTRING)); + assertThatIllegalArgumentException().isThrownBy(() -> literal("", CoreDatatype.RDF.DIRLANGSTRING)); } @@ -911,6 +956,7 @@ public void testCoreDatatypeStringValue() { assertThat(literal(label).stringValue()).isEqualTo(label); assertThat(literal(label, language).stringValue()).isEqualTo(label); + assertThat(literal(label, language, Literal.BaseDirection.LTR).stringValue()).isEqualTo(label); assertThat(literal(label, datatype).stringValue()).isEqualTo(label); } @@ -1442,49 +1488,6 @@ public final void testCoreDatatypeCalendarValue() throws DatatypeConfigurationEx //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - @Test - public void testCoreDatatypeEqualsAndHashCode() { - - Literal plain = literal("plain"); - Literal tagged = literal("tagged", "en"); - Literal typed = literal("typed", datatype("http://example.org/datatype")); - - Literal _plain = literal(plain.getLabel()); - Literal _tagged = literal(tagged.getLabel(), tagged.getLanguage().orElse("")); - Literal _typed = literal(typed.getLabel(), typed.getDatatype()); - - assertThat(plain).isEqualTo(plain); - assertThat(plain).isEqualTo(_plain); - - assertThat(tagged).isEqualTo(tagged); - assertThat(tagged).isEqualTo(_tagged); - - assertThat(typed).isEqualTo(typed); - assertThat(typed).isEqualTo(_typed); - - assertThat(plain).isNotEqualTo(null); - assertThat(plain).isNotEqualTo(new Object()); - - assertThat(plain).isNotEqualTo(tagged); - assertThat(plain).isNotEqualTo(typed); - assertThat(tagged).isNotEqualTo(typed); - - assertThat(plain).isNotEqualTo(literal("other")); - assertThat(tagged).isNotEqualTo(literal(tagged.getLabel(), "other")); - assertThat(typed).isNotEqualTo(literal(typed.getLabel(), "http://example.org/other")); - - // hashCode() should return identical values for literals for which equals() is true - - assertThat(plain.hashCode()).isEqualTo(_plain.hashCode()); - assertThat(tagged.hashCode()).isEqualTo(_tagged.hashCode()); - assertThat(typed.hashCode()).isEqualTo(_typed.hashCode()); - - assertThat(tagged.hashCode()) - .as("computed according to contract") - .isEqualTo(tagged.getLabel().hashCode()); // !!! label >> label+language+datatype - - } - @Test public final void testCoreDatatypeEqualsAndHashCodeCaseInsensitiveLanguage() { @@ -1528,6 +1531,23 @@ public final void testSerializationWithCoreDatatypeRdfLangString() { assertEquals(CoreDatatype.RDF.LANGSTRING, roundTrip.getCoreDatatype()); } + @Test + public final void testSerializationWithCoreDatatypeRdfDirLangString() { + Literal literal = literal("hello", "en", Literal.BaseDirection.LTR); + assertEquals(CoreDatatype.RDF.DIRLANGSTRING, literal.getCoreDatatype()); + assertThat(literal.getLanguage()).isPresent(); + assertEquals("en", literal.getLanguage().get()); + assertEquals(Literal.BaseDirection.LTR, literal.getBaseDirection()); + + byte[] bytes = objectToBytes(literal); + Literal roundTrip = (Literal) bytesToObject(bytes); + + assertEquals(CoreDatatype.RDF.DIRLANGSTRING, roundTrip.getCoreDatatype()); + assertThat(roundTrip.getLanguage()).isPresent(); + assertEquals("en", roundTrip.getLanguage().get()); + assertEquals(Literal.BaseDirection.LTR, roundTrip.getBaseDirection()); + } + @Test public final void testSerializationWithCoreDatatypeGEO() { Literal literal = literal("1", CoreDatatype.GEO.WKT_LITERAL); @@ -1549,6 +1569,22 @@ public final void testSerializationWithCoreDatatype4() { assertEquals(CoreDatatype.XSD.NONE, roundTrip.getCoreDatatype()); } + @Test + void testBaseDirectionEnumFromString() { + assertThat(Literal.BaseDirection.fromString("")).isEqualTo(Literal.BaseDirection.NONE); + assertThat(Literal.BaseDirection.fromString(null)).isEqualTo(Literal.BaseDirection.NONE); + assertThat(Literal.BaseDirection.fromString(Literal.LTR_SUFFIX)).isEqualTo(Literal.BaseDirection.LTR); + assertThat(Literal.BaseDirection.fromString(Literal.RTL_SUFFIX)).isEqualTo(Literal.BaseDirection.RTL); + assertThrows(IllegalArgumentException.class, () -> Literal.BaseDirection.fromString("--invalid")); + } + + @Test + void testBaseDirectionEnumSuffix() { + assertThat(Literal.BaseDirection.LTR.toString()).isEqualTo(Literal.LTR_SUFFIX); + assertThat(Literal.BaseDirection.RTL.toString()).isEqualTo(Literal.RTL_SUFFIX); + assertThat(Literal.BaseDirection.NONE.toString()).isEmpty(); + } + private byte[] objectToBytes(Serializable object) { try (var byteArrayOutputStream = new ByteArrayOutputStream()) { try (var objectOutputStream = new ObjectOutputStream(byteArrayOutputStream)) { diff --git a/core/model-api/src/test/java/org/eclipse/rdf4j/model/ValueFactoryTest.java b/core/model-api/src/test/java/org/eclipse/rdf4j/model/ValueFactoryTest.java index 197b7a45369..5f051a81170 100644 --- a/core/model-api/src/test/java/org/eclipse/rdf4j/model/ValueFactoryTest.java +++ b/core/model-api/src/test/java/org/eclipse/rdf4j/model/ValueFactoryTest.java @@ -71,6 +71,7 @@ import javax.xml.datatype.DatatypeFactory; import javax.xml.datatype.XMLGregorianCalendar; +import org.eclipse.rdf4j.model.base.CoreDatatype; import org.junit.jupiter.api.Test; /** @@ -537,4 +538,16 @@ public void testCreateLiteralDate() throws DatatypeConfigurationException { } + @Test + public void testCreateDirLangLiteral() { + final Literal literal = factory().createLiteral("label", "he", Literal.BaseDirection.RTL); + + assertThat(literal).isNotNull(); + assertThat(literal.getLabel()).isEqualTo("label"); + assertThat(literal.getLanguage()).contains("he"); + assertThat(literal.getBaseDirection()).isEqualTo(Literal.BaseDirection.RTL); + assertThat(literal.getBaseDirection().toString()).isEqualTo("--rtl"); + assertThat(literal.getDatatype()).isEqualTo(CoreDatatype.RDF.DIRLANGSTRING.getIri()); + } + } diff --git a/core/model-api/src/test/java/org/eclipse/rdf4j/model/base/AbstractLiteralTest.java b/core/model-api/src/test/java/org/eclipse/rdf4j/model/base/AbstractLiteralTest.java index 03849f7a2c5..148f1693d96 100644 --- a/core/model-api/src/test/java/org/eclipse/rdf4j/model/base/AbstractLiteralTest.java +++ b/core/model-api/src/test/java/org/eclipse/rdf4j/model/base/AbstractLiteralTest.java @@ -11,11 +11,14 @@ package org.eclipse.rdf4j.model.base; +import static org.assertj.core.api.Assertions.assertThat; + import org.eclipse.rdf4j.model.IRI; import org.eclipse.rdf4j.model.Literal; import org.eclipse.rdf4j.model.LiteralTest; import org.eclipse.rdf4j.model.ValueFactory; import org.eclipse.rdf4j.model.base.AbstractValueFactoryTest.GenericValueFactory; +import org.junit.jupiter.api.Test; /** * Unit tests for {@link AbstractLiteral}. @@ -37,6 +40,11 @@ protected Literal literal(String label, String language) { return factory.createLiteral(label, language); } + @Override + protected Literal literal(String label, String language, Literal.BaseDirection dir) { + return factory.createLiteral(label, language, dir); + } + @Override protected Literal literal(String label, IRI datatype) { return factory.createLiteral(label, datatype); @@ -51,5 +59,4 @@ protected Literal literal(String label, CoreDatatype datatype) { protected IRI datatype(String iri) { return factory.createIRI(iri); } - } diff --git a/core/model-vocabulary/pom.xml b/core/model-vocabulary/pom.xml index bd27791c1d8..3716904ecc4 100644 --- a/core/model-vocabulary/pom.xml +++ b/core/model-vocabulary/pom.xml @@ -4,7 +4,7 @@ org.eclipse.rdf4j rdf4j-core - 5.1.0-SNAPSHOT + 6.0.0 rdf4j-model-vocabulary RDF4J: RDF Vocabularies diff --git a/core/model-vocabulary/src/main/java/org/eclipse/rdf4j/model/vocabulary/RDF.java b/core/model-vocabulary/src/main/java/org/eclipse/rdf4j/model/vocabulary/RDF.java index 92bb07e4fe4..e53679ff122 100644 --- a/core/model-vocabulary/src/main/java/org/eclipse/rdf4j/model/vocabulary/RDF.java +++ b/core/model-vocabulary/src/main/java/org/eclipse/rdf4j/model/vocabulary/RDF.java @@ -57,6 +57,9 @@ public class RDF { /** http://www.w3.org/1999/02/22-rdf-syntax-ns#Statement */ public final static IRI STATEMENT = Vocabularies.createIRI(RDF.NAMESPACE, "Statement"); + /** http://www.w3.org/1999/02/22-rdf-syntax-ns#reifies */ + public final static IRI REIFIES = Vocabularies.createIRI(RDF.NAMESPACE, "reifies"); + /** http://www.w3.org/1999/02/22-rdf-syntax-ns#Bag */ public final static IRI BAG = Vocabularies.createIRI(RDF.NAMESPACE, "Bag"); @@ -87,7 +90,13 @@ public class RDF { /** http://www.w3.org/1999/02/22-rdf-syntax-ns#langString */ public static final IRI LANGSTRING = CoreDatatype.RDF.LANGSTRING.getIri(); + /** http://www.w3.org/1999/02/22-rdf-syntax-ns#dirLangString */ + public static final IRI DIRLANGSTRING = CoreDatatype.RDF.DIRLANGSTRING.getIri(); + /** http://www.w3.org/1999/02/22-rdf-syntax-ns#HTML */ public static final IRI HTML = CoreDatatype.RDF.HTML.getIri(); + /** http://www.w3.org/1999/02/22-rdf-syntax-ns#JSON */ + public static final IRI JSON = CoreDatatype.RDF.JSON.getIri(); + } diff --git a/core/model/pom.xml b/core/model/pom.xml index 17a4deb868b..0d8795571cb 100644 --- a/core/model/pom.xml +++ b/core/model/pom.xml @@ -4,7 +4,7 @@ org.eclipse.rdf4j rdf4j-core - 5.1.0-SNAPSHOT + 6.0.0 rdf4j-model RDF4J: Model diff --git a/core/model/src/main/java/org/eclipse/rdf4j/model/impl/SimpleLiteral.java b/core/model/src/main/java/org/eclipse/rdf4j/model/impl/SimpleLiteral.java index fb86f383183..e39a424760f 100644 --- a/core/model/src/main/java/org/eclipse/rdf4j/model/impl/SimpleLiteral.java +++ b/core/model/src/main/java/org/eclipse/rdf4j/model/impl/SimpleLiteral.java @@ -63,6 +63,11 @@ public class SimpleLiteral extends AbstractLiteral { // Cached CoreDatatype, or null if not yet computed. private CoreDatatype coreDatatype = null; + /** + * The literal's base direction. + */ + private BaseDirection baseDirection = BaseDirection.NONE; + /*--------------* * Constructors * *--------------*/ @@ -88,8 +93,13 @@ protected SimpleLiteral(String label) { * @param language The language tag for the literal, must not be null and not be empty. */ protected SimpleLiteral(String label, String language) { + this(label, language, BaseDirection.NONE); + } + + protected SimpleLiteral(String label, String language, BaseDirection baseDirection) { setLabel(label); setLanguage(language); + setBaseDirection(baseDirection); } /** @@ -100,8 +110,9 @@ protected SimpleLiteral(String label, String language) { */ protected SimpleLiteral(String label, IRI datatype) { setLabel(label); - if (org.eclipse.rdf4j.model.vocabulary.RDF.LANGSTRING.equals(datatype)) { - throw new IllegalArgumentException("datatype rdf:langString requires a language tag"); + if (org.eclipse.rdf4j.model.vocabulary.RDF.LANGSTRING.equals(datatype) + || org.eclipse.rdf4j.model.vocabulary.RDF.DIRLANGSTRING.equals(datatype)) { + throw new IllegalArgumentException("datatype rdf:langString or rdf:dirLangString requires a language tag"); } else if (datatype == null) { setDatatype(CoreDatatype.XSD.STRING); } else { @@ -122,8 +133,8 @@ protected SimpleLiteral(String label, IRI datatype, CoreDatatype coreDatatype) { assert datatype != null; assert coreDatatype == CoreDatatype.NONE || datatype == coreDatatype.getIri(); - if (CoreDatatype.RDF.LANGSTRING == coreDatatype) { - throw new IllegalArgumentException("datatype rdf:langString requires a language tag"); + if (CoreDatatype.RDF.LANGSTRING == coreDatatype || CoreDatatype.RDF.DIRLANGSTRING == coreDatatype) { + throw new IllegalArgumentException("datatype rdf:langString or rdf:dirLangString requires a language tag"); } setLabel(label); @@ -133,8 +144,8 @@ protected SimpleLiteral(String label, IRI datatype, CoreDatatype coreDatatype) { protected SimpleLiteral(String label, CoreDatatype datatype) { setLabel(label); - if (datatype == CoreDatatype.RDF.LANGSTRING) { - throw new IllegalArgumentException("datatype rdf:langString requires a language tag"); + if (datatype == CoreDatatype.RDF.LANGSTRING || datatype == CoreDatatype.RDF.DIRLANGSTRING) { + throw new IllegalArgumentException("datatype rdf:langString or rdf:dirLangString requires a language tag"); } else { setDatatype(datatype); } @@ -163,7 +174,16 @@ protected void setLanguage(String language) { } this.language = language; optionalLanguageCache = Optional.of(language); - setDatatype(CoreDatatype.RDF.LANGSTRING); + } + + protected void setBaseDirection(BaseDirection baseDirection) { + Objects.requireNonNull(baseDirection, "null baseDirection"); + this.baseDirection = baseDirection; + if (this.baseDirection != BaseDirection.NONE) { + setDatatype(CoreDatatype.RDF.DIRLANGSTRING); + } else { + setDatatype(CoreDatatype.RDF.LANGSTRING); + } } @Override @@ -174,6 +194,10 @@ public Optional getLanguage() { return optionalLanguageCache; } + public BaseDirection getBaseDirection() { + return baseDirection; + } + protected void setDatatype(IRI datatype) { this.datatype = datatype; coreDatatype = CoreDatatype.from(datatype); @@ -260,6 +284,7 @@ public String toString() { StringBuilder sb = new StringBuilder(label.length() + language.length() + 3); sb.append('"').append(label).append('"'); sb.append('@').append(language); + sb.append(getBaseDirection()); return sb.toString(); } else if (org.eclipse.rdf4j.model.vocabulary.XSD.STRING.equals(datatype) || datatype == null) { StringBuilder sb = new StringBuilder(label.length() + 2); diff --git a/core/model/src/main/java/org/eclipse/rdf4j/model/impl/SimpleTriple.java b/core/model/src/main/java/org/eclipse/rdf4j/model/impl/SimpleTriple.java index 50584bfb482..ca6c4ac1a82 100644 --- a/core/model/src/main/java/org/eclipse/rdf4j/model/impl/SimpleTriple.java +++ b/core/model/src/main/java/org/eclipse/rdf4j/model/impl/SimpleTriple.java @@ -77,13 +77,13 @@ public Value getObject() { public String stringValue() { StringBuilder sb = new StringBuilder(256); - sb.append("<<"); + sb.append("<<( "); sb.append(getSubject()); sb.append(" "); sb.append(getPredicate()); sb.append(" "); sb.append(getObject()); - sb.append(">>"); + sb.append(" )>>"); return sb.toString(); } diff --git a/core/model/src/main/java/org/eclipse/rdf4j/model/impl/SimpleValueFactory.java b/core/model/src/main/java/org/eclipse/rdf4j/model/impl/SimpleValueFactory.java index b9b685b7fcd..e0b208b6c15 100644 --- a/core/model/src/main/java/org/eclipse/rdf4j/model/impl/SimpleValueFactory.java +++ b/core/model/src/main/java/org/eclipse/rdf4j/model/impl/SimpleValueFactory.java @@ -103,6 +103,11 @@ public Literal createLiteral(String value, String language) { return new SimpleLiteral(value, language); } + @Override + public Literal createLiteral(String value, String language, Literal.BaseDirection baseDirection) { + return new SimpleLiteral(value, language, baseDirection); + } + @Override public Literal createLiteral(boolean b) { return b ? BooleanLiteral.TRUE : BooleanLiteral.FALSE; diff --git a/core/model/src/main/java/org/eclipse/rdf4j/model/impl/ValidatingValueFactory.java b/core/model/src/main/java/org/eclipse/rdf4j/model/impl/ValidatingValueFactory.java index 0cfe2860938..7bddd6d8b15 100644 --- a/core/model/src/main/java/org/eclipse/rdf4j/model/impl/ValidatingValueFactory.java +++ b/core/model/src/main/java/org/eclipse/rdf4j/model/impl/ValidatingValueFactory.java @@ -134,10 +134,15 @@ public Literal createLiteral(String label, IRI datatype, CoreDatatype coreDataty @Override public Literal createLiteral(String label, String language) { + return createLiteral(label, language, Literal.BaseDirection.NONE); + } + + @Override + public Literal createLiteral(String label, String language, Literal.BaseDirection baseDirection) { if (!Literals.isValidLanguageTag(language)) { throw new IllegalArgumentException("Not a valid language tag: " + language); } - return delegate.createLiteral(label, language); + return delegate.createLiteral(label, language, baseDirection); } @Override diff --git a/core/model/src/main/java/org/eclipse/rdf4j/model/util/GraphComparisons.java b/core/model/src/main/java/org/eclipse/rdf4j/model/util/GraphComparisons.java index 1f3ceb59c80..85509db575b 100644 --- a/core/model/src/main/java/org/eclipse/rdf4j/model/util/GraphComparisons.java +++ b/core/model/src/main/java/org/eclipse/rdf4j/model/util/GraphComparisons.java @@ -11,6 +11,7 @@ package org.eclipse.rdf4j.model.util; import static org.eclipse.rdf4j.model.util.Values.bnode; +import static org.eclipse.rdf4j.model.util.Values.triple; import java.math.BigInteger; import java.nio.charset.StandardCharsets; @@ -34,6 +35,7 @@ import org.eclipse.rdf4j.model.Model; import org.eclipse.rdf4j.model.Resource; import org.eclipse.rdf4j.model.Statement; +import org.eclipse.rdf4j.model.Triple; import org.eclipse.rdf4j.model.Value; import org.eclipse.rdf4j.model.impl.DynamicModelFactory; import org.slf4j.Logger; @@ -213,6 +215,18 @@ protected static Set getBlankNodes(Model m) { if (st.getContext() != null && st.getContext().isBNode()) { blankNodes.add((BNode) st.getContext()); } + + Triple t = triple(st); + while (t.getObject().isTriple()) { + t = (Triple) t.getObject(); + + if (t.getSubject().isBNode()) { + blankNodes.add((BNode) t.getSubject()); + } + if (t.getObject().isBNode()) { + blankNodes.add((BNode) t.getObject()); + } + } }); return blankNodes; } @@ -306,18 +320,31 @@ private static Model labelModel(Model original, Map hash) { Model result = new DynamicModelFactory().createEmptyModel(); for (Statement st : original) { - if (st.getSubject().isBNode() || st.getObject().isBNode() + if (st.getSubject().isBNode() || st.getObject().isBNode() || st.getObject().isTriple() || (st.getContext() != null && st.getContext().isBNode())) { Resource subject = st.getSubject().isBNode() ? createCanonicalBNode((BNode) st.getSubject(), hash) : st.getSubject(); IRI predicate = st.getPredicate(); - Value object = st.getObject().isBNode() - ? createCanonicalBNode((BNode) st.getObject(), hash) - : st.getObject(); Resource context = (st.getContext() != null && st.getContext().isBNode()) ? createCanonicalBNode((BNode) st.getContext(), hash) : st.getContext(); + Value object; + if (st.getObject().isBNode()) { + object = createCanonicalBNode((BNode) st.getObject(), hash); + } else if (st.getObject().isTriple()) { + Triple triple = (Triple) st.getObject(); + object = triple( + triple.getSubject().isBNode() + ? createCanonicalBNode((BNode) triple.getSubject(), hash) + : triple.getSubject(), + triple.getPredicate(), + triple.getObject().isBNode() + ? createCanonicalBNode((BNode) triple.getObject(), hash) + : triple.getObject()); + } else { + object = st.getObject(); + } result.add(subject, predicate, object, context); } else { @@ -357,12 +384,41 @@ private static Partitioning hashBNodes(Model m, Partitioning partitioning) { partitioning.setCurrentHashCode(b, hashBag(c, partitioning.getCurrentHashCode(b))); } + + for (Statement st : m.getStatements(null, null, null)) { + if (st.getObject().isTriple()) { + hashBNodeInTripleTerms((Triple) st.getObject(), b, partitioning); + } + } + } } while (!partitioning.isFullyDistinguished()); } return partitioning; } + private static void hashBNodeInTripleTerms(Triple t, BNode b, Partitioning partitioning) { + if (t.getSubject().equals(b)) { + HashCode c = hashTuple( + partitioning.getPreviousHashCode(t.getObject()), + partitioning.getPreviousHashCode(t.getPredicate()), + outgoing); + partitioning.setCurrentHashCode(b, + hashBag(c, partitioning.getCurrentHashCode(b))); + } + if (t.getObject().equals(b)) { + HashCode c = hashTuple( + partitioning.getPreviousHashCode(t.getSubject()), + partitioning.getPreviousHashCode(t.getPredicate()), + incoming); + partitioning.setCurrentHashCode(b, + hashBag(c, partitioning.getCurrentHashCode(b))); + } + if (t.getObject().isTriple()) { + hashBNodeInTripleTerms((Triple) t.getObject(), b, partitioning); + } + } + protected static HashCode hashTuple(HashCode... hashCodes) { return Hashing.combineOrdered(Arrays.asList(hashCodes)); } @@ -430,6 +486,11 @@ public HashCode getPreviousHashCode(Value value) { if (value.isLiteral()) { return getStaticLiteralHashCode((Literal) value); } + if (value.isTriple()) { + return hashTuple(getPreviousHashCode(((Triple) value).getSubject()), + getPreviousHashCode(((Triple) value).getPredicate()), + getPreviousHashCode(((Triple) value).getObject())); + } return staticValueMapping.computeIfAbsent(value, v -> hashFunction.hashString(v.stringValue(), StandardCharsets.UTF_8)); diff --git a/core/model/src/main/java/org/eclipse/rdf4j/model/util/Literals.java b/core/model/src/main/java/org/eclipse/rdf4j/model/util/Literals.java index cfd77d59ebe..671aa1fc06e 100644 --- a/core/model/src/main/java/org/eclipse/rdf4j/model/util/Literals.java +++ b/core/model/src/main/java/org/eclipse/rdf4j/model/util/Literals.java @@ -473,7 +473,8 @@ public static boolean canCreateLiteral(Object object) { * @return True if the literal has a language tag attached to it and false otherwise. */ public static boolean isLanguageLiteral(Literal literal) { - return literal.getCoreDatatype() == CoreDatatype.RDF.LANGSTRING; + return literal.getCoreDatatype() == CoreDatatype.RDF.LANGSTRING + || literal.getCoreDatatype() == CoreDatatype.RDF.DIRLANGSTRING; } /** @@ -495,7 +496,7 @@ public static String normalizeLanguageTag(String languageTag) throws IllformedLo new Locale.Builder().setLanguageTag(languageTag); // all subtags are case-insensitive - String normalizedTag = languageTag.toLowerCase(); + final String normalizedTag = languageTag.toLowerCase(); String[] subtags = normalizedTag.split("-"); for (int i = 1; i < subtags.length; i++) { diff --git a/core/model/src/main/java/org/eclipse/rdf4j/model/util/Models.java b/core/model/src/main/java/org/eclipse/rdf4j/model/util/Models.java index 2ca46af582f..52824b66e54 100644 --- a/core/model/src/main/java/org/eclipse/rdf4j/model/util/Models.java +++ b/core/model/src/main/java/org/eclipse/rdf4j/model/util/Models.java @@ -821,7 +821,7 @@ public static Model synchronizedModel(Model toSynchronize) { } /** - * Converts the supplied RDF-star model to RDF reification statements. The converted statements are sent to the + * Converts the supplied RDF 1.2 model to RDF 1.1 reification statements. The converted statements are sent to the * supplied consumer function. *

* The supplied value factory is used to create all new statements. @@ -831,68 +831,68 @@ public static Model synchronizedModel(Model toSynchronize) { * @param consumer the {@link Consumer} function for the produced statements. */ @Experimental - public static void convertRDFStarToReification(ValueFactory vf, Model model, Consumer consumer) { - model.forEach(st -> Statements.convertRDFStarToReification(vf, st, consumer)); + public static void convertRDF12ReificationToRDF11(ValueFactory vf, Model model, Consumer consumer) { + model.forEach(st -> Statements.convertRDF12ReificationToRDF11(vf, st, consumer)); } /** - * Converts the supplied RDF-star model to RDF reification statements. The converted statements are sent to the + * Converts the supplied RDF 1.2 model to RDF 1.1 reification statements. The converted statements are sent to the * supplied consumer function. * * @param model the {@link Model} to convert. * @param consumer the {@link Consumer} function for the produced statements. */ @Experimental - public static void convertRDFStarToReification(Model model, Consumer consumer) { - convertRDFStarToReification(SimpleValueFactory.getInstance(), model, consumer); + public static void convertRDF12ReificationToRDF11(Model model, Consumer consumer) { + convertRDF12ReificationToRDF11(SimpleValueFactory.getInstance(), model, consumer); } /** - * Converts the statements in supplied RDF-star model to a new RDF model using reificiation. + * Converts the statements in supplied RDF 1.2 model to a new RDF 1.1 model using reificiation. *

* The supplied value factory is used to create all new statements. * * @param vf the {@link ValueFactory} to use for creating statements. * @param model the {@link Model} to convert. - * @return a new {@link Model} with RDF-star statements converted to reified triples. + * @return a new {@link Model} with RDF 1.2 statements converted to reified triples. */ @Experimental - public static Model convertRDFStarToReification(ValueFactory vf, Model model) { + public static Model convertRDF12ReificationToRDF11(ValueFactory vf, Model model) { Model reificationModel = new LinkedHashModel(); - convertRDFStarToReification(vf, model, (Consumer) reificationModel::add); + convertRDF12ReificationToRDF11(vf, model, (Consumer) reificationModel::add); return reificationModel; } /** - * Converts the statements in supplied RDF-star model to a new RDF model using reificiation. + * Converts the statements in supplied RDF 1.2 model to a new RDF 1.1 model using reificiation. *

* The supplied value factory is used to create all new statements. * * @param vf the {@link ValueFactory} to use for creating statements. * @param model the {@link Model} to convert. * @param modelFactory the {@link ModelFactory} used to create the new output {@link Model}. - * @return a new {@link Model} with RDF-star statements converted to reified triples. + * @return a new {@link Model} with RDF 1.2 statements converted to reified triples. */ @Experimental - public static Model convertRDFStarToReification(ValueFactory vf, Model model, ModelFactory modelFactory) { + public static Model convertRDF12ReificationToRDF11(ValueFactory vf, Model model, ModelFactory modelFactory) { Model reificationModel = modelFactory.createEmptyModel(); - convertRDFStarToReification(vf, model, (Consumer) reificationModel::add); + convertRDF12ReificationToRDF11(vf, model, (Consumer) reificationModel::add); return reificationModel; } /** - * Converts the statements in the supplied RDF-star model to a new RDF model using reification. + * Converts the statements in the supplied RDF 1.2 model to a new RDF 1.1 model using reification. * * @param model the {@link Model} to convert. - * @return a new {@link Model} with RDF-star statements converted to reified triples. + * @return a new {@link Model} with RDF 1.2 statements converted to reified triples. */ @Experimental - public static Model convertRDFStarToReification(Model model) { - return convertRDFStarToReification(SimpleValueFactory.getInstance(), model); + public static Model convertRDF12ReificationToRDF11(Model model) { + return convertRDF12ReificationToRDF11(SimpleValueFactory.getInstance(), model); } /** - * Converts the supplied RDF reification model to RDF-star statements. The converted statements are sent to the + * Converts the supplied RDF 1.1 reification model to RDF-12 statements. The converted statements are sent to the * supplied consumer function. *

* The supplied value factory is used to create all new statements. @@ -902,110 +902,93 @@ public static Model convertRDFStarToReification(Model model) { * @param consumer the {@link Consumer} function for the produced statements. */ @Experimental - public static void convertReificationToRDFStar(ValueFactory vf, Model model, Consumer consumer) { - Map convertedStatements = new HashMap<>(); + public static void convertReificationToRDF12(ValueFactory vf, Model model, Consumer consumer) { + Set reifiers = new HashSet<>(); model.filter(null, RDF.TYPE, RDF.STATEMENT).forEach((s) -> { - Value subject = object(model.filter(s.getSubject(), RDF.SUBJECT, null)).orElse(null); - if (!(subject instanceof IRI) && !(subject instanceof BNode)) { + Resource reifier = s.getSubject(); + Value subject = object(model.filter(reifier, RDF.SUBJECT, null)).orElse(null); + if (!(subject instanceof Resource)) { return; } - Value predicate = object(model.filter(s.getSubject(), RDF.PREDICATE, null)).orElse(null); + Value predicate = object(model.filter(reifier, RDF.PREDICATE, null)).orElse(null); if (!(predicate instanceof IRI)) { return; } - Value object = object(model.filter(s.getSubject(), RDF.OBJECT, null)).orElse(null); + Value object = object(model.filter(reifier, RDF.OBJECT, null)).orElse(null); if (!(object instanceof Value)) { return; } + + // Statement successfully converted - add reifier to list of successfully converted reifiers + reifiers.add(reifier); Triple t = vf.createTriple((Resource) subject, (IRI) predicate, object); - convertedStatements.put(s.getSubject(), t); + consumer.accept(vf.createStatement(reifier, RDF.REIFIES, t, s.getContext())); }); - for (Map.Entry e : convertedStatements.entrySet()) { - Triple t = e.getValue(); - Resource subject = convertedStatements.get(t.getSubject()); - Resource object = convertedStatements.get(t.getObject()); - if (subject != null || object != null) { - // Triples within triples, replace them in the map - Triple nt = vf.createTriple(subject != null ? subject : t.getSubject(), t.getPredicate(), - object != null ? object : t.getObject()); - e.setValue(nt); - } - } - model.forEach((s) -> { Resource subject = s.getSubject(); IRI predicate = s.getPredicate(); Value object = s.getObject(); - Triple subjectTriple = convertedStatements.get(subject); - Triple objectTriple = convertedStatements.get(object); - - if (subjectTriple == null && objectTriple == null) { - // Statement not part of detected reification, add it as is + if (!(reifiers.contains(subject) + && ((predicate.equals(RDF.TYPE) && object.equals(RDF.STATEMENT)) || predicate.equals(RDF.SUBJECT) + || predicate.equals(RDF.OBJECT) || predicate.equals(RDF.PREDICATE)))) { consumer.accept(s); - } else if (subjectTriple == null || ((!RDF.TYPE.equals(predicate) || !RDF.STATEMENT.equals(object)) - && !RDF.SUBJECT.equals(predicate) && !RDF.PREDICATE.equals(predicate) - && !RDF.OBJECT.equals(predicate))) { - // Statement uses reified data and needs to be converted - Statement ns = vf.createStatement(subjectTriple != null ? subjectTriple : s.getSubject(), - s.getPredicate(), objectTriple != null ? objectTriple : s.getObject(), s.getContext()); - consumer.accept(ns); - } // else: Statement part of reification and needs to be removed (skipped) + } // else: Statement part of original RDF 1.1 reification and needs to be removed (skipped) }); } /** - * Converts the supplied RDF reification model to RDF-star statements. The converted statements are sent to the + * Converts the supplied RDF 1.1 reification model to RDF 1.2 statements. The converted statements are sent to the * supplied consumer function. * * @param model the {@link Model} to convert. * @param consumer the {@link Consumer} function for the produced statements. */ @Experimental - public static void convertReificationToRDFStar(Model model, Consumer consumer) { - convertReificationToRDFStar(SimpleValueFactory.getInstance(), model, consumer); + public static void convertReificationToRDF12(Model model, Consumer consumer) { + convertReificationToRDF12(SimpleValueFactory.getInstance(), model, consumer); } /** - * Converts the statements in supplied RDF reification model to a new RDF-star model. + * Converts the statements in supplied RDF 1.1 reification model to a new RDF 1.2 model. *

* The supplied value factory is used to create all new statements. * * @param vf the {@link ValueFactory} to use for creating statements. * @param model the {@link Model} to convert. * @param modelFactory the {@link ModelFactory} to use for creating a new Model object for the output. - * @return a new {@link Model} with reification statements converted to RDF-star {@link Triple}s. + * @return a new {@link Model} with reification statements converted to RDF 1.2 {@link Triple}s. */ @Experimental - public static Model convertReificationToRDFStar(ValueFactory vf, Model model, ModelFactory modelFactory) { - Model rdfStarModel = modelFactory.createEmptyModel(); - convertReificationToRDFStar(vf, model, (Consumer) rdfStarModel::add); - return rdfStarModel; + public static Model convertReificationToRDF12(ValueFactory vf, Model model, ModelFactory modelFactory) { + Model rdf11Model = modelFactory.createEmptyModel(); + convertReificationToRDF12(vf, model, (Consumer) rdf11Model::add); + return rdf11Model; } /** - * Converts the statements in supplied RDF reification model to a new RDF-star model. + * Converts the statements in supplied RDF 1.1 reification model to a new RDF 1.2 model. *

* The supplied value factory is used to create all new statements. * * @param vf the {@link ValueFactory} to use for creating statements. * @param model the {@link Model} to convert. - * @return a new {@link Model} with reification statements converted to RDF-star {@link Triple}s. + * @return a new {@link Model} with reification statements converted to RDF 1.2 {@link Triple}s. */ @Experimental - public static Model convertReificationToRDFStar(ValueFactory vf, Model model) { - return convertReificationToRDFStar(vf, model, new DynamicModelFactory()); + public static Model convertReificationToRDF12(ValueFactory vf, Model model) { + return convertReificationToRDF12(vf, model, new DynamicModelFactory()); } /** - * Converts the supplied RDF reification model to a new RDF-star model. + * Converts the supplied RDF 1.1 reification model to a new RDF 1.2 model. * * @param model the {@link Model} to convert. - * @return a new {@link Model} with reification statements converted to RDF-star {@link Triple}s. + * @return a new {@link Model} with reification statements converted to RDF 1.2 {@link Triple}s. */ @Experimental - public static Model convertReificationToRDFStar(Model model) { - return convertReificationToRDFStar(SimpleValueFactory.getInstance(), model); + public static Model convertReificationToRDF12(Model model) { + return convertReificationToRDF12(SimpleValueFactory.getInstance(), model); } private static boolean isSubsetInternal(Set model1, Model model2) { diff --git a/core/model/src/main/java/org/eclipse/rdf4j/model/util/Statements.java b/core/model/src/main/java/org/eclipse/rdf4j/model/util/Statements.java index bea10611167..3c7f6b82e28 100644 --- a/core/model/src/main/java/org/eclipse/rdf4j/model/util/Statements.java +++ b/core/model/src/main/java/org/eclipse/rdf4j/model/util/Statements.java @@ -28,8 +28,8 @@ import org.eclipse.rdf4j.model.vocabulary.RDF; /** - * Utility methods for working with {@link Statement} objects, including conversion to/from {@link Triple RDF-star - * triple objects}. + * Utility methods for working with {@link Statement} objects, including conversion to/from {@link Triple RDF 1.2 triple + * objects}. * * @author Jeen Broekstra */ @@ -125,10 +125,10 @@ public static Statement stripContext(ValueFactory vf, Statement statement) { } /** - * Create an {@link Triple RDF-star triple} from the supplied {@link Statement} + * Create an {@link Triple RDF 1.2 triple} from the supplied {@link Statement} * - * @param statement a statement to convert to an RDF-star triple - * @return an {@link Triple RDF-star triple} with the same subject, predicate and object as the input statement. + * @param statement a statement to convert to an RDF 1.2 triple + * @return an {@link Triple RDF 1.2 triple} with the same subject, predicate and object as the input statement. * @since 3.4.0 * @deprecated Use {@link Values#triple(Statement)} instead */ @@ -138,11 +138,11 @@ public static Triple toTriple(Statement statement) { } /** - * Create an {@link Triple RDF-star triple} from the supplied {@link Statement} + * Create an {@link Triple RDF 1.2 triple} from the supplied {@link Statement} * * @param vf the {@link ValueFactory} to use for creating the {@link Triple} object. - * @param statement a statement to convert to an RDF-star triple - * @return an {@link Triple RDF-star triple} with the same subject, predicate and object as the input statement. + * @param statement a statement to convert to an RDF 1.2 triple + * @return an {@link Triple RDF 1.2 triple} with the same subject, predicate and object as the input statement. * @since 3.4.0 * @deprecated Use {@link Values#triple(ValueFactory, Statement)} instead */ @@ -152,9 +152,9 @@ public static Triple toTriple(ValueFactory vf, Statement statement) { } /** - * Create a {@link Statement} from the supplied {@link Triple RDF-star triple} + * Create a {@link Statement} from the supplied {@link Triple RDF 1.2 triple} * - * @param triple an RDF-star triple to convert to a {@link Statement}. + * @param triple an RDF 1.2 triple to convert to a {@link Statement}. * @return an {@link Statement} with the same subject, predicate and object as the input triple, and no context. * @since 3.4.0 * @deprecated Use {@link #statement(Triple)} instead @@ -164,9 +164,9 @@ public static Statement toStatement(Triple triple) { } /** - * Create a {@link Statement} from the supplied {@link Triple RDF-star triple} + * Create a {@link Statement} from the supplied {@link Triple RDF 1.2 triple} * - * @param triple an RDF-star triple to convert to a {@link Statement}. + * @param triple an RDF 1.2 triple to convert to a {@link Statement}. * @return an {@link Statement} with the same subject, predicate and object as the input triple, and no context. * @since 3.4.0 */ @@ -175,9 +175,9 @@ public static Statement statement(Triple triple) { } /** - * Create a {@link Statement} from the supplied {@link Triple RDF-star triple} and context. + * Create a {@link Statement} from the supplied {@link Triple RDF 1.2 triple} and context. * - * @param triple an RDF-star triple to convert to a {@link Statement}. + * @param triple an RDF 1.2 triple to convert to a {@link Statement}. * @param context the context to assign to the {@link Statement}. * @return an {@link Statement} with the same subject, predicate and object as the input triple, and having the * supplied context. @@ -188,9 +188,9 @@ public static Statement statement(Triple triple, Resource context) { } /** - * Create a {@link Statement} from the supplied {@link Triple RDF-star triple} and context. + * Create a {@link Statement} from the supplied {@link Triple RDF 1.2 triple} and context. * - * @param triple an RDF-star triple to convert to a {@link Statement}. + * @param triple an RDF 1.2 triple to convert to a {@link Statement}. * @param context the context to assign to the {@link Statement}. * @return an {@link Statement} with the same subject, predicate and object as the input triple, and having the * supplied context. @@ -202,10 +202,10 @@ public static Statement toStatement(Triple triple, Resource context) { } /** - * Create a {@link Statement} from the supplied {@link Triple RDF-star triple} and context. + * Create a {@link Statement} from the supplied {@link Triple RDF 1.2 triple} and context. * * @param vf the {@link ValueFactory} to use for creating the {@link Statement} object. - * @param triple an RDF-star triple to convert to a {@link Statement}. + * @param triple an RDF 1.2 triple to convert to a {@link Statement}. * @param context the context to assign to the {@link Statement}. May be null to indicate no context. * @return an {@link Statement} with the same subject, predicate and object as the input triple, and having the * supplied context. @@ -217,10 +217,10 @@ public static Statement toStatement(ValueFactory vf, Triple triple, Resource con } /** - * Create a {@link Statement} from the supplied {@link Triple RDF-star triple} and context. + * Create a {@link Statement} from the supplied {@link Triple RDF 1.2 triple} and context. * * @param vf the {@link ValueFactory} to use for creating the {@link Statement} object. - * @param triple an RDF-star triple to convert to a {@link Statement}. + * @param triple an RDF 1.2 triple to convert to a {@link Statement}. * @param context the context to assign to the {@link Statement}. May be null to indicate no context. * @return an {@link Statement} with the same subject, predicate and object as the input triple, and having the * supplied context. @@ -284,8 +284,8 @@ public static boolean isSameTriple(Statement st1, Statement st2) { } /** - * Converts the supplied RDF-star statement to RDF reification statements, and sends the resultant statements to the - * supplied consumer. If the supplied statement is not RDF-star it will be sent to the consumer as is. + * Converts the supplied RDF 1.2 statement to RDF reification statements, and sends the resultant statements to the + * supplied consumer. If the supplied statement is not RDF 1.2 it will be sent to the consumer as is. *

* The statements needed to represent reification will use blank nodes. * @@ -293,85 +293,43 @@ public static boolean isSameTriple(Statement st1, Statement st2) { * @param consumer the {@link Consumer} function for the produced statements. */ @Experimental - public static void convertRDFStarToReification(Statement st, Consumer consumer) { - convertRDFStarToReification(SimpleValueFactory.getInstance(), st, consumer); + public static void convertRDF12ReificationToRDF11(Statement st, Consumer consumer) { + convertRDF12ReificationToRDF11(SimpleValueFactory.getInstance(), st, consumer); } /** - * Converts the supplied RDF-star statement to RDF reification statements, and sends the resultant statements to the - * supplied consumer. If the supplied statement is not RDF-star it will be sent to the consumer as is. + * Converts the supplied RDF 1.2 statement to RDF 1.1 reification statements, and sends the resultant statements to + * the supplied consumer. If the supplied statement does not contain a triple term it will be sent to the consumer + * as is. *

- * The statements needed to represent reification will use blank nodes. - *

- * The supplied value factory is used to create all new statements and blank nodes. + * The supplied value factory is used to create all new statements. * * @param vf the {@link ValueFactory} to use for creating statements. - * @param st the {@link Statement} to convert. + * @param st the {@link Statement} to convert, * @param consumer the {@link Consumer} function for the produced statements. */ @Experimental - public static void convertRDFStarToReification(ValueFactory vf, Statement st, Consumer consumer) { - convertRDFStarToReification(vf, TRIPLE_BNODE_MAPPER, st, consumer); - } - - /** - * Converts the supplied RDF-star statement to RDF reification statements, and sends the resultant statements to the - * supplied consumer. If the supplied statement is not RDF-star it will be sent to the consumer as is. - *

- * The supplied value factory is used to create all new statements. - *

- * The supplied mapper function maps a {@link Triple} to a {@link Resource} and is used to create the ID of the RDF - * reification statement corresponding to the converted triple. The function must return the same value for - * identical triples in order to produce consistent results between invocations. See {@link #TRIPLE_BNODE_MAPPER}. - * - * @param vf the {@link ValueFactory} to use for creating statements. - * @param reifiedIdMapper the mapper {@link Function} from {@link Triple} to {@link Resource}. - * @param st the {@link Statement} to convert, - * @param consumer the {@link Consumer} function for the produced statements. - */ - @Experimental - public static void convertRDFStarToReification(ValueFactory vf, Function reifiedIdMapper, - Statement st, Consumer consumer) { + public static void convertRDF12ReificationToRDF11(ValueFactory vf, Statement st, Consumer consumer) { Resource subject = st.getSubject(); + IRI predicate = st.getPredicate(); Value object = st.getObject(); - if (subject instanceof Triple || object instanceof Triple) { - if (subject instanceof Triple) { - subject = createReifiedStatement(vf, reifiedIdMapper, (Triple) subject, st.getContext(), consumer); + Resource context = st.getContext(); + + if (object.isTriple()) { + if (!predicate.equals(RDF.REIFIES)) { + throw new IllegalArgumentException( + "Cannot convert triple term statement with predicate other than rdf:reifies"); } - if (object instanceof Triple) { - object = createReifiedStatement(vf, reifiedIdMapper, (Triple) object, st.getContext(), consumer); + Triple triple = (Triple) object; + if (triple.getObject().isTriple()) { + throw new IllegalArgumentException("Nested triples cannot be converted to RDF 1.1 reification"); } - st = vf.createStatement(subject, st.getPredicate(), object, st.getContext()); + consumer.accept(vf.createStatement(subject, RDF.TYPE, RDF.STATEMENT, context)); + consumer.accept(vf.createStatement(subject, RDF.SUBJECT, triple.getSubject(), context)); + consumer.accept(vf.createStatement(subject, RDF.PREDICATE, triple.getPredicate(), context)); + consumer.accept(vf.createStatement(subject, RDF.OBJECT, triple.getObject(), context)); + } else { + consumer.accept(st); } - consumer.accept(st); - } - - /** - * Converts the supplied RDF-star triple to a series of RDF reification statements and sends the statements to the - * supplied consumer. The subject of the created statements is returned. - *

- * The supplied value factory is used to create all new statements. - *

- * The supplied mapper function maps a {@link Triple} to a {@link Resource} and is used to create the ID of the RDF - * reification statement corresponding to the converted triple. - * - * @param vf the {@link ValueFactory} to use for creating statements. - * @param reifiedIdMapper the mapper {@link Function} from {@link Triple} to {@link Resource}. - * @param triple the {@link Triple} to convert. - * @param consumer the {@link Consumer} function for the produced statements. - * @return the {@link Resource} that was used as the subject of the created RDF reification statements. - */ - private static Resource createReifiedStatement(ValueFactory vf, Function reifiedIdMapper, - Triple triple, Resource context, Consumer consumer) { - Resource stId = reifiedIdMapper.apply(triple); - Statement reifiedSt = vf.createStatement(stId, RDF.TYPE, RDF.STATEMENT, context); - consumer.accept(reifiedSt); - Statement reifiedStSubject = vf.createStatement(stId, RDF.SUBJECT, triple.getSubject(), context); - convertRDFStarToReification(vf, reifiedIdMapper, reifiedStSubject, consumer); - Statement reifiedStPredicate = vf.createStatement(stId, RDF.PREDICATE, triple.getPredicate(), context); - consumer.accept(reifiedStPredicate); - Statement reifiedStObject = vf.createStatement(stId, RDF.OBJECT, triple.getObject(), context); - convertRDFStarToReification(vf, reifiedIdMapper, reifiedStObject, consumer); - return stId; } } diff --git a/core/model/src/main/java/org/eclipse/rdf4j/model/util/Values.java b/core/model/src/main/java/org/eclipse/rdf4j/model/util/Values.java index 6eeb898002e..1a41acaa207 100644 --- a/core/model/src/main/java/org/eclipse/rdf4j/model/util/Values.java +++ b/core/model/src/main/java/org/eclipse/rdf4j/model/util/Values.java @@ -609,7 +609,7 @@ public static Literal literal(ValueFactory vf, Object object, boolean failOnUnkn /* triple factory methods */ /** - * Creates a new {@link Triple RDF-star embedded triple} with the supplied subject, predicate, and object. + * Creates a new {@link Triple embedded triple} with the supplied subject, predicate, and object. * * @param subject the Triple subject * @param predicate the Triple predicate @@ -622,7 +622,7 @@ public static Triple triple(Resource subject, IRI predicate, Value object) { } /** - * Creates a new {@link Triple RDF-star embedded triple} with the supplied subject, predicate, and object. + * Creates a new {@link Triple embedded triple} with the supplied subject, predicate, and object. * * @param vf the {@link ValueFactory} to use for creation of the {@link Triple} * @param subject the Triple subject @@ -640,7 +640,7 @@ public static Triple triple(ValueFactory vf, Resource subject, IRI predicate, Va } /** - * Creates a new {@link Triple RDF-star embedded triple} using the subject, predicate and object from the supplied + * Creates a new {@link Triple embedded triple} using the subject, predicate and object from the supplied * {@link Statement}. * * @param statement the {@link Statement} from which to construct a {@link Triple} @@ -653,7 +653,7 @@ public static Triple triple(Statement statement) { } /** - * Creates a new {@link Triple RDF-star embedded triple} using the subject, predicate and object from the supplied + * Creates a new {@link Triple embedded triple} using the subject, predicate and object from the supplied * {@link Statement}. * * @param vf the {@link ValueFactory} to use for creation of the {@link Triple} diff --git a/core/model/src/test/java/org/eclipse/rdf4j/model/impl/SimpleLiteralTest.java b/core/model/src/test/java/org/eclipse/rdf4j/model/impl/SimpleLiteralTest.java index 61dab2ff8e3..82b6a40d8f6 100644 --- a/core/model/src/test/java/org/eclipse/rdf4j/model/impl/SimpleLiteralTest.java +++ b/core/model/src/test/java/org/eclipse/rdf4j/model/impl/SimpleLiteralTest.java @@ -30,6 +30,11 @@ protected Literal literal(String label, String language) { return new SimpleLiteral(label, language); } + @Override + protected Literal literal(String label, String language, Literal.BaseDirection dir) { + return new SimpleLiteral(label, language, dir); + } + @Override protected Literal literal(String label, IRI datatype) { return new SimpleLiteral(label, datatype); diff --git a/core/model/src/test/java/org/eclipse/rdf4j/model/util/ModelReificationTestHelper.java b/core/model/src/test/java/org/eclipse/rdf4j/model/util/ModelReificationTestHelper.java new file mode 100644 index 00000000000..5f93cf69e97 --- /dev/null +++ b/core/model/src/test/java/org/eclipse/rdf4j/model/util/ModelReificationTestHelper.java @@ -0,0 +1,187 @@ +/******************************************************************************* + * Copyright (c) 2020 Eclipse RDF4J contributors. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Distribution License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + *******************************************************************************/ +package org.eclipse.rdf4j.model.util; + +import org.eclipse.rdf4j.model.BNode; +import org.eclipse.rdf4j.model.IRI; +import org.eclipse.rdf4j.model.Literal; +import org.eclipse.rdf4j.model.Model; +import org.eclipse.rdf4j.model.ValueFactory; +import org.eclipse.rdf4j.model.impl.LinkedHashModel; +import org.eclipse.rdf4j.model.impl.SimpleValueFactory; +import org.eclipse.rdf4j.model.vocabulary.RDF; + +public class ModelReificationTestHelper { + private final static ValueFactory VF = SimpleValueFactory.getInstance(); + + private final static IRI GRAPH_NULL = null; + private final static IRI GRAPH_1 = VF.createIRI("urn:graph1"); + private final static IRI GRAPH_2 = VF.createIRI("urn:graph2"); + private final static IRI IRI_1 = VF.createIRI("urn:a"); + private final static IRI IRI_2 = VF.createIRI("urn:b"); + private final static IRI IRI_3 = VF.createIRI("urn:c"); + private final static IRI IRI_4 = VF.createIRI("urn:d"); + private final static IRI IRI_5 = VF.createIRI("urn:e"); + private final static IRI IRI_6 = VF.createIRI("urn:f"); + private final static Literal LITERAL_1 = VF.createLiteral("literal 1"); + private final static Literal LITERAL_2 = VF.createLiteral("literal 2"); + private final static BNode BNODE_1 = VF.createBNode("bnode1"); + private final static BNode BNODE_2 = VF.createBNode("bnode2"); + + public static Model createRDF12ReificationModel() { + Model rdf12Model = new LinkedHashModel(); + Statements.create(VF, IRI_1, IRI_2, IRI_3, rdf12Model, GRAPH_NULL); + + // maps iri1 iri2 <> to RDF 1.2 reification + BNode t1 = VF.createBNode(); + Statements.create(VF, IRI_1, IRI_2, t1, rdf12Model, GRAPH_1); + Statements.create(VF, t1, RDF.REIFIES, VF.createTriple(IRI_4, IRI_5, LITERAL_1), rdf12Model, GRAPH_1); + + // maps iri1 iri3 <> to reification + // same triple/reification statements as previous entry + Statements.create(VF, IRI_1, IRI_3, t1, rdf12Model, GRAPH_1); + + // maps <> iri3 _:bnode1 to reification + BNode t2 = VF.createBNode(); + Statements.create(VF, t2, IRI_3, BNODE_1, rdf12Model, GRAPH_2); + Statements.create(VF, t2, RDF.REIFIES, VF.createTriple(IRI_5, IRI_6, IRI_4), rdf12Model, GRAPH_2); + + // maps a complex nested statement to reification + // subj: << <> iri3 <> >> + // pred: iri2 + // obj: << <<_:bnode2 iri3 "literal2">> iri4 <> >> + BNode t3 = VF.createBNode(); + BNode t4 = VF.createBNode(); + BNode t5 = VF.createBNode(); + BNode t6 = VF.createBNode(); + BNode t7 = VF.createBNode(); + BNode t8 = VF.createBNode(); + Statements.create(VF, t3, IRI_2, t4, rdf12Model, GRAPH_2); + Statements.create(VF, t3, RDF.REIFIES, VF.createTriple(t5, IRI_3, t6), rdf12Model, GRAPH_2); + Statements.create(VF, t4, RDF.REIFIES, VF.createTriple(t7, IRI_4, t8), rdf12Model, GRAPH_2); + Statements.create(VF, t5, RDF.REIFIES, VF.createTriple(IRI_1, IRI_2, LITERAL_2), rdf12Model, GRAPH_2); + Statements.create(VF, t6, RDF.REIFIES, VF.createTriple(IRI_4, IRI_5, IRI_6), rdf12Model, GRAPH_2); + Statements.create(VF, t7, RDF.REIFIES, VF.createTriple(BNODE_2, IRI_3, LITERAL_2), rdf12Model, GRAPH_2); + Statements.create(VF, t8, RDF.REIFIES, VF.createTriple(IRI_3, IRI_6, IRI_1), rdf12Model, GRAPH_2); + + return rdf12Model; + } + + public static Model createRDF11ReificationModel() { + Model rdf11Model = new LinkedHashModel(); + Statements.create(VF, IRI_1, IRI_2, IRI_3, rdf11Model, GRAPH_NULL); + + // maps iri1 iri2 <> to RDF 1.1 reification + BNode t1 = VF.createBNode(); + Statements.create(VF, IRI_1, IRI_2, t1, rdf11Model, GRAPH_1); + Statements.create(VF, t1, RDF.TYPE, RDF.STATEMENT, rdf11Model, GRAPH_1); + Statements.create(VF, t1, RDF.SUBJECT, IRI_4, rdf11Model, GRAPH_1); + Statements.create(VF, t1, RDF.PREDICATE, IRI_5, rdf11Model, GRAPH_1); + Statements.create(VF, t1, RDF.OBJECT, LITERAL_1, rdf11Model, GRAPH_1); + + // maps iri1 iri3 <> to reification + // same triple/reification statements as previous entry + Statements.create(VF, IRI_1, IRI_3, t1, rdf11Model, GRAPH_1); + Statements.create(VF, t1, RDF.TYPE, RDF.STATEMENT, rdf11Model, GRAPH_1); + Statements.create(VF, t1, RDF.SUBJECT, IRI_4, rdf11Model, GRAPH_1); + Statements.create(VF, t1, RDF.PREDICATE, IRI_5, rdf11Model, GRAPH_1); + Statements.create(VF, t1, RDF.OBJECT, LITERAL_1, rdf11Model, GRAPH_1); + + // maps <> iri3 _:bnode1 to reification + BNode t2 = VF.createBNode(); + Statements.create(VF, t2, IRI_3, BNODE_1, rdf11Model, GRAPH_2); + Statements.create(VF, t2, RDF.TYPE, RDF.STATEMENT, rdf11Model, GRAPH_2); + Statements.create(VF, t2, RDF.SUBJECT, IRI_5, rdf11Model, GRAPH_2); + Statements.create(VF, t2, RDF.PREDICATE, IRI_6, rdf11Model, GRAPH_2); + Statements.create(VF, t2, RDF.OBJECT, IRI_4, rdf11Model, GRAPH_2); + + // maps a complex nested statement to reification + // t3 + // t5 t6 + // subj: << <> iri3 <> >> + // pred: iri2 + // obj: << <<_:bnode2 iri3 "literal2">> iri4 <> >> + // t7 t8 + // t4 + BNode t3 = VF.createBNode(); + BNode t4 = VF.createBNode(); + BNode t5 = VF.createBNode(); + BNode t6 = VF.createBNode(); + BNode t7 = VF.createBNode(); + BNode t8 = VF.createBNode(); + Statements.create(VF, t3, IRI_2, t4, rdf11Model, GRAPH_2); + Statements.create(VF, t3, RDF.TYPE, RDF.STATEMENT, rdf11Model, GRAPH_2); + Statements.create(VF, t3, RDF.SUBJECT, t5, rdf11Model, GRAPH_2); + Statements.create(VF, t3, RDF.PREDICATE, IRI_3, rdf11Model, GRAPH_2); + Statements.create(VF, t3, RDF.OBJECT, t6, rdf11Model, GRAPH_2); + Statements.create(VF, t5, RDF.TYPE, RDF.STATEMENT, rdf11Model, GRAPH_2); + Statements.create(VF, t5, RDF.SUBJECT, IRI_1, rdf11Model, GRAPH_2); + Statements.create(VF, t5, RDF.PREDICATE, IRI_2, rdf11Model, GRAPH_2); + Statements.create(VF, t5, RDF.OBJECT, LITERAL_2, rdf11Model, GRAPH_2); + Statements.create(VF, t6, RDF.TYPE, RDF.STATEMENT, rdf11Model, GRAPH_2); + Statements.create(VF, t6, RDF.SUBJECT, IRI_4, rdf11Model, GRAPH_2); + Statements.create(VF, t6, RDF.PREDICATE, IRI_5, rdf11Model, GRAPH_2); + Statements.create(VF, t6, RDF.OBJECT, IRI_6, rdf11Model, GRAPH_2); + Statements.create(VF, t4, RDF.TYPE, RDF.STATEMENT, rdf11Model, GRAPH_2); + Statements.create(VF, t4, RDF.SUBJECT, t7, rdf11Model, GRAPH_2); + Statements.create(VF, t4, RDF.PREDICATE, IRI_4, rdf11Model, GRAPH_2); + Statements.create(VF, t4, RDF.OBJECT, t8, rdf11Model, GRAPH_2); + Statements.create(VF, t7, RDF.TYPE, RDF.STATEMENT, rdf11Model, GRAPH_2); + Statements.create(VF, t7, RDF.SUBJECT, BNODE_2, rdf11Model, GRAPH_2); + Statements.create(VF, t7, RDF.PREDICATE, IRI_3, rdf11Model, GRAPH_2); + Statements.create(VF, t7, RDF.OBJECT, LITERAL_2, rdf11Model, GRAPH_2); + Statements.create(VF, t8, RDF.TYPE, RDF.STATEMENT, rdf11Model, GRAPH_2); + Statements.create(VF, t8, RDF.SUBJECT, IRI_3, rdf11Model, GRAPH_2); + Statements.create(VF, t8, RDF.PREDICATE, IRI_6, rdf11Model, GRAPH_2); + Statements.create(VF, t8, RDF.OBJECT, IRI_1, rdf11Model, GRAPH_2); + + return rdf11Model; + } + + public static Model createIncompleteRDF11ReificationModel() { + Model reifiedModel = new LinkedHashModel(); + Statements.create(VF, IRI_1, IRI_2, IRI_3, reifiedModel, GRAPH_NULL); + + // maps iri1 iri2 <> to reification + BNode t1 = VF.createBNode(); + Statements.create(VF, IRI_1, IRI_2, t1, reifiedModel, GRAPH_1); + // Incomplete reification: missing t1 RDF.TYPE RDF.STATEMENT + Statements.create(VF, t1, RDF.SUBJECT, IRI_4, reifiedModel, GRAPH_1); + Statements.create(VF, t1, RDF.PREDICATE, IRI_5, reifiedModel, GRAPH_1); + Statements.create(VF, t1, RDF.OBJECT, LITERAL_1, reifiedModel, GRAPH_1); + + // maps <> iri3 _:bnode1 to reification + BNode t2 = VF.createBNode(); + Statements.create(VF, t2, IRI_3, BNODE_1, reifiedModel, GRAPH_2); + Statements.create(VF, t2, RDF.TYPE, RDF.STATEMENT, reifiedModel, GRAPH_2); + // Incomplete reification: missing t2 RDF.SUBJECT iri5 + Statements.create(VF, t2, RDF.PREDICATE, IRI_6, reifiedModel, GRAPH_2); + Statements.create(VF, t2, RDF.OBJECT, IRI_4, reifiedModel, GRAPH_2); + + // maps <> iri3 iri6 to reification + BNode t3 = VF.createBNode(); + Statements.create(VF, t3, IRI_3, IRI_6, reifiedModel, GRAPH_2); + Statements.create(VF, t3, RDF.TYPE, RDF.STATEMENT, reifiedModel, GRAPH_2); + Statements.create(VF, t3, RDF.SUBJECT, IRI_1, reifiedModel, GRAPH_2); + // Incomplete reification: missing t3 RDF.PREDICATE iri2 + Statements.create(VF, t3, RDF.OBJECT, IRI_4, reifiedModel, GRAPH_2); + + // maps iri6 iri3 <> to reification + BNode t4 = VF.createBNode(); + Statements.create(VF, IRI_6, IRI_3, t4, reifiedModel, GRAPH_2); + Statements.create(VF, t4, RDF.TYPE, RDF.STATEMENT, reifiedModel, GRAPH_2); + Statements.create(VF, t4, RDF.SUBJECT, IRI_1, reifiedModel, GRAPH_2); + Statements.create(VF, t4, RDF.PREDICATE, IRI_2, reifiedModel, GRAPH_2); + // Incomplete reification: missing t4 RDF.OBJECT "literal2" + + return reifiedModel; + } +} diff --git a/core/model/src/test/java/org/eclipse/rdf4j/model/util/ModelsTest.java b/core/model/src/test/java/org/eclipse/rdf4j/model/util/ModelsTest.java index 0e48d4daa87..38fcd03eb9e 100644 --- a/core/model/src/test/java/org/eclipse/rdf4j/model/util/ModelsTest.java +++ b/core/model/src/test/java/org/eclipse/rdf4j/model/util/ModelsTest.java @@ -136,6 +136,27 @@ public void testModelsIsomorphic_BlankNodeContext() { assertTrue(Models.isomorphic(model1, model2)); } + @Test + public void testModelsIsomorphic_TripleTerms_SingleContext() { + model1.add(VF.createBNode("X"), RDF.REIFIES, VF.createTriple(VF.createBNode("a"), RDF.TYPE, bar), foo); + model2.add(VF.createBNode("Y"), RDF.REIFIES, VF.createTriple(VF.createBNode("b"), RDF.TYPE, bar), foo); + + assertTrue(Models.isomorphic(model1, model2)); + } + + @Test + public void testModelsIsomorphic_TripleTerms_MultipleContexts() { + model1.add(VF.createBNode("X"), RDF.REIFIES, VF.createTriple(VF.createBNode("a"), RDF.TYPE, bar), foo); + model2.add(VF.createBNode("Y"), RDF.REIFIES, VF.createTriple(VF.createBNode("b"), RDF.TYPE, bar), foo); + + model1.add(VF.createBNode("Z"), RDF.REIFIES, + VF.createTriple(VF.createBNode("A"), RDF.ALT, VF.createLiteral("some text")), bar); + model2.add(VF.createBNode("W"), RDF.REIFIES, + VF.createTriple(VF.createBNode("B"), RDF.ALT, VF.createLiteral("some text")), bar); + + assertTrue(Models.isomorphic(model1, model2)); + } + @Test public void testIsSubset() { @@ -456,75 +477,75 @@ public void testStripContextsSpecificContext() { } @Test - public void testConvertReificationToRDFStar() { - Model reificationModel = RDFStarTestHelper.createRDFReificationModel(); - Model referenceRDFStarModel = RDFStarTestHelper.createRDFStarModel(); - - Model rdfStarModel1 = Models.convertReificationToRDFStar(VF, reificationModel); - assertTrue("RDF reification conversion to RDF-star with explicit VF, model-to-model", - Models.isomorphic(rdfStarModel1, referenceRDFStarModel)); - - Model rdfStarModel2 = Models.convertReificationToRDFStar(reificationModel); - assertTrue("RDF reification conversion to RDF-star with implicit VF, model-to-model", - Models.isomorphic(rdfStarModel2, referenceRDFStarModel)); - - Model rdfStarModel3 = new TreeModel(); - Models.convertReificationToRDFStar(VF, reificationModel, (Consumer) rdfStarModel3::add); - assertTrue("RDF reification conversion to RDF-star with explicit VF, model-to-consumer", - Models.isomorphic(rdfStarModel3, referenceRDFStarModel)); - - Model rdfStarModel4 = new TreeModel(); - Models.convertReificationToRDFStar(reificationModel, rdfStarModel4::add); - assertTrue("RDF reification conversion to RDF-star with implicit VF, model-to-consumer", - Models.isomorphic(rdfStarModel4, referenceRDFStarModel)); + public void testConvertReificationToRDF12() { + Model rdf11Model = ModelReificationTestHelper.createRDF11ReificationModel(); + Model referenceRdf12Model = ModelReificationTestHelper.createRDF12ReificationModel(); + + Model convertedRdf11Model = Models.convertReificationToRDF12(VF, rdf11Model); + assertTrue("RDF 1.1 reification conversion to RDF 1.2 with explicit VF, model-to-model", + Models.isomorphic(convertedRdf11Model, referenceRdf12Model)); + + Model convertedRdf11Model2 = Models.convertReificationToRDF12(rdf11Model); + assertTrue("RDF reification conversion to RDF 1.2 with implicit VF, model-to-model", + Models.isomorphic(convertedRdf11Model2, referenceRdf12Model)); + + Model convertedRdf11Model3 = new TreeModel(); + Models.convertReificationToRDF12(VF, rdf11Model, (Consumer) convertedRdf11Model3::add); + assertTrue("RDF reification conversion to RDF 1.2 with explicit VF, model-to-consumer", + Models.isomorphic(convertedRdf11Model3, referenceRdf12Model)); + + Model convertedRdf11Model4 = new TreeModel(); + Models.convertReificationToRDF12(rdf11Model, convertedRdf11Model4::add); + assertTrue("RDF reification conversion to RDF 1.2 with implicit VF, model-to-consumer", + Models.isomorphic(convertedRdf11Model4, referenceRdf12Model)); } @Test public void testConvertIncompleteReificationToRDFStar() { // Incomplete RDF reification (missing type, subject, predicate or object) should not add statements // and should not remove any of the existing incomplete reification statements. - Model incompleteReificationModel = RDFStarTestHelper.createIncompleteRDFReificationModel(); + Model incompleteReificationModel = ModelReificationTestHelper.createIncompleteRDF11ReificationModel(); - Model rdfStarModel1 = Models.convertReificationToRDFStar(VF, incompleteReificationModel); - assertTrue("Incomplete RDF reification conversion to RDF-star with explicit VF, model-to-model", + Model rdfStarModel1 = Models.convertReificationToRDF12(VF, incompleteReificationModel); + assertTrue("Incomplete RDF reification conversion to RDF 1.2 with explicit VF, model-to-model", Models.isomorphic(rdfStarModel1, incompleteReificationModel)); - Model rdfStarModel2 = Models.convertReificationToRDFStar(incompleteReificationModel); - assertTrue("Incomplete RDF reification conversion to RDF-star with implicit VF, model-to-model", + Model rdfStarModel2 = Models.convertReificationToRDF12(incompleteReificationModel); + assertTrue("Incomplete RDF reification conversion to RDF 1.2 with implicit VF, model-to-model", Models.isomorphic(rdfStarModel2, incompleteReificationModel)); Model rdfStarModel3 = new TreeModel(); - Models.convertReificationToRDFStar(VF, incompleteReificationModel, (Consumer) rdfStarModel3::add); - assertTrue("Incomplete RDF reification conversion to RDF-star with explicit VF, model-to-consumer", + Models.convertReificationToRDF12(VF, incompleteReificationModel, (Consumer) rdfStarModel3::add); + assertTrue("Incomplete RDF reification conversion to RDF 1.2 with explicit VF, model-to-consumer", Models.isomorphic(rdfStarModel3, incompleteReificationModel)); Model rdfStarModel4 = new TreeModel(); - Models.convertReificationToRDFStar(incompleteReificationModel, rdfStarModel4::add); - assertTrue("Incomplete RDF reification conversion to RDF-star with implicit VF, model-to-consumer", + Models.convertReificationToRDF12(incompleteReificationModel, rdfStarModel4::add); + assertTrue("Incomplete RDF reification conversion to RDF 1.2 with implicit VF, model-to-consumer", Models.isomorphic(rdfStarModel4, incompleteReificationModel)); } @Test public void testConvertRDFStarToReification() { - Model rdfStarModel = RDFStarTestHelper.createRDFStarModel(); - Model referenceModel = RDFStarTestHelper.createRDFReificationModel(); + Model rdf12ReificationModel = ModelReificationTestHelper.createRDF12ReificationModel(); + Model referenceModel = ModelReificationTestHelper.createRDF11ReificationModel(); - Model reificationModel1 = Models.convertRDFStarToReification(VF, rdfStarModel); - assertTrue("RDF-star conversion to reification with explicit VF, model-to-model", + Model reificationModel1 = Models.convertRDF12ReificationToRDF11(VF, rdf12ReificationModel); + assertTrue("RDF 1.2 conversion to RDF 1.1 reification with explicit VF, model-to-model", Models.isomorphic(reificationModel1, referenceModel)); - Model reificationModel2 = Models.convertRDFStarToReification(rdfStarModel); - assertTrue("RDF-star conversion to reification with implicit VF, model-to-model", + Model reificationModel2 = Models.convertRDF12ReificationToRDF11(rdf12ReificationModel); + assertTrue("RDF 1.2 conversion to RDF 1.1 reification with implicit VF, model-to-model", Models.isomorphic(reificationModel2, referenceModel)); Model reificationModel3 = new TreeModel(); - Models.convertRDFStarToReification(VF, rdfStarModel, (Consumer) reificationModel3::add); - assertTrue("RDF-star conversion to reification with explicit VF, model-to-consumer", + Models.convertRDF12ReificationToRDF11(VF, rdf12ReificationModel, (Consumer) reificationModel3::add); + assertTrue("RDF 1.2 conversion to RDF 1.1 reification with explicit VF, model-to-consumer", Models.isomorphic(reificationModel3, referenceModel)); Model reificationModel4 = new TreeModel(); - Models.convertRDFStarToReification(rdfStarModel, reificationModel4::add); - assertTrue("RDF-star conversion to reification with explicit VF, model-to-consumer", + Models.convertRDF12ReificationToRDF11(rdf12ReificationModel, reificationModel4::add); + assertTrue("RDF 1.2 conversion to RDF 1.1 reification with explicit VF, model-to-consumer", Models.isomorphic(reificationModel4, referenceModel)); } diff --git a/core/model/src/test/java/org/eclipse/rdf4j/model/util/RDFStarTestHelper.java b/core/model/src/test/java/org/eclipse/rdf4j/model/util/RDFStarTestHelper.java deleted file mode 100644 index f1eac83b89a..00000000000 --- a/core/model/src/test/java/org/eclipse/rdf4j/model/util/RDFStarTestHelper.java +++ /dev/null @@ -1,164 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2020 Eclipse RDF4J contributors. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Distribution License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * SPDX-License-Identifier: BSD-3-Clause - *******************************************************************************/ -package org.eclipse.rdf4j.model.util; - -import org.eclipse.rdf4j.model.BNode; -import org.eclipse.rdf4j.model.IRI; -import org.eclipse.rdf4j.model.Literal; -import org.eclipse.rdf4j.model.Model; -import org.eclipse.rdf4j.model.ValueFactory; -import org.eclipse.rdf4j.model.impl.LinkedHashModel; -import org.eclipse.rdf4j.model.impl.SimpleValueFactory; -import org.eclipse.rdf4j.model.vocabulary.RDF; - -public class RDFStarTestHelper { - private final static ValueFactory VF = SimpleValueFactory.getInstance(); - - private final static IRI GRAPH_NULL = null; - private final static IRI GRAPH_1 = VF.createIRI("urn:graph1"); - private final static IRI GRAPH_2 = VF.createIRI("urn:graph2"); - private final static IRI IRI_1 = VF.createIRI("urn:a"); - private final static IRI IRI_2 = VF.createIRI("urn:b"); - private final static IRI IRI_3 = VF.createIRI("urn:c"); - private final static IRI IRI_4 = VF.createIRI("urn:d"); - private final static IRI IRI_5 = VF.createIRI("urn:e"); - private final static IRI IRI_6 = VF.createIRI("urn:f"); - private final static Literal LITERAL_1 = VF.createLiteral("literal 1"); - private final static Literal LITERAL_2 = VF.createLiteral("literal 2"); - private final static BNode BNODE_1 = VF.createBNode("bnode1"); - private final static BNode BNODE_2 = VF.createBNode("bnode2"); - - public static Model createRDFStarModel() { - Model rdfStarModel = new LinkedHashModel(); - Statements.create(VF, IRI_1, IRI_2, IRI_3, rdfStarModel, GRAPH_NULL); - // The same triple repeated twice - Statements.create(VF, IRI_1, IRI_2, VF.createTriple(IRI_4, IRI_5, LITERAL_1), rdfStarModel, GRAPH_1); - Statements.create(VF, IRI_1, IRI_3, VF.createTriple(IRI_4, IRI_5, LITERAL_1), rdfStarModel, GRAPH_1); - Statements.create(VF, VF.createTriple(IRI_5, IRI_6, IRI_4), IRI_3, BNODE_1, rdfStarModel, GRAPH_2); - Statements.create(VF, VF.createTriple(VF.createTriple(IRI_1, IRI_2, LITERAL_2), - IRI_3, VF.createTriple(IRI_4, IRI_5, IRI_6)), - IRI_2, VF.createTriple(VF.createTriple(BNODE_2, IRI_3, LITERAL_2), - IRI_4, VF.createTriple(IRI_3, IRI_6, IRI_1)), - rdfStarModel, GRAPH_2); - - return rdfStarModel; - } - - public static Model createRDFReificationModel() { - Model reifiedModel = new LinkedHashModel(); - Statements.create(VF, IRI_1, IRI_2, IRI_3, reifiedModel, GRAPH_NULL); - - // maps iri1 iri2 <> to reification - BNode t1 = VF.createBNode(); - Statements.create(VF, IRI_1, IRI_2, t1, reifiedModel, GRAPH_1); - Statements.create(VF, t1, RDF.TYPE, RDF.STATEMENT, reifiedModel, GRAPH_1); - Statements.create(VF, t1, RDF.SUBJECT, IRI_4, reifiedModel, GRAPH_1); - Statements.create(VF, t1, RDF.PREDICATE, IRI_5, reifiedModel, GRAPH_1); - Statements.create(VF, t1, RDF.OBJECT, LITERAL_1, reifiedModel, GRAPH_1); - - // maps iri1 iri2 <> to reification - // same triple/reification statements as previous entry - Statements.create(VF, IRI_1, IRI_3, t1, reifiedModel, GRAPH_1); - Statements.create(VF, t1, RDF.TYPE, RDF.STATEMENT, reifiedModel, GRAPH_1); - Statements.create(VF, t1, RDF.SUBJECT, IRI_4, reifiedModel, GRAPH_1); - Statements.create(VF, t1, RDF.PREDICATE, IRI_5, reifiedModel, GRAPH_1); - Statements.create(VF, t1, RDF.OBJECT, LITERAL_1, reifiedModel, GRAPH_1); - - // maps <> iri3 _:bnode1 to reification - BNode t2 = VF.createBNode(); - Statements.create(VF, t2, IRI_3, BNODE_1, reifiedModel, GRAPH_2); - Statements.create(VF, t2, RDF.TYPE, RDF.STATEMENT, reifiedModel, GRAPH_2); - Statements.create(VF, t2, RDF.SUBJECT, IRI_5, reifiedModel, GRAPH_2); - Statements.create(VF, t2, RDF.PREDICATE, IRI_6, reifiedModel, GRAPH_2); - Statements.create(VF, t2, RDF.OBJECT, IRI_4, reifiedModel, GRAPH_2); - - // maps a complex nested statement to reification - // t3 - // t5 t6 - // subj: << <> iri3 <> >> - // pred: iri2 - // obj: << <<_:bnode2 iri3 "literal2">> iri4 <> >> - // t7 t8 - // t4 - BNode t3 = VF.createBNode(); - BNode t4 = VF.createBNode(); - BNode t5 = VF.createBNode(); - BNode t6 = VF.createBNode(); - BNode t7 = VF.createBNode(); - BNode t8 = VF.createBNode(); - Statements.create(VF, t3, IRI_2, t4, reifiedModel, GRAPH_2); - Statements.create(VF, t3, RDF.TYPE, RDF.STATEMENT, reifiedModel, GRAPH_2); - Statements.create(VF, t3, RDF.SUBJECT, t5, reifiedModel, GRAPH_2); - Statements.create(VF, t3, RDF.PREDICATE, IRI_3, reifiedModel, GRAPH_2); - Statements.create(VF, t3, RDF.OBJECT, t6, reifiedModel, GRAPH_2); - Statements.create(VF, t5, RDF.TYPE, RDF.STATEMENT, reifiedModel, GRAPH_2); - Statements.create(VF, t5, RDF.SUBJECT, IRI_1, reifiedModel, GRAPH_2); - Statements.create(VF, t5, RDF.PREDICATE, IRI_2, reifiedModel, GRAPH_2); - Statements.create(VF, t5, RDF.OBJECT, LITERAL_2, reifiedModel, GRAPH_2); - Statements.create(VF, t6, RDF.TYPE, RDF.STATEMENT, reifiedModel, GRAPH_2); - Statements.create(VF, t6, RDF.SUBJECT, IRI_4, reifiedModel, GRAPH_2); - Statements.create(VF, t6, RDF.PREDICATE, IRI_5, reifiedModel, GRAPH_2); - Statements.create(VF, t6, RDF.OBJECT, IRI_6, reifiedModel, GRAPH_2); - Statements.create(VF, t4, RDF.TYPE, RDF.STATEMENT, reifiedModel, GRAPH_2); - Statements.create(VF, t4, RDF.SUBJECT, t7, reifiedModel, GRAPH_2); - Statements.create(VF, t4, RDF.PREDICATE, IRI_4, reifiedModel, GRAPH_2); - Statements.create(VF, t4, RDF.OBJECT, t8, reifiedModel, GRAPH_2); - Statements.create(VF, t7, RDF.TYPE, RDF.STATEMENT, reifiedModel, GRAPH_2); - Statements.create(VF, t7, RDF.SUBJECT, BNODE_2, reifiedModel, GRAPH_2); - Statements.create(VF, t7, RDF.PREDICATE, IRI_3, reifiedModel, GRAPH_2); - Statements.create(VF, t7, RDF.OBJECT, LITERAL_2, reifiedModel, GRAPH_2); - Statements.create(VF, t8, RDF.TYPE, RDF.STATEMENT, reifiedModel, GRAPH_2); - Statements.create(VF, t8, RDF.SUBJECT, IRI_3, reifiedModel, GRAPH_2); - Statements.create(VF, t8, RDF.PREDICATE, IRI_6, reifiedModel, GRAPH_2); - Statements.create(VF, t8, RDF.OBJECT, IRI_1, reifiedModel, GRAPH_2); - - return reifiedModel; - } - - public static Model createIncompleteRDFReificationModel() { - Model reifiedModel = new LinkedHashModel(); - Statements.create(VF, IRI_1, IRI_2, IRI_3, reifiedModel, GRAPH_NULL); - - // maps iri1 iri2 <> to reification - BNode t1 = VF.createBNode(); - Statements.create(VF, IRI_1, IRI_2, t1, reifiedModel, GRAPH_1); - // Incomplete reification: missing t1 RDF.TYPE RDF.STATEMENT - Statements.create(VF, t1, RDF.SUBJECT, IRI_4, reifiedModel, GRAPH_1); - Statements.create(VF, t1, RDF.PREDICATE, IRI_5, reifiedModel, GRAPH_1); - Statements.create(VF, t1, RDF.OBJECT, LITERAL_1, reifiedModel, GRAPH_1); - - // maps <> iri3 _:bnode1 to reification - BNode t2 = VF.createBNode(); - Statements.create(VF, t2, IRI_3, BNODE_1, reifiedModel, GRAPH_2); - Statements.create(VF, t2, RDF.TYPE, RDF.STATEMENT, reifiedModel, GRAPH_2); - // Incomplete reification: missing t2 RDF.SUBJECT iri5 - Statements.create(VF, t2, RDF.PREDICATE, IRI_6, reifiedModel, GRAPH_2); - Statements.create(VF, t2, RDF.OBJECT, IRI_4, reifiedModel, GRAPH_2); - - // maps <> iri3 iri6 to reification - BNode t3 = VF.createBNode(); - Statements.create(VF, t3, IRI_3, IRI_6, reifiedModel, GRAPH_2); - Statements.create(VF, t3, RDF.TYPE, RDF.STATEMENT, reifiedModel, GRAPH_2); - Statements.create(VF, t3, RDF.SUBJECT, IRI_1, reifiedModel, GRAPH_2); - // Incomplete reification: missing t3 RDF.PREDICATE iri2 - Statements.create(VF, t3, RDF.OBJECT, IRI_4, reifiedModel, GRAPH_2); - - // maps iri6 iri3 <> to reification - BNode t4 = VF.createBNode(); - Statements.create(VF, IRI_6, IRI_3, t4, reifiedModel, GRAPH_2); - Statements.create(VF, t4, RDF.TYPE, RDF.STATEMENT, reifiedModel, GRAPH_2); - Statements.create(VF, t4, RDF.SUBJECT, IRI_1, reifiedModel, GRAPH_2); - Statements.create(VF, t4, RDF.PREDICATE, IRI_2, reifiedModel, GRAPH_2); - // Incomplete reification: missing t4 RDF.OBJECT "literal2" - - return reifiedModel; - } -} diff --git a/core/model/src/test/java/org/eclipse/rdf4j/model/util/StatementsTest.java b/core/model/src/test/java/org/eclipse/rdf4j/model/util/StatementsTest.java index 53281bd9aab..f8cc6c61cf0 100644 --- a/core/model/src/test/java/org/eclipse/rdf4j/model/util/StatementsTest.java +++ b/core/model/src/test/java/org/eclipse/rdf4j/model/util/StatementsTest.java @@ -86,25 +86,19 @@ public void testInvalidInput() { @Test public void testRDFStarReification() { - Model rdfStarModel = RDFStarTestHelper.createRDFStarModel(); + Model rdfStarModel = ModelReificationTestHelper.createRDF12ReificationModel(); - Model reifiedModel = RDFStarTestHelper.createRDFReificationModel(); + Model reifiedModel = ModelReificationTestHelper.createRDF11ReificationModel(); Model convertedModel1 = new LinkedHashModel(); - rdfStarModel.forEach((s) -> Statements.convertRDFStarToReification(s, convertedModel1::add)); - assertTrue("RDF-star conversion to reification with implicit VF", + rdfStarModel.forEach((s) -> Statements.convertRDF12ReificationToRDF11(s, convertedModel1::add)); + assertTrue("RDF 1.2 conversion to reification with implicit VF", Models.isomorphic(reifiedModel, convertedModel1)); Model convertedModel2 = new LinkedHashModel(); - rdfStarModel.forEach((s) -> Statements.convertRDFStarToReification(vf, s, convertedModel2::add)); - assertTrue("RDF-star conversion to reification with explicit VF", + rdfStarModel.forEach((s) -> Statements.convertRDF12ReificationToRDF11(vf, s, convertedModel2::add)); + assertTrue("RDF 1.2 conversion to reification with explicit VF", Models.isomorphic(reifiedModel, convertedModel2)); - - Model convertedModel3 = new LinkedHashModel(); - rdfStarModel.forEach((s) -> Statements.convertRDFStarToReification(vf, (t) -> vf.createBNode(t.stringValue()), - s, convertedModel3::add)); - assertTrue("RDF-star conversion to reification with explicit VF and custom BNode mapping", - Models.isomorphic(reifiedModel, convertedModel3)); } @Test diff --git a/core/pom.xml b/core/pom.xml index ed94faedcde..2fa72088ce1 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -4,7 +4,7 @@ org.eclipse.rdf4j rdf4j - 5.1.0-SNAPSHOT + 6.0.0 rdf4j-core pom diff --git a/core/query/pom.xml b/core/query/pom.xml index 6600bd51a4e..e7a555297dd 100644 --- a/core/query/pom.xml +++ b/core/query/pom.xml @@ -4,7 +4,7 @@ org.eclipse.rdf4j rdf4j-core - 5.1.0-SNAPSHOT + 6.0.0 rdf4j-query RDF4J: Query diff --git a/core/queryalgebra/evaluation/pom.xml b/core/queryalgebra/evaluation/pom.xml index a29c5f1ab29..03d9f01ad14 100644 --- a/core/queryalgebra/evaluation/pom.xml +++ b/core/queryalgebra/evaluation/pom.xml @@ -4,7 +4,7 @@ org.eclipse.rdf4j rdf4j-queryalgebra - 5.1.0-SNAPSHOT + 6.0.0 rdf4j-queryalgebra-evaluation RDF4J: Query algebra - evaluation diff --git a/core/queryalgebra/evaluation/src/test/java/org/eclipse/rdf4j/query/algebra/evaluation/function/triple/StatementFunctionTest.java b/core/queryalgebra/evaluation/src/test/java/org/eclipse/rdf4j/query/algebra/evaluation/function/triple/StatementFunctionTest.java index b491dd19312..0eaf4074476 100644 --- a/core/queryalgebra/evaluation/src/test/java/org/eclipse/rdf4j/query/algebra/evaluation/function/triple/StatementFunctionTest.java +++ b/core/queryalgebra/evaluation/src/test/java/org/eclipse/rdf4j/query/algebra/evaluation/function/triple/StatementFunctionTest.java @@ -156,58 +156,6 @@ public void testEvaluateBNodeAndTriple() { assertEquals(value, other, "expect to be the same"); } - @Test - public void testEvaluateTripleAndIRI() { - IRI pred = f.createIRI("urn:b"); - IRI obj = f.createIRI("urn:c"); - Triple subj = f.createTriple(pred, pred, pred); - - Value value = function.evaluate(f, subj, pred, obj); - assertNotNull(value); - assertTrue(value instanceof Triple, "expect Triple"); - Triple other = f.createTriple(subj, pred, obj); - assertEquals(value, other, "expect to be the same"); - } - - @Test - public void testEvaluateTripleAndBNode() { - IRI pred = f.createIRI("urn:b"); - BNode obj = f.createBNode(); - Triple subj = f.createTriple(pred, pred, pred); - - Value value = function.evaluate(f, subj, pred, obj); - assertNotNull(value); - assertTrue(value instanceof Triple, "expect Triple"); - Triple other = f.createTriple(subj, pred, obj); - assertEquals(value, other, "expect to be the same"); - } - - @Test - public void testEvaluateTripleAndLiteral() { - IRI pred = f.createIRI("urn:b"); - Literal obj = f.createLiteral(1); - Triple subj = f.createTriple(pred, pred, pred); - - Value value = function.evaluate(f, subj, pred, obj); - assertNotNull(value); - assertTrue(value instanceof Triple, "expect Triple"); - Triple other = f.createTriple(subj, pred, obj); - assertEquals(value, other, "expect to be the same"); - } - - @Test - public void testEvaluateTripleAndTriple() { - IRI pred = f.createIRI("urn:b"); - Triple obj = f.createTriple(pred, pred, pred); - Triple subj = f.createTriple(pred, pred, pred); - - Value value = function.evaluate(f, subj, pred, obj); - assertNotNull(value); - assertTrue(value instanceof Triple, "expect Triple"); - Triple other = f.createTriple(subj, pred, obj); - assertEquals(value, other, "expect to be the same"); - } - @Test public void testNegariveWrongNumberOfArguments() { IRI subj = f.createIRI("urn:a"); diff --git a/core/queryalgebra/evaluation/src/test/java/org/eclipse/rdf4j/query/algebra/evaluation/impl/EvaluationStrategyWithRDFStarTest.java b/core/queryalgebra/evaluation/src/test/java/org/eclipse/rdf4j/query/algebra/evaluation/impl/EvaluationStrategyWithRDFStarTest.java index a7dfebcf593..5daccd06b6e 100644 --- a/core/queryalgebra/evaluation/src/test/java/org/eclipse/rdf4j/query/algebra/evaluation/impl/EvaluationStrategyWithRDFStarTest.java +++ b/core/queryalgebra/evaluation/src/test/java/org/eclipse/rdf4j/query/algebra/evaluation/impl/EvaluationStrategyWithRDFStarTest.java @@ -1,358 +1,358 @@ -/******************************************************************************* - * Copyright (c) 2020 Eclipse RDF4J contributors. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Distribution License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * SPDX-License-Identifier: BSD-3-Clause - *******************************************************************************/ -package org.eclipse.rdf4j.query.algebra.evaluation.impl; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import java.util.ArrayList; -import java.util.Iterator; - -import org.eclipse.rdf4j.common.iteration.AbstractCloseableIteration; -import org.eclipse.rdf4j.common.iteration.CloseableIteration; -import org.eclipse.rdf4j.common.iteration.ConvertingIteration; -import org.eclipse.rdf4j.model.IRI; -import org.eclipse.rdf4j.model.Resource; -import org.eclipse.rdf4j.model.Statement; -import org.eclipse.rdf4j.model.Triple; -import org.eclipse.rdf4j.model.Value; -import org.eclipse.rdf4j.model.ValueFactory; -import org.eclipse.rdf4j.model.impl.SimpleValueFactory; -import org.eclipse.rdf4j.model.vocabulary.RDF; -import org.eclipse.rdf4j.query.BindingSet; -import org.eclipse.rdf4j.query.QueryEvaluationException; -import org.eclipse.rdf4j.query.algebra.TripleRef; -import org.eclipse.rdf4j.query.algebra.Var; -import org.eclipse.rdf4j.query.algebra.evaluation.EvaluationStrategy; -import org.eclipse.rdf4j.query.algebra.evaluation.QueryBindingSet; -import org.eclipse.rdf4j.query.algebra.evaluation.RDFStarTripleSource; -import org.eclipse.rdf4j.query.algebra.evaluation.TripleSource; -import org.eclipse.rdf4j.query.impl.EmptyBindingSet; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.ValueSource; - -/** - * The test verifies the evaluation of TripleRef nodes through evaluation strategy that uses a tripleSource implementing - * either {@link TripleSource} or {@link RDFStarTripleSource} interfaces - * - * @author damyan.ognyanov - */ -public class EvaluationStrategyWithRDFStarTest { - - // the triples over which the evaluations is carried - private final ArrayList triples = new ArrayList<>(); - - ValueFactory vf = SimpleValueFactory.getInstance(); - - TripleRef tripleRefNode; - - CommonBaseSource baseSource; - - /** - * this class does it all over a collection of triples but do not IMPLEMENT either TripleSource nor - * RDFStarTripleSource The sources for the eval strategies just forward the evaluation to an instance of that - * - * @author damyan.ognyanov - */ - class CommonBaseSource { - public CloseableIteration getRdfStarTriples(Resource subj, - IRI pred, Value obj) - throws QueryEvaluationException { - return new AbstractCloseableIteration<>() { - - final Iterator iter = triples.iterator(); - - @Override - public boolean hasNext() - throws QueryEvaluationException { - return iter.hasNext(); - } - - @Override - public Triple next() - throws QueryEvaluationException { - return iter.next(); - } - - @Override - public void remove() - throws QueryEvaluationException { - } - - @Override - protected void handleClose() { - - } - }; - } - - public CloseableIteration getStatements(Resource subj, - IRI pred, Value obj, Resource... contexts) - throws QueryEvaluationException { - // handle only arguments with reification vocabulary - // and return iterations accordingly from the same set of Triples - - // handle (*, rdf:type, rdf:Statement) - if (pred != null && pred.equals(RDF.TYPE) && obj != null && obj.equals(RDF.STATEMENT)) { - return new ConvertingIteration( - getRdfStarTriples(null, null, null)) { - @Override - protected Statement convert(Triple sourceObject) - throws QueryEvaluationException { - return vf.createStatement(sourceObject, RDF.TYPE, RDF.STATEMENT); - } - }; - } else if (pred != null && pred.equals(RDF.SUBJECT)) { - // handle (*, rdf:subject, *) - return new ConvertingIteration( - getRdfStarTriples(null, null, null)) { - @Override - protected Statement convert(Triple sourceObject) - throws QueryEvaluationException { - return vf.createStatement(sourceObject, RDF.SUBJECT, sourceObject.getSubject()); - } - }; - } else if (pred != null && pred.equals(RDF.PREDICATE)) { - // handle (*, rdf:predicate, *) - return new ConvertingIteration( - getRdfStarTriples(null, null, null)) { - @Override - protected Statement convert(Triple sourceObject) - throws QueryEvaluationException { - return vf.createStatement(sourceObject, RDF.PREDICATE, sourceObject.getPredicate()); - } - }; - } else if (pred != null && pred.equals(RDF.OBJECT)) { - // handle (*, rdf:object, *) - return new ConvertingIteration( - getRdfStarTriples(null, null, null)) { - @Override - protected Statement convert(Triple sourceObject) - throws QueryEvaluationException { - return vf.createStatement(sourceObject, RDF.OBJECT, sourceObject.getObject()); - } - }; - } - // DO NOT handle anything else - return null; - } - - } - - @BeforeEach - public void setUp() { - // prepare data - triples.clear(); - triples.add(vf.createTriple(vf.createIRI("urn:a"), vf.createIRI("urn:p"), vf.createIRI("urn:b"))); - triples.add(vf.createTriple(vf.createIRI("urn:a"), vf.createIRI("urn:q"), vf.createIRI("urn:b:1"))); - triples.add(vf.createTriple(vf.createIRI("urn:a:1"), vf.createIRI("urn:p"), vf.createIRI("urn:b"))); - triples.add(vf.createTriple(vf.createIRI("urn:a:2"), vf.createIRI("urn:q"), vf.createIRI("urn:c"))); - - baseSource = new CommonBaseSource(); - - tripleRefNode = new TripleRef(new Var("s"), new Var("p"), new Var("o"), new Var("extern")); - } - - /** - * parametrized: either {@link RDFStarTripleSource} or {@link TripleSource} - * - * @param bRDFStarData - */ - private TripleSource createSource(boolean bRDFStarData) { - if (bRDFStarData) { - return new RDFStarTripleSource() { - - @Override - public ValueFactory getValueFactory() { - return vf; - } - - @Override - public CloseableIteration getStatements(Resource subj, - IRI pred, Value obj, Resource... contexts) - throws QueryEvaluationException { - return baseSource.getStatements(subj, pred, obj, contexts); - } - - @Override - public CloseableIteration getRdfStarTriples(Resource subj, - IRI pred, Value obj) - throws QueryEvaluationException { - return baseSource.getRdfStarTriples(subj, pred, obj); - } - }; - } else { - return new TripleSource() { - @Override - public ValueFactory getValueFactory() { - return vf; - } - - @Override - public CloseableIteration getStatements(Resource subj, - IRI pred, Value obj, Resource... contexts) - throws QueryEvaluationException { - return baseSource.getStatements(subj, pred, obj, contexts); - } - }; - } - } - - @ParameterizedTest(name = "RDF-star={0}") - @ValueSource(booleans = { false, true }) - public void testMatchAllUnbound(boolean bRDFStarData) { - EvaluationStrategy strategy = new StrictEvaluationStrategy(createSource(bRDFStarData), null); - // case check all unbound - try (CloseableIteration iter = strategy.precompile(tripleRefNode) - .evaluate( - new EmptyBindingSet())) { - ArrayList expected = new ArrayList<>(); - triples.forEach(t -> { - expected.add(fromTriple(t)); - }); - ArrayList received = new ArrayList<>(); - while (iter.hasNext()) { - received.add(iter.next()); - } - assertTrue(received.containsAll(expected), "all expected must be received"); - assertTrue(expected.containsAll(received), "all received must be expected"); - } - } - - @ParameterizedTest(name = "RDF-star={0}") - @ValueSource(booleans = { false, true }) - public void testSubjVarBound(boolean bRDFStarData) { - EvaluationStrategy strategy = new StrictEvaluationStrategy(createSource(bRDFStarData), null); - try (CloseableIteration iter = strategy.precompile(tripleRefNode) - .evaluate( - createWithVarValue(tripleRefNode.getSubjectVar(), vf.createIRI("urn:a")))) { - ArrayList expected = new ArrayList<>(); - triples.forEach(t -> { - if (t.getSubject().equals(vf.createIRI("urn:a"))) { - expected.add(fromTriple(t)); - } - }); - ArrayList received = new ArrayList<>(); - while (iter.hasNext()) { - received.add(iter.next()); - } - assertTrue(received.containsAll(expected), "all expected must be received"); - assertTrue(expected.containsAll(received), "all received must be expected"); - } - } - - @ParameterizedTest(name = "RDF-star={0}") - @ValueSource(booleans = { false, true }) - public void testPredVarBound(boolean bRDFStarData) { - EvaluationStrategy strategy = new StrictEvaluationStrategy(createSource(bRDFStarData), null); - try (CloseableIteration iter = strategy.precompile(tripleRefNode) - .evaluate( - createWithVarValue(tripleRefNode.getPredicateVar(), vf.createIRI("urn:p")))) { - - ArrayList expected = new ArrayList<>(); - triples.forEach(t -> { - if (t.getPredicate().equals(vf.createIRI("urn:p"))) { - expected.add(fromTriple(t)); - } - }); - ArrayList received = new ArrayList<>(); - while (iter.hasNext()) { - received.add(iter.next()); - } - assertTrue(received.containsAll(expected), "all expected must be received"); - assertTrue(expected.containsAll(received), "all received must be expected"); - } - } - - @ParameterizedTest(name = "RDF-star={0}") - @ValueSource(booleans = { false, true }) - public void testObjVarBound(boolean bRDFStarData) { - EvaluationStrategy strategy = new StrictEvaluationStrategy(createSource(bRDFStarData), null); - try (CloseableIteration iter = strategy.precompile(tripleRefNode) - .evaluate( - createWithVarValue(tripleRefNode.getObjectVar(), vf.createIRI("urn:b")))) { - - ArrayList expected = new ArrayList<>(); - triples.forEach(t -> { - if (t.getObject().equals(vf.createIRI("urn:b"))) { - expected.add(fromTriple(t)); - } - }); - ArrayList received = new ArrayList<>(); - while (iter.hasNext()) { - received.add(iter.next()); - } - assertTrue(received.containsAll(expected), "all expected must be received"); - assertTrue(expected.containsAll(received), "all received must be expected"); - } - } - - @ParameterizedTest(name = "RDF-star={0}") - @ValueSource(booleans = { false, true }) - public void testSubjAndObjVarBound(boolean bRDFStarData) { - QueryBindingSet set = (QueryBindingSet) createWithVarValue(tripleRefNode.getObjectVar(), vf.createIRI("urn:c")); - set.addBinding(tripleRefNode.getSubjectVar().getName(), vf.createIRI("urn:a:2")); - - EvaluationStrategy strategy = new StrictEvaluationStrategy(createSource(bRDFStarData), null); - try (CloseableIteration iter = strategy.precompile(tripleRefNode).evaluate(set)) { - - ArrayList expected = new ArrayList<>(); - triples.forEach(t -> { - if (t.getObject().equals(vf.createIRI("urn:c")) && t.getSubject().equals(vf.createIRI("urn:a:2"))) { - expected.add(fromTriple(t)); - } - }); - ArrayList received = new ArrayList<>(); - while (iter.hasNext()) { - received.add(iter.next()); - } - assertTrue(received.containsAll(expected), "all expected must be received"); - assertTrue(expected.containsAll(received), "all received must be expected"); - } - } - - @ParameterizedTest(name = "RDF-star={0}") - @ValueSource(booleans = { false, true }) - public void testExtVarBound(boolean bRDFStarData) { - Triple triple = triples.get(0); - QueryBindingSet set = (QueryBindingSet) createWithVarValue(tripleRefNode.getExprVar(), triple); - - EvaluationStrategy strategy = new StrictEvaluationStrategy(createSource(bRDFStarData), null); - try (CloseableIteration iter = strategy.precompile(tripleRefNode).evaluate(set)) { - - ArrayList expected = new ArrayList<>(); - expected.add(fromTriple(triple)); - ArrayList received = new ArrayList<>(); - while (iter.hasNext()) { - received.add(iter.next()); - } - - assertThat(received).containsAll(expected); - assertThat(expected).containsAll(received); - } - } - - private BindingSet createWithVarValue(Var var, Value value) { - QueryBindingSet ret = new QueryBindingSet(); - ret.addBinding(var.getName(), value); - return ret; - } - - private BindingSet fromTriple(Triple t) { - QueryBindingSet ret = new QueryBindingSet(); - ret.addBinding("extern", t); - ret.addBinding("s", t.getSubject()); - ret.addBinding("p", t.getPredicate()); - ret.addBinding("o", t.getObject()); - return ret; - } -} +///******************************************************************************* +// * Copyright (c) 2020 Eclipse RDF4J contributors. +// * +// * All rights reserved. This program and the accompanying materials +// * are made available under the terms of the Eclipse Distribution License v1.0 +// * which accompanies this distribution, and is available at +// * http://www.eclipse.org/org/documents/edl-v10.php. +// * +// * SPDX-License-Identifier: BSD-3-Clause +// *******************************************************************************/ +//package org.eclipse.rdf4j.query.algebra.evaluation.impl; +// +//import static org.assertj.core.api.Assertions.assertThat; +//import static org.junit.jupiter.api.Assertions.assertTrue; +// +//import java.util.ArrayList; +//import java.util.Iterator; +// +//import org.eclipse.rdf4j.common.iteration.AbstractCloseableIteration; +//import org.eclipse.rdf4j.common.iteration.CloseableIteration; +//import org.eclipse.rdf4j.common.iteration.ConvertingIteration; +//import org.eclipse.rdf4j.model.IRI; +//import org.eclipse.rdf4j.model.Resource; +//import org.eclipse.rdf4j.model.Statement; +//import org.eclipse.rdf4j.model.Triple; +//import org.eclipse.rdf4j.model.Value; +//import org.eclipse.rdf4j.model.ValueFactory; +//import org.eclipse.rdf4j.model.impl.SimpleValueFactory; +//import org.eclipse.rdf4j.model.vocabulary.RDF; +//import org.eclipse.rdf4j.query.BindingSet; +//import org.eclipse.rdf4j.query.QueryEvaluationException; +//import org.eclipse.rdf4j.query.algebra.TripleRef; +//import org.eclipse.rdf4j.query.algebra.Var; +//import org.eclipse.rdf4j.query.algebra.evaluation.EvaluationStrategy; +//import org.eclipse.rdf4j.query.algebra.evaluation.QueryBindingSet; +//import org.eclipse.rdf4j.query.algebra.evaluation.RDFStarTripleSource; +//import org.eclipse.rdf4j.query.algebra.evaluation.TripleSource; +//import org.eclipse.rdf4j.query.impl.EmptyBindingSet; +//import org.junit.jupiter.api.BeforeEach; +//import org.junit.jupiter.params.ParameterizedTest; +//import org.junit.jupiter.params.provider.ValueSource; +// +///** +// * The test verifies the evaluation of TripleRef nodes through evaluation strategy that uses a tripleSource implementing +// * either {@link TripleSource} or {@link RDFStarTripleSource} interfaces +// * +// * @author damyan.ognyanov +// */ +//public class EvaluationStrategyWithRDFStarTest { +// +// // the triples over which the evaluations is carried +// private final ArrayList triples = new ArrayList<>(); +// +// ValueFactory vf = SimpleValueFactory.getInstance(); +// +// TripleRef tripleRefNode; +// +// CommonBaseSource baseSource; +// +// /** +// * this class does it all over a collection of triples but do not IMPLEMENT either TripleSource nor +// * RDFStarTripleSource The sources for the eval strategies just forward the evaluation to an instance of that +// * +// * @author damyan.ognyanov +// */ +// class CommonBaseSource { +// public CloseableIteration getRdfStarTriples(Resource subj, +// IRI pred, Value obj) +// throws QueryEvaluationException { +// return new AbstractCloseableIteration<>() { +// +// final Iterator iter = triples.iterator(); +// +// @Override +// public boolean hasNext() +// throws QueryEvaluationException { +// return iter.hasNext(); +// } +// +// @Override +// public Triple next() +// throws QueryEvaluationException { +// return iter.next(); +// } +// +// @Override +// public void remove() +// throws QueryEvaluationException { +// } +// +// @Override +// protected void handleClose() { +// +// } +// }; +// } +// +// public CloseableIteration getStatements(Resource subj, +// IRI pred, Value obj, Resource... contexts) +// throws QueryEvaluationException { +// // handle only arguments with reification vocabulary +// // and return iterations accordingly from the same set of Triples +// +// // handle (*, rdf:type, rdf:Statement) +// if (pred != null && pred.equals(RDF.TYPE) && obj != null && obj.equals(RDF.STATEMENT)) { +// return new ConvertingIteration( +// getRdfStarTriples(null, null, null)) { +// @Override +// protected Statement convert(Triple sourceObject) +// throws QueryEvaluationException { +// return vf.createStatement(sourceObject, RDF.TYPE, RDF.STATEMENT); +// } +// }; +// } else if (pred != null && pred.equals(RDF.SUBJECT)) { +// // handle (*, rdf:subject, *) +// return new ConvertingIteration( +// getRdfStarTriples(null, null, null)) { +// @Override +// protected Statement convert(Triple sourceObject) +// throws QueryEvaluationException { +// return vf.createStatement(sourceObject, RDF.SUBJECT, sourceObject.getSubject()); +// } +// }; +// } else if (pred != null && pred.equals(RDF.PREDICATE)) { +// // handle (*, rdf:predicate, *) +// return new ConvertingIteration( +// getRdfStarTriples(null, null, null)) { +// @Override +// protected Statement convert(Triple sourceObject) +// throws QueryEvaluationException { +// return vf.createStatement(sourceObject, RDF.PREDICATE, sourceObject.getPredicate()); +// } +// }; +// } else if (pred != null && pred.equals(RDF.OBJECT)) { +// // handle (*, rdf:object, *) +// return new ConvertingIteration( +// getRdfStarTriples(null, null, null)) { +// @Override +// protected Statement convert(Triple sourceObject) +// throws QueryEvaluationException { +// return vf.createStatement(sourceObject, RDF.OBJECT, sourceObject.getObject()); +// } +// }; +// } +// // DO NOT handle anything else +// return null; +// } +// +// } +// +// @BeforeEach +// public void setUp() { +// // prepare data +// triples.clear(); +// triples.add(vf.createTriple(vf.createIRI("urn:a"), vf.createIRI("urn:p"), vf.createIRI("urn:b"))); +// triples.add(vf.createTriple(vf.createIRI("urn:a"), vf.createIRI("urn:q"), vf.createIRI("urn:b:1"))); +// triples.add(vf.createTriple(vf.createIRI("urn:a:1"), vf.createIRI("urn:p"), vf.createIRI("urn:b"))); +// triples.add(vf.createTriple(vf.createIRI("urn:a:2"), vf.createIRI("urn:q"), vf.createIRI("urn:c"))); +// +// baseSource = new CommonBaseSource(); +// +// tripleRefNode = new TripleRef(new Var("s"), new Var("p"), new Var("o"), new Var("extern")); +// } +// +// /** +// * parametrized: either {@link RDFStarTripleSource} or {@link TripleSource} +// * +// * @param bRDFStarData +// */ +// private TripleSource createSource(boolean bRDFStarData) { +// if (bRDFStarData) { +// return new RDFStarTripleSource() { +// +// @Override +// public ValueFactory getValueFactory() { +// return vf; +// } +// +// @Override +// public CloseableIteration getStatements(Resource subj, +// IRI pred, Value obj, Resource... contexts) +// throws QueryEvaluationException { +// return baseSource.getStatements(subj, pred, obj, contexts); +// } +// +// @Override +// public CloseableIteration getRdfStarTriples(Resource subj, +// IRI pred, Value obj) +// throws QueryEvaluationException { +// return baseSource.getRdfStarTriples(subj, pred, obj); +// } +// }; +// } else { +// return new TripleSource() { +// @Override +// public ValueFactory getValueFactory() { +// return vf; +// } +// +// @Override +// public CloseableIteration getStatements(Resource subj, +// IRI pred, Value obj, Resource... contexts) +// throws QueryEvaluationException { +// return baseSource.getStatements(subj, pred, obj, contexts); +// } +// }; +// } +// } +// +// @ParameterizedTest(name = "RDF-star={0}") +// @ValueSource(booleans = { false, true }) +// public void testMatchAllUnbound(boolean bRDFStarData) { +// EvaluationStrategy strategy = new StrictEvaluationStrategy(createSource(bRDFStarData), null); +// // case check all unbound +// try (CloseableIteration iter = strategy.precompile(tripleRefNode) +// .evaluate( +// new EmptyBindingSet())) { +// ArrayList expected = new ArrayList<>(); +// triples.forEach(t -> { +// expected.add(fromTriple(t)); +// }); +// ArrayList received = new ArrayList<>(); +// while (iter.hasNext()) { +// received.add(iter.next()); +// } +// assertTrue(received.containsAll(expected), "all expected must be received"); +// assertTrue(expected.containsAll(received), "all received must be expected"); +// } +// } +// +// @ParameterizedTest(name = "RDF-star={0}") +// @ValueSource(booleans = { false, true }) +// public void testSubjVarBound(boolean bRDFStarData) { +// EvaluationStrategy strategy = new StrictEvaluationStrategy(createSource(bRDFStarData), null); +// try (CloseableIteration iter = strategy.precompile(tripleRefNode) +// .evaluate( +// createWithVarValue(tripleRefNode.getSubjectVar(), vf.createIRI("urn:a")))) { +// ArrayList expected = new ArrayList<>(); +// triples.forEach(t -> { +// if (t.getSubject().equals(vf.createIRI("urn:a"))) { +// expected.add(fromTriple(t)); +// } +// }); +// ArrayList received = new ArrayList<>(); +// while (iter.hasNext()) { +// received.add(iter.next()); +// } +// assertTrue(received.containsAll(expected), "all expected must be received"); +// assertTrue(expected.containsAll(received), "all received must be expected"); +// } +// } +// +// @ParameterizedTest(name = "RDF-star={0}") +// @ValueSource(booleans = { false, true }) +// public void testPredVarBound(boolean bRDFStarData) { +// EvaluationStrategy strategy = new StrictEvaluationStrategy(createSource(bRDFStarData), null); +// try (CloseableIteration iter = strategy.precompile(tripleRefNode) +// .evaluate( +// createWithVarValue(tripleRefNode.getPredicateVar(), vf.createIRI("urn:p")))) { +// +// ArrayList expected = new ArrayList<>(); +// triples.forEach(t -> { +// if (t.getPredicate().equals(vf.createIRI("urn:p"))) { +// expected.add(fromTriple(t)); +// } +// }); +// ArrayList received = new ArrayList<>(); +// while (iter.hasNext()) { +// received.add(iter.next()); +// } +// assertTrue(received.containsAll(expected), "all expected must be received"); +// assertTrue(expected.containsAll(received), "all received must be expected"); +// } +// } +// +// @ParameterizedTest(name = "RDF-star={0}") +// @ValueSource(booleans = { false, true }) +// public void testObjVarBound(boolean bRDFStarData) { +// EvaluationStrategy strategy = new StrictEvaluationStrategy(createSource(bRDFStarData), null); +// try (CloseableIteration iter = strategy.precompile(tripleRefNode) +// .evaluate( +// createWithVarValue(tripleRefNode.getObjectVar(), vf.createIRI("urn:b")))) { +// +// ArrayList expected = new ArrayList<>(); +// triples.forEach(t -> { +// if (t.getObject().equals(vf.createIRI("urn:b"))) { +// expected.add(fromTriple(t)); +// } +// }); +// ArrayList received = new ArrayList<>(); +// while (iter.hasNext()) { +// received.add(iter.next()); +// } +// assertTrue(received.containsAll(expected), "all expected must be received"); +// assertTrue(expected.containsAll(received), "all received must be expected"); +// } +// } +// +// @ParameterizedTest(name = "RDF-star={0}") +// @ValueSource(booleans = { false, true }) +// public void testSubjAndObjVarBound(boolean bRDFStarData) { +// QueryBindingSet set = (QueryBindingSet) createWithVarValue(tripleRefNode.getObjectVar(), vf.createIRI("urn:c")); +// set.addBinding(tripleRefNode.getSubjectVar().getName(), vf.createIRI("urn:a:2")); +// +// EvaluationStrategy strategy = new StrictEvaluationStrategy(createSource(bRDFStarData), null); +// try (CloseableIteration iter = strategy.precompile(tripleRefNode).evaluate(set)) { +// +// ArrayList expected = new ArrayList<>(); +// triples.forEach(t -> { +// if (t.getObject().equals(vf.createIRI("urn:c")) && t.getSubject().equals(vf.createIRI("urn:a:2"))) { +// expected.add(fromTriple(t)); +// } +// }); +// ArrayList received = new ArrayList<>(); +// while (iter.hasNext()) { +// received.add(iter.next()); +// } +// assertTrue(received.containsAll(expected), "all expected must be received"); +// assertTrue(expected.containsAll(received), "all received must be expected"); +// } +// } +// +// @ParameterizedTest(name = "RDF-star={0}") +// @ValueSource(booleans = { false, true }) +// public void testExtVarBound(boolean bRDFStarData) { +// Triple triple = triples.get(0); +// QueryBindingSet set = (QueryBindingSet) createWithVarValue(tripleRefNode.getExprVar(), triple); +// +// EvaluationStrategy strategy = new StrictEvaluationStrategy(createSource(bRDFStarData), null); +// try (CloseableIteration iter = strategy.precompile(tripleRefNode).evaluate(set)) { +// +// ArrayList expected = new ArrayList<>(); +// expected.add(fromTriple(triple)); +// ArrayList received = new ArrayList<>(); +// while (iter.hasNext()) { +// received.add(iter.next()); +// } +// +// assertThat(received).containsAll(expected); +// assertThat(expected).containsAll(received); +// } +// } +// +// private BindingSet createWithVarValue(Var var, Value value) { +// QueryBindingSet ret = new QueryBindingSet(); +// ret.addBinding(var.getName(), value); +// return ret; +// } +// +// private BindingSet fromTriple(Triple t) { +// QueryBindingSet ret = new QueryBindingSet(); +// ret.addBinding("extern", t); +// ret.addBinding("s", t.getSubject()); +// ret.addBinding("p", t.getPredicate()); +// ret.addBinding("o", t.getObject()); +// return ret; +// } +//} diff --git a/core/queryalgebra/geosparql/pom.xml b/core/queryalgebra/geosparql/pom.xml index 10fcbc837ce..897e591ea62 100644 --- a/core/queryalgebra/geosparql/pom.xml +++ b/core/queryalgebra/geosparql/pom.xml @@ -4,7 +4,7 @@ org.eclipse.rdf4j rdf4j-queryalgebra - 5.1.0-SNAPSHOT + 6.0.0 rdf4j-queryalgebra-geosparql RDF4J: Query algebra - GeoSPARQL diff --git a/core/queryalgebra/model/pom.xml b/core/queryalgebra/model/pom.xml index c561441a066..c0c7117e2ca 100644 --- a/core/queryalgebra/model/pom.xml +++ b/core/queryalgebra/model/pom.xml @@ -4,7 +4,7 @@ org.eclipse.rdf4j rdf4j-queryalgebra - 5.1.0-SNAPSHOT + 6.0.0 rdf4j-queryalgebra-model RDF4J: Query algebra - model diff --git a/core/queryalgebra/pom.xml b/core/queryalgebra/pom.xml index fb04d8339cd..f58e10187ff 100644 --- a/core/queryalgebra/pom.xml +++ b/core/queryalgebra/pom.xml @@ -4,7 +4,7 @@ org.eclipse.rdf4j rdf4j-core - 5.1.0-SNAPSHOT + 6.0.0 rdf4j-queryalgebra pom diff --git a/core/queryparser/api/pom.xml b/core/queryparser/api/pom.xml index 6450c375f42..1f26f7e08be 100644 --- a/core/queryparser/api/pom.xml +++ b/core/queryparser/api/pom.xml @@ -4,7 +4,7 @@ org.eclipse.rdf4j rdf4j-queryparser - 5.1.0-SNAPSHOT + 6.0.0 rdf4j-queryparser-api RDF4J: Query parser - API diff --git a/core/queryparser/pom.xml b/core/queryparser/pom.xml index 0dfcb8573d3..5f85d8284fb 100644 --- a/core/queryparser/pom.xml +++ b/core/queryparser/pom.xml @@ -4,7 +4,7 @@ org.eclipse.rdf4j rdf4j-core - 5.1.0-SNAPSHOT + 6.0.0 rdf4j-queryparser pom diff --git a/core/queryparser/sparql/pom.xml b/core/queryparser/sparql/pom.xml index d21ecf2b1b2..9b5e1ed30da 100644 --- a/core/queryparser/sparql/pom.xml +++ b/core/queryparser/sparql/pom.xml @@ -4,7 +4,7 @@ org.eclipse.rdf4j rdf4j-queryparser - 5.1.0-SNAPSHOT + 6.0.0 rdf4j-queryparser-sparql RDF4J: Query parser - SPARQL diff --git a/core/queryparser/sparql/src/main/java/org/eclipse/rdf4j/query/parser/sparql/SPARQLUpdateDataBlockParser.java b/core/queryparser/sparql/src/main/java/org/eclipse/rdf4j/query/parser/sparql/SPARQLUpdateDataBlockParser.java index df080232afb..d1d6f0635fa 100644 --- a/core/queryparser/sparql/src/main/java/org/eclipse/rdf4j/query/parser/sparql/SPARQLUpdateDataBlockParser.java +++ b/core/queryparser/sparql/src/main/java/org/eclipse/rdf4j/query/parser/sparql/SPARQLUpdateDataBlockParser.java @@ -19,25 +19,24 @@ import org.eclipse.rdf4j.rio.RDFFormat; import org.eclipse.rdf4j.rio.RDFHandlerException; import org.eclipse.rdf4j.rio.RDFParseException; -import org.eclipse.rdf4j.rio.trigstar.TriGStarParser; +import org.eclipse.rdf4j.rio.trig.TriGParser; import org.eclipse.rdf4j.rio.turtle.TurtleUtil; /** - * An extension of {@link TriGStarParser} that processes data in the format specified in the SPARQL 1.1 grammar for Quad + * An extension of {@link TriGParser} that processes data in the format specified in the SPARQL 1.1 grammar for Quad * data (assuming no variables, as is the case for INSERT DATA and DELETE DATA operations). This format is almost * completely compatible with TriG, except for three differences: *

    *
  • it introduces the 'GRAPH' keyword in front of each named graph identifier *
  • it does not allow the occurrence of blank nodes. *
  • it does not require curly braces around the default graph. - *
  • it adds support for RDF-star triples (from TriG-star).
  • *
* * @author Jeen Broekstra * @see SPARQL 1.1 Grammar production for INSERT DATA * @see SPARQL 1.1 Grammar production for DELETE DATA */ -public class SPARQLUpdateDataBlockParser extends TriGStarParser { +public class SPARQLUpdateDataBlockParser extends TriGParser { private boolean allowBlankNodes = true; private int lineNumberOffset; diff --git a/core/queryparser/sparql/src/test/java/org/eclipse/rdf4j/query/parser/sparql/SPARQLUpdateDataBlockParserTest.java b/core/queryparser/sparql/src/test/java/org/eclipse/rdf4j/query/parser/sparql/SPARQLUpdateDataBlockParserTest.java index 87cb15e3283..a76940efd13 100644 --- a/core/queryparser/sparql/src/test/java/org/eclipse/rdf4j/query/parser/sparql/SPARQLUpdateDataBlockParserTest.java +++ b/core/queryparser/sparql/src/test/java/org/eclipse/rdf4j/query/parser/sparql/SPARQLUpdateDataBlockParserTest.java @@ -15,6 +15,7 @@ import org.eclipse.rdf4j.rio.RDFHandlerException; import org.eclipse.rdf4j.rio.RDFParseException; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; /** @@ -37,6 +38,7 @@ public void testParseGraph() throws RDFParseException, RDFHandlerException, IOEx } @Test + @Disabled("pending SPARQL 1.2 implementation and updating test for RDF 1.2") public void testParseRDFStar() throws IOException { SPARQLUpdateDataBlockParser parser = new SPARQLUpdateDataBlockParser(); diff --git a/core/queryrender/pom.xml b/core/queryrender/pom.xml index 8db12169a80..73703896a03 100644 --- a/core/queryrender/pom.xml +++ b/core/queryrender/pom.xml @@ -4,7 +4,7 @@ org.eclipse.rdf4j rdf4j-core - 5.1.0-SNAPSHOT + 6.0.0 rdf4j-queryrender RDF4J: Query Rendering diff --git a/core/queryresultio/api/pom.xml b/core/queryresultio/api/pom.xml index 273fe3b9801..c9771d0de15 100644 --- a/core/queryresultio/api/pom.xml +++ b/core/queryresultio/api/pom.xml @@ -4,7 +4,7 @@ org.eclipse.rdf4j rdf4j-queryresultio - 5.1.0-SNAPSHOT + 6.0.0 rdf4j-queryresultio-api RDF4J: Query result IO - API diff --git a/core/queryresultio/api/src/main/java/org/eclipse/rdf4j/query/resultio/AbstractQueryResultParser.java b/core/queryresultio/api/src/main/java/org/eclipse/rdf4j/query/resultio/AbstractQueryResultParser.java index 9da3659335b..a182c974998 100644 --- a/core/queryresultio/api/src/main/java/org/eclipse/rdf4j/query/resultio/AbstractQueryResultParser.java +++ b/core/queryresultio/api/src/main/java/org/eclipse/rdf4j/query/resultio/AbstractQueryResultParser.java @@ -88,8 +88,8 @@ public QueryResultParser setValueFactory(ValueFactory valueFactory) { @Override public QueryResultParser setQueryResultHandler(QueryResultHandler handler) { - if (getParserConfig().get(BasicParserSettings.PROCESS_ENCODED_RDF_STAR)) { - handler = new RDFStarDecodingQueryResultHandler(handler); + if (getParserConfig().get(BasicParserSettings.PROCESS_ENCODED_TRIPLE_TERMS)) { + handler = new TripleTermDecodingQueryResultHandler(handler); } this.handler = handler; return this; diff --git a/core/queryresultio/api/src/main/java/org/eclipse/rdf4j/query/resultio/AbstractQueryResultWriter.java b/core/queryresultio/api/src/main/java/org/eclipse/rdf4j/query/resultio/AbstractQueryResultWriter.java index a595504cb09..eb5ed45764c 100644 --- a/core/queryresultio/api/src/main/java/org/eclipse/rdf4j/query/resultio/AbstractQueryResultWriter.java +++ b/core/queryresultio/api/src/main/java/org/eclipse/rdf4j/query/resultio/AbstractQueryResultWriter.java @@ -21,7 +21,7 @@ import org.eclipse.rdf4j.rio.RioSetting; import org.eclipse.rdf4j.rio.WriterConfig; import org.eclipse.rdf4j.rio.helpers.BasicWriterSettings; -import org.eclipse.rdf4j.rio.helpers.RDFStarUtil; +import org.eclipse.rdf4j.rio.helpers.TripleTermUtil; /** * Base class for {@link QueryResultWriter}s offering common functionality for query result writers. @@ -32,7 +32,7 @@ public abstract class AbstractQueryResultWriter implements QueryResultWriter, Si private WriterConfig writerConfig = new WriterConfig(); - private boolean encodeRDFStar; + private boolean encodeTripleTerms; @Override public void setWriterConfig(WriterConfig config) { @@ -46,7 +46,7 @@ public WriterConfig getWriterConfig() { @Override public Collection> getSupportedSettings() { - return Arrays.asList(BasicWriterSettings.ENCODE_RDF_STAR, BasicWriterSettings.XSD_STRING_TO_PLAIN_LITERAL); + return Arrays.asList(BasicWriterSettings.ENCODE_TRIPLE_TERMS, BasicWriterSettings.XSD_STRING_TO_PLAIN_LITERAL); } @Override @@ -56,17 +56,17 @@ public FileFormat getFileFormat() { @Override public void startQueryResult(List bindingNames) throws TupleQueryResultHandlerException { - // Formats without native RDF-star support obey the ENCODE_RDF_STAR setting and may encode RDF-star triples to + // Formats without native RDF 1.2 support obey the ENCODE_TRIPLE_TERMS setting and may encode RDF 1.2 triples to // IRIs - encodeRDFStar = this instanceof TupleQueryResultWriter + encodeTripleTerms = this instanceof TupleQueryResultWriter && !((TupleQueryResultWriter) this).getTupleQueryResultFormat().supportsRDFStar() - && getWriterConfig().get(BasicWriterSettings.ENCODE_RDF_STAR); + && getWriterConfig().get(BasicWriterSettings.ENCODE_TRIPLE_TERMS); } @Override public void handleSolution(BindingSet bindingSet) throws TupleQueryResultHandlerException { - if (encodeRDFStar) { - handleSolutionImpl(new ValueMappingBindingSet(bindingSet, RDFStarUtil::toRDFEncodedValue)); + if (encodeTripleTerms) { + handleSolutionImpl(new ValueMappingBindingSet(bindingSet, TripleTermUtil::toRDFEncodedValue)); } else { handleSolutionImpl(bindingSet); } @@ -74,7 +74,7 @@ public void handleSolution(BindingSet bindingSet) throws TupleQueryResultHandler /** * Extending classes must implement this method instead of overriding {@link #handleSolution(BindingSet)} in order - * to benefit from automatic handling of RDF-star encoding. + * to benefit from automatic handling of RDF 1.2 encoding. * * @param bindings the solution to handle * @throws TupleQueryResultHandlerException diff --git a/core/queryresultio/api/src/main/java/org/eclipse/rdf4j/query/resultio/RDFStarDecodingQueryResultHandler.java b/core/queryresultio/api/src/main/java/org/eclipse/rdf4j/query/resultio/TripleTermDecodingQueryResultHandler.java similarity index 87% rename from core/queryresultio/api/src/main/java/org/eclipse/rdf4j/query/resultio/RDFStarDecodingQueryResultHandler.java rename to core/queryresultio/api/src/main/java/org/eclipse/rdf4j/query/resultio/TripleTermDecodingQueryResultHandler.java index c3d1c10959d..a2e1f077391 100644 --- a/core/queryresultio/api/src/main/java/org/eclipse/rdf4j/query/resultio/RDFStarDecodingQueryResultHandler.java +++ b/core/queryresultio/api/src/main/java/org/eclipse/rdf4j/query/resultio/TripleTermDecodingQueryResultHandler.java @@ -18,7 +18,7 @@ import org.eclipse.rdf4j.query.QueryResultHandlerException; import org.eclipse.rdf4j.query.TupleQueryResultHandler; import org.eclipse.rdf4j.query.TupleQueryResultHandlerException; -import org.eclipse.rdf4j.rio.helpers.RDFStarUtil; +import org.eclipse.rdf4j.rio.helpers.TripleTermUtil; /** * A {@link QueryResultHandler} that delegates all results to another handler and processes RDF-star triples encoded as @@ -26,10 +26,10 @@ * * @author Pavel Mihaylov */ -class RDFStarDecodingQueryResultHandler implements TupleQueryResultHandler, BooleanQueryResultHandler { +class TripleTermDecodingQueryResultHandler implements TupleQueryResultHandler, BooleanQueryResultHandler { private final QueryResultHandler delegate; - RDFStarDecodingQueryResultHandler(QueryResultHandler delegate) { + TripleTermDecodingQueryResultHandler(QueryResultHandler delegate) { this.delegate = delegate; } @@ -55,6 +55,6 @@ public void endQueryResult() throws TupleQueryResultHandlerException { @Override public void handleSolution(BindingSet bindingSet) throws TupleQueryResultHandlerException { - delegate.handleSolution(new ValueMappingBindingSet(bindingSet, RDFStarUtil::fromRDFEncodedValue)); + delegate.handleSolution(new ValueMappingBindingSet(bindingSet, TripleTermUtil::fromRDFEncodedValue)); } } diff --git a/core/queryresultio/binary/pom.xml b/core/queryresultio/binary/pom.xml index 34df6c0b64f..973051441c8 100644 --- a/core/queryresultio/binary/pom.xml +++ b/core/queryresultio/binary/pom.xml @@ -4,7 +4,7 @@ org.eclipse.rdf4j rdf4j-queryresultio - 5.1.0-SNAPSHOT + 6.0.0 rdf4j-queryresultio-binary RDF4J: Query result IO - binary diff --git a/core/queryresultio/pom.xml b/core/queryresultio/pom.xml index c1ba95a8c53..c297b87b0c5 100644 --- a/core/queryresultio/pom.xml +++ b/core/queryresultio/pom.xml @@ -4,7 +4,7 @@ org.eclipse.rdf4j rdf4j-core - 5.1.0-SNAPSHOT + 6.0.0 rdf4j-queryresultio pom diff --git a/core/queryresultio/sparqljson/pom.xml b/core/queryresultio/sparqljson/pom.xml index c5f589b6457..22f021982ef 100644 --- a/core/queryresultio/sparqljson/pom.xml +++ b/core/queryresultio/sparqljson/pom.xml @@ -4,7 +4,7 @@ org.eclipse.rdf4j rdf4j-queryresultio - 5.1.0-SNAPSHOT + 6.0.0 rdf4j-queryresultio-sparqljson RDF4J: Query result IO - SPARQL/JSON diff --git a/core/queryresultio/sparqljson/src/test/java/org/eclipse/rdf4j/query/resultio/sparqljson/SPARQLJSONTupleTest.java b/core/queryresultio/sparqljson/src/test/java/org/eclipse/rdf4j/query/resultio/sparqljson/SPARQLJSONTupleTest.java index 050f0237250..d12747f389e 100644 --- a/core/queryresultio/sparqljson/src/test/java/org/eclipse/rdf4j/query/resultio/sparqljson/SPARQLJSONTupleTest.java +++ b/core/queryresultio/sparqljson/src/test/java/org/eclipse/rdf4j/query/resultio/sparqljson/SPARQLJSONTupleTest.java @@ -34,6 +34,7 @@ import org.eclipse.rdf4j.query.resultio.TupleQueryResultFormat; import org.eclipse.rdf4j.query.resultio.helpers.QueryResultCollector; import org.eclipse.rdf4j.testsuite.query.resultio.AbstractQueryResultIOTupleTest; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; /** @@ -291,6 +292,7 @@ public void testOtherKeys() throws Exception { } @Test + @Disabled("pending implementation of SPARQL 1.2 and adjusting RDFStar tests to RDF 1.2") public void testRDFStar_extendedFormatRDF4J() throws Exception { SPARQLResultsJSONParser parser = new SPARQLResultsJSONParser(SimpleValueFactory.getInstance()); QueryResultCollector handler = new QueryResultCollector(); @@ -309,6 +311,7 @@ public void testRDFStar_extendedFormatRDF4J() throws Exception { } @Test + @Disabled("pending implementation of SPARQL 1.2 and adjusting RDFStar tests to RDF 1.2") public void testRDFStar_extendedFormatRDF4J_incompleteTriple() { SPARQLResultsJSONParser parser = new SPARQLResultsJSONParser(SimpleValueFactory.getInstance()); QueryResultCollector handler = new QueryResultCollector(); @@ -322,6 +325,7 @@ public void testRDFStar_extendedFormatRDF4J_incompleteTriple() { } @Test + @Disabled("pending implementation of SPARQL 1.2 and adjusting RDFStar tests to RDF 1.2") public void testRDFStar_extendedFormatRDF4J_doubleSubject() { SPARQLResultsJSONParser parser = new SPARQLResultsJSONParser(SimpleValueFactory.getInstance()); QueryResultCollector handler = new QueryResultCollector(); @@ -335,6 +339,7 @@ public void testRDFStar_extendedFormatRDF4J_doubleSubject() { } @Test + @Disabled("pending implementation of SPARQL 1.2 and adjusting RDFStar tests to RDF 1.2") public void testRDFStar_extendedFormatStardog() throws Exception { SPARQLResultsJSONParser parser = new SPARQLResultsJSONParser(SimpleValueFactory.getInstance()); QueryResultCollector handler = new QueryResultCollector(); @@ -353,6 +358,7 @@ public void testRDFStar_extendedFormatStardog() throws Exception { } @Test + @Disabled("pending implementation of SPARQL 1.2 and adjusting RDFStar tests to RDF 1.2") public void testRDFStar_extendedFormatStardog_NamedGraph() throws Exception { SPARQLResultsJSONParser parser = new SPARQLResultsJSONParser(SimpleValueFactory.getInstance()); QueryResultCollector handler = new QueryResultCollector(); @@ -372,6 +378,7 @@ public void testRDFStar_extendedFormatStardog_NamedGraph() throws Exception { } @Test + @Disabled("pending implementation of SPARQL 1.2 and adjusting RDFStar tests to RDF 1.2") public void testRDFStar_extendedFormatJena() throws Exception { SPARQLResultsJSONParser parser = new SPARQLResultsJSONParser(SimpleValueFactory.getInstance()); QueryResultCollector handler = new QueryResultCollector(); diff --git a/core/queryresultio/sparqljson/src/test/java/org/eclipse/rdf4j/query/resultio/sparqljson/SPARQLResultsJSONWriterTest.java b/core/queryresultio/sparqljson/src/test/java/org/eclipse/rdf4j/query/resultio/sparqljson/SPARQLResultsJSONWriterTest.java index 8d5555127d9..7d0592a7c2a 100644 --- a/core/queryresultio/sparqljson/src/test/java/org/eclipse/rdf4j/query/resultio/sparqljson/SPARQLResultsJSONWriterTest.java +++ b/core/queryresultio/sparqljson/src/test/java/org/eclipse/rdf4j/query/resultio/sparqljson/SPARQLResultsJSONWriterTest.java @@ -34,7 +34,7 @@ protected RioSetting[] getExpectedSupportedSettings() { return new RioSetting[] { BasicWriterSettings.PRETTY_PRINT, BasicWriterSettings.XSD_STRING_TO_PLAIN_LITERAL, - BasicWriterSettings.ENCODE_RDF_STAR, + BasicWriterSettings.ENCODE_TRIPLE_TERMS, BasicQueryWriterSettings.JSONP_CALLBACK }; } diff --git a/core/queryresultio/sparqljson/src/test/java/org/eclipse/rdf4j/query/resultio/sparqljson/SPARQLStarResultsJSONWriterTest.java b/core/queryresultio/sparqljson/src/test/java/org/eclipse/rdf4j/query/resultio/sparqljson/SPARQLStarResultsJSONWriterTest.java index ec82419e01e..71b22b6893e 100644 --- a/core/queryresultio/sparqljson/src/test/java/org/eclipse/rdf4j/query/resultio/sparqljson/SPARQLStarResultsJSONWriterTest.java +++ b/core/queryresultio/sparqljson/src/test/java/org/eclipse/rdf4j/query/resultio/sparqljson/SPARQLStarResultsJSONWriterTest.java @@ -34,7 +34,7 @@ protected RioSetting[] getExpectedSupportedSettings() { return new RioSetting[] { BasicWriterSettings.PRETTY_PRINT, BasicWriterSettings.XSD_STRING_TO_PLAIN_LITERAL, - BasicWriterSettings.ENCODE_RDF_STAR, + BasicWriterSettings.ENCODE_TRIPLE_TERMS, BasicQueryWriterSettings.JSONP_CALLBACK }; } diff --git a/core/queryresultio/sparqlxml/pom.xml b/core/queryresultio/sparqlxml/pom.xml index 8d7bee2745b..764a510127f 100644 --- a/core/queryresultio/sparqlxml/pom.xml +++ b/core/queryresultio/sparqlxml/pom.xml @@ -4,7 +4,7 @@ org.eclipse.rdf4j rdf4j-queryresultio - 5.1.0-SNAPSHOT + 6.0.0 rdf4j-queryresultio-sparqlxml RDF4J: Query result IO - SPARQL/XML diff --git a/core/queryresultio/sparqlxml/src/main/java/org/eclipse/rdf4j/query/resultio/sparqlxml/AbstractSPARQLXMLWriter.java b/core/queryresultio/sparqlxml/src/main/java/org/eclipse/rdf4j/query/resultio/sparqlxml/AbstractSPARQLXMLWriter.java index 20f17a74b57..b1e26014526 100644 --- a/core/queryresultio/sparqlxml/src/main/java/org/eclipse/rdf4j/query/resultio/sparqlxml/AbstractSPARQLXMLWriter.java +++ b/core/queryresultio/sparqlxml/src/main/java/org/eclipse/rdf4j/query/resultio/sparqlxml/AbstractSPARQLXMLWriter.java @@ -366,7 +366,7 @@ public final Collection> getSupportedSettings() { result.add(BasicWriterSettings.PRETTY_PRINT); result.add(BasicWriterSettings.XSD_STRING_TO_PLAIN_LITERAL); - result.add(BasicWriterSettings.ENCODE_RDF_STAR); + result.add(BasicWriterSettings.ENCODE_TRIPLE_TERMS); result.add(BasicQueryWriterSettings.ADD_SESAME_QNAME); result.add(XMLWriterSettings.INCLUDE_XML_PI); diff --git a/core/queryresultio/sparqlxml/src/test/java/org/eclipse/rdf4j/query/resultio/sparqlxml/SPARQLStarXMLTupleQueryResultWriterTest.java b/core/queryresultio/sparqlxml/src/test/java/org/eclipse/rdf4j/query/resultio/sparqlxml/SPARQLStarXMLTupleQueryResultWriterTest.java index e9df638284a..d0a5abdc91d 100644 --- a/core/queryresultio/sparqlxml/src/test/java/org/eclipse/rdf4j/query/resultio/sparqlxml/SPARQLStarXMLTupleQueryResultWriterTest.java +++ b/core/queryresultio/sparqlxml/src/test/java/org/eclipse/rdf4j/query/resultio/sparqlxml/SPARQLStarXMLTupleQueryResultWriterTest.java @@ -39,7 +39,7 @@ protected RioSetting[] getExpectedSupportedSettings() { BasicQueryWriterSettings.ADD_SESAME_QNAME, BasicWriterSettings.PRETTY_PRINT, BasicWriterSettings.XSD_STRING_TO_PLAIN_LITERAL, - BasicWriterSettings.ENCODE_RDF_STAR, + BasicWriterSettings.ENCODE_TRIPLE_TERMS, XMLWriterSettings.INCLUDE_XML_PI }; } diff --git a/core/queryresultio/sparqlxml/src/test/java/org/eclipse/rdf4j/query/resultio/sparqlxml/SPARQLXMLTupleQueryResultWriterTest.java b/core/queryresultio/sparqlxml/src/test/java/org/eclipse/rdf4j/query/resultio/sparqlxml/SPARQLXMLTupleQueryResultWriterTest.java index 52a5e48faad..12552f5d5f9 100644 --- a/core/queryresultio/sparqlxml/src/test/java/org/eclipse/rdf4j/query/resultio/sparqlxml/SPARQLXMLTupleQueryResultWriterTest.java +++ b/core/queryresultio/sparqlxml/src/test/java/org/eclipse/rdf4j/query/resultio/sparqlxml/SPARQLXMLTupleQueryResultWriterTest.java @@ -39,7 +39,7 @@ protected RioSetting[] getExpectedSupportedSettings() { BasicQueryWriterSettings.ADD_SESAME_QNAME, BasicWriterSettings.PRETTY_PRINT, BasicWriterSettings.XSD_STRING_TO_PLAIN_LITERAL, - BasicWriterSettings.ENCODE_RDF_STAR, + BasicWriterSettings.ENCODE_TRIPLE_TERMS, XMLWriterSettings.INCLUDE_XML_PI }; } diff --git a/core/queryresultio/text/pom.xml b/core/queryresultio/text/pom.xml index e5f67e0b32e..ce9f0da2e9a 100644 --- a/core/queryresultio/text/pom.xml +++ b/core/queryresultio/text/pom.xml @@ -4,7 +4,7 @@ org.eclipse.rdf4j rdf4j-queryresultio - 5.1.0-SNAPSHOT + 6.0.0 rdf4j-queryresultio-text RDF4J: Query result IO - plain text booleans diff --git a/core/queryresultio/text/src/main/java/org/eclipse/rdf4j/query/resultio/text/tsv/SPARQLResultsTSVWriter.java b/core/queryresultio/text/src/main/java/org/eclipse/rdf4j/query/resultio/text/tsv/SPARQLResultsTSVWriter.java index 3bcbfc74a1a..5991298f931 100644 --- a/core/queryresultio/text/src/main/java/org/eclipse/rdf4j/query/resultio/text/tsv/SPARQLResultsTSVWriter.java +++ b/core/queryresultio/text/src/main/java/org/eclipse/rdf4j/query/resultio/text/tsv/SPARQLResultsTSVWriter.java @@ -137,13 +137,13 @@ public final TupleQueryResultFormat getQueryResultFormat() { protected void writeValue(Value val) throws IOException { if (val instanceof Triple) { - writer.write("<<"); + writer.write("<<( "); writeValue(((Triple) val).getSubject()); writer.write(' '); writeValue(((Triple) val).getPredicate()); writer.write(' '); writeValue(((Triple) val).getObject()); - writer.write(">>"); + writer.write(" )>>"); } else if (val instanceof Resource) { writeResource((Resource) val); } else { diff --git a/core/queryresultio/text/src/test/java/org/eclipse/rdf4j/query/resultio/text/csv/SPARQLCSVTupleBackgroundTest.java b/core/queryresultio/text/src/test/java/org/eclipse/rdf4j/query/resultio/text/csv/SPARQLCSVTupleBackgroundTest.java index 3e43c729d38..5aed51ec4b5 100644 --- a/core/queryresultio/text/src/test/java/org/eclipse/rdf4j/query/resultio/text/csv/SPARQLCSVTupleBackgroundTest.java +++ b/core/queryresultio/text/src/test/java/org/eclipse/rdf4j/query/resultio/text/csv/SPARQLCSVTupleBackgroundTest.java @@ -99,7 +99,7 @@ public void testSingleVarResults() { + "\"\"\"\"\"double-quoted string\"\r\n" + "space at the end \r\n" + "space at the end \r\n" + "\"\"\"\"\"double-quoted string with no datatype\"\r\n" + "\"newline at the end \n\"(\r\n)?" - + "urn:rdf4j:triple:PDw8dXJuOmE-IDxodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjdHlwZT4gPHVybjpiPj4-(\r\n)?", + + "urn:rdf4j:triple:PDwoIDx1cm46YT4gPGh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyN0eXBlPiA8dXJuOmI-ICk-Pg==(\r\n)?", out.toString(StandardCharsets.UTF_8)); } diff --git a/core/queryresultio/text/src/test/java/org/eclipse/rdf4j/query/resultio/text/csv/SPARQLCSVTupleQueryResultWriterTest.java b/core/queryresultio/text/src/test/java/org/eclipse/rdf4j/query/resultio/text/csv/SPARQLCSVTupleQueryResultWriterTest.java index 5a9f3d2761f..ab4f8025e32 100644 --- a/core/queryresultio/text/src/test/java/org/eclipse/rdf4j/query/resultio/text/csv/SPARQLCSVTupleQueryResultWriterTest.java +++ b/core/queryresultio/text/src/test/java/org/eclipse/rdf4j/query/resultio/text/csv/SPARQLCSVTupleQueryResultWriterTest.java @@ -48,7 +48,7 @@ public void testRDFStarHandling_DeepNesting() { @Override protected RioSetting[] getExpectedSupportedSettings() { return new RioSetting[] { - BasicWriterSettings.ENCODE_RDF_STAR, + BasicWriterSettings.ENCODE_TRIPLE_TERMS, BasicWriterSettings.XSD_STRING_TO_PLAIN_LITERAL }; } diff --git a/core/queryresultio/text/src/test/java/org/eclipse/rdf4j/query/resultio/text/csv/SPARQLCSVTupleTest.java b/core/queryresultio/text/src/test/java/org/eclipse/rdf4j/query/resultio/text/csv/SPARQLCSVTupleTest.java index 2280c3800f1..fd08e12c259 100644 --- a/core/queryresultio/text/src/test/java/org/eclipse/rdf4j/query/resultio/text/csv/SPARQLCSVTupleTest.java +++ b/core/queryresultio/text/src/test/java/org/eclipse/rdf4j/query/resultio/text/csv/SPARQLCSVTupleTest.java @@ -99,7 +99,7 @@ public void testSingleVarResults() { + "\"\"\"\"\"double-quoted string\"\r\n" + "space at the end \r\n" + "space at the end \r\n" + "\"\"\"\"\"double-quoted string with no datatype\"\r\n" + "\"newline at the end \n\"(\r\n)?" - + "urn:rdf4j:triple:PDw8dXJuOmE-IDxodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjdHlwZT4gPHVybjpiPj4-(\r\n)?", + + "urn:rdf4j:triple:PDwoIDx1cm46YT4gPGh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyN0eXBlPiA8dXJuOmI-ICk-Pg==(\r\n)?", out.toString(StandardCharsets.UTF_8)); } diff --git a/core/queryresultio/text/src/test/java/org/eclipse/rdf4j/query/resultio/text/tsv/SPARQLStarTSVTupleBackgroundTest.java b/core/queryresultio/text/src/test/java/org/eclipse/rdf4j/query/resultio/text/tsv/SPARQLStarTSVTupleBackgroundTest.java index f36ae4986ce..278a625f6b6 100644 --- a/core/queryresultio/text/src/test/java/org/eclipse/rdf4j/query/resultio/text/tsv/SPARQLStarTSVTupleBackgroundTest.java +++ b/core/queryresultio/text/src/test/java/org/eclipse/rdf4j/query/resultio/text/tsv/SPARQLStarTSVTupleBackgroundTest.java @@ -1,50 +1,50 @@ -/******************************************************************************* - * Copyright (c) 2020 Eclipse RDF4J contributors. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Distribution License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * SPDX-License-Identifier: BSD-3-Clause - *******************************************************************************/ -package org.eclipse.rdf4j.query.resultio.text.tsv; - -import java.io.IOException; -import java.io.InputStream; - -import org.eclipse.rdf4j.query.TupleQueryResult; -import org.eclipse.rdf4j.query.TupleQueryResultHandlerException; -import org.eclipse.rdf4j.query.resultio.BooleanQueryResultFormat; -import org.eclipse.rdf4j.query.resultio.QueryResultIO; -import org.eclipse.rdf4j.query.resultio.QueryResultParseException; -import org.eclipse.rdf4j.query.resultio.TupleQueryResultFormat; -import org.eclipse.rdf4j.query.resultio.UnsupportedQueryResultFormatException; -import org.eclipse.rdf4j.testsuite.query.resultio.AbstractQueryResultIOTupleTest; - -/** - * @author Pavel Mihaylov - */ -public class SPARQLStarTSVTupleBackgroundTest extends AbstractQueryResultIOTupleTest { - - @Override - protected String getFileName() { - return "test.tsvs"; - } - - @Override - protected TupleQueryResultFormat getTupleFormat() { - return TupleQueryResultFormat.TSV_STAR; - } - - @Override - protected BooleanQueryResultFormat getMatchingBooleanFormatOrNull() { - return null; - } - - @Override - protected TupleQueryResult parseTupleInternal(TupleQueryResultFormat format, InputStream in) throws IOException, - QueryResultParseException, TupleQueryResultHandlerException, UnsupportedQueryResultFormatException { - return QueryResultIO.parseTupleBackground(in, format, null); - } -} +///******************************************************************************* +// * Copyright (c) 2020 Eclipse RDF4J contributors. +// * +// * All rights reserved. This program and the accompanying materials +// * are made available under the terms of the Eclipse Distribution License v1.0 +// * which accompanies this distribution, and is available at +// * http://www.eclipse.org/org/documents/edl-v10.php. +// * +// * SPDX-License-Identifier: BSD-3-Clause +// *******************************************************************************/ +//package org.eclipse.rdf4j.query.resultio.text.tsv; +// +//import java.io.IOException; +//import java.io.InputStream; +// +//import org.eclipse.rdf4j.query.TupleQueryResult; +//import org.eclipse.rdf4j.query.TupleQueryResultHandlerException; +//import org.eclipse.rdf4j.query.resultio.BooleanQueryResultFormat; +//import org.eclipse.rdf4j.query.resultio.QueryResultIO; +//import org.eclipse.rdf4j.query.resultio.QueryResultParseException; +//import org.eclipse.rdf4j.query.resultio.TupleQueryResultFormat; +//import org.eclipse.rdf4j.query.resultio.UnsupportedQueryResultFormatException; +//import org.eclipse.rdf4j.testsuite.query.resultio.AbstractQueryResultIOTupleTest; +// +///** +// * @author Pavel Mihaylov +// */ +//public class SPARQLStarTSVTupleBackgroundTest extends AbstractQueryResultIOTupleTest { +// +// @Override +// protected String getFileName() { +// return "test.tsvs"; +// } +// +// @Override +// protected TupleQueryResultFormat getTupleFormat() { +// return TupleQueryResultFormat.TSV_STAR; +// } +// +// @Override +// protected BooleanQueryResultFormat getMatchingBooleanFormatOrNull() { +// return null; +// } +// +// @Override +// protected TupleQueryResult parseTupleInternal(TupleQueryResultFormat format, InputStream in) throws IOException, +// QueryResultParseException, TupleQueryResultHandlerException, UnsupportedQueryResultFormatException { +// return QueryResultIO.parseTupleBackground(in, format, null); +// } +//} diff --git a/core/queryresultio/text/src/test/java/org/eclipse/rdf4j/query/resultio/text/tsv/SPARQLStarTSVTupleQueryResultWriterTest.java b/core/queryresultio/text/src/test/java/org/eclipse/rdf4j/query/resultio/text/tsv/SPARQLStarTSVTupleQueryResultWriterTest.java index c55edb55774..4a441b7885a 100644 --- a/core/queryresultio/text/src/test/java/org/eclipse/rdf4j/query/resultio/text/tsv/SPARQLStarTSVTupleQueryResultWriterTest.java +++ b/core/queryresultio/text/src/test/java/org/eclipse/rdf4j/query/resultio/text/tsv/SPARQLStarTSVTupleQueryResultWriterTest.java @@ -15,6 +15,7 @@ import org.eclipse.rdf4j.rio.RioSetting; import org.eclipse.rdf4j.rio.helpers.BasicWriterSettings; import org.eclipse.rdf4j.testsuite.query.resultio.AbstractTupleQueryResultWriterTest; +import org.junit.jupiter.api.Disabled; /** * @author Jeen Broekstra @@ -34,7 +35,7 @@ protected TupleQueryResultWriterFactory getWriterFactory() { @Override protected RioSetting[] getExpectedSupportedSettings() { return new RioSetting[] { - BasicWriterSettings.ENCODE_RDF_STAR, + BasicWriterSettings.ENCODE_TRIPLE_TERMS, BasicWriterSettings.XSD_STRING_TO_PLAIN_LITERAL }; } diff --git a/core/queryresultio/text/src/test/java/org/eclipse/rdf4j/query/resultio/text/tsv/SPARQLTSVTupleBackgroundTest.java b/core/queryresultio/text/src/test/java/org/eclipse/rdf4j/query/resultio/text/tsv/SPARQLTSVTupleBackgroundTest.java index 858ce74271b..9b8de46d8ad 100644 --- a/core/queryresultio/text/src/test/java/org/eclipse/rdf4j/query/resultio/text/tsv/SPARQLTSVTupleBackgroundTest.java +++ b/core/queryresultio/text/src/test/java/org/eclipse/rdf4j/query/resultio/text/tsv/SPARQLTSVTupleBackgroundTest.java @@ -81,7 +81,7 @@ public void testSingleVarResults() { + "\"?space at the end (\"(\\^\\^)?)?\n" + "\"\\\\\"\\\\\"double-quoted string with no datatype\"(\\^\\^)?\n" + "\"newline at the end \\\\n\"(\\^\\^)?\n?" - + "\n?", + + "\n?", toString(createTupleSingleVarMultipleBindingSets())); } diff --git a/core/queryresultio/text/src/test/java/org/eclipse/rdf4j/query/resultio/text/tsv/SPARQLTSVTupleQueryResultWriterTest.java b/core/queryresultio/text/src/test/java/org/eclipse/rdf4j/query/resultio/text/tsv/SPARQLTSVTupleQueryResultWriterTest.java index 4a33c527bc9..fbd88bd76be 100644 --- a/core/queryresultio/text/src/test/java/org/eclipse/rdf4j/query/resultio/text/tsv/SPARQLTSVTupleQueryResultWriterTest.java +++ b/core/queryresultio/text/src/test/java/org/eclipse/rdf4j/query/resultio/text/tsv/SPARQLTSVTupleQueryResultWriterTest.java @@ -34,7 +34,7 @@ protected TupleQueryResultWriterFactory getWriterFactory() { @Override protected RioSetting[] getExpectedSupportedSettings() { return new RioSetting[] { - BasicWriterSettings.ENCODE_RDF_STAR, + BasicWriterSettings.ENCODE_TRIPLE_TERMS, BasicWriterSettings.XSD_STRING_TO_PLAIN_LITERAL }; } diff --git a/core/queryresultio/text/src/test/java/org/eclipse/rdf4j/query/resultio/text/tsv/SPARQLTSVTupleTest.java b/core/queryresultio/text/src/test/java/org/eclipse/rdf4j/query/resultio/text/tsv/SPARQLTSVTupleTest.java index 90b74ceef1a..6655eff191c 100644 --- a/core/queryresultio/text/src/test/java/org/eclipse/rdf4j/query/resultio/text/tsv/SPARQLTSVTupleTest.java +++ b/core/queryresultio/text/src/test/java/org/eclipse/rdf4j/query/resultio/text/tsv/SPARQLTSVTupleTest.java @@ -71,7 +71,7 @@ public void testSingleVarResults() { + "\"?space at the end (\"(\\^\\^)?)?\n" + "\"\\\\\"\\\\\"double-quoted string with no datatype\"(\\^\\^)?\n" + "\"newline at the end \\\\n\"(\\^\\^)?\n?" - + "\n?", + + "\n?", toString(createTupleSingleVarMultipleBindingSets())); } diff --git a/core/repository/api/pom.xml b/core/repository/api/pom.xml index 48fdeecfad7..2bcbbd59395 100644 --- a/core/repository/api/pom.xml +++ b/core/repository/api/pom.xml @@ -4,7 +4,7 @@ org.eclipse.rdf4j rdf4j-repository - 5.1.0-SNAPSHOT + 6.0.0 rdf4j-repository-api RDF4J: Repository - API diff --git a/core/repository/contextaware/pom.xml b/core/repository/contextaware/pom.xml index 39bcbf0668c..6b579fce3e2 100644 --- a/core/repository/contextaware/pom.xml +++ b/core/repository/contextaware/pom.xml @@ -4,7 +4,7 @@ org.eclipse.rdf4j rdf4j-repository - 5.1.0-SNAPSHOT + 6.0.0 rdf4j-repository-contextaware RDF4J: Repository - context aware (wrapper) diff --git a/core/repository/dataset/pom.xml b/core/repository/dataset/pom.xml index c843dccda42..434a6c7f8d9 100644 --- a/core/repository/dataset/pom.xml +++ b/core/repository/dataset/pom.xml @@ -4,7 +4,7 @@ org.eclipse.rdf4j rdf4j-repository - 5.1.0-SNAPSHOT + 6.0.0 rdf4j-repository-dataset RDF4J: DatasetRepository (wrapper) diff --git a/core/repository/event/pom.xml b/core/repository/event/pom.xml index 3a3109cf967..baa24c1b0d6 100644 --- a/core/repository/event/pom.xml +++ b/core/repository/event/pom.xml @@ -4,7 +4,7 @@ org.eclipse.rdf4j rdf4j-repository - 5.1.0-SNAPSHOT + 6.0.0 rdf4j-repository-event RDF4J: Repository - event (wrapper) diff --git a/core/repository/http/pom.xml b/core/repository/http/pom.xml index 4fc07dc06e9..5c47e620b5b 100644 --- a/core/repository/http/pom.xml +++ b/core/repository/http/pom.xml @@ -4,7 +4,7 @@ org.eclipse.rdf4j rdf4j-repository - 5.1.0-SNAPSHOT + 6.0.0 rdf4j-repository-http RDF4J: HTTPRepository diff --git a/core/repository/http/src/main/java/org/eclipse/rdf4j/repository/http/HTTPRepositoryConnection.java b/core/repository/http/src/main/java/org/eclipse/rdf4j/repository/http/HTTPRepositoryConnection.java index ceccfdeaaeb..a06e1460508 100644 --- a/core/repository/http/src/main/java/org/eclipse/rdf4j/repository/http/HTTPRepositoryConnection.java +++ b/core/repository/http/src/main/java/org/eclipse/rdf4j/repository/http/HTTPRepositoryConnection.java @@ -462,7 +462,7 @@ private RDFFormat getBackwardCompatibleFormat(RDFFormat format) { // default MIME-type. return new RDFFormat(NTRIPLES.getName(), List.of("text/plain"), NTRIPLES.getCharset(), NTRIPLES.getFileExtensions(), NTRIPLES.supportsNamespaces(), NTRIPLES.supportsContexts(), - NTRIPLES.supportsRDFStar()); + NTRIPLES.supportsTripleTerms()); } return format; diff --git a/core/repository/manager/pom.xml b/core/repository/manager/pom.xml index bad53d7101e..e08dbc4005a 100644 --- a/core/repository/manager/pom.xml +++ b/core/repository/manager/pom.xml @@ -4,7 +4,7 @@ org.eclipse.rdf4j rdf4j-repository - 5.1.0-SNAPSHOT + 6.0.0 rdf4j-repository-manager RDF4J: Repository manager diff --git a/core/repository/pom.xml b/core/repository/pom.xml index 873757a9580..1681b340b3e 100644 --- a/core/repository/pom.xml +++ b/core/repository/pom.xml @@ -4,7 +4,7 @@ org.eclipse.rdf4j rdf4j-core - 5.1.0-SNAPSHOT + 6.0.0 rdf4j-repository pom diff --git a/core/repository/sail/pom.xml b/core/repository/sail/pom.xml index fb8fc483b2b..e951b9095b5 100644 --- a/core/repository/sail/pom.xml +++ b/core/repository/sail/pom.xml @@ -4,7 +4,7 @@ org.eclipse.rdf4j rdf4j-repository - 5.1.0-SNAPSHOT + 6.0.0 rdf4j-repository-sail RDF4J: SailRepository diff --git a/core/repository/sparql/pom.xml b/core/repository/sparql/pom.xml index 66d5ee263ce..0fd771c98f7 100644 --- a/core/repository/sparql/pom.xml +++ b/core/repository/sparql/pom.xml @@ -4,7 +4,7 @@ org.eclipse.rdf4j rdf4j-repository - 5.1.0-SNAPSHOT + 6.0.0 rdf4j-repository-sparql RDF4J: SPARQL Repository diff --git a/core/rio/api/pom.xml b/core/rio/api/pom.xml index 3733b074423..f63d2ed8920 100644 --- a/core/rio/api/pom.xml +++ b/core/rio/api/pom.xml @@ -4,7 +4,7 @@ org.eclipse.rdf4j rdf4j-rio - 5.1.0-SNAPSHOT + 6.0.0 rdf4j-rio-api RDF4J: Rio - API diff --git a/core/rio/api/src/main/java/org/eclipse/rdf4j/rio/LanguageHandler.java b/core/rio/api/src/main/java/org/eclipse/rdf4j/rio/LanguageHandler.java index 935e87ebbb4..40bbb1cf7df 100644 --- a/core/rio/api/src/main/java/org/eclipse/rdf4j/rio/LanguageHandler.java +++ b/core/rio/api/src/main/java/org/eclipse/rdf4j/rio/LanguageHandler.java @@ -86,6 +86,28 @@ public interface LanguageHandler { Literal normalizeLanguage(String literalValue, String languageTag, ValueFactory valueFactory) throws LiteralUtilException; + /** + * Normalize both the language tag and the language if appropriate, and use the given value factory to generate a + * literal matching the literal value and language tag. + *

+ * This method must only be called after verifying that {@link #isRecognizedLanguage(String)} returns true for the + * given language tag, and {@link #verifyLanguage(String, String)} also returns true for the given language and + * literal value. + * + * @param literalValue Required literal value to use in the normalization process and to provide the value for the + * resulting literal. + * @param languageTag The language tag which is to be normalized. This tag is available in normalized form from the + * result using {@link Literal#getLanguage()}. + * @param baseDir + * @param valueFactory The {@link ValueFactory} to use to create the result literal. + * @return A {@link Literal} containing the normalized literal value and language tag. + * @throws LiteralUtilException If the language tag was not recognized or verified, or the literal value could not + * be normalized due to an error. + */ + Literal normalizeLanguage(String literalValue, String languageTag, Literal.BaseDirection baseDir, + ValueFactory valueFactory) + throws LiteralUtilException; + /** * A unique key for this language handler to identify it in the LanguageHandlerRegistry. * diff --git a/core/rio/api/src/main/java/org/eclipse/rdf4j/rio/RDFFormat.java b/core/rio/api/src/main/java/org/eclipse/rdf4j/rio/RDFFormat.java index 1bb56957b9d..28fa48334d4 100644 --- a/core/rio/api/src/main/java/org/eclipse/rdf4j/rio/RDFFormat.java +++ b/core/rio/api/src/main/java/org/eclipse/rdf4j/rio/RDFFormat.java @@ -59,14 +59,14 @@ public class RDFFormat extends FileFormat { public static final boolean NO_CONTEXTS = false; /** - * Indicates that RDF-star triples can be serialized natively for this format. + * Indicates that triple terms can be serialized natively for this format. */ - public static final boolean SUPPORTS_RDF_STAR = true; + public static final boolean SUPPORTS_TRIPLE_TERMS = true; /** - * Indicates that RDF-star triples will NOT be serialized natively for this format. + * Indicates that triple terms will NOT be serialized natively for this format. */ - public static final boolean NO_RDF_STAR = false; + public static final boolean NO_TRIPLE_TERMS = false; /** * The RDF/XML file format. @@ -83,7 +83,8 @@ public class RDFFormat extends FileFormat { Arrays.asList("application/rdf+xml", "application/xml", "text/xml"), StandardCharsets.UTF_8, Arrays.asList("rdf", "rdfs", "owl", "xml"), SimpleValueFactory.getInstance().createIRI("http://www.w3.org/ns/formats/RDF_XML"), SUPPORTS_NAMESPACES, - NO_CONTEXTS, NO_RDF_STAR); + NO_CONTEXTS, NO_TRIPLE_TERMS + ); /** * The N-Triples file format. @@ -97,7 +98,8 @@ public class RDFFormat extends FileFormat { public static final RDFFormat NTRIPLES = new RDFFormat("N-Triples", Arrays.asList("application/n-triples", "text/plain"), StandardCharsets.UTF_8, List.of("nt"), SimpleValueFactory.getInstance().createIRI("http://www.w3.org/ns/formats/N-Triples"), NO_NAMESPACES, - NO_CONTEXTS, NO_RDF_STAR); + NO_CONTEXTS, SUPPORTS_TRIPLE_TERMS + ); /** * The Turtle file format. @@ -111,22 +113,8 @@ public class RDFFormat extends FileFormat { public static final RDFFormat TURTLE = new RDFFormat("Turtle", Arrays.asList("text/turtle", "application/x-turtle"), StandardCharsets.UTF_8, List.of("ttl"), SimpleValueFactory.getInstance().createIRI("http://www.w3.org/ns/formats/Turtle"), SUPPORTS_NAMESPACES, - NO_CONTEXTS, NO_RDF_STAR); - - /** - * The Turtle-star file format, a Turtle-based RDF serialization format that supports RDF-star triples. - *

- * The file extension .ttls is recommended for Turtle-star documents. The media type is - * application/x-turtlestar and the encoding is UTF-8. - *

- * - * @see Foundations of an Alternative Approach to Reification in - * RDF - * @see RDF-star and SPARQL-star Draft Community Group Report - */ - public static final RDFFormat TURTLESTAR = new RDFFormat("Turtle-star", - Arrays.asList("text/x-turtlestar", "application/x-turtlestar"), StandardCharsets.UTF_8, - List.of("ttls"), SUPPORTS_NAMESPACES, NO_CONTEXTS, SUPPORTS_RDF_STAR); + NO_CONTEXTS, SUPPORTS_TRIPLE_TERMS + ); /** * The N3/Notation3 file format. @@ -140,7 +128,8 @@ public class RDFFormat extends FileFormat { public static final RDFFormat N3 = new RDFFormat("N3", Arrays.asList("text/n3", "text/rdf+n3"), StandardCharsets.UTF_8, List.of("n3"), SimpleValueFactory.getInstance().createIRI("http://www.w3.org/ns/formats/N3"), SUPPORTS_NAMESPACES, - NO_CONTEXTS, NO_RDF_STAR); + NO_CONTEXTS, NO_TRIPLE_TERMS + ); /** * The TriX file format, an XML-based RDF serialization format that @@ -154,7 +143,8 @@ public class RDFFormat extends FileFormat { */ public static final RDFFormat TRIX = new RDFFormat("TriX", List.of("application/trix"), StandardCharsets.UTF_8, Arrays.asList("xml", "trix"), null, SUPPORTS_NAMESPACES, SUPPORTS_CONTEXTS, - NO_RDF_STAR); + NO_TRIPLE_TERMS + ); /** * The TriG file format, a Turtle-based RDF serialization format that @@ -169,22 +159,8 @@ public class RDFFormat extends FileFormat { public static final RDFFormat TRIG = new RDFFormat("TriG", Arrays.asList("application/trig", "application/x-trig"), StandardCharsets.UTF_8, List.of("trig"), SimpleValueFactory.getInstance().createIRI("http://www.w3.org/ns/formats/TriG"), SUPPORTS_NAMESPACES, - SUPPORTS_CONTEXTS, NO_RDF_STAR); - - /** - * The TriG-star file format, a TriG-based RDF serialization format that supports RDF-star triples. This builds upon - * the idea for the Turtle-star format but adds support for named graphs. - *

- * The file extension .trigs is recommended for TriG-star documents. The media type is - * application/x-trigstar and the encoding is UTF-8. - *

- * - * @see Foundations of an Alternative Approach to Reification in - * RDF - * @see RDF-star and SPARQL-star Draft Community Group Report - */ - public static final RDFFormat TRIGSTAR = new RDFFormat("TriG-star", "application/x-trigstar", - StandardCharsets.UTF_8, "trigs", SUPPORTS_NAMESPACES, SUPPORTS_CONTEXTS, SUPPORTS_RDF_STAR); + SUPPORTS_CONTEXTS, SUPPORTS_TRIPLE_TERMS + ); /** * A binary RDF format. @@ -196,7 +172,7 @@ public class RDFFormat extends FileFormat { * @see Binary RDF in Sesame */ public static final RDFFormat BINARY = new RDFFormat("BinaryRDF", List.of("application/x-binary-rdf"), null, - List.of("brf"), null, SUPPORTS_NAMESPACES, SUPPORTS_CONTEXTS, SUPPORTS_RDF_STAR); + List.of("brf"), null, SUPPORTS_NAMESPACES, SUPPORTS_CONTEXTS, NO_TRIPLE_TERMS); /** * The N-Quads file format, an RDF serialization format that supports @@ -211,7 +187,8 @@ public class RDFFormat extends FileFormat { public static final RDFFormat NQUADS = new RDFFormat("N-Quads", Arrays.asList("application/n-quads", "text/x-nquads", "text/nquads"), StandardCharsets.UTF_8, List.of("nq"), SimpleValueFactory.getInstance().createIRI("http://www.w3.org/ns/formats/N-Quads"), - NO_NAMESPACES, SUPPORTS_CONTEXTS, NO_RDF_STAR); + NO_NAMESPACES, SUPPORTS_CONTEXTS, SUPPORTS_TRIPLE_TERMS + ); /** * The JSON-LD file format, an RDF serialization format that supports @@ -226,7 +203,8 @@ public class RDFFormat extends FileFormat { public static final RDFFormat JSONLD = new RDFFormat("JSON-LD", List.of("application/ld+json"), StandardCharsets.UTF_8, List.of("jsonld"), SimpleValueFactory.getInstance().createIRI("http://www.w3.org/ns/formats/JSON-LD"), SUPPORTS_NAMESPACES, - SUPPORTS_CONTEXTS, NO_RDF_STAR); + SUPPORTS_CONTEXTS, NO_TRIPLE_TERMS + ); /** * The NDJSON-LD is a Newline Delimited JSON-LD format. @@ -237,7 +215,8 @@ public class RDFFormat extends FileFormat { */ public static final RDFFormat NDJSONLD = new RDFFormat("NDJSON-LD", List.of("application/x-ld+ndjson"), StandardCharsets.UTF_8, Arrays.asList("ndjsonld", "jsonl", "ndjson"), null, SUPPORTS_NAMESPACES, - SUPPORTS_CONTEXTS, NO_RDF_STAR); + SUPPORTS_CONTEXTS, NO_TRIPLE_TERMS + ); /** * The RDF/JSON file format, an RDF serialization format that supports @@ -252,7 +231,8 @@ public class RDFFormat extends FileFormat { public static final RDFFormat RDFJSON = new RDFFormat("RDF/JSON", List.of("application/rdf+json"), StandardCharsets.UTF_8, List.of("rj"), SimpleValueFactory.getInstance().createIRI("http://www.w3.org/ns/formats/RDF_JSON"), NO_NAMESPACES, - SUPPORTS_CONTEXTS, NO_RDF_STAR); + SUPPORTS_CONTEXTS, NO_TRIPLE_TERMS + ); /** * The RDFa file format, an RDF serialization format. @@ -267,7 +247,8 @@ public class RDFFormat extends FileFormat { Arrays.asList("application/xhtml+xml", "application/html", "text/html"), StandardCharsets.UTF_8, Arrays.asList("xhtml", "html"), SimpleValueFactory.getInstance().createIRI("http://www.w3.org/ns/formats/RDFa"), SUPPORTS_NAMESPACES, - NO_CONTEXTS, NO_RDF_STAR); + NO_CONTEXTS, NO_TRIPLE_TERMS + ); /** * The HDT file format, an RDF serialization format. @@ -279,7 +260,8 @@ public class RDFFormat extends FileFormat { */ public static final RDFFormat HDT = new RDFFormat("HDT", List.of("application/vnd.hdt"), null, List.of("hdt"), null, - SUPPORTS_NAMESPACES, NO_CONTEXTS, NO_RDF_STAR); + SUPPORTS_NAMESPACES, NO_CONTEXTS, NO_TRIPLE_TERMS + ); /*----------------* * Static methods * @@ -358,9 +340,9 @@ public static List getAcceptParams(Iterable rdfFormats, boole private final boolean supportsContexts; /** - * Flag indicating whether the RDFFormat can encode RDF-star triples natively. + * Flag indicating whether the RDFFormat can encode triples natively. */ - private final boolean supportsRDFStar; + private final boolean supportsTripleTerms; /** * A standard URI published by the W3C or another standards body to uniquely denote this format. @@ -392,30 +374,30 @@ public static List getAcceptParams(Iterable rdfFormats, boole @Deprecated(since = "3.2.0") public RDFFormat(String name, String mimeType, Charset charset, String fileExtension, boolean supportsNamespaces, boolean supportsContexts) { - this(name, mimeType, charset, fileExtension, supportsNamespaces, supportsContexts, NO_RDF_STAR); + this(name, mimeType, charset, fileExtension, supportsNamespaces, supportsContexts, NO_TRIPLE_TERMS); } /** * Creates a new RDFFormat object. * - * @param name The name of the RDF file format, e.g. "RDF/XML". - * @param mimeType The MIME type of the RDF file format, e.g. application/rdf+xml for the - * RDF/XML file format. - * @param charset The default character encoding of the RDF file format. Specify null if not - * applicable. - * @param fileExtension The (default) file extension for the RDF file format, e.g. rdf for RDF/XML - * files. - * @param supportsNamespaces True if the RDFFormat supports the encoding of namespace/prefix information - * and false otherwise. - * @param supportsContexts True if the RDFFormat supports the encoding of contexts/named graphs and - * false otherwise. - * @param supportsRDFStar True if the RDFFormat supports the encoding of RDF-star triples natively and - * false otherwise. + * @param name The name of the RDF file format, e.g. "RDF/XML". + * @param mimeType The MIME type of the RDF file format, e.g. application/rdf+xml for the + * RDF/XML file format. + * @param charset The default character encoding of the RDF file format. Specify null if not + * applicable. + * @param fileExtension The (default) file extension for the RDF file format, e.g. rdf for RDF/XML + * files. + * @param supportsNamespaces True if the RDFFormat supports the encoding of namespace/prefix information + * and false otherwise. + * @param supportsContexts True if the RDFFormat supports the encoding of contexts/named graphs and + * false otherwise. + * @param supportsTripleTerms True if the RDFFormat supports the encoding of triple terms natively and + * false otherwise. */ public RDFFormat(String name, String mimeType, Charset charset, String fileExtension, boolean supportsNamespaces, - boolean supportsContexts, boolean supportsRDFStar) { + boolean supportsContexts, boolean supportsTripleTerms) { this(name, List.of(mimeType), charset, List.of(fileExtension), supportsNamespaces, - supportsContexts, supportsRDFStar); + supportsContexts, supportsTripleTerms); } /** @@ -437,30 +419,30 @@ public RDFFormat(String name, String mimeType, Charset charset, String fileExten @Deprecated(since = "3.2.0") public RDFFormat(String name, String mimeType, Charset charset, Collection fileExtensions, boolean supportsNamespaces, boolean supportsContexts) { - this(name, mimeType, charset, fileExtensions, supportsNamespaces, supportsContexts, NO_RDF_STAR); + this(name, mimeType, charset, fileExtensions, supportsNamespaces, supportsContexts, NO_TRIPLE_TERMS); } /** * Creates a new RDFFormat object. * - * @param name The name of the RDF file format, e.g. "RDF/XML". - * @param mimeType The MIME type of the RDF file format, e.g. application/rdf+xml for the - * RDF/XML file format. - * @param charset The default character encoding of the RDF file format. Specify null if not - * applicable. - * @param fileExtensions The RDF format's file extensions, e.g. rdf for RDF/XML files. The first item - * in the list is interpreted as the default file extension for the format. - * @param supportsNamespaces True if the RDFFormat supports the encoding of namespace/prefix information - * and false otherwise. - * @param supportsContexts True if the RDFFormat supports the encoding of contexts/named graphs and - * false otherwise. - * @param supportsRDFStar True if the RDFFormat supports the encoding of RDF-star triples natively and - * false otherwise. + * @param name The name of the RDF file format, e.g. "RDF/XML". + * @param mimeType The MIME type of the RDF file format, e.g. application/rdf+xml for the + * RDF/XML file format. + * @param charset The default character encoding of the RDF file format. Specify null if not + * applicable. + * @param fileExtensions The RDF format's file extensions, e.g. rdf for RDF/XML files. The first + * item in the list is interpreted as the default file extension for the format. + * @param supportsNamespaces True if the RDFFormat supports the encoding of namespace/prefix information + * and false otherwise. + * @param supportsContexts True if the RDFFormat supports the encoding of contexts/named graphs and + * false otherwise. + * @param supportsTripleTerms True if the RDFFormat supports the encoding of triple terms natively and + * false otherwise. */ public RDFFormat(String name, String mimeType, Charset charset, Collection fileExtensions, - boolean supportsNamespaces, boolean supportsContexts, boolean supportsRDFStar) { + boolean supportsNamespaces, boolean supportsContexts, boolean supportsTripleTerms) { this(name, List.of(mimeType), charset, fileExtensions, supportsNamespaces, supportsContexts, - supportsRDFStar); + supportsTripleTerms); } /** @@ -483,31 +465,31 @@ public RDFFormat(String name, String mimeType, Charset charset, Collection mimeTypes, Charset charset, Collection fileExtensions, boolean supportsNamespaces, boolean supportsContexts) { - this(name, mimeTypes, charset, fileExtensions, null, supportsNamespaces, supportsContexts, NO_RDF_STAR); + this(name, mimeTypes, charset, fileExtensions, null, supportsNamespaces, supportsContexts, NO_TRIPLE_TERMS); } /** * Creates a new RDFFormat object. * - * @param name The name of the RDF file format, e.g. "RDF/XML". - * @param mimeTypes The MIME types of the RDF file format, e.g. application/rdf+xml for the - * RDF/XML file format. The first item in the list is interpreted as the default MIME type - * for the format. - * @param charset The default character encoding of the RDF file format. Specify null if not - * applicable. - * @param fileExtensions The RDF format's file extensions, e.g. rdf for RDF/XML files. The first item - * in the list is interpreted as the default file extension for the format. - * @param supportsNamespaces True if the RDFFormat supports the encoding of namespace/prefix information - * and false otherwise. - * @param supportsContexts True if the RDFFormat supports the encoding of contexts/named graphs and - * false otherwise. - * @param supportsRDFStar True if the RDFFormat supports the encoding of RDF-star triples natively and - * false otherwise. + * @param name The name of the RDF file format, e.g. "RDF/XML". + * @param mimeTypes The MIME types of the RDF file format, e.g. application/rdf+xml for the + * RDF/XML file format. The first item in the list is interpreted as the default MIME + * type for the format. + * @param charset The default character encoding of the RDF file format. Specify null if not + * applicable. + * @param fileExtensions The RDF format's file extensions, e.g. rdf for RDF/XML files. The first + * item in the list is interpreted as the default file extension for the format. + * @param supportsNamespaces True if the RDFFormat supports the encoding of namespace/prefix information + * and false otherwise. + * @param supportsContexts True if the RDFFormat supports the encoding of contexts/named graphs and + * false otherwise. + * @param supportsTripleTerms True if the RDFFormat supports the encoding of triple terms natively and + * false otherwise. */ public RDFFormat(String name, Collection mimeTypes, Charset charset, Collection fileExtensions, - boolean supportsNamespaces, boolean supportsContexts, boolean supportsRDFStar) { + boolean supportsNamespaces, boolean supportsContexts, boolean supportsTripleTerms) { this(name, mimeTypes, charset, fileExtensions, null, supportsNamespaces, supportsContexts, - supportsRDFStar); + supportsTripleTerms); } /** @@ -532,37 +514,39 @@ public RDFFormat(String name, Collection mimeTypes, Charset charset, Col @Deprecated(since = "3.2.0") public RDFFormat(String name, Collection mimeTypes, Charset charset, Collection fileExtensions, IRI standardURI, boolean supportsNamespaces, boolean supportsContexts) { - this(name, mimeTypes, charset, fileExtensions, standardURI, supportsNamespaces, supportsContexts, NO_RDF_STAR); + this(name, mimeTypes, charset, fileExtensions, standardURI, supportsNamespaces, supportsContexts, + NO_TRIPLE_TERMS + ); } /** * Creates a new RDFFormat object. * - * @param name The name of the RDF file format, e.g. "RDF/XML". - * @param mimeTypes The MIME types of the RDF file format, e.g. application/rdf+xml for the - * RDF/XML file format. The first item in the list is interpreted as the default MIME type - * for the format. - * @param charset The default character encoding of the RDF file format. Specify null if not - * applicable. - * @param fileExtensions The RDF format's file extensions, e.g. rdf for RDF/XML files. The first item - * in the list is interpreted as the default file extension for the format. - * @param standardURI The standard URI that has been assigned to this format by a standards organisation or - * null if it does not currently have a standard URI. - * @param supportsNamespaces True if the RDFFormat supports the encoding of namespace/prefix information - * and false otherwise. - * @param supportsContexts True if the RDFFormat supports the encoding of contexts/named graphs and - * false otherwise. - * @param supportsRDFStar True if the RDFFormat supports the encoding of RDF-star triples natively and - * false otherwise. + * @param name The name of the RDF file format, e.g. "RDF/XML". + * @param mimeTypes The MIME types of the RDF file format, e.g. application/rdf+xml for the + * RDF/XML file format. The first item in the list is interpreted as the default MIME + * type for the format. + * @param charset The default character encoding of the RDF file format. Specify null if not + * applicable. + * @param fileExtensions The RDF format's file extensions, e.g. rdf for RDF/XML files. The first + * item in the list is interpreted as the default file extension for the format. + * @param standardURI The standard URI that has been assigned to this format by a standards organisation or + * null if it does not currently have a standard URI. + * @param supportsNamespaces True if the RDFFormat supports the encoding of namespace/prefix information + * and false otherwise. + * @param supportsContexts True if the RDFFormat supports the encoding of contexts/named graphs and + * false otherwise. + * @param supportsTripleTerms True if the RDFFormat supports the encoding of triple terms natively and + * false otherwise. */ public RDFFormat(String name, Collection mimeTypes, Charset charset, Collection fileExtensions, - IRI standardURI, boolean supportsNamespaces, boolean supportsContexts, boolean supportsRDFStar) { + IRI standardURI, boolean supportsNamespaces, boolean supportsContexts, boolean supportsTripleTerms) { super(name, mimeTypes, charset, fileExtensions); this.standardURI = standardURI; this.supportsNamespaces = supportsNamespaces; this.supportsContexts = supportsContexts; - this.supportsRDFStar = supportsRDFStar; + this.supportsTripleTerms = supportsTripleTerms; } /*---------* @@ -584,10 +568,10 @@ public boolean supportsContexts() { } /** - * Return true if the RDFFormat supports the encoding of RDF-star triples natively. + * Return true if the RDFFormat supports the encoding of triple terms natively. */ - public boolean supportsRDFStar() { - return supportsRDFStar; + public boolean supportsTripleTerms() { + return supportsTripleTerms; } /** diff --git a/core/rio/api/src/main/java/org/eclipse/rdf4j/rio/helpers/AbstractRDFParser.java b/core/rio/api/src/main/java/org/eclipse/rdf4j/rio/helpers/AbstractRDFParser.java index e1aeb14ca83..02ea1378e3a 100644 --- a/core/rio/api/src/main/java/org/eclipse/rdf4j/rio/helpers/AbstractRDFParser.java +++ b/core/rio/api/src/main/java/org/eclipse/rdf4j/rio/helpers/AbstractRDFParser.java @@ -291,8 +291,8 @@ protected void clear() { nextBNodePrefix = createUniqueBNodePrefix(); namespaceTable.clear(); // Don't use the setter setValueFactory() as it will update originalValueFactory too - if (getParserConfig().get(BasicParserSettings.PROCESS_ENCODED_RDF_STAR)) { - valueFactory = new RDFStarDecodingValueFactory(originalValueFactory); + if (getParserConfig().get(BasicParserSettings.PROCESS_ENCODED_TRIPLE_TERMS)) { + valueFactory = new TripleTermDecodingValueFactory(originalValueFactory); } else { valueFactory = originalValueFactory; } diff --git a/core/rio/api/src/main/java/org/eclipse/rdf4j/rio/helpers/AbstractRDFWriter.java b/core/rio/api/src/main/java/org/eclipse/rdf4j/rio/helpers/AbstractRDFWriter.java index 205f7590b5b..bb72af30bac 100644 --- a/core/rio/api/src/main/java/org/eclipse/rdf4j/rio/helpers/AbstractRDFWriter.java +++ b/core/rio/api/src/main/java/org/eclipse/rdf4j/rio/helpers/AbstractRDFWriter.java @@ -93,13 +93,14 @@ public void startRDF() throws RDFHandlerException { writingStarted = true; statementConsumer = this::consumeStatement; - if (getWriterConfig().get(BasicWriterSettings.CONVERT_RDF_STAR_TO_REIFICATION)) { - // All writers can convert RDF-star to reification on request - statementConsumer = this::handleStatementConvertRDFStar; - } else if (!getRDFFormat().supportsRDFStar() && getWriterConfig().get(BasicWriterSettings.ENCODE_RDF_STAR)) { - // By default non-RDF-star writers encode RDF-star to special RDF IRIs - // (all parsers, including RDF-star will convert back the encoded IRIs) - statementConsumer = this::handleStatementEncodeRDFStar; + if (getWriterConfig().get(BasicWriterSettings.CONVERT_RDF_12_REIFICATION)) { + // All writers can convert RDF 1.2 to reification on request + statementConsumer = this::handleStatementConvertTripleTerms; + } else if (!getRDFFormat().supportsTripleTerms() + && getWriterConfig().get(BasicWriterSettings.ENCODE_TRIPLE_TERMS)) { + // By default, non-RDF-12 writers encode triple terms to special RDF IRIs + // (all parsers, including RDF 1.2 will convert back the encoded IRIs) + statementConsumer = this::handleStatementEncodeTripleTerms; } } @@ -113,7 +114,7 @@ public void handleStatement(Statement st) throws RDFHandlerException { * Consume a statement. *

* Extending classes must override this method instead of overriding {@link #handleStatement(Statement)} in order to - * benefit from automatic handling of RDF-star conversion or encoding. + * benefit from automatic handling of RDF 1.2 conversion or encoding. * * @param st the statement to consume. */ @@ -141,15 +142,15 @@ protected void checkWritingStarted() { } } - private void handleStatementConvertRDFStar(Statement st) { - Statements.convertRDFStarToReification(st, this::consumeStatement); + private void handleStatementConvertTripleTerms(Statement st) { + Statements.convertRDF12ReificationToRDF11(st, this::consumeStatement); } - private void handleStatementEncodeRDFStar(Statement st) { + private void handleStatementEncodeTripleTerms(Statement st) { Resource s = st.getSubject(); Value o = st.getObject(); if (s instanceof Triple || o instanceof Triple) { - consumeStatement(new RDFStarEncodingStatement(st)); + consumeStatement(new TripleTermEncodingStatement(st)); } else { consumeStatement(st); } diff --git a/core/rio/api/src/main/java/org/eclipse/rdf4j/rio/helpers/BasicParserSettings.java b/core/rio/api/src/main/java/org/eclipse/rdf4j/rio/helpers/BasicParserSettings.java index e6dc74eecee..87bdaf598a6 100644 --- a/core/rio/api/src/main/java/org/eclipse/rdf4j/rio/helpers/BasicParserSettings.java +++ b/core/rio/api/src/main/java/org/eclipse/rdf4j/rio/helpers/BasicParserSettings.java @@ -117,7 +117,7 @@ public class BasicParserSettings { * Can be overridden by setting system property {@code org.eclipse.rdf4j.rio.normalize_language_tags}. */ public static final BooleanRioSetting NORMALIZE_LANGUAGE_TAGS = new BooleanRioSetting( - "org.eclipse.rdf4j.rio.normalize_language_tags", "Normalize recognised language tags", Boolean.FALSE); + "org.eclipse.rdf4j.rio.normalize_language_tags", "Normalize recognised language tags", Boolean.TRUE); /** * Setting used to specify which {@link LanguageHandler} implementations are to be used for a given parser @@ -217,19 +217,19 @@ public class BasicParserSettings { Namespaces.DEFAULT_RDF4J); /** - * Boolean setting for parser to determine whether it should process RDF-star triples encoded as RDF-compatible - * special IRIs back to RDF-star values. These IRIs start with urn:rdf4j:triple: followed by the base64-encoding of - * the N-Triples serialization of the RDF-star triple value. + * Boolean setting for parser to determine whether it should process RDF 1.2 triples encoded as RDF-compatible + * special IRIs back to RDF 1.2 values. These IRIs start with urn:rdf4j:triple: followed by the base64-encoding of + * the N-Triples serialization of the RDF 1.2 triple value. *

- * Parsers that support RDF-star natively will honour this setting too. + * Parsers that support RDF 1.2 natively will honour this setting too. *

* Defaults to true. *

- * Can be overridden by setting system property {@code org.eclipse.rdf4j.rio.process_encoded_rdf_star}. + * Can be overridden by setting system property {@code org.eclipse.rdf4j.rio.process_encoded_triple_terms}. */ - public static final BooleanRioSetting PROCESS_ENCODED_RDF_STAR = new BooleanRioSetting( - "org.eclipse.rdf4j.rio.process_encoded_rdf_star", - "Converts RDF-star triples encoded as RDF-compatible IRIs back to triple values", Boolean.TRUE); + public static final BooleanRioSetting PROCESS_ENCODED_TRIPLE_TERMS = new BooleanRioSetting( + "org.eclipse.rdf4j.rio.process_encoded_triple_terms", + "Converts RDF 1.2 triples encoded as RDF-compatible IRIs back to triple values", Boolean.TRUE); static { List defaultDatatypeHandlers = new ArrayList<>(5); diff --git a/core/rio/api/src/main/java/org/eclipse/rdf4j/rio/helpers/BasicWriterSettings.java b/core/rio/api/src/main/java/org/eclipse/rdf4j/rio/helpers/BasicWriterSettings.java index 87083c8b22b..a99f05ba6a3 100644 --- a/core/rio/api/src/main/java/org/eclipse/rdf4j/rio/helpers/BasicWriterSettings.java +++ b/core/rio/api/src/main/java/org/eclipse/rdf4j/rio/helpers/BasicWriterSettings.java @@ -92,30 +92,30 @@ public class BasicWriterSettings { "org.eclipse.rdf4j.rio.base_directive", "Serialize base directive", Boolean.TRUE); /** - * Boolean setting for writer to determine whether it should convert RDF-star statements to standard RDF - * reification. + * Boolean setting for writer to determine whether it should convert RDF 1.2 statements to standard RDF reification. *

* Defaults to false *

- * Can be overridden by setting system property {@code org.eclipse.rdf4j.rio.convert_rdf_star}. + * Can be overridden by setting system property {@code org.eclipse.rdf4j.rio.convert_rdf_12_reification}. */ - public static final BooleanRioSetting CONVERT_RDF_STAR_TO_REIFICATION = new BooleanRioSetting( - "org.eclipse.rdf4j.rio.convert_rdf_star", "Convert RDF-star statements to RDF reification", Boolean.FALSE); + public static final BooleanRioSetting CONVERT_RDF_12_REIFICATION = new BooleanRioSetting( + "org.eclipse.rdf4j.rio.convert_rdf_12_reification", "Convert RDF 1.2 statements to RDF 1.1 reification", + Boolean.FALSE); /** - * Boolean setting for writer to determine whether it should encode RDF-star triple values to RDF-compatible special + * Boolean setting for writer to determine whether it should encode RDF 1.2 triple values to RDF-compatible special * IRIs. These IRIs start with urn:rdf4j:triple: followed by the base64-encoding of the N-Triples serialization of - * the RDF-star triple value. + * the RDF 1.2 triple value. *

- * Writers that support RDF-star natively will ignore this setting and always serialize RDF-star triples. + * Writers that support RDF 1.2 natively will ignore this setting and always serialize RDF 1.2 triples. *

* Defaults to true. *

- * Can be overridden by setting system property {@code org.eclipse.rdf4j.rio.encode_rdf_star}. + * Can be overridden by setting system property {@code org.eclipse.rdf4j.rio.encode_triple_terms}. */ - public static final BooleanRioSetting ENCODE_RDF_STAR = new BooleanRioSetting( - "org.eclipse.rdf4j.rio.encode_rdf_star", - "Encodes RDF-star triples to special IRIs for compatibility with RDF", Boolean.TRUE); + public static final BooleanRioSetting ENCODE_TRIPLE_TERMS = new BooleanRioSetting( + "org.eclipse.rdf4j.rio.encode_triple_terms", + "Encodes triple terms to special IRIs for compatibility with RDF 1.1", Boolean.TRUE); /** * Private default constructor. diff --git a/core/rio/api/src/main/java/org/eclipse/rdf4j/rio/helpers/NTriplesUtil.java b/core/rio/api/src/main/java/org/eclipse/rdf4j/rio/helpers/NTriplesUtil.java index ad2195abaf0..f20d3905e97 100644 --- a/core/rio/api/src/main/java/org/eclipse/rdf4j/rio/helpers/NTriplesUtil.java +++ b/core/rio/api/src/main/java/org/eclipse/rdf4j/rio/helpers/NTriplesUtil.java @@ -97,9 +97,7 @@ public static Value parseValue(String nTriplesValue, ValueFactory valueFactory) */ public static Resource parseResource(String nTriplesResource, ValueFactory valueFactory) throws IllegalArgumentException { - if (nTriplesResource.startsWith("<<")) { - return parseTriple(nTriplesResource, valueFactory); - } else if (nTriplesResource.startsWith("<")) { + if (nTriplesResource.startsWith("<")) { return parseURI(nTriplesResource, valueFactory); } else if (nTriplesResource.startsWith("_:")) { return parseBNode(nTriplesResource, valueFactory); @@ -119,7 +117,7 @@ public static Resource parseResource(String nTriplesResource, ValueFactory value public static IRI parseURI(String nTriplesURI, ValueFactory valueFactory) throws IllegalArgumentException { if (nTriplesURI.startsWith("<") && nTriplesURI.endsWith(">")) { String uri = nTriplesURI.substring(1, nTriplesURI.length() - 1); - // Disambiguate with RDF-star triple + // Disambiguate with triple term if (!uri.startsWith("<")) { uri = unescapeString(uri); return valueFactory.createIRI(uri); @@ -189,10 +187,9 @@ public static Literal parseLiteral(String nTriplesLiteral, ValueFactory valueFac } /** - * Parses an RDF-star triple (non-standard N-Triples), creates an object for it using the supplied ValueFactory and - * returns this object. + * Parses a tripleterm, creates an object for it using the supplied ValueFactory and returns this object. * - * @param nTriplesTriple The RDF-star triple to parse. + * @param nTriplesTriple The triple term to parse. * @param valueFactory The ValueFactory to use for creating the object. * @return An object representing the parsed triple. * @throws IllegalArgumentException If the supplied triple could not be parsed correctly. @@ -206,18 +203,18 @@ public static Triple parseTriple(String nTriplesTriple, ValueFactory valueFactor } /** - * Parses an RDF-star triple (non-standard N-Triples), creates an object for it using the supplied ValueFactory and - * returns an object that contains the parsed triple and the length of the parsed text. + * Parses a triple term, creates an object for it using the supplied ValueFactory and returns an object that + * contains the parsed triple and the length of the parsed text. * - * @param nTriplesTriple The RDF-star triple to parse. + * @param nTriplesTriple The triple to parse. * @param valueFactory The ValueFactory to use for creating the object. * @return An object representing the parsed triple and the length of the matching text. * @throws IllegalArgumentException If the supplied triple could not be parsed correctly. */ private static TripleMatch parseTripleInternal(String nTriplesTriple, ValueFactory valueFactory) { - if (nTriplesTriple.startsWith("<<")) { - String triple = nTriplesTriple.substring(2); - int offset = 2; + if (nTriplesTriple.startsWith("<<(")) { + String triple = nTriplesTriple.substring(3); + int offset = 3; while (!triple.isEmpty() && Character.isWhitespace(triple.charAt(0))) { triple = triple.substring(1); @@ -283,8 +280,8 @@ private static TripleMatch parseTripleInternal(String nTriplesTriple, ValueFacto } } - if (triple.endsWith(">>")) { - offset += 2; + if (triple.endsWith(")>>")) { + offset += 3; return new TripleMatch(valueFactory.createTriple(subject, predicate, object), offset); } } @@ -347,6 +344,8 @@ public static String toNTriplesString(Value value, boolean xsdStringToPlainLiter return toNTriplesString((Resource) value); } else if (value instanceof Literal) { return toNTriplesString((Literal) value, xsdStringToPlainLiteral); + } else if (value instanceof Triple) { + return toNTriplesString((Triple) value); } else { throw new IllegalArgumentException("Unknown value type: " + value.getClass()); } @@ -383,6 +382,8 @@ public static void append(Value value, Appendable appendable, boolean xsdStringT append((Resource) value, appendable); } else if (value instanceof Literal) { append((Literal) value, appendable, xsdStringToPlainLiteral, escapeUnicode); + } else if (value instanceof Triple) { + append((Triple) value, appendable); } else { throw new IllegalArgumentException("Unknown value type: " + value.getClass()); } @@ -399,8 +400,6 @@ public static String toNTriplesString(Resource resource) { return toNTriplesString((IRI) resource); } else if (resource instanceof BNode) { return toNTriplesString((BNode) resource); - } else if (resource instanceof Triple) { - return toNTriplesString((Triple) resource); } else { throw new IllegalArgumentException("Unknown resource type: " + resource.getClass()); } @@ -418,8 +417,6 @@ public static void append(Resource resource, Appendable appendable) throws IOExc append((IRI) resource, appendable); } else if (resource instanceof BNode) { append((BNode) resource, appendable); - } else if (resource instanceof Triple) { - append((Triple) resource, appendable); } else { throw new IllegalArgumentException("Unknown resource type: " + resource.getClass()); } @@ -565,6 +562,7 @@ public static void append(Literal lit, Appendable appendable, boolean xsdStringT // Append the literal's language appendable.append("@"); appendable.append(lit.getLanguage().get()); + appendable.append(lit.getBaseDirection().toString()); } else { // SES-1917 : In RDF-1.1, all literals have a type, and if they are not // language literals we display the type for backwards compatibility @@ -579,15 +577,15 @@ public static void append(Literal lit, Appendable appendable, boolean xsdStringT } /** - * Creates an N-Triples (non-standard) string for the supplied RDF-star triple. + * Creates an N-Triples string for the supplied triple. * * @param triple * @return string */ public static String toNTriplesString(Triple triple) { - return "<<" + NTriplesUtil.toNTriplesString(triple.getSubject()) + " " + return "<<( " + NTriplesUtil.toNTriplesString(triple.getSubject()) + " " + NTriplesUtil.toNTriplesString(triple.getPredicate()) + " " - + NTriplesUtil.toNTriplesString(triple.getObject()) + ">>"; + + NTriplesUtil.toNTriplesString(triple.getObject()) + " )>>"; } /** @@ -598,13 +596,13 @@ public static String toNTriplesString(Triple triple) { * @throws IOException */ public static void append(Triple triple, Appendable appendable) throws IOException { - appendable.append("<<"); + appendable.append("<<( "); append(triple.getSubject(), appendable); appendable.append(' '); append(triple.getPredicate(), appendable); appendable.append(' '); append(triple.getObject(), appendable); - appendable.append(">>"); + appendable.append(" )>>"); } /** @@ -747,8 +745,12 @@ public static void escapeString(String label, Appendable appendable, boolean esc appendable.append("\\r"); } else if (c == '\t') { appendable.append("\\t"); - } else if (cInt >= 0x0 && cInt <= 0x8 || cInt == 0xB || cInt == 0xC || cInt >= 0xE && cInt <= 0x1F - || cInt >= 0x7F && cInt <= 0xFFFF) { + } else if (c == '\b') { + appendable.append("\\b"); + } else if (c == '\f') { + appendable.append("\\f"); + } else if (cInt >= 0x0 && cInt <= 0x0007 || cInt >= 0xE && cInt <= 0x1F || cInt == 0xB || cInt == 0x7F + || cInt >= 0xFFFE) { if (escapeUnicode) { appendable.append("\\u"); appendable.append(toHexString(cInt, 4)); diff --git a/core/rio/api/src/main/java/org/eclipse/rdf4j/rio/helpers/RDFParserHelper.java b/core/rio/api/src/main/java/org/eclipse/rdf4j/rio/helpers/RDFParserHelper.java index fbb27d608ab..fad0afc2c7b 100644 --- a/core/rio/api/src/main/java/org/eclipse/rdf4j/rio/helpers/RDFParserHelper.java +++ b/core/rio/api/src/main/java/org/eclipse/rdf4j/rio/helpers/RDFParserHelper.java @@ -99,6 +99,7 @@ public static Literal createLiteral(String label, String lang, IRI datatype, Par Literal result = null; String workingLabel = label; Optional workingLang = Optional.ofNullable(lang); + Literal.BaseDirection workingBaseDirection = Literal.BaseDirection.NONE; IRI workingDatatype = datatype; // In RDF-1.1 we must do lang check first as language literals will all @@ -106,31 +107,50 @@ public static Literal createLiteral(String label, String lang, IRI datatype, Par // non-null lang if (workingLang.isPresent() && (workingDatatype == null || RDF.LANGSTRING.equals(workingDatatype))) { boolean recognisedLanguage = false; + + // Split workingLang into language tag and base direction so both can be separately verified + final int index = lang.indexOf(Literal.BASE_DIR_SEPARATOR); + if (index != -1) { + workingLang = Optional.of(lang.substring(0, index)); + final String baseDirectionString = lang.substring(index); + + try { + workingBaseDirection = Literal.BaseDirection.fromString(baseDirectionString); + } catch (IllegalArgumentException e) { + reportFatalError("'" + baseDirectionString + "' is not a valid base direction ", lineNo, columnNo, + errListener); + } + } + for (LanguageHandler nextHandler : parserConfig.get(BasicParserSettings.LANGUAGE_HANDLERS)) { if (nextHandler.isRecognizedLanguage(workingLang.get())) { recognisedLanguage = true; if (parserConfig.get(BasicParserSettings.VERIFY_LANGUAGE_TAGS)) { try { if (!nextHandler.verifyLanguage(workingLabel, workingLang.get())) { - reportError("'" + lang + "' is not a valid language tag ", lineNo, columnNo, + reportError("'" + workingLang.get() + "' is not a valid language tag ", lineNo, + columnNo, BasicParserSettings.VERIFY_LANGUAGE_TAGS, parserConfig, errListener); } } catch (LiteralUtilException e) { reportError("'" + label + " could not be verified by a language handler that recognised it. language was " - + lang, lineNo, columnNo, BasicParserSettings.VERIFY_LANGUAGE_TAGS, parserConfig, + + workingLang.get(), lineNo, columnNo, BasicParserSettings.VERIFY_LANGUAGE_TAGS, + parserConfig, errListener); } } if (parserConfig.get(BasicParserSettings.NORMALIZE_LANGUAGE_TAGS)) { try { - result = nextHandler.normalizeLanguage(workingLabel, workingLang.get(), valueFactory); + result = nextHandler.normalizeLanguage(workingLabel, workingLang.get(), + workingBaseDirection, valueFactory); workingLabel = result.getLabel(); workingLang = result.getLanguage(); workingDatatype = result.getDatatype(); } catch (LiteralUtilException e) { reportError( - "'" + label + "' did not have a valid value for language " + lang + ": " + "'" + label + "' did not have a valid value for language " + workingLang.get() + + ": " + e.getMessage() + " and could not be normalised", lineNo, columnNo, BasicParserSettings.NORMALIZE_LANGUAGE_TAGS, parserConfig, errListener); @@ -141,7 +161,8 @@ public static Literal createLiteral(String label, String lang, IRI datatype, Par if (!recognisedLanguage) { reportError("'" + label + "' was not recognised as a language literal, and could not be verified, with language " - + lang, lineNo, columnNo, BasicParserSettings.FAIL_ON_UNKNOWN_LANGUAGES, parserConfig, + + workingLang.get(), lineNo, columnNo, BasicParserSettings.FAIL_ON_UNKNOWN_LANGUAGES, + parserConfig, errListener); } } else if (workingDatatype != null) { @@ -189,15 +210,18 @@ public static Literal createLiteral(String label, String lang, IRI datatype, Par if (result == null) { try { // Removes datatype for langString datatype with no language tag when VERIFY_DATATYPE_VALUES is False. - if ((workingDatatype == null || RDF.LANGSTRING.equals(workingDatatype)) + if ((workingDatatype == null || RDF.LANGSTRING.equals(workingDatatype) + || RDF.DIRLANGSTRING.equals(workingDatatype)) && (workingLang.isEmpty() || workingLang.get().isEmpty()) && !parserConfig.get(BasicParserSettings.VERIFY_DATATYPE_VALUES)) { workingLang = Optional.ofNullable(null); workingDatatype = null; } // Backup for unnormalised language literal creation - if (workingLang.isPresent() && (workingDatatype == null || RDF.LANGSTRING.equals(workingDatatype))) { - result = valueFactory.createLiteral(workingLabel, workingLang.get().intern()); + if (workingLang.isPresent() + && (workingDatatype == null || RDF.LANGSTRING.equals(workingDatatype) + || RDF.DIRLANGSTRING.equals(workingDatatype))) { + result = valueFactory.createLiteral(workingLabel, workingLang.get().intern(), workingBaseDirection); } // Backup for unnormalised datatype literal creation else if (workingDatatype != null) { diff --git a/core/rio/api/src/main/java/org/eclipse/rdf4j/rio/helpers/RDFStarDecodingValueFactory.java b/core/rio/api/src/main/java/org/eclipse/rdf4j/rio/helpers/TripleTermDecodingValueFactory.java similarity index 87% rename from core/rio/api/src/main/java/org/eclipse/rdf4j/rio/helpers/RDFStarDecodingValueFactory.java rename to core/rio/api/src/main/java/org/eclipse/rdf4j/rio/helpers/TripleTermDecodingValueFactory.java index a324b58c748..17d563f6227 100644 --- a/core/rio/api/src/main/java/org/eclipse/rdf4j/rio/helpers/RDFStarDecodingValueFactory.java +++ b/core/rio/api/src/main/java/org/eclipse/rdf4j/rio/helpers/TripleTermDecodingValueFactory.java @@ -30,14 +30,14 @@ /** * A {@link ValueFactory} that will delegate everything to another {@link ValueFactory} and create statements whose - * subject and object will be converted from RDF-star triples encoded as special IRIs back to RDF-star values. + * subject and object will be converted from RDF 1.2 triples encoded as special IRIs back to RDF 1.2 values. *

* All other values in the subject and object position will be used as is. */ -class RDFStarDecodingValueFactory implements ValueFactory { +class TripleTermDecodingValueFactory implements ValueFactory { private final ValueFactory delegate; - RDFStarDecodingValueFactory(ValueFactory delegate) { + TripleTermDecodingValueFactory(ValueFactory delegate) { this.delegate = delegate; } @@ -71,6 +71,11 @@ public Literal createLiteral(String label, String language) { return delegate.createLiteral(label, language); } + @Override + public Literal createLiteral(String label, String language, Literal.BaseDirection baseDirection) { + return delegate.createLiteral(label, language, baseDirection); + } + @Override public Literal createLiteral(String label, IRI datatype) { return delegate.createLiteral(label, datatype); @@ -154,16 +159,16 @@ public Literal createLiteral(Date date) { @Override public Statement createStatement(Resource subject, IRI predicate, Value object) { - return delegate.createStatement(RDFStarUtil.fromRDFEncodedValue(subject), predicate, - RDFStarUtil.fromRDFEncodedValue(object)); + return delegate.createStatement(subject, predicate, + TripleTermUtil.fromRDFEncodedValue(object)); } @Override public Statement createStatement(Resource subject, IRI predicate, Value object, Resource context) { - return delegate.createStatement(RDFStarUtil.fromRDFEncodedValue(subject), predicate, - RDFStarUtil.fromRDFEncodedValue(object), context); + return delegate.createStatement(subject, predicate, + TripleTermUtil.fromRDFEncodedValue(object), context); } @Override diff --git a/core/rio/api/src/main/java/org/eclipse/rdf4j/rio/helpers/RDFStarEncodingStatement.java b/core/rio/api/src/main/java/org/eclipse/rdf4j/rio/helpers/TripleTermEncodingStatement.java similarity index 79% rename from core/rio/api/src/main/java/org/eclipse/rdf4j/rio/helpers/RDFStarEncodingStatement.java rename to core/rio/api/src/main/java/org/eclipse/rdf4j/rio/helpers/TripleTermEncodingStatement.java index 2e5d4b5f6ce..bf3e263dbee 100644 --- a/core/rio/api/src/main/java/org/eclipse/rdf4j/rio/helpers/RDFStarEncodingStatement.java +++ b/core/rio/api/src/main/java/org/eclipse/rdf4j/rio/helpers/TripleTermEncodingStatement.java @@ -18,21 +18,21 @@ import org.eclipse.rdf4j.model.Value; /** - * Represents a {@link Statement} whose subject or object may be an RDF-star triple that will be encoded as a special - * IRI value on {@link #getSubject()} and {@link #getObject()}. + * Represents a {@link Statement} whose object may be a triple term that will be encoded as a special IRI value on + * {@link #getObject()}. * * @author Pavel Mihaylov */ -class RDFStarEncodingStatement implements Statement { +class TripleTermEncodingStatement implements Statement { private final Statement delegate; - RDFStarEncodingStatement(Statement delegate) { + TripleTermEncodingStatement(Statement delegate) { this.delegate = delegate; } @Override public Resource getSubject() { - return RDFStarUtil.toRDFEncodedValue(delegate.getSubject()); + return TripleTermUtil.toRDFEncodedValue(delegate.getSubject()); } @Override @@ -42,7 +42,7 @@ public IRI getPredicate() { @Override public Value getObject() { - return RDFStarUtil.toRDFEncodedValue(delegate.getObject()); + return TripleTermUtil.toRDFEncodedValue(delegate.getObject()); } @Override diff --git a/core/rio/api/src/main/java/org/eclipse/rdf4j/rio/helpers/RDFStarUtil.java b/core/rio/api/src/main/java/org/eclipse/rdf4j/rio/helpers/TripleTermUtil.java similarity index 70% rename from core/rio/api/src/main/java/org/eclipse/rdf4j/rio/helpers/RDFStarUtil.java rename to core/rio/api/src/main/java/org/eclipse/rdf4j/rio/helpers/TripleTermUtil.java index 283c88b7e7d..8922619bf87 100644 --- a/core/rio/api/src/main/java/org/eclipse/rdf4j/rio/helpers/RDFStarUtil.java +++ b/core/rio/api/src/main/java/org/eclipse/rdf4j/rio/helpers/TripleTermUtil.java @@ -20,27 +20,27 @@ import org.eclipse.rdf4j.model.impl.SimpleValueFactory; /** - * Utility methods for RDF-star triples. + * Utility methods for RDF 1.2 triples. * * @author Pavel Mihaylov */ -public class RDFStarUtil { +public class TripleTermUtil { /** - * IRI prefix for RDF-star triples encoded as IRIs. + * IRI prefix for RDF 1.2 triples encoded as IRIs. */ public static final String TRIPLE_PREFIX = "urn:rdf4j:triple:"; private static final ValueFactory VF = SimpleValueFactory.getInstance(); /** - * Converts the supplied value from RDF-star to an RDF-compatible representation. + * Converts the supplied value from RDF 1.2 to an RDF-compatible representation. *

- * RDF-star triples are encoded as IRIs that start with {@link #TRIPLE_PREFIX}, followed by the base64 encoding of + * RDF 1.2 triples are encoded as IRIs that start with {@link #TRIPLE_PREFIX}, followed by the base64 encoding of * the N-Triples serialization of the triple. *

- * All other RDF-star values are valid in RDF as well and remain unchanged. + * All other RDF 1.2 values are valid in RDF as well and remain unchanged. * - * @param value a RDF-star {@link Value} to encode. + * @param value a RDF 1.2 {@link Value} to encode. * @param * @return the RDF-compatible encoded value, if a {@link Triple} was supplied, or the supplied value otherwise. */ @@ -51,15 +51,15 @@ public static T toRDFEncodedValue(T value) { } /** - * Converts the supplied value from an RDF-compatible representation to an RDF-star value. + * Converts the supplied value from an RDF-compatible representation to an RDF 1.2 value. *

* See {@link #toRDFEncodedValue(Value)}. * - * @param encodedValue an RDF {@link Value} to convert to RDF-star. + * @param encodedValue an RDF {@link Value} to convert to RDF 1.2. * @param - * @return the decoded RDF-star triple, if a {@link Triple} encoded as {@link IRI} was supplied, or the supplied + * @return the decoded RDF 1.2 triple, if a {@link Triple} encoded as {@link IRI} was supplied, or the supplied * value otherwise. - * @throws IllegalArgumentException if the supplied value looked like an RDF-star triple encoded as an IRI but it + * @throws IllegalArgumentException if the supplied value looked like an RDF 1.2 triple encoded as an IRI but it * could not be decoded successfully. */ public static T fromRDFEncodedValue(T encodedValue) { @@ -69,21 +69,21 @@ public static T fromRDFEncodedValue(T encodedValue) { encodedValue.stringValue().substring(TRIPLE_PREFIX.length())), VF) : encodedValue; } catch (IllegalArgumentException e) { - throw new IllegalArgumentException("Invalid RDF-star encoded triple: " + encodedValue); + throw new IllegalArgumentException("Invalid RDF 1.2 encoded triple: " + encodedValue); } } /** - * Converts the supplied value from an RDF-compatible representation to an RDF-star value. + * Converts the supplied value from an RDF-compatible representation to an RDF 1.2 value. *

* See {@link #toRDFEncodedValue(Value)}. * - * @param encodedValue an RDF {@link Value} to convert to RDF-star. + * @param encodedValue an RDF {@link Value} to convert to RDF 1.2. * @param valueFactory the {@link ValueFactory} to use for parsing the triple. * @param - * @return the decoded RDF-star triple, if a {@link Triple} encoded as {@link IRI} was supplied, or the supplied + * @return the decoded RDF 1.2 triple, if a {@link Triple} encoded as {@link IRI} was supplied, or the supplied * value otherwise. - * @throws IllegalArgumentException if the supplied value looked like an RDF-star triple encoded as an IRI but it + * @throws IllegalArgumentException if the supplied value looked like an RDF 1.2 triple encoded as an IRI but it * could not be decoded successfully. */ public static T fromRDFEncodedValue(T encodedValue, ValueFactory valueFactory) { @@ -93,15 +93,15 @@ public static T fromRDFEncodedValue(T encodedValue, ValueFacto encodedValue.stringValue().substring(TRIPLE_PREFIX.length())), valueFactory) : encodedValue; } catch (IllegalArgumentException e) { - throw new IllegalArgumentException("Invalid RDF-star encoded triple: " + encodedValue); + throw new IllegalArgumentException("Invalid RDF 1.2 encoded triple: " + encodedValue); } } /** - * Checks if the supplied {@link Value} represents an RDF-star triple encoded as an IRI. + * Checks if the supplied {@link Value} represents an RDF 1.2 triple encoded as an IRI. * * @param value the value to check. - * @return True if the value is an RDF-star triple encoded as an IRI, false otherwise. + * @return True if the value is an RDF 1.2 triple encoded as an IRI, false otherwise. */ public static boolean isEncodedTriple(Value value) { return value instanceof IRI && value.stringValue().startsWith(TRIPLE_PREFIX); diff --git a/core/rio/api/src/test/java/org/eclipse/rdf4j/rio/AbstractParserHandlingTest.java b/core/rio/api/src/test/java/org/eclipse/rdf4j/rio/AbstractParserHandlingTest.java index 2623b94c14d..70d8cb9b424 100644 --- a/core/rio/api/src/test/java/org/eclipse/rdf4j/rio/AbstractParserHandlingTest.java +++ b/core/rio/api/src/test/java/org/eclipse/rdf4j/rio/AbstractParserHandlingTest.java @@ -22,7 +22,6 @@ import java.io.OutputStream; import java.util.Collection; import java.util.Collections; -import java.util.Date; import java.util.HashSet; import java.util.Locale; import java.util.Map; @@ -42,8 +41,8 @@ import org.eclipse.rdf4j.model.vocabulary.XSD; import org.eclipse.rdf4j.rio.helpers.BasicParserSettings; import org.eclipse.rdf4j.rio.helpers.ParseErrorCollector; -import org.eclipse.rdf4j.rio.helpers.RDFStarUtil; import org.eclipse.rdf4j.rio.helpers.StatementCollector; +import org.eclipse.rdf4j.rio.helpers.TripleTermUtil; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -1002,19 +1001,20 @@ public void testSkolemization() throws Exception { } @Test - public void testRDFStarCompatibility1() throws Exception { + public void testRDF12Compatibility1() throws Exception { Model expectedModel = new LinkedHashModel(); Triple t1 = vf.createTriple(vf.createIRI("http://example.com/1"), vf.createIRI("http://example.com/2"), vf.createLiteral("example", vf.createIRI("http://example.com/3"))); - expectedModel.add(vf.createStatement(t1, DC.SOURCE, vf.createIRI("http://example.com/4"))); - Triple t2 = vf.createTriple(t1, DC.DATE, vf.createLiteral(new Date())); + expectedModel.add(vf.createStatement(vf.createIRI("http://example.com/4"), DC.SOURCE, t1)); + Triple t2 = vf.createTriple(vf.createIRI("http://example.com/s"), DC.DATE, t1); expectedModel.add(vf.createStatement(vf.createIRI("http://example.com/5"), DC.RELATION, t2)); - Triple t3 = vf.createTriple(vf.createTriple(vf.createTriple(vf.createIRI("urn:a"), RDF.TYPE, - vf.createIRI("urn:b")), vf.createIRI("urn:c"), vf.createIRI("urn:d")), vf.createIRI("urn:e"), - vf.createIRI("urn:f")); - expectedModel.add(vf.createStatement(t3, vf.createIRI("urn:same"), t3)); + Triple t3 = vf.createTriple(vf.createIRI("urn:e"), + vf.createIRI("urn:f"), + vf.createTriple(vf.createIRI("urn:c"), vf.createIRI("urn:d"), + vf.createTriple(vf.createIRI("urn:a"), RDF.TYPE, + vf.createIRI("urn:b")))); + expectedModel.add(vf.createStatement(vf.createIRI("http://example.com/s2"), vf.createIRI("urn:same"), t3)); - // Default: formats with RDF-star support handle it natively and non-RDF-star use a compatibility encoding InputStream input1 = serialize(expectedModel); testParser.parse(input1, BASE_URI); assertErrorListener(0, 0, 0); @@ -1022,36 +1022,38 @@ public void testRDFStarCompatibility1() throws Exception { } @Test - public void testRDFStarCompatibility2() throws Exception { + public void testRDF12Compatibility2() throws Exception { Model expectedModel = new LinkedHashModel(); Triple t1 = vf.createTriple(vf.createIRI("http://example.com/1"), vf.createIRI("http://example.com/2"), vf.createLiteral("example", vf.createIRI("http://example.com/3"))); - expectedModel.add(vf.createStatement(t1, DC.SOURCE, vf.createIRI("http://example.com/4"))); - Triple t2 = vf.createTriple(t1, DC.DATE, vf.createLiteral(new Date())); + expectedModel.add(vf.createStatement(vf.createIRI("http://example.com/4"), DC.SOURCE, t1)); + Triple t2 = vf.createTriple(vf.createIRI("http://example.com/s"), DC.DATE, t1); expectedModel.add(vf.createStatement(vf.createIRI("http://example.com/5"), DC.RELATION, t2)); - Triple t3 = vf.createTriple(vf.createTriple(vf.createTriple(vf.createIRI("urn:a"), RDF.TYPE, - vf.createIRI("urn:b")), vf.createIRI("urn:c"), vf.createIRI("urn:d")), vf.createIRI("urn:e"), - vf.createIRI("urn:f")); - expectedModel.add(vf.createStatement(t3, vf.createIRI("urn:same"), t3)); - - // Turn off compatibility on parsing: formats with RDF-star support will produce RDF-star triples, - // non-RDF-star formats will produce IRIs of the kind urn:rdf4j:triple:xxx + Triple t3 = vf.createTriple(vf.createIRI("urn:e"), + vf.createIRI("urn:f"), + vf.createTriple(vf.createIRI("urn:c"), vf.createIRI("urn:d"), + vf.createTriple(vf.createIRI("urn:a"), RDF.TYPE, + vf.createIRI("urn:b")))); + expectedModel.add(vf.createStatement(vf.createIRI("http://example.com/s2"), vf.createIRI("urn:same"), t3)); + + // Turn off compatibility on parsing: formats with triple term support will produce triple term triples, + // non-triple term formats will produce IRIs of the kind urn:rdf4j:triple:xxx InputStream input2 = serialize(expectedModel); - testParser.getParserConfig().set(BasicParserSettings.PROCESS_ENCODED_RDF_STAR, false); + testParser.getParserConfig().set(BasicParserSettings.PROCESS_ENCODED_TRIPLE_TERMS, false); testParser.parse(input2, BASE_URI); assertErrorListener(0, 0, 0); - if (testParser.getRDFFormat().supportsRDFStar()) { + if (testParser.getRDFFormat().supportsTripleTerms()) { assertModel(expectedModel); } else { assertTrue(testStatements.getStatements() - .contains(vf.createStatement(RDFStarUtil.toRDFEncodedValue(t1), DC.SOURCE, - vf.createIRI("http://example.com/4")))); + .contains(vf.createStatement(vf.createIRI("http://example.com/4"), DC.SOURCE, + TripleTermUtil.toRDFEncodedValue(t1)))); assertTrue(testStatements.getStatements() .contains(vf.createStatement(vf.createIRI("http://example.com/5"), DC.RELATION, - RDFStarUtil.toRDFEncodedValue(t2)))); + TripleTermUtil.toRDFEncodedValue(t2)))); assertTrue(testStatements.getStatements() - .contains(vf.createStatement(RDFStarUtil.toRDFEncodedValue(t3), vf.createIRI("urn:same"), - RDFStarUtil.toRDFEncodedValue(t3)))); + .contains(vf.createStatement(vf.createIRI("http://example.com/s2"), vf.createIRI("urn:same"), + TripleTermUtil.toRDFEncodedValue(t3)))); assertEquals(3, testStatements.getStatements().size()); } } diff --git a/core/rio/api/src/test/java/org/eclipse/rdf4j/rio/AbstractParserTest.java b/core/rio/api/src/test/java/org/eclipse/rdf4j/rio/AbstractParserTest.java new file mode 100644 index 00000000000..ec21623b260 --- /dev/null +++ b/core/rio/api/src/test/java/org/eclipse/rdf4j/rio/AbstractParserTest.java @@ -0,0 +1,113 @@ +/******************************************************************************* + * Copyright (c) 2025 Eclipse RDF4J contributors, Aduna, and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Distribution License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + *******************************************************************************/ +package org.eclipse.rdf4j.rio; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; + +import java.io.StringReader; +import java.util.Collection; + +import org.eclipse.rdf4j.model.Literal; +import org.eclipse.rdf4j.model.Statement; +import org.eclipse.rdf4j.model.base.CoreDatatype; +import org.eclipse.rdf4j.rio.helpers.BasicParserSettings; +import org.eclipse.rdf4j.rio.helpers.ParseErrorCollector; +import org.eclipse.rdf4j.rio.helpers.SimpleParseLocationListener; +import org.eclipse.rdf4j.rio.helpers.StatementCollector; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +/* +* Testing base class for Turtle, TriG, NTriples, and NQuads parsers + */ +public abstract class AbstractParserTest { + protected RDFParser parser; + protected ParseErrorCollector errorCollector = new ParseErrorCollector(); + protected StatementCollector statementCollector = new StatementCollector(); + protected TestParseLocationListener locationListener = new TestParseLocationListener(); + + @BeforeEach + public void setUp() { + parser = createRDFParser(); + parser.setParseErrorListener(errorCollector); + parser.setRDFHandler(statementCollector); + parser.setParseLocationListener(locationListener); + } + + protected void dirLangStringTestHelper( + final String data, final String expectedLang, final String expectedBaseDir, final boolean normalize, + final boolean shouldFail) { + parser.getParserConfig().set(BasicParserSettings.FAIL_ON_UNKNOWN_LANGUAGES, true); + parser.getParserConfig().set(BasicParserSettings.NORMALIZE_LANGUAGE_TAGS, normalize); + + try { + parser.parse(new StringReader(data)); + + if (shouldFail) { + fail("default config should result in fatal error / parse exception"); + } + + assertThat(errorCollector.getErrors()).isEmpty(); + + final Collection stmts = statementCollector.getStatements(); + + assertThat(stmts).hasSize(1); + + final Statement stmt = stmts.iterator().next(); + + assertEquals(CoreDatatype.RDF.DIRLANGSTRING.getIri(), ((Literal) stmt.getObject()).getDatatype()); + assertTrue(((Literal) stmt.getObject()).getLanguage().isPresent()); + assertEquals(expectedLang, ((Literal) stmt.getObject()).getLanguage().get()); + assertEquals(expectedBaseDir, ((Literal) stmt.getObject()).getBaseDirection().toString()); + } catch (final Exception e) { + if (!shouldFail) { + fail("parse error on correct data: " + e.getMessage()); + } + } + } + + protected void dirLangStringNoLanguageTestHelper(String data) { + try { + parser.parse(new StringReader(data)); + + assertThat(errorCollector.getErrors()).isEmpty(); + + Collection stmts = statementCollector.getStatements(); + + assertThat(stmts).hasSize(1); + + Statement stmt = stmts.iterator().next(); + + assertEquals(CoreDatatype.XSD.STRING.getIri(), ((Literal) stmt.getObject()).getDatatype()); + } catch (Exception e) { + fail("parse error on correct data: " + e.getMessage()); + } + } + + protected abstract RDFParser createRDFParser(); + + protected static class TestParseLocationListener extends SimpleParseLocationListener { + + public void assertListener(int row, int col) { + assertEquals(row, this.getLineNo(), "Unexpected last row"); + assertEquals(col, this.getColumnNo(), "Unexpected last col"); + } + + } + + @Test + public void dummy() { + } + +} diff --git a/core/rio/api/src/test/java/org/eclipse/rdf4j/rio/RDFWriterTest.java b/core/rio/api/src/test/java/org/eclipse/rdf4j/rio/RDFWriterTest.java index 3a4125c54ac..115bf5dc0ff 100644 --- a/core/rio/api/src/test/java/org/eclipse/rdf4j/rio/RDFWriterTest.java +++ b/core/rio/api/src/test/java/org/eclipse/rdf4j/rio/RDFWriterTest.java @@ -31,6 +31,7 @@ import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.Reader; +import java.io.StringWriter; import java.io.Writer; import java.util.ArrayList; import java.util.Arrays; @@ -50,6 +51,7 @@ import org.eclipse.rdf4j.model.Triple; import org.eclipse.rdf4j.model.Value; import org.eclipse.rdf4j.model.ValueFactory; +import org.eclipse.rdf4j.model.impl.DynamicModelFactory; import org.eclipse.rdf4j.model.impl.LinkedHashModel; import org.eclipse.rdf4j.model.impl.SimpleValueFactory; import org.eclipse.rdf4j.model.util.Models; @@ -131,10 +133,6 @@ public abstract class RDFWriterTest { private final Triple triple4; - private final Triple triple5; - - private final Triple triple6; - private final Literal plainLit; private final Literal dtLit; @@ -203,8 +201,6 @@ protected RDFWriterTest(RDFWriterFactory writerF, RDFParserFactory parserF) { triple2 = vf.createTriple(bnode, uri3, litWithMultipleNewlines); triple3 = vf.createTriple(uri3, uri4, bnodeSingleLetter); triple4 = vf.createTriple(uri5, uri1, uri3); - triple5 = vf.createTriple(triple1, uri3, litBigPlaceholder); - triple6 = vf.createTriple(triple2, uri4, triple5); potentialSubjects = new ArrayList<>(); potentialSubjects.add(bnode); @@ -219,7 +215,6 @@ protected RDFWriterTest(RDFWriterFactory writerF, RDFParserFactory parserF) { potentialSubjects.add(uri3); potentialSubjects.add(uri4); potentialSubjects.add(uri5); - potentialSubjects.addAll(Arrays.asList(triple1, triple2, triple2, triple3, triple4, triple5, triple6)); for (int i = 0; i < 50; i++) { potentialSubjects.add(vf.createBNode()); } @@ -242,7 +237,7 @@ protected RDFWriterTest(RDFWriterFactory writerF, RDFParserFactory parserF) { potentialObjects.add(plainLit); potentialObjects.add(dtLit); potentialObjects.add(langLit); - potentialObjects.addAll(Arrays.asList(triple1, triple2, triple2, triple3, triple4, triple5, triple6)); + potentialObjects.addAll(Arrays.asList(triple1, triple2, triple2, triple3, triple4)); // FIXME: SES-879: The following break the RDF/XML parser/writer // combination in terms of getting the same number of triples back as we // start with @@ -756,7 +751,7 @@ private void testPerformanceInternal(boolean storeParsedStatements) throws Excep IRI pred = potentialPredicates.get(prng.nextInt(potentialPredicates.size())); while (obj instanceof Triple && pred.equals(RDF.TYPE)) { // Avoid statements "x rdf:type <>" as those use the shorter syntax in RDFXMLPrettyWriter - // and the writer produces invalid XML in that case. Even though the RDF-star triples are encoded as + // and the writer produces invalid XML in that case. Even though the triples are encoded as // valid IRIs, XML has limitations on what characters may form an XML tag name and thus a limitation // on what IRIs may be used in predicates (predicates are XML tags) or the short form of rdf:type // (where the type is also an XML tag). @@ -1828,15 +1823,31 @@ public void testBogusIRICharacters() throws Exception { } @Test - public void testRDFStarConversion() throws IOException { + public void testReificationConversion() throws IOException { Model model = new LinkedHashModel(); - model.add(vf.createStatement(triple3, uri1, triple6, uri4)); + + BNode triple1Reifier = vf.createBNode(); + BNode triple2Reifier = vf.createBNode(); + BNode triple3Reifier = vf.createBNode(); + BNode triple5Reifier = vf.createBNode(); + BNode triple6Reifier = vf.createBNode(); + + Triple triple5 = vf.createTriple(triple1Reifier, uri3, litBigPlaceholder); + Triple triple6 = vf.createTriple(triple2Reifier, uri4, triple5Reifier); + + model.add(vf.createStatement(triple1Reifier, RDF.REIFIES, triple1, uri4)); + model.add(vf.createStatement(triple2Reifier, RDF.REIFIES, triple2, uri4)); + model.add(vf.createStatement(triple3Reifier, RDF.REIFIES, triple3, uri4)); + model.add(vf.createStatement(triple5Reifier, RDF.REIFIES, triple5, uri4)); + model.add(vf.createStatement(triple6Reifier, RDF.REIFIES, triple6, uri4)); + + model.add(vf.createStatement(triple3Reifier, uri1, triple6Reifier, uri4)); model.add(vf.createStatement(uri1, uri2, uri3, uri5)); ByteArrayOutputStream outputWriter = new ByteArrayOutputStream(); RDFWriter rdfWriter = rdfWriterFactory.getWriter(outputWriter); setupWriterConfig(rdfWriter.getWriterConfig()); - rdfWriter.getWriterConfig().set(BasicWriterSettings.CONVERT_RDF_STAR_TO_REIFICATION, true); + rdfWriter.getWriterConfig().set(BasicWriterSettings.CONVERT_RDF_12_REIFICATION, true); rdfWriter.startRDF(); model.forEach(rdfWriter::handleStatement); rdfWriter.endRDF(); @@ -1848,13 +1859,8 @@ public void testRDFStarConversion() throws IOException { rdfParser.setRDFHandler(new StatementCollector(parsedOutput)); rdfParser.parse(inputReader, ""); - // 1 non-RDF-star statement - // 1 RDF-star statement whose conversion yields 20 additional statements: - // 4 for triple3 - // 4 for triple6 - // 4 for triple2 (contained in triple6) - // 4 for triple5 (contained in triple6) - // 4 for triple1 (contained in triple5) + // 2 statements without triple terms + // 5 reification statements using RDF 1.2, each translates to 4 RDF 1.1 statements assertEquals(22, parsedOutput.size()); } @@ -1938,4 +1944,21 @@ private void assertSameModel(Model expected, Model actual) { assertEquals(actual.filter(subj, pred, obj).size(), actual.filter(subj, pred, obj).size()); } } + + // Helper method for testing dirLangString literals in supported formats (Turtle, NTriples, TriG, NQuads) + public void dirLangStringTest(RDFFormat format) throws Exception { + Model model = new DynamicModelFactory().createEmptyModel(); + String ns = "http://example.org/"; + IRI uri1 = vf.createIRI(ns, "uri1"); + IRI uri2 = vf.createIRI(ns, "uri2"); + model.add(vf.createStatement(uri1, uri2, vf.createLiteral("hello", "en", Literal.BaseDirection.LTR))); + model.add(vf.createStatement(uri1, uri2, vf.createLiteral("שלום", "he", Literal.BaseDirection.RTL))); + + StringWriter stringWriter = new StringWriter(); + Rio.write(model, stringWriter, format); + String output = stringWriter.toString(); + + assertThat(output).contains("\"hello\"@en--ltr"); + assertThat(output).contains("\"שלום\"@he--rtl"); + } } diff --git a/core/rio/api/src/test/java/org/eclipse/rdf4j/rio/helpers/NTriplesUtilTest.java b/core/rio/api/src/test/java/org/eclipse/rdf4j/rio/helpers/NTriplesUtilTest.java index ea59547447e..dded09b9a1f 100644 --- a/core/rio/api/src/test/java/org/eclipse/rdf4j/rio/helpers/NTriplesUtilTest.java +++ b/core/rio/api/src/test/java/org/eclipse/rdf4j/rio/helpers/NTriplesUtilTest.java @@ -52,37 +52,36 @@ public void testAppendWithoutEncoding() throws Exception { @Test public void testAppendWithEncoding() throws Exception { - Literal l = f.createLiteral("Äbc"); + Literal l = f.createLiteral("\bbc"); NTriplesUtil.append(l, appendable, true, true); - assertThat(appendable.toString()).isEqualTo("\"\\u00C4bc\""); + assertThat(appendable.toString()).isEqualTo("\"\\bbc\""); } @Test public void testSerializeTriple() throws IOException { Object[] triples = new Object[] { f.createTriple(f.createIRI("urn:a"), f.createIRI("urn:b"), f.createIRI("urn:c")), - "<< >>", - // - f.createTriple(f.createTriple(f.createIRI("urn:a"), f.createIRI("urn:b"), f.createIRI("urn:c")), - DC.SOURCE, f.createLiteral("news")), - "<<<< >> \"news\">>", - // + "<<( )>>", + + f.createTriple(f.createIRI("urn:subject"), + DC.SOURCE, f.createTriple(f.createIRI("urn:a"), f.createIRI("urn:b"), f.createIRI("urn:c"))), + "<<( <<( )>> )>>", + f.createTriple(f.createBNode("bnode1"), f.createIRI("urn:x"), f.createTriple(f.createIRI("urn:a"), f.createIRI("urn:b"), f.createIRI("urn:c"))), - "<<_:bnode1 << >>>>" + "<<( _:bnode1 <<( )>> )>>" }; for (int i = 0; i < triples.length; i += 2) { assertEquals(triples[i + 1], NTriplesUtil.toNTriplesString((Triple) triples[i])); - assertEquals(triples[i + 1], NTriplesUtil.toNTriplesString((Resource) triples[i])); assertEquals(triples[i + 1], NTriplesUtil.toNTriplesString((Value) triples[i])); NTriplesUtil.append((Triple) triples[i], appendable); assertEquals(triples[i + 1], appendable.toString()); appendable = new StringBuilder(); - NTriplesUtil.append((Resource) triples[i], appendable); + NTriplesUtil.append((Triple) triples[i], appendable); assertEquals(triples[i + 1], appendable.toString()); appendable = new StringBuilder(); - NTriplesUtil.append((Value) triples[i], appendable); + NTriplesUtil.append((Triple) triples[i], appendable); assertEquals(triples[i + 1], appendable.toString()); appendable = new StringBuilder(); } @@ -91,48 +90,41 @@ public void testSerializeTriple() throws IOException { @Test public void testParseTriple() { String[] triples = new String[] { - "<<<<\"täst\"@de-DE>>>>", - "<>>>", - // - "<< << \"täst\"@de-DE >> >>", - "<>>>", - // - "<<<<_:bnode1foobar\"literál за проба\"^^>>\"test\\\\\\\"lit\">>", - "<<<<_:bnode1foobar urn:täst \"literál за проба\"^^>> http://test/baz \"test\\\"lit\">>", + "<<(<<(\"täst\"@de-DE)>>)>>", + "<<( http://foo.com/bar#baz%20 http://example.com/test <<( urn:foo urn:р \"täst\"@de-DE )>> )>>", // - "<< <<_:bnode1foobar \"literál за проба\"^^ >> \"test\\\\\\\"lit\" >>", - "<<<<_:bnode1foobar urn:täst \"literál за проба\"^^>> http://test/baz \"test\\\"lit\">>", + "<<( <<( \"täst\"@de-DE )>> )>>", + "<<( http://foo.com/bar#baz%20 http://example.com/test <<( urn:foo urn:р \"täst\"@de-DE )>> )>>", // test surrogate pair range in bnode - "<<_:test_\uD800\uDC00_\uD840\uDC00_bnode >>", - "<<_:test_\uD800\uDC00_\uD840\uDC00_bnode urn:x urn:y>>", + "<<( _:test_\uD800\uDC00_\uD840\uDC00_bnode )>>", + "<<( _:test_\uD800\uDC00_\uD840\uDC00_bnode urn:x urn:y )>>", // invalid: missing closing >> for inner triple - "<<<<_:bnode1foobar\"literál за проба\"^^\"test\\\\\\\"lit\">>", + "<<(<<(_:bnode1foobar\"literál за проба\"^^\"test\\\\\\\"lit\">>", null, // invalid: missing closing >> for outer triple - "<<<<_:bnode1foobar\"literál за проба\"^^>>\"test\\\\\\\"lit\"", + "<<(<<(_:bnode1foobar\"literál за проба\"^^)>>\"test\\\\\\\"lit\"", null, // invalid: literal subject - "<<\"test\" \"test\">>", + "<<(\"test\" \"test\")>>", null, // invalid: bnode predicate - "<< _:test \"test\">>", + "<<( _:test \"test\")>>", null, // invalid: triple predicate - "<< << >> >>", + "<<( <<( )>> )>>", null, // tests with empty literal, - "<< \"\">>", - "<>", - "<< \"\"@bg>>", - "<>", - "<< \"\"^^>>", - "<>>" + "<<( \"\")>>", + "<<( urn:1 urn:2 \"\" )>>", + "<<( \"\"@bg)>>", + "<<( urn:1 urn:2 \"\"@bg )>>", + "<<( \"\"^^)>>", + "<<( urn:1 urn:2 \"\"^^ )>>" }; for (int i = 0; i < triples.length; i += 2) { parseTriple(triples[i], triples[i + 1], (t) -> NTriplesUtil.parseTriple(t, f)); parseTriple(triples[i], triples[i + 1], (t) -> (Triple) NTriplesUtil.parseValue(t, f)); - parseTriple(triples[i], triples[i + 1], (t) -> (Triple) NTriplesUtil.parseResource(t, f)); } } @@ -154,7 +146,7 @@ public void testParseIRIvsTriple() { @Test public void testGH3323Stackoverflow() { - String badLiteral = "<< \"Ko te kamupene S.L., he kamupene i whakapumautia i te tau 2009 a i whakatapua ki nga kaupapa korero mo etahi atu kamupene, mai i te 2012 i tiimata te hanga i ona ake hangarau a kua poipoihia e te mahi tahi me nga hinonga a iwi. Ina koa, ko te mahi tahi me te Manatū o te Roto o Spain te mea nui, i runga i te ngana ki te whakawhanake i nga otinga hangarau motuhake e haangai ana ki nga hiahia o nga Hoia Haumaru o te Kawanatanga o Paniora i nga waahi o nga drones me nga anti-drones. te hononga i waenga i te trga me te Manatu o roto i te mana i roto i nga tau e 8 kua hipa kua kitea i roto i nga waahanga nui e rua: i tetahi taha, ko te tautoko a te Minita ki te maha o nga kaupapa R&D i hangaia e AEORUM me te tahua tahua me te iwi whanui. moni; a, i tetahi atu, ko te mahi tahi nui a te Hekeretari o te Whenua mo te Haumarutanga i te wa e whanakehia ana te punaha me . He kamupene hangarau-hangarau e whakarato ana i nga otinga aunoa mo nga pokapu whakahaere me nga waka kaore he tangata, he nui te utu ki nga waahi e hiahia ana kia mamao te whakahaere me te mohio. Mo tenei, ka whakamahia e ia tana ake R&D i roto i nga waahanga o te tirohanga matakite (kitenga / mohio / taatari i nga taiao me nga tauira), te whakahaere waka (whakahaere aunoa me te mohio o nga waka rererangi robotic me nga tauira) me te mohio mohio. Ko te kaupapa uara o te , SL, e whaaia ana mo te hunga e ahuru ana i te ahuru, ko te whakarato i nga taputapu tirotiro hou kia aukati, kia tere, kia tika hoki te whakatau i nga ahuatanga uaua, kia pai ake ai te whakahaere i te ahuru me te karo i nga ahuatanga ohorere. Ko nga punaha i whakawhanakehia i roto i nga whare taiwhanga o , S.L., ka taea te whakamahi i enei waahanga e whai ake nei: · Te Tiakitanga me te Whakahaumaru i nga Hanganga Hanga. · Haumarutanga: he rongoa mo te whakahaere, tirotiro me te tirotiro aunoa i nga whakahaerenga ture, hei awhina i te whanuitanga o nga ahuatanga. · Whakahaerenga ohorere, mo nga rongoa taangata me nga hoia: nga taputapu hei tirotiro mo te waa-tuuturu o nga rohe e pa ana me nga punaha mohio hei awhina i nga mahi whakatau. · Nga Taone Tino me etahi atu whakauru: otinga aunoa hei whakapai ake i te whakahaerenga o te taiao i nga taone, nga tuawhenua me nga rohe takutai (te whakahaere waka, te taiao, nga whare, te whakahaere ururua, te tiaki ...) SL, he ake hangarau hei whirihora i te maha o nga rongoa, ka taea te urutau ki nga hiahia motuhake o ona kaihoko: te rapu me te waahi o nga taangata, te tiaki me nga hanganga whakahirahira, te aukati ahi, te tirotiro i nga taiao taone, te waahi o nga mahi koretake i nga whare / umanga, me era atu. Ko nga hangarau e whai ake nei me whakanui: · : Te Whakawhanake i tetahi Punaha Korero Maatauranga mo te Whakahaere me te Whakahaumaru i nga Hanganga Critical. · : Te Whakawhanake i te punaha Paanui mo te Kimi me te Whakakore i nga tuma me nga . · : , me te mahi tahi me te tari Irirangi o te Awhina. · : Te Whakawhanake i te Punaha Whakatutukitanga Arā Atu Anō mo te Whakaaetanga i nga Whakanui Taone me nga Hanga Tino, me te mahi tahi me nga pirihimana pirihimana e ono. I te taumata o te ao (kei waho o te fg), kei te tuu a S.L. ki etahi kaupapa rereke me nga hoa hangarau, whakaaweawe i nga roopu me nga roopu whanui i nga whenua penei i te , ko nga \">>"; + String badLiteral = "<<( \"Ko te kamupene S.L., he kamupene i whakapumautia i te tau 2009 a i whakatapua ki nga kaupapa korero mo etahi atu kamupene, mai i te 2012 i tiimata te hanga i ona ake hangarau a kua poipoihia e te mahi tahi me nga hinonga a iwi. Ina koa, ko te mahi tahi me te Manatū o te Roto o Spain te mea nui, i runga i te ngana ki te whakawhanake i nga otinga hangarau motuhake e haangai ana ki nga hiahia o nga Hoia Haumaru o te Kawanatanga o Paniora i nga waahi o nga drones me nga anti-drones. te hononga i waenga i te trga me te Manatu o roto i te mana i roto i nga tau e 8 kua hipa kua kitea i roto i nga waahanga nui e rua: i tetahi taha, ko te tautoko a te Minita ki te maha o nga kaupapa R&D i hangaia e AEORUM me te tahua tahua me te iwi whanui. moni; a, i tetahi atu, ko te mahi tahi nui a te Hekeretari o te Whenua mo te Haumarutanga i te wa e whanakehia ana te punaha me . He kamupene hangarau-hangarau e whakarato ana i nga otinga aunoa mo nga pokapu whakahaere me nga waka kaore he tangata, he nui te utu ki nga waahi e hiahia ana kia mamao te whakahaere me te mohio. Mo tenei, ka whakamahia e ia tana ake R&D i roto i nga waahanga o te tirohanga matakite (kitenga / mohio / taatari i nga taiao me nga tauira), te whakahaere waka (whakahaere aunoa me te mohio o nga waka rererangi robotic me nga tauira) me te mohio mohio. Ko te kaupapa uara o te , SL, e whaaia ana mo te hunga e ahuru ana i te ahuru, ko te whakarato i nga taputapu tirotiro hou kia aukati, kia tere, kia tika hoki te whakatau i nga ahuatanga uaua, kia pai ake ai te whakahaere i te ahuru me te karo i nga ahuatanga ohorere. Ko nga punaha i whakawhanakehia i roto i nga whare taiwhanga o , S.L., ka taea te whakamahi i enei waahanga e whai ake nei: · Te Tiakitanga me te Whakahaumaru i nga Hanganga Hanga. · Haumarutanga: he rongoa mo te whakahaere, tirotiro me te tirotiro aunoa i nga whakahaerenga ture, hei awhina i te whanuitanga o nga ahuatanga. · Whakahaerenga ohorere, mo nga rongoa taangata me nga hoia: nga taputapu hei tirotiro mo te waa-tuuturu o nga rohe e pa ana me nga punaha mohio hei awhina i nga mahi whakatau. · Nga Taone Tino me etahi atu whakauru: otinga aunoa hei whakapai ake i te whakahaerenga o te taiao i nga taone, nga tuawhenua me nga rohe takutai (te whakahaere waka, te taiao, nga whare, te whakahaere ururua, te tiaki ...) SL, he ake hangarau hei whirihora i te maha o nga rongoa, ka taea te urutau ki nga hiahia motuhake o ona kaihoko: te rapu me te waahi o nga taangata, te tiaki me nga hanganga whakahirahira, te aukati ahi, te tirotiro i nga taiao taone, te waahi o nga mahi koretake i nga whare / umanga, me era atu. Ko nga hangarau e whai ake nei me whakanui: · : Te Whakawhanake i tetahi Punaha Korero Maatauranga mo te Whakahaere me te Whakahaumaru i nga Hanganga Critical. · : Te Whakawhanake i te punaha Paanui mo te Kimi me te Whakakore i nga tuma me nga . · : , me te mahi tahi me te tari Irirangi o te Awhina. · : Te Whakawhanake i te Punaha Whakatutukitanga Arā Atu Anō mo te Whakaaetanga i nga Whakanui Taone me nga Hanga Tino, me te mahi tahi me nga pirihimana pirihimana e ono. I te taumata o te ao (kei waho o te fg), kei te tuu a S.L. ki etahi kaupapa rereke me nga hoa hangarau, whakaaweawe i nga roopu me nga roopu whanui i nga whenua penei i te , ko nga \")>>"; NTriplesUtil.parseTriple(badLiteral, SimpleValueFactory.getInstance()); } } diff --git a/core/rio/api/src/test/java/org/eclipse/rdf4j/rio/helpers/RDFParserHelperTest.java b/core/rio/api/src/test/java/org/eclipse/rdf4j/rio/helpers/RDFParserHelperTest.java index 2213d046d69..83e7868be60 100644 --- a/core/rio/api/src/test/java/org/eclipse/rdf4j/rio/helpers/RDFParserHelperTest.java +++ b/core/rio/api/src/test/java/org/eclipse/rdf4j/rio/helpers/RDFParserHelperTest.java @@ -13,6 +13,7 @@ import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; @@ -116,6 +117,33 @@ public final void testCreateLiteralLabelAndLanguage() { assertEquals(RDF.LANGSTRING, literal.getDatatype()); } + /** + * Test method for + * {@link org.eclipse.rdf4j.rio.helpers.RDFParserHelper#createLiteral(java.lang.String, java.lang.String, org.eclipse.rdf4j.model.URI, org.eclipse.rdf4j.rio.ParserConfig, org.eclipse.rdf4j.rio.ParseErrorListener, org.eclipse.rdf4j.model.ValueFactory)} + * . + */ + @Test + public final void testCreateLiteralLabelAndLanguageAndDirection() { + Literal literalLTR = RDFParserHelper.createLiteral(LABEL_TESTA, LANG_EN + "--ltr", null, parserConfig, + errListener, + valueFactory); + Literal literalRTL = RDFParserHelper.createLiteral(LABEL_TESTA, "ar--rtl", null, parserConfig, errListener, + valueFactory); + + assertEquals(LABEL_TESTA, literalLTR.getLabel()); + assertEquals(LANG_EN, literalLTR.getLanguage().orElse(null)); + assertEquals(Literal.BaseDirection.LTR, literalLTR.getBaseDirection()); + assertEquals(RDF.DIRLANGSTRING, literalLTR.getDatatype()); + + assertEquals(LABEL_TESTA, literalRTL.getLabel()); + assertEquals("ar", literalRTL.getLanguage().orElse(null)); + assertEquals(Literal.BaseDirection.RTL, literalRTL.getBaseDirection()); + assertEquals(RDF.DIRLANGSTRING, literalRTL.getDatatype()); + + assertThrows(RDFParseException.class, () -> RDFParserHelper.createLiteral(LABEL_TESTA, "he--jsldkfjds", null, + parserConfig, errListener, valueFactory)); + } + /** * Test method for * {@link org.eclipse.rdf4j.rio.helpers.RDFParserHelper#createLiteral(java.lang.String, java.lang.String, org.eclipse.rdf4j.model.URI, org.eclipse.rdf4j.rio.ParserConfig, org.eclipse.rdf4j.rio.ParseErrorListener, org.eclipse.rdf4j.model.ValueFactory)} @@ -171,6 +199,15 @@ public final void testCreateLiteralLabelNoLanguageWithRDFLangStringWithVerify() .isInstanceOf(RDFParseException.class); } + @Test + public final void testCreateLiteralLabelNoLanguageWithRDFDirLangStringWithVerify() { + parserConfig.set(BasicParserSettings.VERIFY_DATATYPE_VALUES, true); + assertTrue(parserConfig.get(BasicParserSettings.VERIFY_DATATYPE_VALUES)); + assertThatThrownBy(() -> RDFParserHelper.createLiteral(LABEL_TESTA, null, RDF.DIRLANGSTRING, parserConfig, + errListener, valueFactory)) + .isInstanceOf(RDFParseException.class); + } + @Test public final void testCreateLiteralLabelNoLanguageWithRDFLangStringWithNoVerify() { parserConfig.set(BasicParserSettings.VERIFY_DATATYPE_VALUES, false); @@ -180,6 +217,15 @@ public final void testCreateLiteralLabelNoLanguageWithRDFLangStringWithNoVerify( assertEquals(XSD.STRING, literal.getDatatype()); } + @Test + public final void testCreateLiteralLabelNoLanguageWithRDFDirLangStringWithNoVerify() { + parserConfig.set(BasicParserSettings.VERIFY_DATATYPE_VALUES, false); + Literal literal = RDFParserHelper.createLiteral(LABEL_TESTA, null, RDF.DIRLANGSTRING, parserConfig, errListener, + valueFactory); + assertFalse(literal.getLanguage().isPresent()); + assertEquals(XSD.STRING, literal.getDatatype()); + } + @Test public final void testReportErrorStringFatalActive() { parserConfig.set(BasicParserSettings.VERIFY_DATATYPE_VALUES, true); diff --git a/core/rio/api/src/test/java/org/eclipse/rdf4j/rio/helpers/RDFStarUtilTest.java b/core/rio/api/src/test/java/org/eclipse/rdf4j/rio/helpers/TripleTermUtilTest.java similarity index 62% rename from core/rio/api/src/test/java/org/eclipse/rdf4j/rio/helpers/RDFStarUtilTest.java rename to core/rio/api/src/test/java/org/eclipse/rdf4j/rio/helpers/TripleTermUtilTest.java index 3497d0cc6e5..295021f1624 100644 --- a/core/rio/api/src/test/java/org/eclipse/rdf4j/rio/helpers/RDFStarUtilTest.java +++ b/core/rio/api/src/test/java/org/eclipse/rdf4j/rio/helpers/TripleTermUtilTest.java @@ -29,61 +29,60 @@ /** * @author Pavel Mihaylov */ -public class RDFStarUtilTest { +public class TripleTermUtilTest { private final ValueFactory vf = SimpleValueFactory.getInstance(); @Test public void testEncoding() { IRI iri = vf.createIRI("urn:a"); - assertSame(iri, RDFStarUtil.toRDFEncodedValue(iri)); - assertFalse(RDFStarUtil.isEncodedTriple(iri)); + assertSame(iri, TripleTermUtil.toRDFEncodedValue(iri)); + assertFalse(TripleTermUtil.isEncodedTriple(iri)); Literal literal1 = vf.createLiteral("plain"); - assertSame(literal1, RDFStarUtil.toRDFEncodedValue(literal1)); - assertFalse(RDFStarUtil.isEncodedTriple(literal1)); + assertSame(literal1, TripleTermUtil.toRDFEncodedValue(literal1)); + assertFalse(TripleTermUtil.isEncodedTriple(literal1)); Literal literal2 = vf.createLiteral(1984L); - assertSame(literal2, RDFStarUtil.toRDFEncodedValue(literal2)); - assertFalse(RDFStarUtil.isEncodedTriple(literal2)); + assertSame(literal2, TripleTermUtil.toRDFEncodedValue(literal2)); + assertFalse(TripleTermUtil.isEncodedTriple(literal2)); Literal literal3 = vf.createLiteral("einfach aber auf deutsch", "de"); - assertSame(literal3, RDFStarUtil.toRDFEncodedValue(literal3)); - assertFalse(RDFStarUtil.isEncodedTriple(literal3)); + assertSame(literal3, TripleTermUtil.toRDFEncodedValue(literal3)); + assertFalse(TripleTermUtil.isEncodedTriple(literal3)); BNode bNode = vf.createBNode("bnode1"); - assertSame(bNode, RDFStarUtil.toRDFEncodedValue(bNode)); - assertFalse(RDFStarUtil.isEncodedTriple(bNode)); + assertSame(bNode, TripleTermUtil.toRDFEncodedValue(bNode)); + assertFalse(TripleTermUtil.isEncodedTriple(bNode)); Triple triple = vf.createTriple(iri, RDF.TYPE, literal1); - assertEquals(vf.createIRI("urn:rdf4j:triple:PDw8dXJuOmE-IDxodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1ze" - + "W50YXgtbnMjdHlwZT4gInBsYWluIj4-"), - RDFStarUtil.toRDFEncodedValue(triple)); - assertFalse(RDFStarUtil.isEncodedTriple(triple)); - assertTrue(RDFStarUtil.isEncodedTriple(RDFStarUtil.toRDFEncodedValue(triple))); + assertEquals(vf.createIRI( + "urn:rdf4j:triple:PDwoIDx1cm46YT4gPGh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyN0eXBlPiAicGxhaW4iICk-Pg=="), + TripleTermUtil.toRDFEncodedValue(triple)); + assertFalse(TripleTermUtil.isEncodedTriple(triple)); + assertTrue(TripleTermUtil.isEncodedTriple(TripleTermUtil.toRDFEncodedValue(triple))); } @Test public void testDecoding() { IRI iri = vf.createIRI("urn:a"); - assertSame(iri, RDFStarUtil.fromRDFEncodedValue(iri)); + assertSame(iri, TripleTermUtil.fromRDFEncodedValue(iri)); Literal literal1 = vf.createLiteral("plain"); - assertSame(literal1, RDFStarUtil.fromRDFEncodedValue(literal1)); - assertFalse(RDFStarUtil.isEncodedTriple(literal1)); + assertSame(literal1, TripleTermUtil.fromRDFEncodedValue(literal1)); + assertFalse(TripleTermUtil.isEncodedTriple(literal1)); Literal literal2 = vf.createLiteral(1984L); - assertSame(literal2, RDFStarUtil.fromRDFEncodedValue(literal2)); + assertSame(literal2, TripleTermUtil.fromRDFEncodedValue(literal2)); Literal literal3 = vf.createLiteral("einfach aber auf deutsch", "de"); - assertSame(literal3, RDFStarUtil.fromRDFEncodedValue(literal3)); - assertFalse(RDFStarUtil.isEncodedTriple(literal3)); + assertSame(literal3, TripleTermUtil.fromRDFEncodedValue(literal3)); + assertFalse(TripleTermUtil.isEncodedTriple(literal3)); BNode bNode = vf.createBNode("bnode1"); - assertSame(bNode, RDFStarUtil.fromRDFEncodedValue(bNode)); + assertSame(bNode, TripleTermUtil.fromRDFEncodedValue(bNode)); - IRI encoded = vf.createIRI("urn:rdf4j:triple:PDw8dXJuOmE-IDxodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1ze" - + "W50YXgtbnMjdHlwZT4gInBsYWluIj4-"); - Value decoded = RDFStarUtil.fromRDFEncodedValue(encoded); + Value encoded = TripleTermUtil.toRDFEncodedValue(vf.createTriple(iri, RDF.TYPE, literal1)); + Value decoded = TripleTermUtil.fromRDFEncodedValue(encoded); assertTrue(decoded instanceof Triple); assertEquals(iri, ((Triple) decoded).getSubject()); assertEquals(RDF.TYPE, ((Triple) decoded).getPredicate()); @@ -106,12 +105,12 @@ public void testInvalidEncodedValue() { }; for (IRI invalidValue : invalidValues) { - assertTrue(RDFStarUtil.isEncodedTriple(invalidValue)); + assertTrue(TripleTermUtil.isEncodedTriple(invalidValue)); try { - RDFStarUtil.fromRDFEncodedValue(invalidValue); + TripleTermUtil.fromRDFEncodedValue(invalidValue); fail("Must fail because of invalid value"); } catch (IllegalArgumentException e) { - assertTrue(e.getMessage().startsWith("Invalid RDF-star encoded triple")); + assertTrue(e.getMessage().startsWith("Invalid RDF 1.2 encoded triple")); } } } diff --git a/core/rio/binary/pom.xml b/core/rio/binary/pom.xml index 4ff5469eddf..646761f61ee 100644 --- a/core/rio/binary/pom.xml +++ b/core/rio/binary/pom.xml @@ -4,7 +4,7 @@ org.eclipse.rdf4j rdf4j-rio - 5.1.0-SNAPSHOT + 6.0.0 rdf4j-rio-binary RDF4J: Rio - Binary diff --git a/core/rio/datatypes/pom.xml b/core/rio/datatypes/pom.xml index b9d9dcadcfb..1ff90682b2b 100644 --- a/core/rio/datatypes/pom.xml +++ b/core/rio/datatypes/pom.xml @@ -4,7 +4,7 @@ org.eclipse.rdf4j rdf4j-rio - 5.1.0-SNAPSHOT + 6.0.0 rdf4j-rio-datatypes RDF4J: Rio - Datatypes diff --git a/core/rio/datatypes/src/main/java/org/eclipse/rdf4j/rio/datatypes/RDFDatatypeHandler.java b/core/rio/datatypes/src/main/java/org/eclipse/rdf4j/rio/datatypes/RDFDatatypeHandler.java index 3868981bfce..d4b70cd2da6 100644 --- a/core/rio/datatypes/src/main/java/org/eclipse/rdf4j/rio/datatypes/RDFDatatypeHandler.java +++ b/core/rio/datatypes/src/main/java/org/eclipse/rdf4j/rio/datatypes/RDFDatatypeHandler.java @@ -37,8 +37,10 @@ public boolean isRecognizedDatatype(IRI datatypeUri) { } return org.eclipse.rdf4j.model.vocabulary.RDF.LANGSTRING.equals(datatypeUri) + || org.eclipse.rdf4j.model.vocabulary.RDF.DIRLANGSTRING.equals(datatypeUri) || org.eclipse.rdf4j.model.vocabulary.RDF.XMLLITERAL.equals(datatypeUri) - || org.eclipse.rdf4j.model.vocabulary.RDF.HTML.equals(datatypeUri); + || org.eclipse.rdf4j.model.vocabulary.RDF.HTML.equals(datatypeUri) + || org.eclipse.rdf4j.model.vocabulary.RDF.JSON.equals(datatypeUri); } @Override diff --git a/core/rio/hdt/pom.xml b/core/rio/hdt/pom.xml index f3647663a65..d414bb8dbad 100644 --- a/core/rio/hdt/pom.xml +++ b/core/rio/hdt/pom.xml @@ -4,7 +4,7 @@ org.eclipse.rdf4j rdf4j-rio - 5.1.0-SNAPSHOT + 6.0.0 rdf4j-rio-hdt jar diff --git a/core/rio/jsonld-legacy/pom.xml b/core/rio/jsonld-legacy/pom.xml index 7509ef4b834..19b55537529 100644 --- a/core/rio/jsonld-legacy/pom.xml +++ b/core/rio/jsonld-legacy/pom.xml @@ -4,7 +4,7 @@ org.eclipse.rdf4j rdf4j-rio - 5.1.0-SNAPSHOT + 6.0.0 rdf4j-rio-jsonld-legacy RDF4J: Rio - JSON-LD 1.0 (legacy) diff --git a/core/rio/jsonld/pom.xml b/core/rio/jsonld/pom.xml index 998013a10ec..ce4232a5696 100644 --- a/core/rio/jsonld/pom.xml +++ b/core/rio/jsonld/pom.xml @@ -4,7 +4,7 @@ org.eclipse.rdf4j rdf4j-rio - 5.1.0-SNAPSHOT + 6.0.0 rdf4j-rio-jsonld RDF4J: Rio - JSON-LD diff --git a/core/rio/languages/pom.xml b/core/rio/languages/pom.xml index b35931702bb..2c5b979e6fe 100644 --- a/core/rio/languages/pom.xml +++ b/core/rio/languages/pom.xml @@ -4,7 +4,7 @@ org.eclipse.rdf4j rdf4j-rio - 5.1.0-SNAPSHOT + 6.0.0 rdf4j-rio-languages RDF4J: Rio - Languages diff --git a/core/rio/languages/src/main/java/org/eclipse/rdf4j/rio/languages/BCP47LanguageHandler.java b/core/rio/languages/src/main/java/org/eclipse/rdf4j/rio/languages/BCP47LanguageHandler.java index e5e91163349..453268bd25a 100644 --- a/core/rio/languages/src/main/java/org/eclipse/rdf4j/rio/languages/BCP47LanguageHandler.java +++ b/core/rio/languages/src/main/java/org/eclipse/rdf4j/rio/languages/BCP47LanguageHandler.java @@ -65,11 +65,19 @@ public boolean verifyLanguage(String literalValue, String languageTag) throws Li @Override public Literal normalizeLanguage(String literalValue, String languageTag, ValueFactory valueFactory) throws LiteralUtilException { + return normalizeLanguage(literalValue, languageTag, Literal.BaseDirection.NONE, valueFactory); + } + + @Override + public Literal normalizeLanguage(String literalValue, String languageTag, Literal.BaseDirection baseDir, + ValueFactory valueFactory) + throws LiteralUtilException { Objects.requireNonNull(languageTag, "Language tag cannot be null"); Objects.requireNonNull(literalValue, "Literal value cannot be null"); try { - return valueFactory.createLiteral(literalValue, Literals.normalizeLanguageTag(languageTag)); + return valueFactory.createLiteral(literalValue, + Literals.normalizeLanguageTag(languageTag), baseDir); } catch (IllformedLocaleException e) { throw new LiteralUtilException("Could not normalize BCP47 language tag", e); } diff --git a/core/rio/languages/src/main/java/org/eclipse/rdf4j/rio/languages/RFC3066LanguageHandler.java b/core/rio/languages/src/main/java/org/eclipse/rdf4j/rio/languages/RFC3066LanguageHandler.java index 37ae95506ce..1d89fb1cd33 100644 --- a/core/rio/languages/src/main/java/org/eclipse/rdf4j/rio/languages/RFC3066LanguageHandler.java +++ b/core/rio/languages/src/main/java/org/eclipse/rdf4j/rio/languages/RFC3066LanguageHandler.java @@ -67,11 +67,18 @@ public boolean verifyLanguage(String literalValue, String languageTag) throws Li @Override public Literal normalizeLanguage(String literalValue, String languageTag, ValueFactory valueFactory) throws LiteralUtilException { + return normalizeLanguage(literalValue, languageTag, Literal.BaseDirection.NONE, valueFactory); + } + + @Override + public Literal normalizeLanguage(String literalValue, String languageTag, Literal.BaseDirection baseDir, + ValueFactory valueFactory) + throws LiteralUtilException { Objects.requireNonNull(languageTag, "Language tag cannot be null"); Objects.requireNonNull(literalValue, "Literal value cannot be null"); if (isRecognizedLanguage(languageTag)) { - return valueFactory.createLiteral(literalValue, languageTag.toLowerCase().intern()); + return valueFactory.createLiteral(literalValue, languageTag.toLowerCase().intern(), baseDir); } throw new LiteralUtilException("Could not normalize RFC3066 language tag"); diff --git a/core/rio/n3/pom.xml b/core/rio/n3/pom.xml index 54ae5fe573c..45ecce4bd7c 100644 --- a/core/rio/n3/pom.xml +++ b/core/rio/n3/pom.xml @@ -4,7 +4,7 @@ org.eclipse.rdf4j rdf4j-rio - 5.1.0-SNAPSHOT + 6.0.0 rdf4j-rio-n3 RDF4J: Rio - N3 (writer-only) diff --git a/core/rio/nquads/pom.xml b/core/rio/nquads/pom.xml index 044216524fb..97839f5633d 100644 --- a/core/rio/nquads/pom.xml +++ b/core/rio/nquads/pom.xml @@ -4,7 +4,7 @@ org.eclipse.rdf4j rdf4j-rio - 5.1.0-SNAPSHOT + 6.0.0 rdf4j-rio-nquads RDF4J: Rio - N-Quads diff --git a/core/rio/nquads/src/main/java/org/eclipse/rdf4j/rio/nquads/NQuadsParser.java b/core/rio/nquads/src/main/java/org/eclipse/rdf4j/rio/nquads/NQuadsParser.java index e88fce23f97..510f9b57254 100644 --- a/core/rio/nquads/src/main/java/org/eclipse/rdf4j/rio/nquads/NQuadsParser.java +++ b/core/rio/nquads/src/main/java/org/eclipse/rdf4j/rio/nquads/NQuadsParser.java @@ -48,15 +48,15 @@ protected void parseStatement() throws RDFParseException, RDFHandlerException { if (!shouldParseLine()) { return; } - parseSubject(); + subject = parseSubject(); skipWhitespace(true); - parsePredicate(); + predicate = parsePredicate(); skipWhitespace(true); - parseObject(); + object = parseObject(); skipWhitespace(true); diff --git a/core/rio/nquads/src/test/java/org/eclipse/rdf4j/rio/nquads/AbstractNQuadsParserUnitTest.java b/core/rio/nquads/src/test/java/org/eclipse/rdf4j/rio/nquads/AbstractNQuadsParserUnitTest.java index 87b9d1c91ae..99e1dee158b 100644 --- a/core/rio/nquads/src/test/java/org/eclipse/rdf4j/rio/nquads/AbstractNQuadsParserUnitTest.java +++ b/core/rio/nquads/src/test/java/org/eclipse/rdf4j/rio/nquads/AbstractNQuadsParserUnitTest.java @@ -13,6 +13,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; @@ -21,6 +22,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; +import java.io.StringReader; import java.util.Collection; import org.eclipse.rdf4j.model.BNode; @@ -29,24 +31,25 @@ import org.eclipse.rdf4j.model.Resource; import org.eclipse.rdf4j.model.Statement; import org.eclipse.rdf4j.model.Value; +import org.eclipse.rdf4j.model.ValueFactory; +import org.eclipse.rdf4j.model.impl.SimpleValueFactory; import org.eclipse.rdf4j.model.vocabulary.RDF; +import org.eclipse.rdf4j.rio.AbstractParserTest; import org.eclipse.rdf4j.rio.RDFHandlerException; import org.eclipse.rdf4j.rio.RDFParseException; import org.eclipse.rdf4j.rio.RDFParser; import org.eclipse.rdf4j.rio.helpers.AbstractRDFHandler; import org.eclipse.rdf4j.rio.helpers.BasicParserSettings; import org.eclipse.rdf4j.rio.helpers.NTriplesParserSettings; -import org.eclipse.rdf4j.rio.helpers.SimpleParseLocationListener; -import org.eclipse.rdf4j.rio.helpers.StatementCollector; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; /** * JUnit test for the N-Quads parser that uses the tests that are available * online. */ -public abstract class AbstractNQuadsParserUnitTest { +public abstract class AbstractNQuadsParserUnitTest extends AbstractParserTest { + + private final ValueFactory vf = SimpleValueFactory.getInstance(); /*-----------* * Constants * @@ -60,33 +63,16 @@ public abstract class AbstractNQuadsParserUnitTest { private static final String NTRIPLES_TEST_FILE = "/testcases/ntriples/test.nt"; - private RDFParser parser; - - private TestRDFHandler rdfHandler; - - @BeforeEach - public void setUp() { - parser = createRDFParser(); - rdfHandler = new TestRDFHandler(); - parser.setRDFHandler(this.rdfHandler); - } - - @AfterEach - public void tearDown() { - parser = null; - } - /*---------* * Methods * *---------*/ public void testNQuadsFile() throws Exception { - RDFParser nquadsParser = createRDFParser(); - nquadsParser.setRDFHandler(new AbstractRDFHandler() { + parser.setRDFHandler(new AbstractRDFHandler() { }); try (InputStream in = AbstractNQuadsParserUnitTest.class.getResourceAsStream(NQUADS_TEST_FILE)) { - nquadsParser.parse(in, NQUADS_TEST_URL); + parser.parse(in, NQUADS_TEST_URL); } catch (RDFParseException e) { fail("NQuadsParser failed to parse N-Quads test document: " + e.getMessage()); } @@ -96,12 +82,11 @@ public void testNQuadsFile() throws Exception { * The N-Quads parser must be able to parse the N-Triples test file without error. */ public void testNTriplesFile() throws Exception { - RDFParser nquadsParser = createRDFParser(); - nquadsParser.setRDFHandler(new AbstractRDFHandler() { + parser.setRDFHandler(new AbstractRDFHandler() { }); try (InputStream in = AbstractNQuadsParserUnitTest.class.getResourceAsStream(NTRIPLES_TEST_FILE)) { - nquadsParser.parse(in, NTRIPLES_TEST_URL); + parser.parse(in, NTRIPLES_TEST_URL); } catch (RDFParseException e) { fail("NQuadsParser failed to parse N-Triples test document: " + e.getMessage()); } @@ -186,10 +171,8 @@ public void testParseNoContext() throws RDFHandlerException, IOException, RDFPar public void testParseEmptyLinesAndComments() throws RDFHandlerException, IOException, RDFParseException { final ByteArrayInputStream bais = new ByteArrayInputStream( " \n\n\n# This is a comment\n\n#this is another comment.".getBytes()); - final TestRDFHandler rdfHandler = new TestRDFHandler(); - parser.setRDFHandler(rdfHandler); parser.parse(bais, "http://test.base.uri"); - assertEquals(rdfHandler.getStatements().size(), 0); + assertEquals(0, statementCollector.getStatements().size()); } /** @@ -200,11 +183,9 @@ public void testParseBasic() throws RDFHandlerException, IOException, RDFParseEx final ByteArrayInputStream bais = new ByteArrayInputStream( " ." .getBytes()); - final TestRDFHandler rdfHandler = new TestRDFHandler(); - parser.setRDFHandler(rdfHandler); parser.parse(bais, "http://test.base.uri"); - assertEquals(1, rdfHandler.getStatements().size()); - final Statement statement = rdfHandler.getStatements().iterator().next(); + assertEquals(1, statementCollector.getStatements().size()); + final Statement statement = statementCollector.getStatements().iterator().next(); assertEquals("http://www.v/dat/4b", statement.getSubject().stringValue()); assertEquals("http://www.w3.org/20/ica#dtend", statement.getPredicate().stringValue()); assertTrue(statement.getObject() instanceof IRI); @@ -220,11 +201,9 @@ public void testParseBasicBNode() throws RDFHandlerException, IOException, RDFPa final ByteArrayInputStream bais = new ByteArrayInputStream( "_:a123456768 ." .getBytes()); - final TestRDFHandler rdfHandler = new TestRDFHandler(); - parser.setRDFHandler(rdfHandler); parser.parse(bais, "http://test.base.uri"); - assertThat(rdfHandler.getStatements()).hasSize(1); - final Statement statement = rdfHandler.getStatements().iterator().next(); + assertThat(statementCollector.getStatements()).hasSize(1); + final Statement statement = statementCollector.getStatements().iterator().next(); assertTrue(statement.getSubject() instanceof BNode); assertEquals("http://www.w3.org/20/ica#dtend", statement.getPredicate().stringValue()); assertTrue(statement.getObject() instanceof IRI); @@ -240,11 +219,9 @@ public void testParseBasicLiteral() throws RDFHandlerException, IOException, RDF final ByteArrayInputStream bais = new ByteArrayInputStream( "_:a123456768 \"2010-05-02\" ." .getBytes()); - final TestRDFHandler rdfHandler = new TestRDFHandler(); - parser.setRDFHandler(rdfHandler); parser.parse(bais, "http://test.base.uri"); - assertThat(rdfHandler.getStatements()).hasSize(1); - final Statement statement = rdfHandler.getStatements().iterator().next(); + assertThat(statementCollector.getStatements()).hasSize(1); + final Statement statement = statementCollector.getStatements().iterator().next(); assertTrue(statement.getSubject() instanceof BNode); assertEquals("http://www.w3.org/20/ica#dtend", statement.getPredicate().stringValue()); assertTrue(statement.getObject() instanceof Literal); @@ -260,10 +237,8 @@ public void testParseBasicLiteralLang() throws RDFHandlerException, IOException, final ByteArrayInputStream bais = new ByteArrayInputStream( " \"2010-05-02\"@en ." .getBytes()); - final TestRDFHandler rdfHandler = new TestRDFHandler(); - parser.setRDFHandler(rdfHandler); parser.parse(bais, "http://test.base.uri"); - final Statement statement = rdfHandler.getStatements().iterator().next(); + final Statement statement = statementCollector.getStatements().iterator().next(); assertEquals("http://www.v/dat/4b2-21", statement.getSubject().stringValue()); assertEquals("http://www.w3.org/20/ica#dtend", statement.getPredicate().stringValue()); assertTrue(statement.getObject() instanceof Literal); @@ -283,10 +258,8 @@ public void testParseBasicLiteralDatatype() throws RDFHandlerException, IOExcept (" " + " " + "\"2010\"^^ " + ".") .getBytes()); - final TestRDFHandler rdfHandler = new TestRDFHandler(); - parser.setRDFHandler(rdfHandler); parser.parse(bais, "http://test.base.uri"); - final Statement statement = rdfHandler.getStatements().iterator().next(); + final Statement statement = statementCollector.getStatements().iterator().next(); assertEquals("http://www.v/dat/4b2-21", statement.getSubject().stringValue()); assertEquals("http://www.w3.org/20/ica#dtend", statement.getPredicate().stringValue()); assertTrue(statement.getObject() instanceof Literal); @@ -307,8 +280,6 @@ public void testParseBasicLiteralDatatypePrefix() throws RDFHandlerException, IO final ByteArrayInputStream bais = new ByteArrayInputStream( (" " + " " + "\"2010\"^^xsd:integer " + ".").getBytes()); - final TestRDFHandler rdfHandler = new TestRDFHandler(); - parser.setRDFHandler(rdfHandler); try { parser.parse(bais, "http://test.base.uri"); fail("Expected exception when passing in a datatype using an N3 style prefix"); @@ -324,19 +295,14 @@ public void testParseBasicLiteralDatatypePrefix() throws RDFHandlerException, IO */ @Test public void testLiteralEscapeManagement1() throws RDFHandlerException, IOException, RDFParseException { - TestParseLocationListener parseLocationListener = new TestParseLocationListener(); - TestRDFHandler rdfHandler = new TestRDFHandler(); - parser.setParseLocationListener(parseLocationListener); - parser.setRDFHandler(rdfHandler); - final ByteArrayInputStream bais = new ByteArrayInputStream( " \"\\\\\" .".getBytes()); parser.parse(bais, "http://base-uri"); - rdfHandler.assertHandler(1); - // parseLocationListener.assertListener(1, 40); + assertEquals(1, statementCollector.getStatements().size()); + // locationListener.assertListener(1, 40); // FIXME: Enable column numbers when parser supports them - parseLocationListener.assertListener(1, 1); + locationListener.assertListener(1, 1); } /** @@ -344,17 +310,12 @@ public void testLiteralEscapeManagement1() throws RDFHandlerException, IOExcepti */ @Test public void testLiteralEscapeManagement2() throws RDFHandlerException, IOException, RDFParseException { - TestParseLocationListener parseLocationListener = new TestParseLocationListener(); - TestRDFHandler rdfHandler = new TestRDFHandler(); - parser.setParseLocationListener(parseLocationListener); - parser.setRDFHandler(rdfHandler); - final ByteArrayInputStream bais = new ByteArrayInputStream( " \"Line text 1\\nLine text 2\" .".getBytes()); parser.parse(bais, "http://base-uri"); - rdfHandler.assertHandler(1); - final Value object = rdfHandler.getStatements().iterator().next().getObject(); + assertEquals(1, statementCollector.getStatements().size()); + final Value object = statementCollector.getStatements().iterator().next().getObject(); assertTrue(object instanceof Literal); final String literalContent = ((Literal) object).getLabel(); assertEquals("Line text 1\nLine text 2", literalContent); @@ -365,18 +326,13 @@ public void testLiteralEscapeManagement2() throws RDFHandlerException, IOExcepti */ @Test public void testURIDecodingManagement() throws RDFHandlerException, IOException, RDFParseException { - TestParseLocationListener parseLocationListener = new TestParseLocationListener(); - TestRDFHandler rdfHandler = new TestRDFHandler(); - parser.setParseLocationListener(parseLocationListener); - parser.setRDFHandler(rdfHandler); - final ByteArrayInputStream bais = new ByteArrayInputStream( " ." .getBytes()); parser.parse(bais, "http://base-uri"); - rdfHandler.assertHandler(1); - final Statement statement = rdfHandler.getStatements().iterator().next(); + assertEquals(1, statementCollector.getStatements().size()); + final Statement statement = statementCollector.getStatements().iterator().next(); final Resource subject = statement.getSubject(); assertTrue(subject instanceof IRI); @@ -401,16 +357,14 @@ public void testURIDecodingManagement() throws RDFHandlerException, IOException, @Test public void testUnicodeLiteralDecoding() throws RDFHandlerException, IOException, RDFParseException { - TestRDFHandler rdfHandler = new TestRDFHandler(); - parser.setRDFHandler(rdfHandler); final String INPUT_LITERAL_PLAIN = "[は]"; final String INPUT_LITERAL_ENCODED = "[\\u306F]"; final String INPUT_STRING = String.format(" \"%s\" .", INPUT_LITERAL_ENCODED); final ByteArrayInputStream bais = new ByteArrayInputStream(INPUT_STRING.getBytes()); parser.parse(bais, "http://base-uri"); - rdfHandler.assertHandler(1); - final Literal obj = (Literal) rdfHandler.getStatements().iterator().next().getObject(); + assertEquals(1, statementCollector.getStatements().size()); + final Literal obj = (Literal) statementCollector.getStatements().iterator().next().getObject(); assertEquals(INPUT_LITERAL_PLAIN, obj.getLabel()); } @@ -452,17 +406,12 @@ public void testEndOfStreamReached() throws RDFHandlerException, IOException, RD */ @Test public void testParserWithAllCases() throws IOException, RDFParseException, RDFHandlerException { - TestParseLocationListener parseLocationListerner = new TestParseLocationListener(); - // SpecificTestRDFHandler rdfHandler = new SpecificTestRDFHandler(); - parser.setParseLocationListener(parseLocationListerner); - parser.setRDFHandler(rdfHandler); - BufferedReader br = new BufferedReader(new InputStreamReader( AbstractNQuadsParserUnitTest.class.getResourceAsStream("/testcases/nquads/test1.nq"))); parser.parse(br, "http://test.base.uri"); - rdfHandler.assertHandler(6); - parseLocationListerner.assertListener(8, 1); + assertEquals(6, statementCollector.getStatements().size()); + locationListener.assertListener(8, 1); } /** @@ -470,16 +419,11 @@ public void testParserWithAllCases() throws IOException, RDFParseException, RDFH */ @Test public void testParserWithRealData() throws IOException, RDFParseException, RDFHandlerException { - TestParseLocationListener parseLocationListener = new TestParseLocationListener(); - TestRDFHandler rdfHandler = new TestRDFHandler(); - parser.setParseLocationListener(parseLocationListener); - parser.setRDFHandler(rdfHandler); - parser.parse(AbstractNQuadsParserUnitTest.class.getResourceAsStream("/testcases/nquads/test2.nq"), "http://test.base.uri"); - rdfHandler.assertHandler(400); - parseLocationListener.assertListener(400, 1); + assertEquals(400, statementCollector.getStatements().size()); + locationListener.assertListener(400, 1); } @Test @@ -566,15 +510,13 @@ public void testStopAtFirstErrorTolerantParsing() throws RDFHandlerException, IO // with // error. " .\n").getBytes()); - final TestRDFHandler rdfHandler = new TestRDFHandler(); - parser.setRDFHandler(rdfHandler); parser.getParserConfig().set(NTriplesParserSettings.FAIL_ON_INVALID_LINES, false); parser.getParserConfig().addNonFatalError(NTriplesParserSettings.FAIL_ON_INVALID_LINES); parser.parse(bais, "http://base-uri"); - rdfHandler.assertHandler(2); - final Collection statements = rdfHandler.getStatements(); + assertEquals(2, statementCollector.getStatements().size()); + final Collection statements = statementCollector.getStatements(); int i = 0; for (Statement nextStatement : statements) { assertEquals("http://s" + i, nextStatement.getSubject().stringValue()); @@ -587,8 +529,6 @@ public void testStopAtFirstErrorTolerantParsing() throws RDFHandlerException, IO private void verifyStatementWithInvalidDatatype(boolean useDatatypeVerification) throws RDFHandlerException, IOException, RDFParseException { - TestRDFHandler rdfHandler = new TestRDFHandler(); - parser.setRDFHandler(rdfHandler); parser.getParserConfig().set(BasicParserSettings.VERIFY_DATATYPE_VALUES, useDatatypeVerification); parser.getParserConfig().set(BasicParserSettings.FAIL_ON_UNKNOWN_DATATYPES, useDatatypeVerification); if (!useDatatypeVerification) { @@ -603,41 +543,106 @@ private void verifyStatementWithInvalidDatatype(boolean useDatatypeVerification) + " .") .getBytes()); parser.parse(bais, "http://base-uri"); - rdfHandler.assertHandler(1); + assertEquals(1, statementCollector.getStatements().size()); } - private class TestParseLocationListener extends SimpleParseLocationListener { + @Test + public void testDirLangStringRTLNoContext() { + final String data = " \"שלום\"@he--rtl"; + dirLangStringTest(data, false, "he", Literal.RTL_SUFFIX, false, false); + } - private void assertListener(int row, int col) { - assertEquals(row, this.getLineNo(), "Unexpected last row"); - assertEquals(col, this.getColumnNo(), "Unexpected last col"); - } + @Test + public void testDirLangStringRTLWithContext() { + final String data = " \"שלום\"@he--rtl"; + dirLangStringTest(data, true, "he", Literal.RTL_SUFFIX, false, false); + } + @Test + public void testDirLangStringLTRWithNormalizationNoContext() { + String data = " \"Hello\"@en--ltr"; + dirLangStringTest(data, false, "en", Literal.LTR_SUFFIX, true, false); } - private class TestRDFHandler extends StatementCollector { + @Test + public void testDirLangStringLTRWithNormalizationWithContext() { + final String data = " \"Hello\"@en--ltr"; + dirLangStringTest(data, true, "en", Literal.LTR_SUFFIX, true, false); + } - private boolean started = false; + @Test + public void testBadDirLangStringNoContext() { + final String data = " \"hello\"@en--unk"; + dirLangStringTest(data, false, "", "", true, true); + } - private boolean ended = false; + @Test + public void testBadDirLangStringWithContext() { + final String data = " \"hello\"@en--unk"; + dirLangStringTest(data, true, "", "", true, true); + } - @Override - public void startRDF() throws RDFHandlerException { - super.startRDF(); - started = true; - } + @Test + public void testBadCapitalizationDirLangStringNoContext() { + final String data = " \"Hello\"@en--LTR"; + dirLangStringTest(data, false, "", "", true, true); + } - @Override - public void endRDF() throws RDFHandlerException { - super.endRDF(); - ended = true; - } + @Test + public void testBadCapitalizationDirLangStringWithContext() { + final String data = " \"Hello\"@en--LTR"; + dirLangStringTest(data, true, "", "", true, true); + } - public void assertHandler(int expected) { - assertTrue(started, "Never started."); - assertTrue(ended, "Never ended."); - assertEquals(expected, getStatements().size(), "Unexpected number of statements."); - } + @Test + public void testDirLangStringNoLanguage() throws IOException { + final String data = " \"Hello\"^^ ."; + dirLangStringNoLanguageTestHelper(data); + } + + private void dirLangStringTest( + final String triple, final boolean withContext, final String expectedLang, final String expectedDir, + final boolean normalize, + final boolean shouldCauseException) { + final String data = triple + (withContext ? " " : "") + " ."; + + dirLangStringTestHelper(data, expectedLang, expectedDir, normalize, shouldCauseException); + } + + @Test + public void testTripleTerm() throws IOException { + final String data = " <<( )>> ."; + parser.parse(new StringReader(data)); + + assertEquals(1, statementCollector.getStatements().size()); + assertEquals( + vf.createTriple(vf.createIRI("http://example/a"), vf.createIRI("http://example/b"), + vf.createIRI("http://example/c")), + statementCollector.getStatements().iterator().next().getObject()); + } + + @Test + public void testTripleTermNoWhitespace() throws IOException { + final String data = "<<()>>."; + parser.parse(new StringReader(data)); + + assertEquals(1, statementCollector.getStatements().size()); + assertEquals( + vf.createTriple(vf.createIRI("http://example/a"), vf.createIRI("http://example/b"), + vf.createIRI("http://example/c")), + statementCollector.getStatements().iterator().next().getObject()); + } + + @Test + public void testBadTripleTermSubject() throws IOException { + final String data = "<<( )>> ."; + assertThrows(RDFParseException.class, () -> parser.parse(new StringReader(data))); + } + + @Test + public void testBadTripleTermMissingObject() throws IOException { + final String data = " <<( )>> ."; + assertThrows(RDFParseException.class, () -> parser.parse(new StringReader(data))); } @Test diff --git a/core/rio/nquads/src/test/java/org/eclipse/rdf4j/rio/nquads/AbstractNQuadsWriterTest.java b/core/rio/nquads/src/test/java/org/eclipse/rdf4j/rio/nquads/AbstractNQuadsWriterTest.java index 3a086558dd3..6968900ed29 100644 --- a/core/rio/nquads/src/test/java/org/eclipse/rdf4j/rio/nquads/AbstractNQuadsWriterTest.java +++ b/core/rio/nquads/src/test/java/org/eclipse/rdf4j/rio/nquads/AbstractNQuadsWriterTest.java @@ -15,10 +15,14 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.io.StringWriter; +import org.eclipse.rdf4j.model.Model; import org.eclipse.rdf4j.model.Statement; import org.eclipse.rdf4j.model.ValueFactory; +import org.eclipse.rdf4j.model.impl.DynamicModelFactory; import org.eclipse.rdf4j.model.impl.SimpleValueFactory; +import org.eclipse.rdf4j.rio.RDFFormat; import org.eclipse.rdf4j.rio.RDFHandlerException; import org.eclipse.rdf4j.rio.RDFParseException; import org.eclipse.rdf4j.rio.RDFParser; @@ -26,6 +30,7 @@ import org.eclipse.rdf4j.rio.RDFWriter; import org.eclipse.rdf4j.rio.RDFWriterFactory; import org.eclipse.rdf4j.rio.RDFWriterTest; +import org.eclipse.rdf4j.rio.Rio; import org.eclipse.rdf4j.rio.RioSetting; import org.eclipse.rdf4j.rio.helpers.BasicWriterSettings; import org.eclipse.rdf4j.rio.helpers.NTriplesWriterSettings; @@ -155,6 +160,64 @@ public void testBlankNodeContextAddXSDString() throws RDFHandlerException { " \"test literal\"^^ _:")); } + @Test + public void testDirLangString() throws Exception { + dirLangStringTest(RDFFormat.NQUADS); + } + + @Test + public void testTripleTerm() { + Model model = new DynamicModelFactory().createEmptyModel(); + String ns = "http://www.example.com/"; + model.setNamespace("", ns); + model.add(vf.createIRI(ns, "s"), vf.createIRI(ns, "p"), + vf.createTriple(vf.createIRI(ns, "s2"), vf.createIRI(ns, "p2"), vf.createIRI(ns, "o")), + vf.createIRI(ns, "context")); + + StringWriter stringWriter = new StringWriter(); + Rio.write(model, stringWriter, RDFFormat.NQUADS); + + assertEquals( + " <<( )>> .\n", + stringWriter.toString()); + } + + @Test + public void testNestedTripleTerm() { + Model model = new DynamicModelFactory().createEmptyModel(); + String ns = "http://www.example.com/"; + model.setNamespace("", ns); + model.add(vf.createIRI(ns, "s"), vf.createIRI(ns, "p"), + vf.createTriple(vf.createIRI(ns, "s2"), vf.createIRI(ns, "p2"), + vf.createTriple(vf.createIRI(ns, "s3"), vf.createIRI(ns, "p3"), vf.createIRI(ns, "o"))), + vf.createIRI(ns, "context")); + + StringWriter stringWriter = new StringWriter(); + Rio.write(model, stringWriter, RDFFormat.NQUADS); + + assertEquals( + " <<( <<( )>> )>> .\n", + stringWriter.toString()); + } + + @Test + public void testNestedTripleTerm2() { + Model model = new DynamicModelFactory().createEmptyModel(); + String ns = "http://www.example.com/"; + model.setNamespace("", ns); + model.add(vf.createBNode("b"), vf.createIRI(ns, "p"), + vf.createTriple(vf.createIRI(ns, "s"), vf.createIRI(ns, "p2"), + vf.createTriple(vf.createBNode("b2"), vf.createIRI(ns, "p3"), vf.createLiteral(9))), + vf.createIRI(ns, "context")); + + StringWriter stringWriter = new StringWriter(); + Rio.write(model, stringWriter, RDFFormat.NQUADS); + + assertEquals( + "_:b <<( <<( _:b2 \"9\"^^ )>> )>> .\n", + stringWriter.toString()); + } + @Override protected RioSetting[] getExpectedSupportedSettings() { return new RioSetting[] { diff --git a/core/rio/ntriples/pom.xml b/core/rio/ntriples/pom.xml index 37553504ed5..c2057da34a4 100644 --- a/core/rio/ntriples/pom.xml +++ b/core/rio/ntriples/pom.xml @@ -4,7 +4,7 @@ org.eclipse.rdf4j rdf4j-rio - 5.1.0-SNAPSHOT + 6.0.0 rdf4j-rio-ntriples RDF4J: Rio - N-Triples diff --git a/core/rio/ntriples/src/main/java/org/eclipse/rdf4j/rio/ntriples/NTriplesParser.java b/core/rio/ntriples/src/main/java/org/eclipse/rdf4j/rio/ntriples/NTriplesParser.java index b5b48815022..53b94c6216f 100644 --- a/core/rio/ntriples/src/main/java/org/eclipse/rdf4j/rio/ntriples/NTriplesParser.java +++ b/core/rio/ntriples/src/main/java/org/eclipse/rdf4j/rio/ntriples/NTriplesParser.java @@ -25,7 +25,9 @@ import org.apache.commons.io.input.BOMInputStream; import org.eclipse.rdf4j.common.text.ASCIIUtil; import org.eclipse.rdf4j.model.IRI; +import org.eclipse.rdf4j.model.Literal; import org.eclipse.rdf4j.model.Resource; +import org.eclipse.rdf4j.model.Triple; import org.eclipse.rdf4j.model.Value; import org.eclipse.rdf4j.model.ValueFactory; import org.eclipse.rdf4j.model.impl.SimpleValueFactory; @@ -134,15 +136,15 @@ protected void parseStatement() throws RDFParseException, RDFHandlerException { if (!shouldParseLine()) { return; } - parseSubject(); + subject = parseSubject(); skipWhitespace(true); - parsePredicate(); + predicate = parsePredicate(); skipWhitespace(true); - parseObject(); + object = parseObject(); skipWhitespace(true); @@ -182,11 +184,11 @@ protected boolean shouldParseLine() { return false; } - protected void parseSubject() { + protected Resource parseSubject() { if (lineChars[currentIndex] == '<') { - subject = parseIRI(); + return parseIRI(); } else if (lineChars[currentIndex] == '_') { - subject = parseNode(); + return parseNode(); } else { throw new RDFParseException( "Expected '<' or '_', found: " + new String(Character.toChars(lineChars[currentIndex])), lineNo, @@ -194,9 +196,9 @@ protected void parseSubject() { } } - protected void parsePredicate() { + protected IRI parsePredicate() { if (lineChars[currentIndex] == '<') { - predicate = parseIRI(); + return parseIRI(); } else { throw new RDFParseException( "Expected '<', found: " + new String(Character.toChars(lineChars[currentIndex])), lineNo, @@ -204,13 +206,17 @@ protected void parsePredicate() { } } - protected void parseObject() { + protected Value parseObject() { if (lineChars[currentIndex] == '<') { - object = parseIRI(); + if (lineChars.length > currentIndex + 1 && lineChars[currentIndex + 1] == '<') { + return parseTripleTerm(); + } else { + return parseIRI(); + } } else if (lineChars[currentIndex] == '_') { - object = parseNode(); + return parseNode(); } else if (lineChars[currentIndex] == '"') { - parseLiteral(); + return parseLiteral(); } else { throw new RDFParseException( "Expected '<' or '_', found: " + new String(Character.toChars(lineChars[currentIndex])), lineNo, @@ -272,16 +278,47 @@ protected Resource parseNode() { return createNode(new String(lineChars, startIndex, currentIndex - startIndex)); } - private void parseLiteral() { + private Literal parseLiteral() { String label = parseLabel(); incrementIndexOrThrowEOF(); + skipWhitespace(true); if (currentIndex < lineChars.length - 1 && lineChars[currentIndex] == '^') { - parseLiteralWithDatatype(label); + return parseLiteralWithDatatype(label); } else if (lineChars[currentIndex] == '@') { - parseLangLiteral(label); + return parseLangLiteral(label); } else { - object = createLiteral(label, null, ((IRI) null), lineNo, lineChars[currentIndex]); + return createLiteral(label, null, ((IRI) null), lineNo, lineChars[currentIndex]); + } + } + + private Triple parseTripleTerm() { + if (currentIndex + 2 >= lineChars.length || lineChars[currentIndex] != '<' || lineChars[currentIndex + 1] != '<' + || lineChars[currentIndex + 2] != '(') { + reportError( + "Triple term must start with '<<(', is: " + new String(Character.toChars(lineChars[currentIndex])), + NTriplesParserSettings.FAIL_ON_INVALID_LINES); + } + currentIndex += 3; + + skipWhitespace(true); + final Resource ttSubject = parseSubject(); + + skipWhitespace(true); + final IRI ttPredicate = parsePredicate(); + + skipWhitespace(true); + final Value ttObject = parseObject(); + + skipWhitespace(true); + + if (currentIndex + 2 >= lineChars.length || lineChars[currentIndex] != ')' || lineChars[currentIndex + 1] != '>' + || lineChars[currentIndex + 2] != '>') { + reportError( + "Triple term must end with ')>>', is: " + new String(Character.toChars(lineChars[currentIndex])), + NTriplesParserSettings.FAIL_ON_INVALID_LINES); } + currentIndex += 3; + return valueFactory.createTriple(ttSubject, ttPredicate, ttObject); } private String parseLabel() { @@ -300,20 +337,21 @@ private String parseLabel() { } } - private void parseLiteralWithDatatype(String label) { + private Literal parseLiteralWithDatatype(String label) { if (lineChars[currentIndex + 1] != '^') { reportError("Expected '^', found: " + new String(Character.toChars(lineChars[currentIndex + 1])), NTriplesParserSettings.FAIL_ON_INVALID_LINES); } currentIndex += 2; + skipWhitespace(true); if (currentIndex >= lineChars.length || lineChars[currentIndex] != '<') { reportError("Expected '<', found: " + new String(Character.toChars(lineChars[currentIndex])), NTriplesParserSettings.FAIL_ON_INVALID_LINES); } - object = createLiteral(label, null, parseIRI(), lineNo, lineChars[currentIndex]); + return createLiteral(label, null, parseIRI(), lineNo, lineChars[currentIndex]); } - private void parseLangLiteral(String label) { + private Literal parseLangLiteral(String label) { incrementIndexOrThrowEOF(); if (!ASCIIUtil.isLetter(lineChars[currentIndex])) { reportError("Expected a letter, found: " + new String(Character.toChars(lineChars[currentIndex])), @@ -329,7 +367,7 @@ private void parseLangLiteral(String label) { if (currentIndex >= lineChars.length) { throwEOFException(); } - object = createLiteral(label, new String(lineChars, startIndex, currentIndex - startIndex), ((IRI) null), + return createLiteral(label, new String(lineChars, startIndex, currentIndex - startIndex), ((IRI) null), lineNo, lineChars[currentIndex]); } diff --git a/core/rio/ntriples/src/main/java/org/eclipse/rdf4j/rio/ntriples/NTriplesWriter.java b/core/rio/ntriples/src/main/java/org/eclipse/rdf4j/rio/ntriples/NTriplesWriter.java index d763449042a..f1e1f4f178e 100644 --- a/core/rio/ntriples/src/main/java/org/eclipse/rdf4j/rio/ntriples/NTriplesWriter.java +++ b/core/rio/ntriples/src/main/java/org/eclipse/rdf4j/rio/ntriples/NTriplesWriter.java @@ -25,6 +25,7 @@ import org.eclipse.rdf4j.model.IRI; import org.eclipse.rdf4j.model.Literal; import org.eclipse.rdf4j.model.Statement; +import org.eclipse.rdf4j.model.Triple; import org.eclipse.rdf4j.model.Value; import org.eclipse.rdf4j.rio.RDFFormat; import org.eclipse.rdf4j.rio.RDFHandlerException; @@ -145,6 +146,8 @@ protected void writeValue(Value value) throws IOException { writeBNode((BNode) value); } else if (value instanceof Literal) { writeLiteral((Literal) value); + } else if (value instanceof Triple) { + writeTriple((Triple) value); } else { throw new IllegalArgumentException("Unknown value type: " + value.getClass()); } @@ -189,4 +192,14 @@ private void writeLiteral(Literal lit) throws IOException { NTriplesUtil.append(lit, writer, getWriterConfig().get(BasicWriterSettings.XSD_STRING_TO_PLAIN_LITERAL), escapeUnicode); } + + private void writeTriple(Triple t) throws IOException { + writer.write("<<( "); + writeValue(t.getSubject()); + writer.write(" "); + writeIRI(t.getPredicate()); + writer.write(" "); + writeValue(t.getObject()); + writer.write(" )>>"); + } } diff --git a/core/rio/ntriples/src/main/java/org/eclipse/rdf4j/rio/ntriples/NTriplesWriterSettings.java b/core/rio/ntriples/src/main/java/org/eclipse/rdf4j/rio/ntriples/NTriplesWriterSettings.java index 1f10c0a4463..52f4c275ebc 100644 --- a/core/rio/ntriples/src/main/java/org/eclipse/rdf4j/rio/ntriples/NTriplesWriterSettings.java +++ b/core/rio/ntriples/src/main/java/org/eclipse/rdf4j/rio/ntriples/NTriplesWriterSettings.java @@ -30,7 +30,7 @@ public class NTriplesWriterSettings { * Can be overridden by setting system property {@code org.eclipse.rdf4j.rio.ntriples.escape_unicode} */ public static final BooleanRioSetting ESCAPE_UNICODE = new BooleanRioSetting( - "org.eclipse.rdf4j.rio.ntriples.escape_unicode", "Escape Unicode characters", Boolean.FALSE); + "org.eclipse.rdf4j.rio.ntriples.escape_unicode", "Escape Unicode characters", Boolean.TRUE); /** * Private constructor diff --git a/core/rio/ntriples/src/test/java/org/eclipse/rdf4j/rio/ntriples/AbstractNTriplesParserUnitTest.java b/core/rio/ntriples/src/test/java/org/eclipse/rdf4j/rio/ntriples/AbstractNTriplesParserUnitTest.java index 6787dedc80a..04b4bd81ad5 100644 --- a/core/rio/ntriples/src/test/java/org/eclipse/rdf4j/rio/ntriples/AbstractNTriplesParserUnitTest.java +++ b/core/rio/ntriples/src/test/java/org/eclipse/rdf4j/rio/ntriples/AbstractNTriplesParserUnitTest.java @@ -15,6 +15,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; +import java.io.IOException; import java.io.InputStream; import java.io.StringReader; import java.util.ArrayList; @@ -24,17 +25,21 @@ import java.util.List; import java.util.TreeSet; +import org.eclipse.rdf4j.model.Literal; import org.eclipse.rdf4j.model.Model; +import org.eclipse.rdf4j.model.ValueFactory; import org.eclipse.rdf4j.model.impl.LinkedHashModel; +import org.eclipse.rdf4j.model.impl.SimpleValueFactory; import org.eclipse.rdf4j.model.util.Models; import org.eclipse.rdf4j.model.vocabulary.XSD; +import org.eclipse.rdf4j.rio.AbstractParserTest; import org.eclipse.rdf4j.rio.RDFHandlerException; import org.eclipse.rdf4j.rio.RDFParseException; import org.eclipse.rdf4j.rio.RDFParser; import org.eclipse.rdf4j.rio.helpers.BasicParserSettings; import org.eclipse.rdf4j.rio.helpers.NTriplesParserSettings; -import org.eclipse.rdf4j.rio.helpers.ParseErrorCollector; import org.eclipse.rdf4j.rio.helpers.StatementCollector; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; /** @@ -42,20 +47,28 @@ * * @author Peter Ansell */ -public abstract class AbstractNTriplesParserUnitTest { +public abstract class AbstractNTriplesParserUnitTest extends AbstractParserTest { + + private final ValueFactory vf = SimpleValueFactory.getInstance(); private static final String NTRIPLES_TEST_URL = "http://www.w3.org/2000/10/rdf-tests/rdfcore/ntriples/test.nt"; private static final String NTRIPLES_TEST_FILE = "/testcases/ntriples/test.nt"; + private Model model; + + @BeforeEach + @Override + public void setUp() { + model = new LinkedHashModel(); + statementCollector = new StatementCollector(model); + super.setUp(); + } + @Test public void testNTriplesFile() throws Exception { - RDFParser ntriplesParser = createRDFParser(); - Model model = new LinkedHashModel(); - ntriplesParser.setRDFHandler(new StatementCollector(model)); - try (InputStream in = this.getClass().getResourceAsStream(NTRIPLES_TEST_FILE)) { - ntriplesParser.parse(in, NTRIPLES_TEST_URL); + parser.parse(in, NTRIPLES_TEST_URL); } catch (RDFParseException e) { fail("Failed to parse N-Triples test document: " + e.getMessage()); } @@ -70,15 +83,11 @@ public void testNTriplesFile() throws Exception { public void testExceptionHandlingWithDefaultSettings() throws Exception { String data = "invalid nt"; - RDFParser ntriplesParser = createRDFParser(); - Model model = new LinkedHashModel(); - ntriplesParser.setRDFHandler(new StatementCollector(model)); - try { - ntriplesParser.parse(new StringReader(data), NTRIPLES_TEST_URL); + parser.parse(new StringReader(data), NTRIPLES_TEST_URL); fail("expected RDFParseException due to invalid data"); } catch (RDFParseException expected) { - assertEquals(expected.getLineNumber(), 1); + assertEquals(1, expected.getLineNumber()); } } @@ -86,17 +95,13 @@ public void testExceptionHandlingWithDefaultSettings() throws Exception { public void testExceptionHandlingWithStopAtFirstError() throws Exception { String data = "invalid nt"; - RDFParser ntriplesParser = createRDFParser(); - ntriplesParser.getParserConfig().set(NTriplesParserSettings.FAIL_ON_INVALID_LINES, Boolean.TRUE); - - Model model = new LinkedHashModel(); - ntriplesParser.setRDFHandler(new StatementCollector(model)); + parser.getParserConfig().set(NTriplesParserSettings.FAIL_ON_INVALID_LINES, Boolean.TRUE); try { - ntriplesParser.parse(new StringReader(data), NTRIPLES_TEST_URL); + parser.parse(new StringReader(data), NTRIPLES_TEST_URL); fail("expected RDFParseException due to invalid data"); } catch (RDFParseException expected) { - assertEquals(expected.getLineNumber(), 1); + assertEquals(1, expected.getLineNumber()); } } @@ -104,13 +109,9 @@ public void testExceptionHandlingWithStopAtFirstError() throws Exception { public void testExceptionHandlingWithoutStopAtFirstError() throws Exception { String data = "invalid nt"; - RDFParser ntriplesParser = createRDFParser(); - ntriplesParser.getParserConfig().addNonFatalError(NTriplesParserSettings.FAIL_ON_INVALID_LINES); + parser.getParserConfig().addNonFatalError(NTriplesParserSettings.FAIL_ON_INVALID_LINES); - Model model = new LinkedHashModel(); - ntriplesParser.setRDFHandler(new StatementCollector(model)); - - ntriplesParser.parse(new StringReader(data), NTRIPLES_TEST_URL); + parser.parse(new StringReader(data), NTRIPLES_TEST_URL); assertEquals(0, model.size()); assertEquals(0, model.subjects().size()); @@ -122,13 +123,9 @@ public void testExceptionHandlingWithoutStopAtFirstError() throws Exception { public void testExceptionHandlingWithoutStopAtFirstError2() throws Exception { String data = "invalid nt"; - RDFParser ntriplesParser = createRDFParser(); - ntriplesParser.getParserConfig().set(NTriplesParserSettings.FAIL_ON_INVALID_LINES, false); + parser.getParserConfig().set(NTriplesParserSettings.FAIL_ON_INVALID_LINES, false); - Model model = new LinkedHashModel(); - ntriplesParser.setRDFHandler(new StatementCollector(model)); - - ntriplesParser.parse(new StringReader(data), NTRIPLES_TEST_URL); + parser.parse(new StringReader(data), NTRIPLES_TEST_URL); assertEquals(0, model.size()); assertEquals(0, model.subjects().size()); @@ -138,10 +135,7 @@ public void testExceptionHandlingWithoutStopAtFirstError2() throws Exception { @Test public void testEscapes() throws Exception { - RDFParser ntriplesParser = createRDFParser(); - Model model = new LinkedHashModel(); - ntriplesParser.setRDFHandler(new StatementCollector(model)); - ntriplesParser.parse( + parser.parse( new StringReader(" \" \\t \\b \\n \\r \\f \\\" \\' \\\\ \" . "), "http://example/"); assertEquals(1, model.size()); @@ -150,10 +144,7 @@ public void testEscapes() throws Exception { @Test public void testEndOfLineCommentNoSpace() throws Exception { - RDFParser ntriplesParser = createRDFParser(); - Model model = new LinkedHashModel(); - ntriplesParser.setRDFHandler(new StatementCollector(model)); - ntriplesParser.parse( + parser.parse( new StringReader(" .#endoflinecomment\n"), "http://example/"); assertEquals(1, model.size()); @@ -162,10 +153,7 @@ public void testEndOfLineCommentNoSpace() throws Exception { @Test public void testEndOfLineCommentWithSpaceBefore() throws Exception { - RDFParser ntriplesParser = createRDFParser(); - Model model = new LinkedHashModel(); - ntriplesParser.setRDFHandler(new StatementCollector(model)); - ntriplesParser.parse( + parser.parse( new StringReader(" . #endoflinecomment\n"), "http://example/"); assertEquals(1, model.size()); @@ -174,10 +162,7 @@ public void testEndOfLineCommentWithSpaceBefore() throws Exception { @Test public void testEndOfLineCommentWithSpaceAfter() throws Exception { - RDFParser ntriplesParser = createRDFParser(); - Model model = new LinkedHashModel(); - ntriplesParser.setRDFHandler(new StatementCollector(model)); - ntriplesParser.parse( + parser.parse( new StringReader(" .# endoflinecomment\n"), "http://example/"); assertEquals(1, model.size()); @@ -186,10 +171,7 @@ public void testEndOfLineCommentWithSpaceAfter() throws Exception { @Test public void testEndOfLineCommentWithSpaceBoth() throws Exception { - RDFParser ntriplesParser = createRDFParser(); - Model model = new LinkedHashModel(); - ntriplesParser.setRDFHandler(new StatementCollector(model)); - ntriplesParser.parse( + parser.parse( new StringReader(" . # endoflinecomment\n"), "http://example/"); assertEquals(1, model.size()); @@ -198,10 +180,7 @@ public void testEndOfLineCommentWithSpaceBoth() throws Exception { @Test public void testEndOfLineCommentsNoSpace() throws Exception { - RDFParser ntriplesParser = createRDFParser(); - Model model = new LinkedHashModel(); - ntriplesParser.setRDFHandler(new StatementCollector(model)); - ntriplesParser.parse(new StringReader( + parser.parse(new StringReader( " .#endoflinecomment\n . # endoflinecomment\n"), "http://example/"); assertEquals(2, model.size()); @@ -209,10 +188,7 @@ public void testEndOfLineCommentsNoSpace() throws Exception { @Test public void testEndOfLineCommentsWithSpaceBefore() throws Exception { - RDFParser ntriplesParser = createRDFParser(); - Model model = new LinkedHashModel(); - ntriplesParser.setRDFHandler(new StatementCollector(model)); - ntriplesParser.parse(new StringReader( + parser.parse(new StringReader( " . #endoflinecomment\n . # endoflinecomment\n"), "http://example/"); assertEquals(2, model.size()); @@ -220,10 +196,7 @@ public void testEndOfLineCommentsWithSpaceBefore() throws Exception { @Test public void testEndOfLineCommentsWithSpaceAfter() throws Exception { - RDFParser ntriplesParser = createRDFParser(); - Model model = new LinkedHashModel(); - ntriplesParser.setRDFHandler(new StatementCollector(model)); - ntriplesParser.parse(new StringReader( + parser.parse(new StringReader( " .# endoflinecomment\n . # endoflinecomment\n"), "http://example/"); assertEquals(2, model.size()); @@ -231,10 +204,7 @@ public void testEndOfLineCommentsWithSpaceAfter() throws Exception { @Test public void testEndOfLineCommentsWithSpaceBoth() throws Exception { - RDFParser ntriplesParser = createRDFParser(); - Model model = new LinkedHashModel(); - ntriplesParser.setRDFHandler(new StatementCollector(model)); - ntriplesParser.parse(new StringReader( + parser.parse(new StringReader( " . # endoflinecomment\n . # endoflinecomment\n"), "http://example/"); assertEquals(2, model.size()); @@ -242,10 +212,7 @@ public void testEndOfLineCommentsWithSpaceBoth() throws Exception { @Test public void testEndOfLineEmptyCommentNoSpace() throws Exception { - RDFParser ntriplesParser = createRDFParser(); - Model model = new LinkedHashModel(); - ntriplesParser.setRDFHandler(new StatementCollector(model)); - ntriplesParser.parse(new StringReader(" .#\n"), + parser.parse(new StringReader(" .#\n"), "http://example/"); assertEquals(1, model.size()); assertEquals(Collections.singleton("urn:test:object"), Models.objectStrings(model)); @@ -253,10 +220,7 @@ public void testEndOfLineEmptyCommentNoSpace() throws Exception { @Test public void testEndOfLineEmptyCommentWithSpaceBefore() throws Exception { - RDFParser ntriplesParser = createRDFParser(); - Model model = new LinkedHashModel(); - ntriplesParser.setRDFHandler(new StatementCollector(model)); - ntriplesParser.parse(new StringReader(" . #\n"), + parser.parse(new StringReader(" . #\n"), "http://example/"); assertEquals(1, model.size()); assertEquals(Collections.singleton("urn:test:object"), Models.objectStrings(model)); @@ -264,10 +228,7 @@ public void testEndOfLineEmptyCommentWithSpaceBefore() throws Exception { @Test public void testEndOfLineEmptyCommentWithSpaceAfter() throws Exception { - RDFParser ntriplesParser = createRDFParser(); - Model model = new LinkedHashModel(); - ntriplesParser.setRDFHandler(new StatementCollector(model)); - ntriplesParser.parse(new StringReader(" .# \n"), + parser.parse(new StringReader(" .# \n"), "http://example/"); assertEquals(1, model.size()); assertEquals(Collections.singleton("urn:test:object"), Models.objectStrings(model)); @@ -275,10 +236,7 @@ public void testEndOfLineEmptyCommentWithSpaceAfter() throws Exception { @Test public void testEndOfLineEmptyCommentWithSpaceBoth() throws Exception { - RDFParser ntriplesParser = createRDFParser(); - Model model = new LinkedHashModel(); - ntriplesParser.setRDFHandler(new StatementCollector(model)); - ntriplesParser.parse(new StringReader(" . # \n"), + parser.parse(new StringReader(" . # \n"), "http://example/"); assertEquals(1, model.size()); assertEquals(Collections.singleton("urn:test:object"), Models.objectStrings(model)); @@ -286,10 +244,7 @@ public void testEndOfLineEmptyCommentWithSpaceBoth() throws Exception { @Test public void testBlankNodeIdentifiersRDF11() throws Exception { - RDFParser ntriplesParser = createRDFParser(); - Model model = new LinkedHashModel(); - ntriplesParser.setRDFHandler(new StatementCollector(model)); - ntriplesParser.parse(new StringReader("_:123 _:456 ."), "http://example/"); + parser.parse(new StringReader("_:123 _:456 ."), "http://example/"); assertEquals(1, model.size()); } @@ -300,14 +255,10 @@ public void testSupportedSettings() { @Test public void testUriWithSpaceShouldFailToParse() throws Exception { - RDFParser ntriplesParser = createRDFParser(); - Model model = new LinkedHashModel(); - ntriplesParser.setRDFHandler(new StatementCollector(model)); - String nt = " ."; try { - ntriplesParser.parse(new StringReader(nt), NTRIPLES_TEST_URL); + parser.parse(new StringReader(nt), NTRIPLES_TEST_URL); fail("Should have failed to parse invalid N-Triples uri with space"); } catch (RDFParseException ignored) { } @@ -320,14 +271,10 @@ public void testUriWithSpaceShouldFailToParse() throws Exception { @Test public void testUriWithEscapeCharactersShouldFailToParse() throws Exception { - RDFParser ntriplesParser = createRDFParser(); - Model model = new LinkedHashModel(); - ntriplesParser.setRDFHandler(new StatementCollector(model)); - String nt = " ."; try { - ntriplesParser.parse(new StringReader(nt), NTRIPLES_TEST_URL); + parser.parse(new StringReader(nt), NTRIPLES_TEST_URL); fail("Should have failed to parse invalid N-Triples uri with space"); } catch (RDFParseException ignored) { } @@ -341,10 +288,7 @@ public void testUriWithEscapeCharactersShouldFailToParse() throws Exception { @Test public void testBlankNodeIdentifiersWithUnderScore() throws Exception { // The characters _ and [0-9] may appear anywhere in a blank node label. - RDFParser ntriplesParser = new NTriplesParser(); - Model model = new LinkedHashModel(); - ntriplesParser.setRDFHandler(new StatementCollector(model)); - ntriplesParser.parse(new StringReader("_:123_ _:_456 ."), NTRIPLES_TEST_URL); + parser.parse(new StringReader("_:123_ _:_456 ."), NTRIPLES_TEST_URL); assertEquals(1, model.size()); assertEquals(1, model.subjects().size()); @@ -355,10 +299,7 @@ public void testBlankNodeIdentifiersWithUnderScore() throws Exception { @Test public void testBlankNodeIdentifiersWithDot() throws Exception { // The character . may appear anywhere except the first or last character. - RDFParser ntriplesParser = new NTriplesParser(); - Model model = new LinkedHashModel(); - ntriplesParser.setRDFHandler(new StatementCollector(model)); - ntriplesParser.parse(new StringReader("_:1.23 _:45.6 ."), NTRIPLES_TEST_URL); + parser.parse(new StringReader("_:1.23 _:45.6 ."), NTRIPLES_TEST_URL); assertEquals(1, model.size()); assertEquals(1, model.subjects().size()); @@ -369,11 +310,8 @@ public void testBlankNodeIdentifiersWithDot() throws Exception { @Test public void testBlankNodeIdentifiersWithDotAsFirstCahracter() { // The character . may appear anywhere except the first or last character. - RDFParser ntriplesParser = new NTriplesParser(); - Model model = new LinkedHashModel(); - ntriplesParser.setRDFHandler(new StatementCollector(model)); try { - ntriplesParser.parse(new StringReader("_:123 _:.456 ."), NTRIPLES_TEST_URL); + parser.parse(new StringReader("_:123 _:.456 ."), NTRIPLES_TEST_URL); fail("Should have failed to parse invalid N-Triples bnode with '.' at the begining of the bnode label"); } catch (Exception e) { } @@ -387,11 +325,8 @@ public void testBlankNodeIdentifiersWithDotAsFirstCahracter() { @Test public void testBlankNodeIdentifiersWithDotAsLastCahracter() { // The character . may appear anywhere except the first or last character. - RDFParser ntriplesParser = new NTriplesParser(); - Model model = new LinkedHashModel(); - ntriplesParser.setRDFHandler(new StatementCollector(model)); assertThrows(RDFParseException.class, - () -> ntriplesParser.parse(new StringReader("_:123 _:456. ."), NTRIPLES_TEST_URL)); + () -> parser.parse(new StringReader("_:123 _:456. ."), NTRIPLES_TEST_URL)); assertEquals(0, model.size()); assertEquals(0, model.subjects().size()); assertEquals(0, model.predicates().size()); @@ -412,13 +347,12 @@ public void testBlankNodeIdentifiersWithOtherCharacters() { for (int i = 0; i < charactersList.size(); i++) { Character character = charactersList.get(i); - RDFParser ntriplesParser = new NTriplesParser(); Model model = new LinkedHashModel(); - ntriplesParser.setRDFHandler(new StatementCollector(model)); + parser.setRDFHandler(new StatementCollector(model)); String triple = " _:1" + character + " . "; try { - ntriplesParser.parse(new StringReader(triple), NTRIPLES_TEST_URL); + parser.parse(new StringReader(triple), NTRIPLES_TEST_URL); } catch (Exception e) { fail(" Failed to parse triple : " + triple + " containing character '" + character + "' at index " + i + " in charactersList"); @@ -448,12 +382,11 @@ public void testBlankNodeIdentifiersWithOtherCharactersAsFirstCharacter() { charactersList.add('\u203F'); for (Character character : charactersList) { - RDFParser ntriplesParser = new NTriplesParser(); Model model = new LinkedHashModel(); - ntriplesParser.setRDFHandler(new StatementCollector(model)); + parser.setRDFHandler(new StatementCollector(model)); assertThrows(RDFParseException.class, () -> { - ntriplesParser.parse( + parser.parse( new StringReader(" _:" + character + "1 . "), NTRIPLES_TEST_URL); }); @@ -479,12 +412,11 @@ public void handleComment(String comment) throws RDFHandlerException { @Test public void testHandleComment() throws Exception { - RDFParser ntriplesParser = createRDFParser(); Model model = new LinkedHashModel(); String commentStr = "some comment in it's own line"; CommentCollector cc = new CommentCollector(model); - ntriplesParser.setRDFHandler(cc); - ntriplesParser.parse( + parser.setRDFHandler(cc); + parser.parse( new StringReader(" .\n#" + commentStr + "\n ."), "http://example/"); assertEquals(2, model.size()); @@ -494,16 +426,13 @@ public void testHandleComment() throws Exception { @Test public void testLinenumberDatatypeValidation() throws Exception { - RDFParser ntriplesParser = createRDFParser(); - ntriplesParser.getParserConfig().addNonFatalError(BasicParserSettings.VERIFY_DATATYPE_VALUES); - ntriplesParser.getParserConfig().set(BasicParserSettings.VERIFY_DATATYPE_VALUES, true); - ParseErrorCollector collector = new ParseErrorCollector(); - ntriplesParser.setParseErrorListener(collector); + parser.getParserConfig().addNonFatalError(BasicParserSettings.VERIFY_DATATYPE_VALUES); + parser.getParserConfig().set(BasicParserSettings.VERIFY_DATATYPE_VALUES, true); - ntriplesParser.parse( + parser.parse( new StringReader(" \"invalid\"^^<" + XSD.DATETIME.stringValue() + "> ."), NTRIPLES_TEST_URL); - List errors = collector.getErrors(); + List errors = errorCollector.getErrors(); assertEquals(1, errors.size()); assertTrue(errors.get(0).contains("(1, 32)"), "Unknown line number"); @@ -511,21 +440,92 @@ public void testLinenumberDatatypeValidation() throws Exception { @Test public void testLinenumberLanguagetagValidation() throws Exception { - RDFParser ntriplesParser = createRDFParser(); - ntriplesParser.getParserConfig().addNonFatalError(BasicParserSettings.FAIL_ON_UNKNOWN_LANGUAGES); - ntriplesParser.getParserConfig().set(BasicParserSettings.FAIL_ON_UNKNOWN_LANGUAGES, true); - ntriplesParser.getParserConfig().set(BasicParserSettings.VERIFY_LANGUAGE_TAGS, true); - ParseErrorCollector collector = new ParseErrorCollector(); - ntriplesParser.setParseErrorListener(collector); - - ntriplesParser.parse( + parser.getParserConfig().addNonFatalError(BasicParserSettings.FAIL_ON_UNKNOWN_LANGUAGES); + parser.getParserConfig().set(BasicParserSettings.FAIL_ON_UNKNOWN_LANGUAGES, true); + parser.getParserConfig().set(BasicParserSettings.VERIFY_LANGUAGE_TAGS, true); + + parser.parse( new StringReader(" \"hello\"@inv+alid ."), NTRIPLES_TEST_URL); - List errors = collector.getErrors(); + List errors = errorCollector.getErrors(); assertEquals(1, errors.size()); assertTrue(errors.get(0).contains("(1, 32)"), "Unknown line number"); } + @Test + public void testDirLangStringLTR() { + final String data = " \"Hello\"@en--ltr ."; + dirLangStringTestHelper(data, "en", Literal.LTR_SUFFIX, false, false); + } + + @Test + public void testDirLangStringRTL() { + final String data = " \"שלום\"@he--rtl ."; + dirLangStringTestHelper(data, "he", Literal.RTL_SUFFIX, false, false); + } + + @Test + public void testDirLangStringLTRWithNormalization() { + final String data = " \"Hello\"@en--ltr ."; + dirLangStringTestHelper(data, "en", Literal.LTR_SUFFIX, true, false); + } + + @Test + public void testDirLangStringRTLWithNormalization() { + final String data = " \"שלום\"@HE--rtl ."; + dirLangStringTestHelper(data, "he", Literal.RTL_SUFFIX, true, false); + } + + @Test + public void testBadDirLangString() { + final String data = " \"hello\"@en--unk ."; + dirLangStringTestHelper(data, "", "", true, true); + } + + @Test + public void testBadCapitalizationDirLangString() { + final String data = " \"Hello\"@en--LTR ."; + dirLangStringTestHelper(data, "", "", true, true); + } + + @Test + public void testDirLangStringNoLanguage() throws IOException { + final String data = " \"Hello\"^^ ."; + dirLangStringNoLanguageTestHelper(data); + } + + @Test + public void testTripleTerm() throws IOException { + String data = " <<( )>> ."; + parser.parse(new StringReader(data)); + + assertEquals(1, model.size()); + assertEquals(vf.createTriple(vf.createIRI("http://example/a"), vf.createIRI("http://example/b"), + vf.createIRI("http://example/c")), Models.object(model).get()); + } + + @Test + public void testTripleTermNoWhitespace() throws IOException { + String data = "<<()>>."; + parser.parse(new StringReader(data)); + + assertEquals(1, model.size()); + assertEquals(vf.createTriple(vf.createIRI("http://example/a"), vf.createIRI("http://example/b"), + vf.createIRI("http://example/c")), Models.object(model).get()); + } + + @Test + public void testBadTripleTermSubject() throws IOException { + String data = "<<( )>> ."; + assertThrows(RDFParseException.class, () -> parser.parse(new StringReader(data))); + } + + @Test + public void testBadTripleTermMissingObject() throws IOException { + String data = " <<( )>> ."; + assertThrows(RDFParseException.class, () -> parser.parse(new StringReader(data))); + } + protected abstract RDFParser createRDFParser(); } diff --git a/core/rio/ntriples/src/test/java/org/eclipse/rdf4j/rio/ntriples/AbstractNTriplesWriterTest.java b/core/rio/ntriples/src/test/java/org/eclipse/rdf4j/rio/ntriples/AbstractNTriplesWriterTest.java index 705727b203a..653fd26cf74 100644 --- a/core/rio/ntriples/src/test/java/org/eclipse/rdf4j/rio/ntriples/AbstractNTriplesWriterTest.java +++ b/core/rio/ntriples/src/test/java/org/eclipse/rdf4j/rio/ntriples/AbstractNTriplesWriterTest.java @@ -10,12 +10,21 @@ *******************************************************************************/ package org.eclipse.rdf4j.rio.ntriples; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.io.StringWriter; + +import org.eclipse.rdf4j.model.Model; +import org.eclipse.rdf4j.model.impl.DynamicModelFactory; +import org.eclipse.rdf4j.rio.RDFFormat; import org.eclipse.rdf4j.rio.RDFParserFactory; import org.eclipse.rdf4j.rio.RDFWriterFactory; import org.eclipse.rdf4j.rio.RDFWriterTest; +import org.eclipse.rdf4j.rio.Rio; import org.eclipse.rdf4j.rio.RioSetting; import org.eclipse.rdf4j.rio.helpers.BasicWriterSettings; import org.eclipse.rdf4j.rio.helpers.NTriplesWriterSettings; +import org.junit.jupiter.api.Test; /** * @author Jeen Broekstra @@ -34,4 +43,58 @@ protected RioSetting[] getExpectedSupportedSettings() { }; } + @Test + public void testDirLangString() throws Exception { + dirLangStringTest(RDFFormat.NTRIPLES); + } + + @Test + public void testTripleTerm() { + Model model = new DynamicModelFactory().createEmptyModel(); + String ns = "http://www.example.com/"; + model.setNamespace("", ns); + model.add(vf.createIRI(ns, "s"), vf.createIRI(ns, "p"), + vf.createTriple(vf.createIRI(ns, "s2"), vf.createIRI(ns, "p2"), vf.createIRI(ns, "o"))); + + StringWriter stringWriter = new StringWriter(); + Rio.write(model, stringWriter, RDFFormat.NTRIPLES); + + assertEquals( + " <<( )>> .\n", + stringWriter.toString()); + } + + @Test + public void testNestedTripleTerm() { + Model model = new DynamicModelFactory().createEmptyModel(); + String ns = "http://www.example.com/"; + model.setNamespace("", ns); + model.add(vf.createIRI(ns, "s"), vf.createIRI(ns, "p"), + vf.createTriple(vf.createIRI(ns, "s2"), vf.createIRI(ns, "p2"), + vf.createTriple(vf.createIRI(ns, "s3"), vf.createIRI(ns, "p3"), vf.createIRI(ns, "o")))); + + StringWriter stringWriter = new StringWriter(); + Rio.write(model, stringWriter, RDFFormat.NTRIPLES); + + assertEquals( + " <<( <<( )>> )>> .\n", + stringWriter.toString()); + } + + @Test + public void testNestedTripleTerm2() { + Model model = new DynamicModelFactory().createEmptyModel(); + String ns = "http://www.example.com/"; + model.setNamespace("", ns); + model.add(vf.createBNode("b"), vf.createIRI(ns, "p"), + vf.createTriple(vf.createIRI(ns, "s"), vf.createIRI(ns, "p2"), + vf.createTriple(vf.createBNode("b2"), vf.createIRI(ns, "p3"), vf.createLiteral(9)))); + + StringWriter stringWriter = new StringWriter(); + Rio.write(model, stringWriter, RDFFormat.NTRIPLES); + + assertEquals( + "_:b <<( <<( _:b2 \"9\"^^ )>> )>> .\n", + stringWriter.toString()); + } } diff --git a/core/rio/ntriples/src/test/java/org/eclipse/rdf4j/rio/ntriples/NTriplesWriterTest.java b/core/rio/ntriples/src/test/java/org/eclipse/rdf4j/rio/ntriples/NTriplesWriterTest.java index 4b6c195b81d..9284845efff 100644 --- a/core/rio/ntriples/src/test/java/org/eclipse/rdf4j/rio/ntriples/NTriplesWriterTest.java +++ b/core/rio/ntriples/src/test/java/org/eclipse/rdf4j/rio/ntriples/NTriplesWriterTest.java @@ -10,6 +10,17 @@ *******************************************************************************/ package org.eclipse.rdf4j.rio.ntriples; +import static org.assertj.core.api.Assertions.assertThat; + +import java.io.StringWriter; + +import org.eclipse.rdf4j.model.IRI; +import org.eclipse.rdf4j.model.Model; +import org.eclipse.rdf4j.model.impl.DynamicModelFactory; +import org.eclipse.rdf4j.rio.RDFFormat; +import org.eclipse.rdf4j.rio.Rio; +import org.junit.jupiter.api.Test; + /** * JUnit test for the RDF/JSON parser. * diff --git a/core/rio/pom.xml b/core/rio/pom.xml index 77fc1cee292..ff4f779aa85 100644 --- a/core/rio/pom.xml +++ b/core/rio/pom.xml @@ -4,7 +4,7 @@ org.eclipse.rdf4j rdf4j-core - 5.1.0-SNAPSHOT + 6.0.0 rdf4j-rio pom diff --git a/core/rio/rdfjson/pom.xml b/core/rio/rdfjson/pom.xml index 55a3e3ad374..d3efe502a7b 100644 --- a/core/rio/rdfjson/pom.xml +++ b/core/rio/rdfjson/pom.xml @@ -4,7 +4,7 @@ org.eclipse.rdf4j rdf4j-rio - 5.1.0-SNAPSHOT + 6.0.0 rdf4j-rio-rdfjson RDF4J: Rio - RDF/JSON diff --git a/core/rio/rdfxml/pom.xml b/core/rio/rdfxml/pom.xml index 08a1e0f6eb3..574590fbb4d 100644 --- a/core/rio/rdfxml/pom.xml +++ b/core/rio/rdfxml/pom.xml @@ -4,7 +4,7 @@ org.eclipse.rdf4j rdf4j-rio - 5.1.0-SNAPSHOT + 6.0.0 rdf4j-rio-rdfxml RDF4J: Rio - RDF/XML diff --git a/core/rio/trig/pom.xml b/core/rio/trig/pom.xml index 2736b12a916..8f1864c4173 100644 --- a/core/rio/trig/pom.xml +++ b/core/rio/trig/pom.xml @@ -4,7 +4,7 @@ org.eclipse.rdf4j rdf4j-rio - 5.1.0-SNAPSHOT + 6.0.0 rdf4j-rio-trig RDF4J: Rio - TriG diff --git a/core/rio/trig/src/main/java/org/eclipse/rdf4j/rio/trig/TriGParser.java b/core/rio/trig/src/main/java/org/eclipse/rdf4j/rio/trig/TriGParser.java index d6fe2ee0e93..c4bce7852cb 100644 --- a/core/rio/trig/src/main/java/org/eclipse/rdf4j/rio/trig/TriGParser.java +++ b/core/rio/trig/src/main/java/org/eclipse/rdf4j/rio/trig/TriGParser.java @@ -133,7 +133,8 @@ protected void parseGraph() throws IOException, RDFParseException, RDFHandlerExc unread(c); } c = readCodePoint(); - } else if (c == '<' || TurtleUtil.isPrefixStartChar(c) || (c == ':' && c2 != '-') || (c == '_' && c2 == ':')) { + } else if ((c == '<' && c2 != '<') || TurtleUtil.isPrefixStartChar(c) || (c == ':' && c2 != '-') + || (c == '_' && c2 == ':')) { unread(c); Value value = parseValue(); @@ -230,6 +231,17 @@ protected void parseTriples() throws IOException, RDFParseException, RDFHandlerE if (c != '.' && c != '}') { parsePredicateObjectList(); } + } else if (peekIsReifiedTriple()) { + subject = parseReifiedTriple(); + skipWSC(); + + // if this is not the end of the statement, recurse into the list of + // predicate and objects, using the subject parsed above as the + // subject + // of the statement. + if (peekCodePoint() != '.' && c != '}') { + parsePredicateObjectList(); + } } else { parseSubject(); skipWSC(); diff --git a/core/rio/trig/src/main/java/org/eclipse/rdf4j/rio/trigstar/TriGStarParser.java b/core/rio/trig/src/main/java/org/eclipse/rdf4j/rio/trigstar/TriGStarParser.java index 8eb8ab706e7..835d9b8e586 100644 --- a/core/rio/trig/src/main/java/org/eclipse/rdf4j/rio/trigstar/TriGStarParser.java +++ b/core/rio/trig/src/main/java/org/eclipse/rdf4j/rio/trigstar/TriGStarParser.java @@ -10,17 +10,6 @@ *******************************************************************************/ package org.eclipse.rdf4j.rio.trigstar; -import java.io.IOException; - -import org.eclipse.rdf4j.model.BNode; -import org.eclipse.rdf4j.model.IRI; -import org.eclipse.rdf4j.model.Resource; -import org.eclipse.rdf4j.model.Value; -import org.eclipse.rdf4j.model.ValueFactory; -import org.eclipse.rdf4j.model.impl.SimpleValueFactory; -import org.eclipse.rdf4j.rio.RDFFormat; -import org.eclipse.rdf4j.rio.RDFHandlerException; -import org.eclipse.rdf4j.rio.RDFParseException; import org.eclipse.rdf4j.rio.trig.TriGParser; /** @@ -28,43 +17,6 @@ * * @author Pavel Mihaylov */ +@Deprecated public class TriGStarParser extends TriGParser { - /** - * Creates a new TriGStarParser that will use a {@link SimpleValueFactory} to create RDF-star model objects. - */ - public TriGStarParser() { - super(); - } - - /** - * Creates a new TriGStarParser that will use the supplied ValueFactory to create RDF-star model objects. - * - * @param valueFactory A ValueFactory. - */ - public TriGStarParser(ValueFactory valueFactory) { - super(valueFactory); - } - - @Override - public RDFFormat getRDFFormat() { - return RDFFormat.TRIGSTAR; - } - - @Override - protected Value parseValue() throws IOException, RDFParseException, RDFHandlerException { - if (peekIsTripleValue()) { - return parseTripleValue(); - } - - return super.parseValue(); - } - - @Override - protected void setContext(Resource context) { - if (context != null && !(context instanceof IRI || context instanceof BNode)) { - reportFatalError("Illegal context value: " + context); - } - - super.setContext(context); - } } diff --git a/core/rio/trig/src/main/java/org/eclipse/rdf4j/rio/trigstar/TriGStarParserFactory.java b/core/rio/trig/src/main/java/org/eclipse/rdf4j/rio/trigstar/TriGStarParserFactory.java index ce953bf17eb..7fb421fe3e9 100644 --- a/core/rio/trig/src/main/java/org/eclipse/rdf4j/rio/trigstar/TriGStarParserFactory.java +++ b/core/rio/trig/src/main/java/org/eclipse/rdf4j/rio/trigstar/TriGStarParserFactory.java @@ -10,29 +10,13 @@ *******************************************************************************/ package org.eclipse.rdf4j.rio.trigstar; -import org.eclipse.rdf4j.rio.RDFFormat; -import org.eclipse.rdf4j.rio.RDFParser; -import org.eclipse.rdf4j.rio.RDFParserFactory; +import org.eclipse.rdf4j.rio.turtle.TurtleParserFactory; /** * An {@link RDFParserFactory} for TriG-star parsers. * * @author Pavel Mihaylov */ -public class TriGStarParserFactory implements RDFParserFactory { - /** - * Returns {@link RDFFormat#TRIGSTAR}. - */ - @Override - public RDFFormat getRDFFormat() { - return RDFFormat.TRIGSTAR; - } - - /** - * Returns a new instance of {@link TriGStarParser}. - */ - @Override - public RDFParser getParser() { - return new TriGStarParser(); - } -} +@Deprecated +public class TriGStarParserFactory extends TurtleParserFactory { +} \ No newline at end of file diff --git a/core/rio/trig/src/main/java/org/eclipse/rdf4j/rio/trigstar/TriGStarWriter.java b/core/rio/trig/src/main/java/org/eclipse/rdf4j/rio/trigstar/TriGStarWriter.java index 1298090ebf0..689a1b120ac 100644 --- a/core/rio/trig/src/main/java/org/eclipse/rdf4j/rio/trigstar/TriGStarWriter.java +++ b/core/rio/trig/src/main/java/org/eclipse/rdf4j/rio/trigstar/TriGStarWriter.java @@ -10,14 +10,10 @@ *******************************************************************************/ package org.eclipse.rdf4j.rio.trigstar; -import java.io.IOException; import java.io.OutputStream; import java.io.Writer; -import org.eclipse.rdf4j.common.lang.FileFormat; import org.eclipse.rdf4j.common.net.ParsedIRI; -import org.eclipse.rdf4j.model.Triple; -import org.eclipse.rdf4j.rio.RDFFormat; import org.eclipse.rdf4j.rio.trig.TriGWriter; /** @@ -26,6 +22,7 @@ * * @author Pavel Mihaylov */ +@Deprecated public class TriGStarWriter extends TriGWriter { /** * Creates a new TriGStarWriter that will write to the supplied OutputStream. @@ -64,21 +61,4 @@ public TriGStarWriter(Writer writer) { public TriGStarWriter(Writer writer, ParsedIRI baseIRI) { super(writer, baseIRI); } - - @Override - public RDFFormat getRDFFormat() { - return RDFFormat.TRIGSTAR; - } - - @Override - public boolean acceptsFileFormat(FileFormat format) { - // since TriG-star is a superset of regular TriG, this Sink also accepts regular TriG - // serialization - return super.acceptsFileFormat(format) || RDFFormat.TRIG.equals(format); - } - - @Override - protected void writeTriple(Triple triple, boolean canShorten) throws IOException { - writeTripleRDFStar(triple, canShorten); - } -} +} \ No newline at end of file diff --git a/core/rio/trig/src/main/java/org/eclipse/rdf4j/rio/trigstar/TriGStarWriterFactory.java b/core/rio/trig/src/main/java/org/eclipse/rdf4j/rio/trigstar/TriGStarWriterFactory.java index 1b0943783c3..5b67dc4d3d9 100644 --- a/core/rio/trig/src/main/java/org/eclipse/rdf4j/rio/trigstar/TriGStarWriterFactory.java +++ b/core/rio/trig/src/main/java/org/eclipse/rdf4j/rio/trigstar/TriGStarWriterFactory.java @@ -10,63 +10,14 @@ *******************************************************************************/ package org.eclipse.rdf4j.rio.trigstar; -import java.io.OutputStream; -import java.io.Writer; -import java.net.URISyntaxException; - -import org.eclipse.rdf4j.common.net.ParsedIRI; -import org.eclipse.rdf4j.rio.RDFFormat; -import org.eclipse.rdf4j.rio.RDFWriter; import org.eclipse.rdf4j.rio.RDFWriterFactory; +import org.eclipse.rdf4j.rio.trig.TriGWriterFactory; /** * An {@link RDFWriterFactory} for TriG-star writers. * * @author Pavel Mihaylov */ -public class TriGStarWriterFactory implements RDFWriterFactory { - - /** - * Returns {@link RDFFormat#TRIGSTAR}. - */ - @Override - public RDFFormat getRDFFormat() { - return RDFFormat.TRIGSTAR; - } - - /** - * Returns a new instance of {@link TriGStarWriter}. - */ - @Override - public RDFWriter getWriter(OutputStream out) { - return new TriGStarWriter(out); - } - - /** - * Returns a new instance of {@link TriGStarWriter}. - * - * @throws URISyntaxException - */ - @Override - public RDFWriter getWriter(OutputStream out, String baseURI) throws URISyntaxException { - return new TriGStarWriter(out, new ParsedIRI(baseURI)); - } - - /** - * Returns a new instance of {@link TriGStarWriter}. - */ - @Override - public RDFWriter getWriter(Writer writer) { - return new TriGStarWriter(writer); - } - - /** - * Returns a new instance of {@link TriGStarWriter}. - * - * @throws URISyntaxException - */ - @Override - public RDFWriter getWriter(Writer writer, String baseURI) throws URISyntaxException { - return new TriGStarWriter(writer, new ParsedIRI(baseURI)); - } -} +@Deprecated +public class TriGStarWriterFactory extends TriGWriterFactory { +} \ No newline at end of file diff --git a/core/rio/trig/src/test/java/org/eclipse/rdf4j/rio/trig/AbstractTriGWriterTest.java b/core/rio/trig/src/test/java/org/eclipse/rdf4j/rio/trig/AbstractTriGWriterTest.java index 820f9304fda..f7b2df2fde5 100644 --- a/core/rio/trig/src/test/java/org/eclipse/rdf4j/rio/trig/AbstractTriGWriterTest.java +++ b/core/rio/trig/src/test/java/org/eclipse/rdf4j/rio/trig/AbstractTriGWriterTest.java @@ -10,12 +10,14 @@ *******************************************************************************/ package org.eclipse.rdf4j.rio.trig; +import org.eclipse.rdf4j.rio.RDFFormat; import org.eclipse.rdf4j.rio.RDFParserFactory; import org.eclipse.rdf4j.rio.RDFWriterFactory; import org.eclipse.rdf4j.rio.RDFWriterTest; import org.eclipse.rdf4j.rio.RioSetting; import org.eclipse.rdf4j.rio.helpers.BasicWriterSettings; import org.eclipse.rdf4j.rio.helpers.TurtleWriterSettings; +import org.junit.jupiter.api.Test; /** * @author Jeen Broesktra @@ -36,4 +38,9 @@ protected RioSetting[] getExpectedSupportedSettings() { TurtleWriterSettings.ABBREVIATE_NUMBERS }; } + + @Test + public void testDirLangString() throws Exception { + dirLangStringTest(RDFFormat.TRIG); + } } diff --git a/core/rio/trig/src/test/java/org/eclipse/rdf4j/rio/trig/TriGParserCustomTest.java b/core/rio/trig/src/test/java/org/eclipse/rdf4j/rio/trig/TriGParserCustomTest.java index 7f60657a274..2ea3a7adc8e 100644 --- a/core/rio/trig/src/test/java/org/eclipse/rdf4j/rio/trig/TriGParserCustomTest.java +++ b/core/rio/trig/src/test/java/org/eclipse/rdf4j/rio/trig/TriGParserCustomTest.java @@ -12,26 +12,30 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; +import java.io.IOException; import java.io.StringReader; +import java.math.BigInteger; import java.util.concurrent.TimeUnit; import org.eclipse.rdf4j.model.BNode; +import org.eclipse.rdf4j.model.Literal; import org.eclipse.rdf4j.model.Model; +import org.eclipse.rdf4j.model.Resource; import org.eclipse.rdf4j.model.ValueFactory; import org.eclipse.rdf4j.model.impl.LinkedHashModel; import org.eclipse.rdf4j.model.impl.SimpleValueFactory; import org.eclipse.rdf4j.model.util.Models; -import org.eclipse.rdf4j.rio.ParserConfig; +import org.eclipse.rdf4j.model.vocabulary.RDF; +import org.eclipse.rdf4j.rio.AbstractParserTest; import org.eclipse.rdf4j.rio.RDFFormat; import org.eclipse.rdf4j.rio.RDFParseException; import org.eclipse.rdf4j.rio.RDFParser; import org.eclipse.rdf4j.rio.Rio; -import org.eclipse.rdf4j.rio.helpers.BasicParserSettings; -import org.eclipse.rdf4j.rio.helpers.ParseErrorCollector; import org.eclipse.rdf4j.rio.helpers.StatementCollector; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -43,34 +47,23 @@ * @author Peter Ansell */ @Timeout(value = 10, unit = TimeUnit.MINUTES) -public class TriGParserCustomTest { - private ValueFactory vf; +public class TriGParserCustomTest extends AbstractParserTest { - private ParserConfig settingsNoVerifyLangTag; + private Model model; - private ParseErrorCollector errors; + private ValueFactory vf = SimpleValueFactory.getInstance(); - private RDFParser parser; - - private StatementCollector statementCollector; - - /** - */ @BeforeEach public void setUp() { - vf = SimpleValueFactory.getInstance(); - settingsNoVerifyLangTag = new ParserConfig(); - settingsNoVerifyLangTag.set(BasicParserSettings.VERIFY_LANGUAGE_TAGS, false); - errors = new ParseErrorCollector(); - parser = Rio.createParser(RDFFormat.TRIG); - statementCollector = new StatementCollector(new LinkedHashModel()); - parser.setRDFHandler(statementCollector); + model = new LinkedHashModel(); + statementCollector = new StatementCollector(model); + super.setUp(); } @Test public void testSPARQLGraphKeyword() throws Exception { - Model model = Rio.parse(new StringReader("GRAPH { [] \"Foo\" }"), "", - RDFFormat.TRIG); + String data = "GRAPH { [] \"Foo\" }"; + parser.parse(new StringReader(data)); assertEquals(1, model.size()); assertNotNull(model.contexts().iterator().next()); @@ -82,8 +75,8 @@ public void testSPARQLGraphKeyword() throws Exception { @Test public void testGraph() throws Exception { - Model model = Rio.parse(new StringReader(" { [] \"Foo\" }"), "", - RDFFormat.TRIG); + String data = " { [] \"Foo\" }"; + parser.parse(new StringReader(data)); assertEquals(1, model.size()); assertNotNull(model.contexts().iterator().next()); @@ -95,9 +88,8 @@ public void testGraph() throws Exception { @Test public void testGraphLocalNameGraph() throws Exception { - Model model = Rio.parse( - new StringReader("@prefix graph: .\n graph:a { [] \"Foo\" }"), "", - RDFFormat.TRIG); + String data = "@prefix graph: .\n graph:a { [] \"Foo\" }"; + parser.parse(new StringReader(data)); assertEquals(1, model.size()); assertNotNull(model.contexts().iterator().next()); @@ -109,9 +101,8 @@ public void testGraphLocalNameGraph() throws Exception { @Test public void testGraphLocalNameIntegerGraph() throws Exception { - Model model = Rio.parse( - new StringReader("@prefix graph: .\n graph:1 { [] \"Foo\" }"), "", - RDFFormat.TRIG); + String data = "@prefix graph: .\n graph:1 { [] \"Foo\" }"; + parser.parse(new StringReader(data)); assertEquals(1, model.size()); assertNotNull(model.contexts().iterator().next()); @@ -123,9 +114,8 @@ public void testGraphLocalNameIntegerGraph() throws Exception { @Test public void testGraphLocalNameNotGraph() throws Exception { - Model model = Rio.parse( - new StringReader("@prefix ex: .\n ex:a { [] \"Foo\" }"), "", - RDFFormat.TRIG); + String data = "@prefix ex: .\n ex:a { [] \"Foo\" }"; + parser.parse(new StringReader(data)); assertEquals(1, model.size()); assertNotNull(model.contexts().iterator().next()); @@ -137,9 +127,8 @@ public void testGraphLocalNameNotGraph() throws Exception { @Test public void testGraphLocalNameIntegerNotGraph() throws Exception { - Model model = Rio.parse( - new StringReader("@prefix ex: .\n ex:1 { [] \"Foo\" }"), "", - RDFFormat.TRIG); + String data = "@prefix ex: .\n ex:1 { [] \"Foo\" }"; + parser.parse(new StringReader(data)); assertEquals(1, model.size()); assertNotNull(model.contexts().iterator().next()); @@ -151,40 +140,38 @@ public void testGraphLocalNameIntegerNotGraph() throws Exception { @Test public void testTrailingSemicolon() throws Exception { - Rio.parse(new StringReader("{ ;}"), "", RDFFormat.TRIG); + parser.parse(new StringReader("{ ;}"), ""); } @Test public void testAnonymousGraph1() throws Exception { - Rio.parse(new StringReader("PREFIX : \n GRAPH [] { :s :p :o }"), "", RDFFormat.TRIG); + parser.parse(new StringReader("PREFIX : \n GRAPH [] { :s :p :o }"), ""); } @Test public void testAnonymousGraph2() throws Exception { - Rio.parse(new StringReader("PREFIX : \n [] { :s :p :o }"), "", RDFFormat.TRIG); + parser.parse(new StringReader("PREFIX : \n [] { :s :p :o }"), ""); } @Test public void testTurtle() throws Exception { - Rio.parse(new StringReader(" "), "", RDFFormat.TRIG); + parser.parse(new StringReader(" "), ""); } @Test public void testMinimalWhitespace() throws Exception { - Rio.parse(this.getClass().getResourceAsStream("/testcases/trig/trig-syntax-minimal-whitespace-01.trig"), "", - RDFFormat.TRIG); + parser.parse(this.getClass().getResourceAsStream("/testcases/trig/trig-syntax-minimal-whitespace-01.trig"), ""); } @Test public void testMinimalWhitespaceLine12() throws Exception { - Rio.parse(new StringReader("@prefix : . {_:s:p :o ._:s:p\"Alice\". _:s:p _:o .}"), "", - RDFFormat.TRIG); + parser.parse(new StringReader("@prefix : . {_:s:p :o ._:s:p\"Alice\". _:s:p _:o .}"), ""); } @Test public void testBadPname02() throws Exception { try { - Rio.parse(new StringReader("@prefix : . {:a%2 :p :o .}"), "", RDFFormat.TRIG); + parser.parse(new StringReader("@prefix : . {:a%2 :p :o .}"), ""); fail("Did not receive expected exception"); } catch (RDFParseException e) { @@ -198,35 +185,153 @@ public void testSupportedSettings() { @Test public void testParseTruePrefix() throws Exception { - Rio.parse(new StringReader("@prefix true: . {true:s true:p true:o .}"), "", RDFFormat.TRIG); + parser.parse(new StringReader("@prefix true: . {true:s true:p true:o .}"), ""); } @Test public void testParseTrig_booleanLiteral() throws Exception { String trig = "{\n" + " true.\n" + "}"; - Model m = Rio.parse(new StringReader(trig), "http://ex/", RDFFormat.TRIG); - assertEquals(1, m.size()); + parser.parse(new StringReader(trig), "http://ex/"); + assertEquals(1, model.size()); } @Test public void testParseTrig_booleanLiteral_space() throws Exception { String trig = "{\n" + " true .\n" + "}"; - Model m = Rio.parse(new StringReader(trig), "http://ex/", RDFFormat.TRIG); - assertEquals(1, m.size()); + parser.parse(new StringReader(trig), "http://ex/"); + assertEquals(1, model.size()); } @Test public void testParseTrig_intLiteral() throws Exception { String trig = "{\n" + " 1.\n" + "}"; - Model m = Rio.parse(new StringReader(trig), "http://ex/", RDFFormat.TRIG); - assertEquals(1, Models.objectLiteral(m).get().intValue()); + parser.parse(new StringReader(trig), "http://ex/"); + assertEquals(1, Models.objectLiteral(model).get().intValue()); } @Test public void testParseTrig_doubleLiteral() throws Exception { String trig = "{\n" + " 1.2.\n" + "}"; - Model m = Rio.parse(new StringReader(trig), "http://ex/", RDFFormat.TRIG); - assertEquals(1.2d, Models.objectLiteral(m).get().doubleValue(), 0.01); + parser.parse(new StringReader(trig), "http://ex/"); + assertEquals(1.2d, Models.objectLiteral(model).get().doubleValue(), 0.01); + } + + @Test + public void testDirLangStringRTLNoContext() { + String data = " \"שלום\"@he--rtl"; + dirLangStringTest(data, false, "he", Literal.RTL_SUFFIX, false, false); + } + + @Test + public void testDirLangStringRTLWithContext() { + String data = " \"שלום\"@he--rtl"; + dirLangStringTest(data, true, "he", Literal.RTL_SUFFIX, false, false); + } + + @Test + public void testDirLangStringLTRWithNormalizationNoContext() { + String data = " \"Hello\"@en--ltr"; + dirLangStringTest(data, false, "en", Literal.LTR_SUFFIX, true, false); + } + + @Test + public void testDirLangStringLTRWithNormalizationWithContext() { + String data = " \"Hello\"@en--ltr"; + dirLangStringTest(data, true, "en", Literal.LTR_SUFFIX, true, false); + } + + @Test + public void testBadDirLangStringNoContext() { + String data = " \"hello\"@en--unk"; + dirLangStringTest(data, false, "", "", true, true); + } + + @Test + public void testBadDirLangStringWithContext() { + String data = " \"hello\"@en--unk"; + dirLangStringTest(data, true, "", "", true, true); + } + + @Test + public void testBadCapitalizationDirLangStringNoContext() { + String data = " \"Hello\"@en--LTR"; + dirLangStringTest(data, false, "", "", true, true); } + @Test + public void testBadCapitalizationDirLangStringWithContext() { + final String data = " \"Hello\"@en--LTR"; + dirLangStringTest(data, true, "", "", true, true); + } + + @Test + public void testDirLangStringNoLanguage() throws IOException { + final String data = " \"Hello\"^^ ."; + dirLangStringNoLanguageTestHelper(data); + } + + private void dirLangStringTest( + final String triple, final boolean withContext, final String expectedLang, final String expectedBaseDir, + final boolean normalize, + final boolean shouldCauseException) { + final String data = (withContext ? " { " : "") + triple + " ." + + (withContext ? " }" : ""); + + dirLangStringTestHelper(data, expectedLang, expectedBaseDir, normalize, shouldCauseException); + } + + @Test + public void testSubjectReifiedTriple() throws IOException { + String data = "PREFIX : \n" + + "<<:s :p :o>> :q 123 ."; + try { + Model model = new LinkedHashModel(); + statementCollector = new StatementCollector(model); + parser.setRDFHandler(statementCollector); + parser.parse(new StringReader(data)); + + assertThat(errorCollector.getErrors()).isEmpty(); + + assertThat(model).hasSize(2); + + Model reifyingTriples = model.filter(null, RDF.REIFIES, vf.createTriple(vf.createIRI("http://example/s"), + vf.createIRI("http://example/p"), vf.createIRI("http://example/o"))); + assertThat(reifyingTriples).hasSize(1); + Resource reifier = Models.subject(reifyingTriples).get(); + assertInstanceOf(BNode.class, reifier); + assertTrue(model.contains(reifier, vf.createIRI("http://example/q"), + vf.createLiteral(BigInteger.valueOf(123)))); + } catch (RDFParseException e) { + fail("parse error on correct data: " + e.getMessage()); + } + } + + @Test + public void testSubjectReifiedTripleNoPredicateObjectList() throws IOException { + String data = "PREFIX : \n" + + "<<:s :p :o >> ."; + try { + Model model = new LinkedHashModel(); + statementCollector = new StatementCollector(model); + parser.setRDFHandler(statementCollector); + parser.parse(new StringReader(data)); + + assertThat(errorCollector.getErrors()).isEmpty(); + + assertThat(model).hasSize(1); + + Model reifyingTriples = model.filter(null, RDF.REIFIES, vf.createTriple(vf.createIRI("http://example/s"), + vf.createIRI("http://example/p"), vf.createIRI("http://example/o"))); + assertThat(reifyingTriples).hasSize(1); + Resource reifier = Models.subject(reifyingTriples).get(); + assertInstanceOf(BNode.class, reifier); + } catch (RDFParseException e) { + fail("parse error on correct data: " + e.getMessage()); + } + } + + @Override + public RDFParser createRDFParser() { + return new TriGParser(); + } } diff --git a/core/rio/trig/src/test/java/org/eclipse/rdf4j/rio/trigstar/TriGStarHandlingTest.java b/core/rio/trig/src/test/java/org/eclipse/rdf4j/rio/trigstar/TriGStarHandlingTest.java deleted file mode 100644 index 80ed7d08c59..00000000000 --- a/core/rio/trig/src/test/java/org/eclipse/rdf4j/rio/trigstar/TriGStarHandlingTest.java +++ /dev/null @@ -1,32 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2020 Eclipse RDF4J contributors. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Distribution License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * SPDX-License-Identifier: BSD-3-Clause - *******************************************************************************/ -package org.eclipse.rdf4j.rio.trigstar; - -import java.io.OutputStream; - -import org.eclipse.rdf4j.rio.AbstractParserHandlingTest; -import org.eclipse.rdf4j.rio.RDFParser; -import org.eclipse.rdf4j.rio.RDFWriter; - -/** - * @author Pavel Mihaylov - */ -public class TriGStarHandlingTest extends AbstractParserHandlingTest { - @Override - protected RDFParser getParser() { - return new TriGStarParser(); - } - - @Override - protected RDFWriter createWriter(OutputStream output) { - return new TriGStarWriter(output); - } -} diff --git a/core/rio/trig/src/test/java/org/eclipse/rdf4j/rio/trigstar/TriGStarMimeTypeRDFFormatTest.java b/core/rio/trig/src/test/java/org/eclipse/rdf4j/rio/trigstar/TriGStarMimeTypeRDFFormatTest.java deleted file mode 100644 index c1fe8659478..00000000000 --- a/core/rio/trig/src/test/java/org/eclipse/rdf4j/rio/trigstar/TriGStarMimeTypeRDFFormatTest.java +++ /dev/null @@ -1,62 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2020 Eclipse RDF4J contributors. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Distribution License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * SPDX-License-Identifier: BSD-3-Clause - *******************************************************************************/ -package org.eclipse.rdf4j.rio.trigstar; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -import java.io.IOException; -import java.io.StringWriter; -import java.io.Writer; - -import org.eclipse.rdf4j.rio.RDFFormat; -import org.eclipse.rdf4j.rio.Rio; -import org.junit.jupiter.api.Test; - -/** - * @author Pavel Mihaylov - */ -public class TriGStarMimeTypeRDFFormatTest { - private final RDFFormat expectedRDFFormat = RDFFormat.TRIGSTAR; - - @Test - public void testApplicationXTrigStar() { - assertEquals(expectedRDFFormat, Rio.getParserFormatForMIMEType("application/x-trigstar") - .orElseThrow(Rio.unsupportedFormat(expectedRDFFormat))); - } - - @Test - public void testApplicationXTrigStarUtf8() { - assertEquals(RDFFormat.TRIGSTAR, Rio.getParserFormatForMIMEType("application/x-trigstar;charset=UTF-8") - .orElseThrow(Rio.unsupportedFormat(expectedRDFFormat))); - } - - @Test - public void testRDFFormatParser() { - assertEquals(expectedRDFFormat, new TriGStarParser().getRDFFormat()); - } - - @Test - public void testRDFFormatWriter() throws IOException { - try (Writer w = new StringWriter()) { - assertEquals(expectedRDFFormat, new TriGStarWriter(w).getRDFFormat()); - } - } - - @Test - public void testRDFFormatParserFactory() { - assertEquals(expectedRDFFormat, new TriGStarParserFactory().getRDFFormat()); - } - - @Test - public void testRDFFormatWriterFactory() { - assertEquals(expectedRDFFormat, new TriGStarWriterFactory().getRDFFormat()); - } -} diff --git a/core/rio/trig/src/test/java/org/eclipse/rdf4j/rio/trigstar/TriGStarParserTest.java b/core/rio/trig/src/test/java/org/eclipse/rdf4j/rio/trigstar/TriGStarParserTest.java deleted file mode 100644 index 038d37062ea..00000000000 --- a/core/rio/trig/src/test/java/org/eclipse/rdf4j/rio/trigstar/TriGStarParserTest.java +++ /dev/null @@ -1,145 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2020 Eclipse RDF4J contributors. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Distribution License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * SPDX-License-Identifier: BSD-3-Clause - *******************************************************************************/ -package org.eclipse.rdf4j.rio.trigstar; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assertions.fail; - -import java.io.IOException; -import java.io.InputStream; -import java.io.Reader; -import java.io.StringReader; -import java.util.Collection; - -import org.eclipse.rdf4j.model.IRI; -import org.eclipse.rdf4j.model.Literal; -import org.eclipse.rdf4j.model.Statement; -import org.eclipse.rdf4j.model.Triple; -import org.eclipse.rdf4j.model.ValueFactory; -import org.eclipse.rdf4j.model.impl.SimpleValueFactory; -import org.eclipse.rdf4j.model.vocabulary.DCTERMS; -import org.eclipse.rdf4j.model.vocabulary.FOAF; -import org.eclipse.rdf4j.model.vocabulary.XSD; -import org.eclipse.rdf4j.rio.RDFParseException; -import org.eclipse.rdf4j.rio.helpers.ParseErrorCollector; -import org.eclipse.rdf4j.rio.helpers.SimpleParseLocationListener; -import org.eclipse.rdf4j.rio.helpers.StatementCollector; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -/** - * @author Pavel Mihaylov - */ -public class TriGStarParserTest { - private TriGStarParser parser; - - private final ValueFactory vf = SimpleValueFactory.getInstance(); - - private final ParseErrorCollector errorCollector = new ParseErrorCollector(); - - private final StatementCollector statementCollector = new StatementCollector(); - - private final String baseURI = "http://example.org/"; - - private final SimpleParseLocationListener locationListener = new SimpleParseLocationListener(); - - @BeforeEach - public void setUp() { - parser = new TriGStarParser(); - parser.setParseErrorListener(errorCollector); - parser.setRDFHandler(statementCollector); - parser.setParseLocationListener(locationListener); - } - - @Test - public void testParseRDFStarData() throws IOException { - IRI graph = vf.createIRI("http://example.com/rdfstar"); - - IRI bob = vf.createIRI("http://example.com/bob"); - IRI alice = vf.createIRI("http://example.com/alice"); - IRI book = vf.createIRI("http://example.com/book"); - IRI otherbook = vf.createIRI("http://example.com/otherbook"); - IRI bobshomepage = vf.createIRI("http://example.com/bobshomepage"); - IRI a = vf.createIRI("http://example.org/a"); - IRI b = vf.createIRI("http://example.com/b"); - IRI c = vf.createIRI("http://example.com/c"); - IRI valid = vf.createIRI("http://example.com/valid"); - Literal abcDate = vf.createLiteral("1999-08-16", XSD.DATE); - Literal birthDate = vf.createLiteral("1908-03-18", XSD.DATE); - Literal titleEn = vf.createLiteral("Example book", "en"); - Literal titleDe = vf.createLiteral("Beispielbuch", "de"); - Literal titleEnUs = vf.createLiteral("Example Book", "en-US"); - - Triple bobCreatedBook = vf.createTriple(bob, DCTERMS.CREATED, book); - Triple aliceKnowsBobCreatedBook = vf.createTriple(alice, FOAF.KNOWS, bobCreatedBook); - Triple bobCreatedBookKnowsAlice = vf.createTriple(bobCreatedBook, FOAF.KNOWS, alice); - Triple bookCreatorAlice = vf.createTriple(book, DCTERMS.CREATOR, alice); - Triple aliceCreatedBook = vf.createTriple(alice, DCTERMS.CREATED, book); - Triple abc = vf.createTriple(a, b, c); - Triple bobBirthdayDate = vf.createTriple(bob, FOAF.BIRTHDAY, birthDate); - Triple bookTitleEn = vf.createTriple(book, DCTERMS.TITLE, titleEn); - Triple bookTitleDe = vf.createTriple(book, DCTERMS.TITLE, titleDe); - Triple bookTitleEnUs = vf.createTriple(book, DCTERMS.TITLE, titleEnUs); - - try (InputStream in = this.getClass().getResourceAsStream("/test-rdfstar.trigs")) { - parser.parse(in, baseURI); - - Collection stmts = statementCollector.getStatements(); - - assertEquals(10, stmts.size()); - - assertTrue(stmts.contains(vf.createStatement(bob, FOAF.KNOWS, aliceKnowsBobCreatedBook, graph))); - assertTrue(stmts.contains(vf.createStatement(bobCreatedBookKnowsAlice, DCTERMS.SOURCE, otherbook, graph))); - assertTrue(stmts.contains(vf.createStatement(bobshomepage, DCTERMS.SOURCE, bookCreatorAlice, graph))); - assertTrue(stmts.contains(vf.createStatement(bookCreatorAlice, DCTERMS.SOURCE, bobshomepage, graph))); - assertTrue(stmts.contains(vf.createStatement(bookCreatorAlice, DCTERMS.REQUIRES, aliceCreatedBook, graph))); - assertTrue(stmts.contains(vf.createStatement(abc, valid, abcDate, graph))); - assertTrue(stmts.contains(vf.createStatement(bobBirthdayDate, DCTERMS.SOURCE, bobshomepage, graph))); - assertTrue(stmts.contains(vf.createStatement(bookTitleEn, DCTERMS.SOURCE, bobshomepage, graph))); - assertTrue(stmts.contains(vf.createStatement(bookTitleDe, DCTERMS.SOURCE, bobshomepage, graph))); - assertTrue(stmts.contains(vf.createStatement(bookTitleEnUs, DCTERMS.SOURCE, bobshomepage, graph))); - } - } - - @Test - public void testTripleInPredicate() throws IOException { - String data = "@prefix ex: .\ngraph ex:G { ex:Example <<>> \"foo\"}"; - try (Reader r = new StringReader(data)) { - parser.parse(r, baseURI); - fail("Must fail with RDFParseException"); - } catch (RDFParseException e) { - assertEquals("Illegal predicate value: <> [line 2]", e.getMessage()); - } - } - - @Test - public void testTripleInGraph() throws IOException { - String data = "@prefix ex: .\ngraph << >> {ex:Example ex:p \"foo\" }"; - try (Reader r = new StringReader(data)) { - parser.parse(r, baseURI); - fail("Must fail with RDFParseException"); - } catch (RDFParseException e) { - assertEquals("Illegal context value: <> [line 2]", e.getMessage()); - } - } - - @Test - public void testTripleInDatatype() throws IOException { - String data = "@prefix ex: .\ngraph ex:g { ex:Example ex:p \"foo\"^^<<>> }"; - try (Reader r = new StringReader(data)) { - parser.parse(r, baseURI); - fail("Must fail with RDFParseException"); - } catch (RDFParseException e) { - assertEquals("Illegal datatype value: <> [line 2]", e.getMessage()); - } - } -} diff --git a/core/rio/trig/src/test/java/org/eclipse/rdf4j/rio/trigstar/TriGStarPrettyWriterTest.java b/core/rio/trig/src/test/java/org/eclipse/rdf4j/rio/trigstar/TriGStarPrettyWriterTest.java deleted file mode 100644 index 92a5fefaa78..00000000000 --- a/core/rio/trig/src/test/java/org/eclipse/rdf4j/rio/trigstar/TriGStarPrettyWriterTest.java +++ /dev/null @@ -1,29 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2020 Eclipse RDF4J contributors. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Distribution License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * SPDX-License-Identifier: BSD-3-Clause - *******************************************************************************/ -package org.eclipse.rdf4j.rio.trigstar; - -import org.eclipse.rdf4j.rio.WriterConfig; -import org.eclipse.rdf4j.rio.helpers.BasicWriterSettings; -import org.eclipse.rdf4j.rio.trig.AbstractTriGWriterTest; - -/** - * @author Pavel Mihaylov - */ -public class TriGStarPrettyWriterTest extends AbstractTriGWriterTest { - public TriGStarPrettyWriterTest() { - super(new TriGStarWriterFactory(), new TriGStarParserFactory()); - } - - @Override - protected void setupWriterConfig(WriterConfig config) { - config.set(BasicWriterSettings.PRETTY_PRINT, true); - } -} diff --git a/core/rio/trig/src/test/java/org/eclipse/rdf4j/rio/trigstar/TriGStarWriterTest.java b/core/rio/trig/src/test/java/org/eclipse/rdf4j/rio/trigstar/TriGStarWriterTest.java deleted file mode 100644 index 79e09022263..00000000000 --- a/core/rio/trig/src/test/java/org/eclipse/rdf4j/rio/trigstar/TriGStarWriterTest.java +++ /dev/null @@ -1,30 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2020 Eclipse RDF4J contributors. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Distribution License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * SPDX-License-Identifier: BSD-3-Clause - *******************************************************************************/ -package org.eclipse.rdf4j.rio.trigstar; - -import org.eclipse.rdf4j.rio.WriterConfig; -import org.eclipse.rdf4j.rio.helpers.BasicWriterSettings; -import org.eclipse.rdf4j.rio.trig.AbstractTriGWriterTest; - -/** - * @author Pavel Mihaylov - */ -public class TriGStarWriterTest extends AbstractTriGWriterTest { - public TriGStarWriterTest() { - super(new TriGStarWriterFactory(), new TriGStarParserFactory()); - } - - @Override - protected void setupWriterConfig(WriterConfig config) { - config.set(BasicWriterSettings.PRETTY_PRINT, false); - } - -} diff --git a/core/rio/trix/pom.xml b/core/rio/trix/pom.xml index a8b99df7634..ff732f9a2de 100644 --- a/core/rio/trix/pom.xml +++ b/core/rio/trix/pom.xml @@ -4,7 +4,7 @@ org.eclipse.rdf4j rdf4j-rio - 5.1.0-SNAPSHOT + 6.0.0 rdf4j-rio-trix RDF4J: Rio - TriX diff --git a/core/rio/trix/src/main/java/org/eclipse/rdf4j/rio/trix/TriXWriter.java b/core/rio/trix/src/main/java/org/eclipse/rdf4j/rio/trix/TriXWriter.java index 9ba40282e9d..5d000ae091c 100644 --- a/core/rio/trix/src/main/java/org/eclipse/rdf4j/rio/trix/TriXWriter.java +++ b/core/rio/trix/src/main/java/org/eclipse/rdf4j/rio/trix/TriXWriter.java @@ -51,7 +51,6 @@ public class TriXWriter extends AbstractRDFWriter implements CharSink { private boolean inActiveContext = false; - private boolean convertRDFStar; private Resource currentContext = null; /** diff --git a/core/rio/turtle/pom.xml b/core/rio/turtle/pom.xml index 087f4221601..05e11634aa2 100644 --- a/core/rio/turtle/pom.xml +++ b/core/rio/turtle/pom.xml @@ -4,7 +4,7 @@ org.eclipse.rdf4j rdf4j-rio - 5.1.0-SNAPSHOT + 6.0.0 rdf4j-rio-turtle RDF4J: Rio - Turtle diff --git a/core/rio/turtle/src/main/java/org/eclipse/rdf4j/rio/turtle/TurtleParser.java b/core/rio/turtle/src/main/java/org/eclipse/rdf4j/rio/turtle/TurtleParser.java index 93c86c300a8..518c2bbf638 100644 --- a/core/rio/turtle/src/main/java/org/eclipse/rdf4j/rio/turtle/TurtleParser.java +++ b/core/rio/turtle/src/main/java/org/eclipse/rdf4j/rio/turtle/TurtleParser.java @@ -24,6 +24,7 @@ import org.apache.commons.io.input.BOMInputStream; import org.eclipse.rdf4j.common.text.ASCIIUtil; +import org.eclipse.rdf4j.model.BNode; import org.eclipse.rdf4j.model.IRI; import org.eclipse.rdf4j.model.Literal; import org.eclipse.rdf4j.model.Resource; @@ -71,6 +72,10 @@ public class TurtleParser extends AbstractRDFParser { protected Value object; + protected Resource currReifier; + + protected Triple currTripleTerm; + private int lineNumber = 1; private final StringBuilder parsingBuilder = new StringBuilder(); @@ -329,6 +334,17 @@ protected void parseTriples() throws IOException, RDFParseException, RDFHandlerE if (c != '.') { parsePredicateObjectList(); } + } else if (peekIsReifiedTriple()) { + subject = parseReifiedTriple(); + skipWSC(); + + // if this is not the end of the statement, recurse into the list of + // predicate and objects, using the subject parsed above as the + // subject + // of the statement. + if (peekCodePoint() != '.') { + parsePredicateObjectList(); + } } else { parseSubject(); skipWSC(); @@ -353,7 +369,7 @@ protected void parsePredicateObjectList() throws IOException, RDFParseException, int c = skipWSC(); if (c == '.' || // end of triple - c == ']' || c == '}') // end of predicateObjectList inside + c == ']' || c == '}' || c == '|') // end of predicateObjectList inside // blank // node { @@ -374,14 +390,17 @@ protected void parsePredicateObjectList() throws IOException, RDFParseException, protected void parseObjectList() throws IOException, RDFParseException, RDFHandlerException { parseObject(); - if (skipWSC() == '{') { + int c = skipWSC(); + if (c == '{' || c == '~') { parseAnnotation(); } while (skipWSC() == ',') { readCodePoint(); skipWSC(); parseObject(); - if (skipWSC() == '{') { + + c = skipWSC(); + if (c == '{' || c == '~') { parseAnnotation(); } } @@ -442,17 +461,16 @@ protected IRI parsePredicate() throws IOException, RDFParseException, RDFHandler protected void parseObject() throws IOException, RDFParseException, RDFHandlerException { int c = peekCodePoint(); - switch (c) { - case '(': + if (c == '(') { object = parseCollection(); - break; - case '[': + } else if (c == '[') { object = parseImplicitBlank(); - break; - default: + } else if (peekIsReifiedTriple()) { + object = parseReifiedTriple(); + reportStatement(subject, predicate, object); + } else { object = parseValue(); reportStatement(subject, predicate, object); - break; } } @@ -560,8 +578,8 @@ protected Resource parseImplicitBlank() throws IOException, RDFParseException, R * Parses an RDF value. This method parses uriref, qname, node ID, quoted literal, integer, double and boolean. */ protected Value parseValue() throws IOException, RDFParseException, RDFHandlerException { - if (getParserConfig().get(TurtleParserSettings.ACCEPT_TURTLESTAR) && peekIsTripleValue()) { - return parseTripleValue(); + if (peekIsTripleTerm()) { + return parseTripleTerm(); } int c = peekCodePoint(); @@ -575,6 +593,8 @@ protected Value parseValue() throws IOException, RDFParseException, RDFHandlerEx } else if (c == '_') { // node ID, e.g. _:n1 return parseNodeID(); + } else if (c == '[') { + return parseAnonymousBlank(); } else if (c == '"' || c == '\'') { // quoted literal, e.g. "foo" or """foo""" or 'foo' or '''foo''' return parseQuotedLiteral(); @@ -590,6 +610,17 @@ protected Value parseValue() throws IOException, RDFParseException, RDFHandlerEx } } + protected BNode parseAnonymousBlank() throws IOException { + verifyCharacterOrFail(readCodePoint(), "["); + if (skipWSC() != ']') { + reportFatalError("Expected whitespace in anonymous blank, found '" + + new String(Character.toChars(peekCodePoint())) + "'"); + return null; + } + readCodePoint(); + return valueFactory.createBNode(); + } + /** * Parses a quoted string, optionally followed by a language tag or datatype. */ @@ -1349,70 +1380,192 @@ private static void appendCodepoint(StringBuilder dst, int codePoint) { } /** - * Peeks at the next two Unicode code points without advancing the reader and returns true if they indicate the - * start of an RDF-star triple value. Such values start with '<<'. + * Peeks at the next three Unicode code points without advancing the reader and returns true if they indicate the + * start of an RDF-1.2 triple term. Such values start with '<<('. + * + * @return true if the next code points indicate the beginning of an RDF-1.2 triple term, false otherwise + * @throws IOException + */ + protected boolean peekIsTripleTerm() throws IOException { + int c0 = readCodePoint(); + int c1 = readCodePoint(); + int c2 = readCodePoint(); + unread(c2); + unread(c1); + unread(c0); + + return c0 == '<' && c1 == '<' && c2 == '('; + } + + /** + * Peeks at the next three Unicode code points without advancing the reader and returns true if they indicate the + * start of an RDF-1.2 reifiedTriple. Such values start with '<<'. * - * @return true if the next code points indicate the beginning of an RDF-star triple value, false otherwise + * @return true if the next code points indicate the beginning of an RDF-1.2 reifiedTriple, false otherwise * @throws IOException */ - protected boolean peekIsTripleValue() throws IOException { + protected boolean peekIsReifiedTriple() throws IOException { int c0 = readCodePoint(); int c1 = readCodePoint(); + int c2 = readCodePoint(); + unread(c2); unread(c1); unread(c0); - return c0 == '<' && c1 == '<'; + return c0 == '<' && c1 == '<' && c2 != '('; } /** - * Parser an RDF-star triple value and returns it. + * Parser an RDF-1.2 triple term and returns it. * - * @return An RDF-star triple. + * @return An RDF-1.2 triple term. * @throws IOException */ - protected Triple parseTripleValue() throws IOException { + protected Triple parseTripleTerm() throws IOException { verifyCharacterOrFail(readCodePoint(), "<"); verifyCharacterOrFail(readCodePoint(), "<"); + verifyCharacterOrFail(readCodePoint(), "("); skipWSC(); Value subject = parseValue(); if (subject instanceof Resource) { skipWSC(); - Value predicate = parseValue(); - if (predicate instanceof IRI) { + IRI predicate = parsePredicate(); + skipWSC(); + Value object = parseValue(); + if (object != null) { skipWSC(); - Value object = parseValue(); - if (object != null) { - skipWSC(); - verifyCharacterOrFail(readCodePoint(), ">"); - verifyCharacterOrFail(readCodePoint(), ">"); - return valueFactory.createTriple((Resource) subject, (IRI) predicate, object); + verifyCharacterOrFail(readCodePoint(), ")"); + verifyCharacterOrFail(readCodePoint(), ">"); + verifyCharacterOrFail(readCodePoint(), ">"); + return valueFactory.createTriple((Resource) subject, predicate, object); + } else { + reportFatalError("Missing object in triple term"); + } + } else { + reportFatalError("Illegal subject val in triple term: " + subject); + } + + return null; + } + + protected Resource parseReifiedTriple() throws IOException { + verifyCharacterOrFail(readCodePoint(), "<"); + verifyCharacterOrFail(readCodePoint(), "<"); + skipWSC(); + + Triple oldTripleTerm = currTripleTerm; + + Value rtSubject; + if (peekIsReifiedTriple()) { + rtSubject = parseReifiedTriple(); + } else { + rtSubject = parseValue(); + } + + if (rtSubject instanceof Resource) { + skipWSC(); + IRI predicate = parsePredicate(); + skipWSC(); + Value rtObject; + if (peekIsReifiedTriple()) { + rtObject = parseReifiedTriple(); + } else { + rtObject = parseValue(); + } + + if (rtObject != null) { + + currTripleTerm = valueFactory.createTriple((Resource) rtSubject, predicate, rtObject); + + Resource reifier; + + if (skipWSC() == '~') { + reifier = parseReifier(); } else { - reportFatalError("Missing object in RDF-star triple"); + reifier = valueFactory.createBNode(); } + + skipWSC(); + verifyCharacterOrFail(readCodePoint(), ">"); + verifyCharacterOrFail(readCodePoint(), ">"); + + addReifyingTriple(reifier); + + currTripleTerm = oldTripleTerm; + + return currReifier; } else { - reportFatalError("Illegal predicate value in RDF-star triple: " + predicate); + reportFatalError("Missing object in triple term"); } } else { - reportFatalError("Illegal subject val in RDF-star triple: " + subject); + reportFatalError("Illegal subject val in reified triple: " + rtSubject); } + return null; + } + protected void addReifyingTriple(Resource reifier) { + currReifier = reifier; + reportStatement(currReifier, RDF.REIFIES, currTripleTerm); + } + + protected Resource parseReifier() throws IOException { + verifyCharacterOrFail(readCodePoint(), "~"); + + final int c = skipWSC(); + // check if c is valid start character for a blank node or IRI + if (c == '_' || c == '[' || c == '<' || c == ':' || TurtleUtil.isPN_CHARS_BASE(c)) { + final Value reifier = parseValue(); + if (reifier instanceof Resource) { + return (Resource) reifier; + } else { + reportFatalError("Reifier must be a blank node or IRI"); + } + } else { + return valueFactory.createBNode(); + } return null; } - protected void parseAnnotation() throws IOException { + protected void parseAnnotationBlock() throws IOException { verifyCharacterOrFail(readCodePoint(), "{"); verifyCharacterOrFail(readCodePoint(), "|"); skipWSC(); - // keep reference to original subject and predicate while processing the annotation content - final Resource currentSubject = subject; - final IRI currentPredicate = predicate; - subject = Values.triple(previousStatement); + final Triple oldTripleTerm = currTripleTerm; + + if (currReifier == null) { + addReifyingTriple(valueFactory.createBNode()); + } + + subject = currReifier; + parsePredicateObjectList(); verifyCharacterOrFail(readCodePoint(), "|"); verifyCharacterOrFail(readCodePoint(), "}"); - subject = currentSubject; - predicate = currentPredicate; + + currReifier = null; + currTripleTerm = oldTripleTerm; + } + + protected void parseAnnotation() throws IOException { + final Resource oldSubject = subject; + final IRI oldPredicate = predicate; + + currTripleTerm = valueFactory.createTriple(subject, predicate, object); + currReifier = null; + + int c = skipWSC(); + while (c == '{' || c == '~') { + if (c == '~') { + addReifyingTriple(parseReifier()); + } else { + parseAnnotationBlock(); + } + c = skipWSC(); + } + + subject = oldSubject; + predicate = oldPredicate; } } diff --git a/core/rio/turtle/src/main/java/org/eclipse/rdf4j/rio/turtle/TurtleWriter.java b/core/rio/turtle/src/main/java/org/eclipse/rdf4j/rio/turtle/TurtleWriter.java index 75460b08952..2213910471a 100644 --- a/core/rio/turtle/src/main/java/org/eclipse/rdf4j/rio/turtle/TurtleWriter.java +++ b/core/rio/turtle/src/main/java/org/eclipse/rdf4j/rio/turtle/TurtleWriter.java @@ -501,6 +501,8 @@ protected void writeValue(Value val, boolean canShorten) throws IOException { stack.addLast((BNode) val); } else if (val instanceof Resource) { writeResource((Resource) val, canShorten); + } else if (val instanceof Triple) { + writeTriple((Triple) val, canShorten); } else { writeLiteral((Literal) val); } @@ -625,22 +627,20 @@ protected void writeBNode(BNode bNode, boolean canShorten) throws IOException { } protected void writeTriple(Triple triple, boolean canShorten) throws IOException { - throw new IOException(getRDFFormat().getName() + " does not support RDF-star triples"); - } - - protected void writeTripleRDFStar(Triple triple, boolean canShorten) throws IOException { - writer.write("<<"); - writeResource(triple.getSubject()); + writer.write("<<( "); + writeResource(triple.getSubject(), canShorten); writer.write(" "); writeURI(triple.getPredicate()); writer.write(" "); Value object = triple.getObject(); if (object instanceof Literal) { writeLiteral((Literal) object); + } else if (object instanceof Triple) { + writeTriple((Triple) object, canShorten); } else { writeResource((Resource) object, canShorten); } - writer.write(">>"); + writer.write(" )>>"); } protected void writeLiteral(Literal lit) throws IOException { @@ -682,6 +682,7 @@ protected void writeLiteral(Literal lit) throws IOException { // Append the literal's language writer.write("@"); writer.write(lit.getLanguage().get()); + writer.write(lit.getBaseDirection().toString()); } else if (!xsdStringToPlainLiteral || !XSD.STRING.equals(datatype)) { // Append the literal's datatype (possibly written as an abbreviated // URI) diff --git a/core/rio/turtle/src/main/java/org/eclipse/rdf4j/rio/turtlestar/TurtleStarParser.java b/core/rio/turtle/src/main/java/org/eclipse/rdf4j/rio/turtlestar/TurtleStarParser.java index e4ce2cb5179..22cc935f275 100644 --- a/core/rio/turtle/src/main/java/org/eclipse/rdf4j/rio/turtlestar/TurtleStarParser.java +++ b/core/rio/turtle/src/main/java/org/eclipse/rdf4j/rio/turtlestar/TurtleStarParser.java @@ -10,14 +10,6 @@ *******************************************************************************/ package org.eclipse.rdf4j.rio.turtlestar; -import java.io.IOException; - -import org.eclipse.rdf4j.model.Value; -import org.eclipse.rdf4j.model.ValueFactory; -import org.eclipse.rdf4j.model.impl.SimpleValueFactory; -import org.eclipse.rdf4j.rio.RDFFormat; -import org.eclipse.rdf4j.rio.RDFHandlerException; -import org.eclipse.rdf4j.rio.RDFParseException; import org.eclipse.rdf4j.rio.turtle.TurtleParser; /** @@ -25,33 +17,6 @@ * * @author Pavel Mihaylov */ +@Deprecated public class TurtleStarParser extends TurtleParser { - /** - * Creates a new TurtleStarParser that will use a {@link SimpleValueFactory} to create RDF-star model objects. - */ - public TurtleStarParser() { - super(); - } - - /** - * Creates a new TurtleStarParser that will use the supplied ValueFactory to create RDF-star model objects. - * - * @param valueFactory A ValueFactory. - */ - public TurtleStarParser(ValueFactory valueFactory) { - super(valueFactory); - } - - @Override - public RDFFormat getRDFFormat() { - return RDFFormat.TURTLESTAR; - } - - @Override - protected Value parseValue() throws IOException, RDFParseException, RDFHandlerException { - if (peekIsTripleValue()) { - return parseTripleValue(); - } - return super.parseValue(); - } } diff --git a/core/rio/turtle/src/main/java/org/eclipse/rdf4j/rio/turtlestar/TurtleStarParserFactory.java b/core/rio/turtle/src/main/java/org/eclipse/rdf4j/rio/turtlestar/TurtleStarParserFactory.java index 5fa9ce53178..779f22731bb 100644 --- a/core/rio/turtle/src/main/java/org/eclipse/rdf4j/rio/turtlestar/TurtleStarParserFactory.java +++ b/core/rio/turtle/src/main/java/org/eclipse/rdf4j/rio/turtlestar/TurtleStarParserFactory.java @@ -13,26 +13,13 @@ import org.eclipse.rdf4j.rio.RDFFormat; import org.eclipse.rdf4j.rio.RDFParser; import org.eclipse.rdf4j.rio.RDFParserFactory; +import org.eclipse.rdf4j.rio.turtle.TurtleParserFactory; /** * An {@link RDFParserFactory} for Turtle-star parsers. * * @author Pavel Mihaylov */ -public class TurtleStarParserFactory implements RDFParserFactory { - /** - * Returns {@link RDFFormat#TURTLESTAR}. - */ - @Override - public RDFFormat getRDFFormat() { - return RDFFormat.TURTLESTAR; - } - - /** - * Returns a new instance of {@link TurtleStarParser}. - */ - @Override - public RDFParser getParser() { - return new TurtleStarParser(); - } +@Deprecated +public class TurtleStarParserFactory extends TurtleParserFactory { } diff --git a/core/rio/turtle/src/main/java/org/eclipse/rdf4j/rio/turtlestar/TurtleStarWriter.java b/core/rio/turtle/src/main/java/org/eclipse/rdf4j/rio/turtlestar/TurtleStarWriter.java index 72e2078cec0..f770c8ed705 100644 --- a/core/rio/turtle/src/main/java/org/eclipse/rdf4j/rio/turtlestar/TurtleStarWriter.java +++ b/core/rio/turtle/src/main/java/org/eclipse/rdf4j/rio/turtlestar/TurtleStarWriter.java @@ -10,14 +10,10 @@ *******************************************************************************/ package org.eclipse.rdf4j.rio.turtlestar; -import java.io.IOException; import java.io.OutputStream; import java.io.Writer; -import org.eclipse.rdf4j.common.lang.FileFormat; import org.eclipse.rdf4j.common.net.ParsedIRI; -import org.eclipse.rdf4j.model.Triple; -import org.eclipse.rdf4j.rio.RDFFormat; import org.eclipse.rdf4j.rio.turtle.TurtleWriter; /** @@ -26,6 +22,7 @@ * * @author Pavel Mihaylov */ +@Deprecated public class TurtleStarWriter extends TurtleWriter { /** * Creates a new TurtleStarWriter that will write to the supplied OutputStream. @@ -64,21 +61,4 @@ public TurtleStarWriter(Writer writer) { public TurtleStarWriter(Writer writer, ParsedIRI baseIRI) { super(writer, baseIRI); } - - @Override - public RDFFormat getRDFFormat() { - return RDFFormat.TURTLESTAR; - } - - @Override - public boolean acceptsFileFormat(FileFormat format) { - // since Turtle-star is a superset of regular Turtle, this Sink also accepts regular Turtle - // serialization - return super.acceptsFileFormat(format) || RDFFormat.TURTLE.equals(format); - } - - @Override - protected void writeTriple(Triple triple, boolean canShorten) throws IOException { - writeTripleRDFStar(triple, canShorten); - } -} +} \ No newline at end of file diff --git a/core/rio/turtle/src/main/java/org/eclipse/rdf4j/rio/turtlestar/TurtleStarWriterFactory.java b/core/rio/turtle/src/main/java/org/eclipse/rdf4j/rio/turtlestar/TurtleStarWriterFactory.java index 43352308cc8..47889911de6 100644 --- a/core/rio/turtle/src/main/java/org/eclipse/rdf4j/rio/turtlestar/TurtleStarWriterFactory.java +++ b/core/rio/turtle/src/main/java/org/eclipse/rdf4j/rio/turtlestar/TurtleStarWriterFactory.java @@ -10,53 +10,14 @@ *******************************************************************************/ package org.eclipse.rdf4j.rio.turtlestar; -import java.io.OutputStream; -import java.io.Writer; -import java.net.URISyntaxException; - -import org.eclipse.rdf4j.common.net.ParsedIRI; -import org.eclipse.rdf4j.rio.RDFFormat; -import org.eclipse.rdf4j.rio.RDFWriter; import org.eclipse.rdf4j.rio.RDFWriterFactory; +import org.eclipse.rdf4j.rio.turtle.TurtleWriterFactory; /** * An {@link RDFWriterFactory} for Turtle-star writers. * * @author Pavel Mihaylov */ -public class TurtleStarWriterFactory implements RDFWriterFactory { - - /** - * Returns {@link RDFFormat#TURTLESTAR}. - */ - @Override - public RDFFormat getRDFFormat() { - return RDFFormat.TURTLESTAR; - } - - /** - * Returns a new instance of {@link TurtleStarWriter}. - */ - @Override - public RDFWriter getWriter(OutputStream out) { - return new TurtleStarWriter(out); - } - - @Override - public RDFWriter getWriter(OutputStream out, String baseURI) throws URISyntaxException { - return new TurtleStarWriter(out, new ParsedIRI(baseURI)); - } - - /** - * Returns a new instance of {@link TurtleStarWriter}. - */ - @Override - public RDFWriter getWriter(Writer writer) { - return new TurtleStarWriter(writer); - } - - @Override - public RDFWriter getWriter(Writer writer, String baseURI) throws URISyntaxException { - return new TurtleStarWriter(writer, new ParsedIRI(baseURI)); - } -} +@Deprecated +public class TurtleStarWriterFactory extends TurtleWriterFactory { +} \ No newline at end of file diff --git a/core/rio/turtle/src/test/java/org/eclipse/rdf4j/rio/turtle/AbstractTurtleWriterTest.java b/core/rio/turtle/src/test/java/org/eclipse/rdf4j/rio/turtle/AbstractTurtleWriterTest.java index 1a4977f12f8..20f6b87d54c 100644 --- a/core/rio/turtle/src/test/java/org/eclipse/rdf4j/rio/turtle/AbstractTurtleWriterTest.java +++ b/core/rio/turtle/src/test/java/org/eclipse/rdf4j/rio/turtle/AbstractTurtleWriterTest.java @@ -15,12 +15,10 @@ import org.eclipse.rdf4j.model.util.Values; import org.eclipse.rdf4j.model.vocabulary.RDF; import org.eclipse.rdf4j.model.vocabulary.XSD; -import org.eclipse.rdf4j.rio.RDFParserFactory; -import org.eclipse.rdf4j.rio.RDFWriterFactory; -import org.eclipse.rdf4j.rio.RDFWriterTest; -import org.eclipse.rdf4j.rio.RioSetting; +import org.eclipse.rdf4j.rio.*; import org.eclipse.rdf4j.rio.helpers.BasicWriterSettings; import org.eclipse.rdf4j.rio.helpers.TurtleWriterSettings; +import org.junit.jupiter.api.Test; /** * @author Jeen Broekstra @@ -49,4 +47,9 @@ protected Model getAbbrevTestModel() { m.add(Values.iri("http://www.example.com/decimal"), RDF.VALUE, Values.literal("55.66", XSD.DECIMAL)); return m; } + + @Test + public void dirLangStringTest() throws Exception { + dirLangStringTest(RDFFormat.TURTLE); + } } diff --git a/core/rio/turtle/src/test/java/org/eclipse/rdf4j/rio/turtle/TurtleParserTest.java b/core/rio/turtle/src/test/java/org/eclipse/rdf4j/rio/turtle/TurtleParserTest.java index 1ac74f3ac32..e2a7f28683b 100644 --- a/core/rio/turtle/src/test/java/org/eclipse/rdf4j/rio/turtle/TurtleParserTest.java +++ b/core/rio/turtle/src/test/java/org/eclipse/rdf4j/rio/turtle/TurtleParserTest.java @@ -13,6 +13,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -22,56 +23,56 @@ import java.io.InputStream; import java.io.Reader; import java.io.StringReader; +import java.math.BigInteger; import java.net.URL; import java.util.Collection; import java.util.Iterator; +import java.util.List; -import org.eclipse.rdf4j.model.IRI; +import org.eclipse.rdf4j.model.BNode; import org.eclipse.rdf4j.model.Literal; +import org.eclipse.rdf4j.model.Model; import org.eclipse.rdf4j.model.Resource; import org.eclipse.rdf4j.model.Statement; import org.eclipse.rdf4j.model.Triple; import org.eclipse.rdf4j.model.ValueFactory; +import org.eclipse.rdf4j.model.base.CoreDatatype; +import org.eclipse.rdf4j.model.impl.LinkedHashModel; import org.eclipse.rdf4j.model.impl.SimpleValueFactory; +import org.eclipse.rdf4j.model.util.Models; import org.eclipse.rdf4j.model.vocabulary.DC; import org.eclipse.rdf4j.model.vocabulary.DCTERMS; import org.eclipse.rdf4j.model.vocabulary.FOAF; +import org.eclipse.rdf4j.model.vocabulary.RDF; import org.eclipse.rdf4j.model.vocabulary.XSD; +import org.eclipse.rdf4j.rio.AbstractParserTest; +import org.eclipse.rdf4j.rio.LanguageHandler; import org.eclipse.rdf4j.rio.RDFParseException; import org.eclipse.rdf4j.rio.RDFParser; import org.eclipse.rdf4j.rio.helpers.BasicParserSettings; -import org.eclipse.rdf4j.rio.helpers.ParseErrorCollector; -import org.eclipse.rdf4j.rio.helpers.SimpleParseLocationListener; import org.eclipse.rdf4j.rio.helpers.StatementCollector; -import org.eclipse.rdf4j.rio.helpers.TurtleParserSettings; -import org.junit.jupiter.api.BeforeEach; +import org.eclipse.rdf4j.rio.languages.RFC3066LanguageHandler; import org.junit.jupiter.api.Test; /** * @author jeen */ -public class TurtleParserTest { - - private TurtleParser parser; +public class TurtleParserTest extends AbstractParserTest { private final ValueFactory vf = SimpleValueFactory.getInstance(); - private final ParseErrorCollector errorCollector = new ParseErrorCollector(); - - private final StatementCollector statementCollector = new StatementCollector(); - private final String prefixes = "@prefix ex: . \n@prefix : . \n"; private final String baseURI = "http://example.org/"; - private final SimpleParseLocationListener locationListener = new SimpleParseLocationListener(); + private final Statement simpleSPOStatement = vf.createStatement(vf.createIRI("http://example/s"), + vf.createIRI("http://example/p"), vf.createIRI("http://example/o")); + private final Triple simpleSPOTriple = vf.createTriple(vf.createIRI("http://example/s"), + vf.createIRI("http://example/p"), vf.createIRI("http://example/o")); - @BeforeEach - public void setUp() { - parser = new TurtleParser(); - parser.setParseErrorListener(errorCollector); - parser.setRDFHandler(statementCollector); - parser.setParseLocationListener(locationListener); + @Override + protected RDFParser createRDFParser() { + return new TurtleParser(); } @Test @@ -275,99 +276,80 @@ public void testLineNumberReporting() throws IOException { final String error = errorCollector.getFatalErrors().get(0); // expected to fail at line 9. assertTrue(error.contains("(9,")); - assertEquals(9, locationListener.getLineNo()); - assertEquals(-1, locationListener.getColumnNo()); + locationListener.assertListener(9, -1); } } @Test public void testLineNumberReportingNoErrorsSingleLine() throws IOException { - assertEquals(0, locationListener.getLineNo()); - assertEquals(0, locationListener.getColumnNo()); + locationListener.assertListener(0, 0); Reader in = new StringReader(" ."); parser.parse(in, baseURI); - assertEquals(1, locationListener.getLineNo()); - assertEquals(-1, locationListener.getColumnNo()); + locationListener.assertListener(1, -1); } @Test public void testLineNumberReportingNoErrorsSingleLineEndNewline() throws IOException { - assertEquals(0, locationListener.getLineNo()); - assertEquals(0, locationListener.getColumnNo()); + locationListener.assertListener(0, 0); Reader in = new StringReader(" .\n"); parser.parse(in, baseURI); - assertEquals(2, locationListener.getLineNo()); - assertEquals(-1, locationListener.getColumnNo()); + locationListener.assertListener(2, -1); } @Test public void testLineNumberReportingNoErrorsMultipleLinesNoEndNewline() throws IOException { - assertEquals(0, locationListener.getLineNo()); - assertEquals(0, locationListener.getColumnNo()); + locationListener.assertListener(0, 0); Reader in = new StringReader(" .\n ."); parser.parse(in, baseURI); - assertEquals(2, locationListener.getLineNo()); - assertEquals(-1, locationListener.getColumnNo()); + locationListener.assertListener(2, -1); } @Test public void testLineNumberReportingNoErrorsMultipleLinesEndNewline() throws IOException { - assertEquals(0, locationListener.getLineNo()); - assertEquals(0, locationListener.getColumnNo()); + locationListener.assertListener(0, 0); Reader in = new StringReader(" .\n .\n"); parser.parse(in, baseURI); - assertEquals(3, locationListener.getLineNo()); - assertEquals(-1, locationListener.getColumnNo()); + locationListener.assertListener(3, -1); } @Test public void testLineNumberReportingOnlySingleCommentNoEndline() throws IOException { - assertEquals(0, locationListener.getLineNo()); - assertEquals(0, locationListener.getColumnNo()); + locationListener.assertListener(0, 0); Reader in = new StringReader("# This is just a comment"); parser.parse(in, baseURI); - assertEquals(1, locationListener.getLineNo()); - assertEquals(-1, locationListener.getColumnNo()); + locationListener.assertListener(1, -1); } @Test public void testLineNumberReportingOnlySingleCommentEndline() throws IOException { - assertEquals(0, locationListener.getLineNo()); - assertEquals(0, locationListener.getColumnNo()); + locationListener.assertListener(0, 0); Reader in = new StringReader("# This is just a comment\n"); parser.parse(in, baseURI); - assertEquals(2, locationListener.getLineNo()); - assertEquals(-1, locationListener.getColumnNo()); + locationListener.assertListener(2, -1); } @Test public void testLineNumberReportingOnlySingleCommentCarriageReturn() throws IOException { - assertEquals(0, locationListener.getLineNo()); - assertEquals(0, locationListener.getColumnNo()); + locationListener.assertListener(0, 0); Reader in = new StringReader("# This is just a comment\r"); parser.parse(in, baseURI); - assertEquals(2, locationListener.getLineNo()); - assertEquals(-1, locationListener.getColumnNo()); + locationListener.assertListener(2, -1); } @Test public void testLineNumberReportingOnlySingleCommentCarriageReturnNewline() throws IOException { - assertEquals(0, locationListener.getLineNo()); - assertEquals(0, locationListener.getColumnNo()); + locationListener.assertListener(0, 0); Reader in = new StringReader("# This is just a comment\r\n"); parser.parse(in, baseURI); - assertEquals(2, locationListener.getLineNo()); - assertEquals(-1, locationListener.getColumnNo()); + locationListener.assertListener(2, -1); } @Test public void testLineNumberReportingInLongStringLiterals() throws IOException { - assertEquals(0, locationListener.getLineNo()); - assertEquals(0, locationListener.getColumnNo()); + locationListener.assertListener(0, 0); Reader in = new StringReader(" \"\"\"is\nallowed\nin\na very long string\"\"\" ."); parser.parse(in, baseURI); - assertEquals(4, locationListener.getLineNo()); - assertEquals(-1, locationListener.getColumnNo()); + locationListener.assertListener(4, -1); } @Test @@ -520,64 +502,587 @@ public void testOverflowingUnicodeInTripleSubject() throws IOException { } } + @Test + public void testParseAdditionalDatatypes() throws IOException { + String data = prefixes + ":s :p \"o\"^^rdf:JSON . \n" + + ":s :p \"o\"^^rdf:HTML . \n" + + ":s :p \"o\"^^rdf:XMLLiteral . "; + Reader r = new StringReader(data); + + try { + parser.getParserConfig().set(BasicParserSettings.FAIL_ON_UNKNOWN_DATATYPES, true); + + parser.parse(r, baseURI); + + assertThat(errorCollector.getErrors()).isEmpty(); + + Collection stmts = statementCollector.getStatements(); + + assertThat(stmts).hasSize(3); + + Iterator iter = stmts.iterator(); + + Statement stmt1 = iter.next(), stmt2 = iter.next(), stmt3 = iter.next(); + + assertEquals(CoreDatatype.RDF.JSON.getIri(), ((Literal) stmt1.getObject()).getDatatype()); + assertEquals(CoreDatatype.RDF.HTML.getIri(), ((Literal) stmt2.getObject()).getDatatype()); + assertEquals(CoreDatatype.RDF.XMLLITERAL.getIri(), ((Literal) stmt3.getObject()).getDatatype()); + } catch (RDFParseException e) { + fail("parse error on correct data: " + e.getMessage()); + } + } + /** - * Extend standard Turtle parser to also accept RDF-star data (see GH-2511) + * https://w3c.github.io/rdf-tests/rdf/rdf12/rdf-turtle/syntax/nt-ttl12-langdir-1.ttl */ @Test - public void testParseRDFStarData() throws IOException { - IRI bob = vf.createIRI("http://example.com/bob"); - IRI alice = vf.createIRI("http://example.com/alice"); - IRI book = vf.createIRI("http://example.com/book"); - IRI otherbook = vf.createIRI("http://example.com/otherbook"); - IRI bobshomepage = vf.createIRI("http://example.com/bobshomepage"); - IRI a = vf.createIRI("http://example.org/a"); - IRI b = vf.createIRI("http://example.com/b"); - IRI c = vf.createIRI("http://example.com/c"); - IRI valid = vf.createIRI("http://example.com/valid"); - Literal abcDate = vf.createLiteral("1999-08-16", XSD.DATE); - Literal birthDate = vf.createLiteral("1908-03-18", XSD.DATE); - Literal titleEn = vf.createLiteral("Example book", "en"); - Literal titleDe = vf.createLiteral("Beispielbuch", "de"); - Literal titleEnUs = vf.createLiteral("Example Book", "en-US"); - - Triple bobCreatedBook = vf.createTriple(bob, DCTERMS.CREATED, book); - Triple aliceKnowsBobCreatedBook = vf.createTriple(alice, FOAF.KNOWS, bobCreatedBook); - Triple bobCreatedBookKnowsAlice = vf.createTriple(bobCreatedBook, FOAF.KNOWS, alice); - Triple bookCreatorAlice = vf.createTriple(book, DCTERMS.CREATOR, alice); - Triple aliceCreatedBook = vf.createTriple(alice, DCTERMS.CREATED, book); - Triple abc = vf.createTriple(a, b, c); - Triple bobBirthdayDate = vf.createTriple(bob, FOAF.BIRTHDAY, birthDate); - Triple bookTitleEn = vf.createTriple(book, DCTERMS.TITLE, titleEn); - Triple bookTitleDe = vf.createTriple(book, DCTERMS.TITLE, titleDe); - Triple bookTitleEnUs = vf.createTriple(book, DCTERMS.TITLE, titleEnUs); - - try (InputStream in = this.getClass().getResourceAsStream("/test-rdfstar.ttls")) { - parser.parse(in, baseURI); + public void testLanguageDirectionLTR() throws IOException { + String data = " \"Hello\"@en--ltr ."; + dirLangStringTestHelper(data, "en", Literal.LTR_SUFFIX, false, false); + } + + /** + * https://w3c.github.io/rdf-tests/rdf/rdf12/rdf-turtle/syntax/nt-ttl12-langdir-1.ttl + */ + @Test + public void testLanguageDirectionLTRWithNormalization() throws IOException { + String data = " \"Hello\"@EN--ltr ."; + dirLangStringTestHelper(data, "en", Literal.LTR_SUFFIX, true, false); + } + + /** + * https://w3c.github.io/rdf-tests/rdf/rdf12/rdf-turtle/syntax/nt-ttl12-langdir-2.ttl + */ + @Test + public void testLanguageDirectionRTL() throws IOException { + String data = " \"Hello\"@en--rtl ."; + dirLangStringTestHelper(data, "en", Literal.RTL_SUFFIX, false, false); + } + + /** + * https://w3c.github.io/rdf-tests/rdf/rdf12/rdf-turtle/syntax/nt-ttl12-langdir-2.ttl + */ + @Test + public void testLanguageDirectionRTLWithNormalization() throws IOException { + String data = " \"Hello\"@EN--rtl ."; + dirLangStringTestHelper(data, "en", Literal.RTL_SUFFIX, true, false); + } + + /** + * https://w3c.github.io/rdf-tests/rdf/rdf12/rdf-turtle/syntax/nt-ttl12-langdir-bad-1.ttl + */ + @Test + public void testBadLanguageDirection() throws IOException { + String data = " \"Hello\"@en--unk ."; + dirLangStringTestHelper(data, "", "", false, true); + } + + /** + * https://w3c.github.io/rdf-tests/rdf/rdf12/rdf-turtle/syntax/nt-ttl12-langdir-bad-2.ttl + */ + @Test + public void testBadCapitalizationLanguageDirection() throws IOException { + String data = " \"Hello\"@en--LTR ."; + dirLangStringTestHelper(data, "", "", false, true); + } + + @Test + public void testDirLangStringNoLanguage() throws IOException { + String data = " \"Hello\"^^rdf:dirLangString ."; + dirLangStringNoLanguageTestHelper(data); + } + + @Test + public void testRFC3066LanguageHandler() throws IOException { + String data = " \"Hello\"@en--ltr ."; + + try { + List customHandlers = List.of(new RFC3066LanguageHandler()); + parser.getParserConfig().set(BasicParserSettings.LANGUAGE_HANDLERS, customHandlers); + parser.parse(new StringReader(data), baseURI); + + assertThat(errorCollector.getErrors()).isEmpty(); + + Collection stmts = statementCollector.getStatements(); + + assertThat(stmts).hasSize(1); + + Iterator iter = stmts.iterator(); + Statement stmt1 = iter.next(); + + assertEquals(CoreDatatype.RDF.DIRLANGSTRING.getIri(), ((Literal) stmt1.getObject()).getDatatype()); + } catch (RDFParseException e) { + fail("parse error on correct data: " + e.getMessage()); + } + } + + private Statement simpleExampleStatement(String s, String p, String o) { + return vf.createStatement(vf.createIRI("http://example/" + s), vf.createIRI("http://example/" + p), + vf.createIRI("http://example/" + o)); + } + + private Triple simpleExampleTriple(String s, String p, String o) { + return vf.createTriple(vf.createIRI("http://example/" + s), vf.createIRI("http://example/" + p), + vf.createIRI("http://example/" + o)); + } + + /* + * https://w3c.github.io/rdf-tests/rdf/rdf12/rdf-turtle/syntax/turtle12-syntax-basic-03.ttl + */ + @Test + public void testTripleTermInObjectPosition() throws IOException { + String data = "PREFIX : \n" + ":s :p <<(:s :p :o )>> ."; + + try { + parser.parse(new StringReader(data)); + assertEquals(1, statementCollector.getStatements().size()); + + assertThat(errorCollector.getErrors()).isEmpty(); + + Collection stmts = statementCollector.getStatements(); + + assertThat(stmts).hasSize(1); + + Iterator iter = stmts.iterator(); + Statement stmt1 = iter.next(); + + assertEquals(stmt1.getSubject(), vf.createIRI("http://example/s")); + assertEquals(stmt1.getPredicate(), vf.createIRI("http://example/p")); + assertTrue(stmt1.getObject() instanceof Triple); + assertEquals(stmt1.getObject(), simpleSPOTriple); + } catch (RDFParseException e) { + fail("parse error on correct data: " + e.getMessage()); + } + } + + @Test + public void testBadTripleTermInSubjectPosition() throws IOException { + String data = "PREFIX : \n" + "<<(:s :p :o )>> :p :o ."; + assertThrows(RDFParseException.class, () -> parser.parse(new StringReader(data))); + } + + @Test + public void testNestedTripleTerm() throws IOException { + String data = "PREFIX : \n" + ":s :p <<(:s2 :p2 <<( :s3 :p3 :o3 )>> )>> ."; + + try { + parser.parse(new StringReader(data)); + assertEquals(1, statementCollector.getStatements().size()); + + assertThat(errorCollector.getErrors()).isEmpty(); + + Collection stmts = statementCollector.getStatements(); + + assertThat(stmts).hasSize(1); + + Iterator iter = stmts.iterator(); + Statement stmt1 = iter.next(); + + assertEquals(stmt1.getSubject(), vf.createIRI("http://example/s")); + assertEquals(stmt1.getPredicate(), vf.createIRI("http://example/p")); + + assertInstanceOf(Triple.class, stmt1.getObject()); + Triple obj = (Triple) stmt1.getObject(); + assertEquals(obj.getSubject(), vf.createIRI("http://example/s2")); + assertEquals(obj.getPredicate(), vf.createIRI("http://example/p2")); + + assertInstanceOf(Triple.class, obj.getObject()); + Triple objObj = (Triple) obj.getObject(); + assertEquals(objObj, simpleExampleTriple("s3", "p3", "o3")); + } catch (RDFParseException e) { + fail("parse error on correct data: " + e.getMessage()); + } + } + + @Test + public void testNestedTripleTerm2() throws IOException { + String data = "PREFIX : \n" + "_:b :p <<(:s2 :p2 <<( _:b2 :p3 \"9\"^^xsd:int )>> )>> ."; + + try { + parser.getParserConfig().set(BasicParserSettings.PRESERVE_BNODE_IDS, true); + parser.parse(new StringReader(data)); + assertEquals(1, statementCollector.getStatements().size()); + + assertThat(errorCollector.getErrors()).isEmpty(); + + Collection stmts = statementCollector.getStatements(); + + assertThat(stmts).hasSize(1); + + Iterator iter = stmts.iterator(); + Statement stmt1 = iter.next(); + + assertEquals(stmt1.getSubject(), vf.createBNode("b")); + assertEquals(stmt1.getPredicate(), vf.createIRI("http://example/p")); + + assertTrue(stmt1.getObject().isTriple()); + Triple obj = (Triple) stmt1.getObject(); + assertEquals(obj.getSubject(), vf.createIRI("http://example/s2")); + assertEquals(obj.getPredicate(), vf.createIRI("http://example/p2")); + + assertTrue(obj.getObject().isTriple()); + obj = (Triple) obj.getObject(); + assertEquals(obj.getSubject(), vf.createBNode("b2")); + assertEquals(obj.getPredicate(), vf.createIRI("http://example/p3")); + assertEquals(obj.getObject(), vf.createLiteral(9)); + } catch (RDFParseException e) { + fail("parse error on correct data: " + e.getMessage()); + } + } + + /* + * https://w3c.github.io/rdf-tests/rdf/rdf12/rdf-turtle/syntax/nt-ttl12-syntax-1.ttl + */ + @Test + public void testTripleTermNTriples() throws IOException { + String data = " <<( )>> ."; + try { + parser.parse(new StringReader(data)); + assertEquals(1, statementCollector.getStatements().size()); + + assertThat(errorCollector.getErrors()).isEmpty(); + + Collection stmts = statementCollector.getStatements(); + + assertThat(stmts).hasSize(1); + + Iterator iter = stmts.iterator(); + Statement stmt1 = iter.next(); + + assertEquals(vf.createIRI("http://example/a"), stmt1.getSubject()); + assertEquals(RDF.REIFIES, stmt1.getPredicate()); + assertInstanceOf(Triple.class, stmt1.getObject()); + assertEquals(stmt1.getObject(), simpleSPOTriple); + } catch (RDFParseException e) { + fail("parse error on correct data: " + e.getMessage()); + } + } + + /* + * https://w3c.github.io/rdf-tests/rdf/rdf12/rdf-turtle/syntax/nt-ttl12-syntax-2.ttl + */ + @Test + public void testTripleTermNTriplesNoWhitespace() throws IOException { + String data = "<<()>>."; + + try { + parser.parse(new StringReader(data)); + assertEquals(1, statementCollector.getStatements().size()); + + assertThat(errorCollector.getErrors()).isEmpty(); + + Collection stmts = statementCollector.getStatements(); + + assertThat(stmts).hasSize(1); + + Iterator iter = stmts.iterator(); + Statement stmt1 = iter.next(); + + assertEquals(vf.createIRI("http://example/s"), stmt1.getSubject()); + assertEquals(RDF.REIFIES, stmt1.getPredicate()); + assertInstanceOf(Triple.class, stmt1.getObject()); + assertEquals(stmt1.getObject(), vf.createTriple(vf.createIRI("http://example/s2"), + vf.createIRI("http://example/p2"), vf.createIRI("http://example/o2"))); + } catch (RDFParseException e) { + fail("parse error on correct data: " + e.getMessage()); + } + } + + /* + * https://w3c.github.io/rdf-tests/rdf/rdf12/rdf-turtle/syntax/nt-ttl12-nested-1.ttl + */ + @Test + public void testNestedTripleTerms() throws IOException { + String data = " .\n" + + " <<( )>> .\n" + + + " <<( <<( )>> )>> ."; + + try { + parser.parse(new StringReader(data)); + + assertThat(errorCollector.getErrors()).isEmpty(); Collection stmts = statementCollector.getStatements(); - assertEquals(10, stmts.size()); + assertThat(stmts).hasSize(3); + + Iterator iter = stmts.iterator(); + Statement stmt1 = iter.next(), stmt2 = iter.next(), stmt3 = iter.next(); + + assertEquals(stmt1, simpleSPOStatement); + assertEquals(stmt2, vf.createStatement(vf.createIRI("http://example/a"), RDF.REIFIES, + simpleExampleTriple("s1", "p1", "o1"))); + assertEquals(stmt3, vf.createStatement(vf.createIRI("http://example/r"), RDF.REIFIES, + vf.createTriple(vf.createIRI("http://example/23"), RDF.REIFIES, + simpleExampleTriple("s3", "p3", "o3")))); + } catch (RDFParseException e) { + fail("parse error on correct data: " + e.getMessage()); + } + } + + /* + * https://w3c.github.io/rdf-tests/rdf/rdf12/rdf-turtle/syntax/turtle12-syntax-basic-01.ttl + */ + @Test + public void testSubjectReifiedTriple() throws IOException { + String data = "PREFIX : \n" + + "\n" + + ":s :p :o .\n" + + "<<:s :p :o>> :q 123 ."; + try { + Model model = new LinkedHashModel(); + statementCollector = new StatementCollector(model); + parser.setRDFHandler(statementCollector); + parser.parse(new StringReader(data)); + + assertThat(errorCollector.getErrors()).isEmpty(); + + assertThat(model).hasSize(3); + + assertTrue(model.contains(simpleSPOStatement)); + Model reifyingTriples = model.filter(null, RDF.REIFIES, simpleSPOTriple); + assertThat(reifyingTriples).hasSize(1); + Resource reifier = Models.subject(reifyingTriples).get(); + assertInstanceOf(BNode.class, reifier); + assertTrue(model.contains(reifier, vf.createIRI("http://example/q"), + vf.createLiteral(BigInteger.valueOf(123)))); + } catch (RDFParseException e) { + fail("parse error on correct data: " + e.getMessage()); + } + } + + /* + * https://w3c.github.io/rdf-tests/rdf/rdf12/rdf-turtle/syntax/turtle12-syntax-basic-02.ttl + */ + @Test + public void testObjectReifiedTriple() throws IOException { + String data = "PREFIX : \n" + + "\n" + + ":s :p :o .\n" + + ":x :p <<:s :p :o>> ."; + try { + Model model = new LinkedHashModel(); + statementCollector = new StatementCollector(model); + parser.setRDFHandler(statementCollector); + parser.parse(new StringReader(data)); + + assertThat(errorCollector.getErrors()).isEmpty(); + + assertThat(model).hasSize(3); + + assertTrue(model.contains(simpleSPOStatement)); + Model reifyingTriples = model.filter(null, RDF.REIFIES, simpleSPOTriple); + assertThat(reifyingTriples).hasSize(1); + Resource reifier = Models.subject(reifyingTriples).get(); + assertInstanceOf(BNode.class, reifier); + assertTrue(model.contains(vf.createIRI("http://example/x"), vf.createIRI("http://example/p"), reifier)); + } catch (RDFParseException e) { + fail("parse error on correct data: " + e.getMessage()); + } + } + + /* + * https://w3c.github.io/rdf-tests/rdf/rdf12/rdf-turtle/syntax/turtle12-syntax-basic-04.ttl + */ + @Test + public void testReifiedTripleNoPredObjList() throws IOException { + String data = "PREFIX : \n" + + "\n" + + ":s :p :o .\n" + + "<<:s :p :o>> ."; + try { + Model model = new LinkedHashModel(); + statementCollector = new StatementCollector(model); + parser.setRDFHandler(statementCollector); + parser.parse(new StringReader(data)); + + assertThat(errorCollector.getErrors()).isEmpty(); + + assertThat(model).hasSize(2); + + assertTrue(model.contains(simpleSPOStatement)); + Model reifyingTriples = model.filter(null, RDF.REIFIES, simpleSPOTriple); + assertThat(reifyingTriples).hasSize(1); + Resource reifier = Models.subject(reifyingTriples).get(); + assertInstanceOf(BNode.class, reifier); + } catch (RDFParseException e) { + fail("parse error on correct data: " + e.getMessage()); + } + } + + /* + * https://w3c.github.io/rdf-tests/rdf/rdf12/rdf-turtle/syntax/turtle12-syntax-inside-01.ttl + */ + @Test + public void testReifiedTripleInBlankNodePropertyList() throws IOException { + String data = "PREFIX : \n" + + "\n" + + ":s :p :o .\n" + + "[ :q <<:s :p :o>> ] :b :c ."; + try { + Model model = new LinkedHashModel(); + statementCollector = new StatementCollector(model); + parser.setRDFHandler(statementCollector); + parser.parse(new StringReader(data)); + + assertThat(errorCollector.getErrors()).isEmpty(); + + assertThat(model).hasSize(4); + + assertTrue(model.contains(simpleSPOStatement)); + Model reifyingTriples = model.filter(null, RDF.REIFIES, simpleSPOTriple); + assertThat(reifyingTriples).hasSize(1); + Resource reifier = Models.subject(reifyingTriples).get(); + assertInstanceOf(BNode.class, reifier); + assertTrue(model.contains(null, vf.createIRI("http://example/q"), reifier)); + assertTrue(model.contains(null, vf.createIRI("http://example/b"), vf.createIRI("http://example/c"))); + } catch (RDFParseException e) { + fail("parse error on correct data: " + e.getMessage()); + } + } + + /* + * https://w3c.github.io/rdf-tests/rdf/rdf12/rdf-turtle/syntax/turtle12-syntax-inside-02.ttl + */ + @Test + public void testReifiedTripleInCollection() throws IOException { + String data = "PREFIX : \n" + + "\n" + + ":s :p :o1 .\n" + + ":s :p :o2 .\n" + + "( <<:s :p :o1>> <<:s :p :o2>> ) :q 123 ."; + try { + Model model = new LinkedHashModel(); + statementCollector = new StatementCollector(model); + parser.setRDFHandler(statementCollector); + parser.parse(new StringReader(data)); + + assertThat(errorCollector.getErrors()).isEmpty(); + + assertThat(model).hasSize(9); + } catch (RDFParseException e) { + fail("parse error on correct data: " + e.getMessage()); + } + } + + @Test + public void testReifierInReifiedTriple() throws IOException { + String data = "PREFIX : \n" + + ":x :p <<:s :p :o ~ _:b1 >> ."; + try { + Model model = new LinkedHashModel(); + statementCollector = new StatementCollector(model); + parser.setRDFHandler(statementCollector); + parser.set(BasicParserSettings.PRESERVE_BNODE_IDS, true); + parser.parse(new StringReader(data)); + + assertThat(errorCollector.getErrors()).isEmpty(); - assertTrue(stmts.contains(vf.createStatement(bob, FOAF.KNOWS, aliceKnowsBobCreatedBook))); - assertTrue(stmts.contains(vf.createStatement(bobCreatedBookKnowsAlice, DCTERMS.SOURCE, otherbook))); - assertTrue(stmts.contains(vf.createStatement(bobshomepage, DCTERMS.SOURCE, bookCreatorAlice))); - assertTrue(stmts.contains(vf.createStatement(bookCreatorAlice, DCTERMS.SOURCE, bobshomepage))); - assertTrue(stmts.contains(vf.createStatement(bookCreatorAlice, DCTERMS.REQUIRES, aliceCreatedBook))); - assertTrue(stmts.contains(vf.createStatement(abc, valid, abcDate))); - assertTrue(stmts.contains(vf.createStatement(bobBirthdayDate, DCTERMS.SOURCE, bobshomepage))); - assertTrue(stmts.contains(vf.createStatement(bookTitleEn, DCTERMS.SOURCE, bobshomepage))); - assertTrue(stmts.contains(vf.createStatement(bookTitleDe, DCTERMS.SOURCE, bobshomepage))); - assertTrue(stmts.contains(vf.createStatement(bookTitleEnUs, DCTERMS.SOURCE, bobshomepage))); + assertThat(model).hasSize(2); + + assertTrue(model.contains(vf.createBNode("b1"), RDF.REIFIES, simpleSPOTriple)); + assertTrue(model.contains(vf.createIRI("http://example/x"), vf.createIRI("http://example/p"), + vf.createBNode("b1"))); + } catch (RDFParseException e) { + fail("parse error on correct data: " + e.getMessage()); } } @Test - public void testParseRDFStar_TurtleStarDisabled() throws IOException { - parser.getParserConfig().set(TurtleParserSettings.ACCEPT_TURTLESTAR, false); + public void testReifierWithoutNode() throws IOException { + String data = "PREFIX : \n" + + ":s :p :o ~ ."; + try { + Model model = new LinkedHashModel(); + statementCollector = new StatementCollector(model); + parser.setRDFHandler(statementCollector); + parser.set(BasicParserSettings.PRESERVE_BNODE_IDS, true); + parser.parse(new StringReader(data)); - try (InputStream in = this.getClass().getResourceAsStream("/test-rdfstar.ttls")) { - assertThrows(RDFParseException.class, () -> parser.parse(in, baseURI)); + assertThat(errorCollector.getErrors()).isEmpty(); + + assertThat(model).hasSize(2); + + assertTrue(model.contains(null, RDF.REIFIES, simpleSPOTriple)); + assertTrue(model.contains(simpleSPOStatement)); + } catch (RDFParseException e) { + fail("parse error on correct data: " + e.getMessage()); } } + @Test + public void testReifierAnnotation() throws IOException { + String data = "PREFIX : \n" + + ":s :p :o ~ _:b1 ."; + try { + Model model = new LinkedHashModel(); + statementCollector = new StatementCollector(model); + parser.setRDFHandler(statementCollector); + parser.set(BasicParserSettings.PRESERVE_BNODE_IDS, true); + parser.parse(new StringReader(data)); + + assertThat(errorCollector.getErrors()).isEmpty(); + + assertThat(model).hasSize(2); + + assertTrue(model.contains(vf.createBNode("b1"), RDF.REIFIES, simpleSPOTriple)); + assertTrue(model.contains(simpleSPOStatement)); + } catch (RDFParseException e) { + fail("parse error on correct data: " + e.getMessage()); + } + } + + @Test + public void testReifierAnnotationBlock() throws IOException { + String data = "PREFIX : \n" + + ":s :p :o ~ _:b1 {| :p2 :o2 |} ."; + try { + Model model = new LinkedHashModel(); + statementCollector = new StatementCollector(model); + parser.setRDFHandler(statementCollector); + parser.set(BasicParserSettings.PRESERVE_BNODE_IDS, true); + parser.parse(new StringReader(data)); + + assertThat(errorCollector.getErrors()).isEmpty(); + + assertThat(model).hasSize(3); + + assertTrue(model.contains(vf.createBNode("b1"), RDF.REIFIES, simpleSPOTriple)); + assertTrue(model.contains(simpleSPOStatement)); + assertTrue(model.contains(vf.createBNode("b1"), vf.createIRI("http://example/p2"), + vf.createIRI("http://example/o2"))); + } catch (RDFParseException e) { + fail("parse error on correct data: " + e.getMessage()); + } + } + + @Test + public void testAnnotationBlock() throws IOException { + String data = "PREFIX : \n" + + ":s :p :o {| :p2 :o2 ; :p3 :o3 |} ."; + try { + Model model = new LinkedHashModel(); + statementCollector = new StatementCollector(model); + parser.setRDFHandler(statementCollector); + parser.set(BasicParserSettings.PRESERVE_BNODE_IDS, true); + parser.parse(new StringReader(data)); + + assertThat(errorCollector.getErrors()).isEmpty(); + + assertThat(model).hasSize(4); + + assertTrue(model.contains(simpleSPOStatement)); + + Model reifyingTriples = model.filter(null, RDF.REIFIES, simpleSPOTriple); + assertThat(reifyingTriples).hasSize(1); + Resource reifier = Models.subject(reifyingTriples).get(); + assertInstanceOf(BNode.class, reifier); + + assertTrue(model.contains(reifier, vf.createIRI("http://example/p2"), vf.createIRI("http://example/o2"))); + assertTrue(model.contains(reifier, vf.createIRI("http://example/p3"), vf.createIRI("http://example/o3"))); + } catch (RDFParseException e) { + fail("parse error on correct data: " + e.getMessage()); + } + } } diff --git a/core/rio/turtle/src/test/java/org/eclipse/rdf4j/rio/turtle/TurtleWriterTest.java b/core/rio/turtle/src/test/java/org/eclipse/rdf4j/rio/turtle/TurtleWriterTest.java index c6069c87c5c..281b583450d 100644 --- a/core/rio/turtle/src/test/java/org/eclipse/rdf4j/rio/turtle/TurtleWriterTest.java +++ b/core/rio/turtle/src/test/java/org/eclipse/rdf4j/rio/turtle/TurtleWriterTest.java @@ -18,6 +18,7 @@ import org.eclipse.rdf4j.model.IRI; import org.eclipse.rdf4j.model.Model; +import org.eclipse.rdf4j.model.base.CoreDatatype; import org.eclipse.rdf4j.model.impl.DynamicModelFactory; import org.eclipse.rdf4j.model.util.Models; import org.eclipse.rdf4j.model.vocabulary.RDFS; @@ -754,4 +755,69 @@ public void testIgnoreAbbreviateNumbers() { assertTrue(result.contains("\"-2\"^^")); assertTrue(result.contains("\"55.66\"^^")); } + + @Test + public void testAdditionalDatatypes() { + Model model = new DynamicModelFactory().createEmptyModel(); + String ns = "http://www.example.com/"; + model.add(vf.createIRI(ns, "subject"), vf.createIRI(ns, "predicate"), + vf.createLiteral("object1", CoreDatatype.RDF.JSON)); + model.add(vf.createIRI(ns, "subject"), vf.createIRI(ns, "predicate"), + vf.createLiteral("object2", CoreDatatype.RDF.HTML)); + model.add(vf.createIRI(ns, "subject"), vf.createIRI(ns, "predicate"), + vf.createLiteral("object3", CoreDatatype.RDF.XMLLITERAL)); + + StringWriter stringWriter = new StringWriter(); + Rio.write(model, stringWriter, RDFFormat.TURTLE); + + assertThat(stringWriter.toString()).contains("\"object1\"^^"); + assertThat(stringWriter.toString()).contains("\"object2\"^^"); + assertThat(stringWriter.toString()) + .contains("\"object3\"^^"); + } + + @Test + public void testTripleTerm() { + Model model = new DynamicModelFactory().createEmptyModel(); + String ns = "http://www.example.com/"; + model.setNamespace("", ns); + model.add(vf.createIRI(ns, "s"), vf.createIRI(ns, "p"), + vf.createTriple(vf.createIRI(ns, "s2"), vf.createIRI(ns, "p2"), vf.createIRI(ns, "o"))); + + StringWriter stringWriter = new StringWriter(); + Rio.write(model, stringWriter, RDFFormat.TURTLE); + + assertTrue(stringWriter.toString().contains(":s :p <<( :s2 :p2 :o )>>")); + } + + @Test + public void testNestedTripleTerm() { + Model model = new DynamicModelFactory().createEmptyModel(); + String ns = "http://www.example.com/"; + model.setNamespace("", ns); + model.add(vf.createIRI(ns, "s"), vf.createIRI(ns, "p"), + vf.createTriple(vf.createIRI(ns, "s2"), vf.createIRI(ns, "p2"), + vf.createTriple(vf.createIRI(ns, "s3"), vf.createIRI(ns, "p3"), vf.createIRI(ns, "o")))); + + StringWriter stringWriter = new StringWriter(); + Rio.write(model, stringWriter, RDFFormat.TURTLE); + + assertTrue(stringWriter.toString().contains(":s :p <<( :s2 :p2 <<( :s3 :p3 :o )>> )>> .")); + } + + @Test + public void testNestedTripleTerm2() { + Model model = new DynamicModelFactory().createEmptyModel(); + String ns = "http://www.example.com/"; + model.setNamespace("", ns); + model.add(vf.createBNode("b"), vf.createIRI(ns, "p"), + vf.createTriple(vf.createIRI(ns, "s"), vf.createIRI(ns, "p2"), + vf.createTriple(vf.createBNode("b2"), vf.createIRI(ns, "p3"), vf.createLiteral(9)))); + + StringWriter stringWriter = new StringWriter(); + Rio.write(model, stringWriter, RDFFormat.TURTLE); + + assertTrue(stringWriter.toString() + .contains("_:b :p <<( :s :p2 <<( _:b2 :p3 \"9\"^^ )>> )>> .")); + } } diff --git a/core/rio/turtle/src/test/java/org/eclipse/rdf4j/rio/turtlestar/TestGH3323StackoverflowRDFStar.java b/core/rio/turtle/src/test/java/org/eclipse/rdf4j/rio/turtlestar/TestGH3323StackoverflowRDFStar.java deleted file mode 100644 index 2d7c66eb2d1..00000000000 --- a/core/rio/turtle/src/test/java/org/eclipse/rdf4j/rio/turtlestar/TestGH3323StackoverflowRDFStar.java +++ /dev/null @@ -1,31 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2021 Eclipse RDF4J contributors. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Distribution License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * SPDX-License-Identifier: BSD-3-Clause - *******************************************************************************/ -package org.eclipse.rdf4j.rio.turtlestar; - -import java.io.IOException; -import java.io.StringReader; - -import org.eclipse.rdf4j.rio.RDFFormat; -import org.eclipse.rdf4j.rio.RDFHandlerException; -import org.eclipse.rdf4j.rio.RDFParseException; -import org.eclipse.rdf4j.rio.RDFParser; -import org.eclipse.rdf4j.rio.Rio; -import org.junit.jupiter.api.Test; - -public class TestGH3323StackoverflowRDFStar { - - @Test - public void testUsingParser() throws RDFParseException, RDFHandlerException, IOException { - String ntdata = " ."; - RDFParser parser = Rio.createParser(RDFFormat.TURTLESTAR); - parser.parse(new StringReader(ntdata)); - } -} diff --git a/core/rio/turtle/src/test/java/org/eclipse/rdf4j/rio/turtlestar/TurtleStarHandlingTest.java b/core/rio/turtle/src/test/java/org/eclipse/rdf4j/rio/turtlestar/TurtleStarHandlingTest.java deleted file mode 100644 index 5e27260c98e..00000000000 --- a/core/rio/turtle/src/test/java/org/eclipse/rdf4j/rio/turtlestar/TurtleStarHandlingTest.java +++ /dev/null @@ -1,32 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2020 Eclipse RDF4J contributors. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Distribution License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * SPDX-License-Identifier: BSD-3-Clause - *******************************************************************************/ -package org.eclipse.rdf4j.rio.turtlestar; - -import java.io.OutputStream; - -import org.eclipse.rdf4j.rio.AbstractParserHandlingTest; -import org.eclipse.rdf4j.rio.RDFParser; -import org.eclipse.rdf4j.rio.RDFWriter; - -/** - * @author Pavel Mihaylov - */ -public class TurtleStarHandlingTest extends AbstractParserHandlingTest { - @Override - protected RDFParser getParser() { - return new TurtleStarParser(); - } - - @Override - protected RDFWriter createWriter(OutputStream output) { - return new TurtleStarWriter(output); - } -} diff --git a/core/rio/turtle/src/test/java/org/eclipse/rdf4j/rio/turtlestar/TurtleStarMimeTypeRDFFormatTest.java b/core/rio/turtle/src/test/java/org/eclipse/rdf4j/rio/turtlestar/TurtleStarMimeTypeRDFFormatTest.java deleted file mode 100644 index 4154daf44e1..00000000000 --- a/core/rio/turtle/src/test/java/org/eclipse/rdf4j/rio/turtlestar/TurtleStarMimeTypeRDFFormatTest.java +++ /dev/null @@ -1,62 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2020 Eclipse RDF4J contributors. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Distribution License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * SPDX-License-Identifier: BSD-3-Clause - *******************************************************************************/ -package org.eclipse.rdf4j.rio.turtlestar; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -import java.io.IOException; -import java.io.StringWriter; -import java.io.Writer; - -import org.eclipse.rdf4j.rio.RDFFormat; -import org.eclipse.rdf4j.rio.Rio; -import org.junit.jupiter.api.Test; - -/** - * @author Pavel Mihaylov - */ -public class TurtleStarMimeTypeRDFFormatTest { - private final RDFFormat expectedRDFFormat = RDFFormat.TURTLESTAR; - - @Test - public void testApplicationXTurtleStarUtf8() { - assertEquals(expectedRDFFormat, Rio.getParserFormatForMIMEType("application/x-turtlestar;charset=UTF-8") - .orElseThrow(Rio.unsupportedFormat(expectedRDFFormat))); - } - - @Test - public void testApplicationXTurtleStar() { - assertEquals(expectedRDFFormat, Rio.getParserFormatForMIMEType("application/x-turtlestar") - .orElseThrow(Rio.unsupportedFormat(expectedRDFFormat))); - } - - @Test - public void testRDFFormatParser() { - assertEquals(expectedRDFFormat, new TurtleStarParser().getRDFFormat()); - } - - @Test - public void testRDFFormatWriter() throws IOException { - try (Writer w = new StringWriter()) { - assertEquals(expectedRDFFormat, new TurtleStarWriter(w).getRDFFormat()); - } - } - - @Test - public void testRDFFormatParserFactory() { - assertEquals(expectedRDFFormat, new TurtleStarParserFactory().getRDFFormat()); - } - - @Test - public void testRDFFormatWriterFactory() { - assertEquals(expectedRDFFormat, new TurtleStarWriterFactory().getRDFFormat()); - } -} diff --git a/core/rio/turtle/src/test/java/org/eclipse/rdf4j/rio/turtlestar/TurtleStarParserTest.java b/core/rio/turtle/src/test/java/org/eclipse/rdf4j/rio/turtlestar/TurtleStarParserTest.java deleted file mode 100644 index 445b0090a02..00000000000 --- a/core/rio/turtle/src/test/java/org/eclipse/rdf4j/rio/turtlestar/TurtleStarParserTest.java +++ /dev/null @@ -1,222 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2020 Eclipse RDF4J contributors. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Distribution License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * SPDX-License-Identifier: BSD-3-Clause - *******************************************************************************/ -package org.eclipse.rdf4j.rio.turtlestar; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.eclipse.rdf4j.model.util.Statements.statement; -import static org.eclipse.rdf4j.model.util.Values.iri; -import static org.eclipse.rdf4j.model.util.Values.literal; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assertions.fail; - -import java.io.IOException; -import java.io.InputStream; -import java.io.Reader; -import java.io.StringReader; -import java.util.Collection; - -import org.eclipse.rdf4j.model.IRI; -import org.eclipse.rdf4j.model.Literal; -import org.eclipse.rdf4j.model.Statement; -import org.eclipse.rdf4j.model.Triple; -import org.eclipse.rdf4j.model.ValueFactory; -import org.eclipse.rdf4j.model.impl.SimpleValueFactory; -import org.eclipse.rdf4j.model.util.Values; -import org.eclipse.rdf4j.model.vocabulary.DCTERMS; -import org.eclipse.rdf4j.model.vocabulary.FOAF; -import org.eclipse.rdf4j.model.vocabulary.XSD; -import org.eclipse.rdf4j.rio.RDFParseException; -import org.eclipse.rdf4j.rio.helpers.ParseErrorCollector; -import org.eclipse.rdf4j.rio.helpers.SimpleParseLocationListener; -import org.eclipse.rdf4j.rio.helpers.StatementCollector; -import org.eclipse.rdf4j.rio.helpers.TurtleParserSettings; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -/** - * @author Pavel Mihaylov - */ -public class TurtleStarParserTest { - private TurtleStarParser parser; - - private final ValueFactory vf = SimpleValueFactory.getInstance(); - - private final ParseErrorCollector errorCollector = new ParseErrorCollector(); - - private final StatementCollector statementCollector = new StatementCollector(); - - private final String baseURI = "http://example.org/"; - - private final SimpleParseLocationListener locationListener = new SimpleParseLocationListener(); - - @BeforeEach - public void setUp() { - parser = new TurtleStarParser(); - parser.setParseErrorListener(errorCollector); - parser.setRDFHandler(statementCollector); - parser.setParseLocationListener(locationListener); - } - - @Test - public void testParseRDFStarData() throws IOException { - IRI bob = vf.createIRI("http://example.com/bob"); - IRI alice = vf.createIRI("http://example.com/alice"); - IRI book = vf.createIRI("http://example.com/book"); - IRI otherbook = vf.createIRI("http://example.com/otherbook"); - IRI bobshomepage = vf.createIRI("http://example.com/bobshomepage"); - IRI a = vf.createIRI("http://example.org/a"); - IRI b = vf.createIRI("http://example.com/b"); - IRI c = vf.createIRI("http://example.com/c"); - IRI valid = vf.createIRI("http://example.com/valid"); - Literal abcDate = vf.createLiteral("1999-08-16", XSD.DATE); - Literal birthDate = vf.createLiteral("1908-03-18", XSD.DATE); - Literal titleEn = vf.createLiteral("Example book", "en"); - Literal titleDe = vf.createLiteral("Beispielbuch", "de"); - Literal titleEnUs = vf.createLiteral("Example Book", "en-US"); - - Triple bobCreatedBook = vf.createTriple(bob, DCTERMS.CREATED, book); - Triple aliceKnowsBobCreatedBook = vf.createTriple(alice, FOAF.KNOWS, bobCreatedBook); - Triple bobCreatedBookKnowsAlice = vf.createTriple(bobCreatedBook, FOAF.KNOWS, alice); - Triple bookCreatorAlice = vf.createTriple(book, DCTERMS.CREATOR, alice); - Triple aliceCreatedBook = vf.createTriple(alice, DCTERMS.CREATED, book); - Triple abc = vf.createTriple(a, b, c); - Triple bobBirthdayDate = vf.createTriple(bob, FOAF.BIRTHDAY, birthDate); - Triple bookTitleEn = vf.createTriple(book, DCTERMS.TITLE, titleEn); - Triple bookTitleDe = vf.createTriple(book, DCTERMS.TITLE, titleDe); - Triple bookTitleEnUs = vf.createTriple(book, DCTERMS.TITLE, titleEnUs); - - try (InputStream in = this.getClass().getResourceAsStream("/test-rdfstar.ttls")) { - parser.parse(in, baseURI); - - Collection stmts = statementCollector.getStatements(); - - assertEquals(10, stmts.size()); - - assertTrue(stmts.contains(vf.createStatement(bob, FOAF.KNOWS, aliceKnowsBobCreatedBook))); - assertTrue(stmts.contains(vf.createStatement(bobCreatedBookKnowsAlice, DCTERMS.SOURCE, otherbook))); - assertTrue(stmts.contains(vf.createStatement(bobshomepage, DCTERMS.SOURCE, bookCreatorAlice))); - assertTrue(stmts.contains(vf.createStatement(bookCreatorAlice, DCTERMS.SOURCE, bobshomepage))); - assertTrue(stmts.contains(vf.createStatement(bookCreatorAlice, DCTERMS.REQUIRES, aliceCreatedBook))); - assertTrue(stmts.contains(vf.createStatement(abc, valid, abcDate))); - assertTrue(stmts.contains(vf.createStatement(bobBirthdayDate, DCTERMS.SOURCE, bobshomepage))); - assertTrue(stmts.contains(vf.createStatement(bookTitleEn, DCTERMS.SOURCE, bobshomepage))); - assertTrue(stmts.contains(vf.createStatement(bookTitleDe, DCTERMS.SOURCE, bobshomepage))); - assertTrue(stmts.contains(vf.createStatement(bookTitleEnUs, DCTERMS.SOURCE, bobshomepage))); - } - } - - @Test - public void testParseRDFStar_TurtleStarDisabled() throws IOException { - parser.getParserConfig().set(TurtleParserSettings.ACCEPT_TURTLESTAR, false); - - try (InputStream in = this.getClass().getResourceAsStream("/test-rdfstar.ttls")) { - parser.parse(in, baseURI); - } catch (RDFParseException e) { - fail("parser setting should have no influence on TurtleStarParser handling of RDF-star data"); - } - } - - @Test - public void testTripleInPredicate() throws IOException { - String data = "@prefix ex: .\nex:Example << >> \"foo\" ."; - try (Reader r = new StringReader(data)) { - parser.parse(r, baseURI); - fail("Must fail with RDFParseException"); - } catch (RDFParseException e) { - assertEquals("Illegal predicate value: <> [line 2]", e.getMessage()); - } - } - - @Test - public void testTripleInDatatype() throws IOException { - String data = "@prefix ex: .\nex:Example ex:p \"foo\"^^<< >> ."; - try (Reader r = new StringReader(data)) { - parser.parse(r, baseURI); - fail("Must fail with RDFParseException"); - } catch (RDFParseException e) { - assertEquals("Illegal datatype value: <> [line 2]", e.getMessage()); - } - } - - @Test - public void testTripleAnnotation() throws IOException { - IRI example = iri("http://example.com/Example"); - IRI a = iri("urn:a"), b = iri("urn:b"), c = iri("urn:c"); - Literal foo = literal("foo"); - String data = "@prefix ex: .\nex:Example {| \"foo\" |}."; - Statement st = statement(example, a, b, null); - try (Reader r = new StringReader(data)) { - parser.parse(r, baseURI); - Collection stmts = statementCollector.getStatements(); - - assertThat(stmts).contains(st); - assertThat(stmts).contains(statement(Values.triple(st), c, foo, null)); - } - } - - @Test - public void testTripleMultipleAnnotationSameObject() throws IOException { - IRI example = iri("http://example.com/Example"); - IRI a = iri("urn:a"), b = iri("urn:b"), c = iri("urn:c"), d = iri("urn:d"); - Literal foo = literal("foo"), bar = literal("bar"); - String data = "@prefix ex: .\n" - + "ex:Example {| \"foo\", \"bar\"; \"foo\" |}." - + "ex:Example ."; - - Statement annotatedSt = statement(example, a, b, null); - try (Reader r = new StringReader(data)) { - parser.parse(r, baseURI); - Collection stmts = statementCollector.getStatements(); - - assertThat(stmts).contains(annotatedSt); - assertThat(stmts).contains(statement(Values.triple(annotatedSt), c, foo, null)); - assertThat(stmts).contains(statement(Values.triple(annotatedSt), c, bar, null)); - assertThat(stmts).contains(statement(Values.triple(annotatedSt), d, foo, null)); - assertThat(stmts).contains(statement(example, d, a, null)); - } - } - - @Test - public void testTripleMultipleAnnotationMultipleObjects() throws IOException { - IRI example = iri("http://example.com/Example"); - IRI a = iri("urn:a"), b = iri("urn:b"), c = iri("urn:c"), d = iri("urn:d"); - Literal foo = literal("foo"), bar = literal("bar"); - String data = "@prefix ex: .\n" - + "ex:Example {| \"foo\" |}, {| \"bar\" |}." - + "ex:Example ."; - - Statement annotatedSt1 = statement(example, a, b, null), annotatedSt2 = statement(example, a, d, null); - try (Reader r = new StringReader(data)) { - parser.parse(r, baseURI); - Collection stmts = statementCollector.getStatements(); - - assertThat(stmts).contains(annotatedSt1); - assertThat(stmts).contains(statement(Values.triple(annotatedSt1), c, foo, null)); - assertThat(stmts).contains(statement(Values.triple(annotatedSt2), c, bar, null)); - assertThat(stmts).contains(statement(example, d, a, null)); - assertThat(stmts).doesNotContain(statement(Values.triple(annotatedSt1), c, bar, null)); - - } - } - - @Test - public void testMalformedTripleAnnotation() throws IOException { - String data = "@prefix ex: .\nex:Example {| \"foo\" }."; - try (Reader r = new StringReader(data)) { - assertThatThrownBy(() -> parser.parse(r, baseURI)) - .isInstanceOf(RDFParseException.class) - .hasMessageContaining("Expected '|', found '}'"); - } - } - -} diff --git a/core/rio/turtle/src/test/java/org/eclipse/rdf4j/rio/turtlestar/TurtleStarPrettyWriterTest.java b/core/rio/turtle/src/test/java/org/eclipse/rdf4j/rio/turtlestar/TurtleStarPrettyWriterTest.java deleted file mode 100644 index eaad82f9256..00000000000 --- a/core/rio/turtle/src/test/java/org/eclipse/rdf4j/rio/turtlestar/TurtleStarPrettyWriterTest.java +++ /dev/null @@ -1,29 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2020 Eclipse RDF4J contributors. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Distribution License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * SPDX-License-Identifier: BSD-3-Clause - *******************************************************************************/ -package org.eclipse.rdf4j.rio.turtlestar; - -import org.eclipse.rdf4j.rio.WriterConfig; -import org.eclipse.rdf4j.rio.helpers.BasicWriterSettings; -import org.eclipse.rdf4j.rio.turtle.AbstractTurtleWriterTest; - -/** - * @author Pavel Mihaylov - */ -public class TurtleStarPrettyWriterTest extends AbstractTurtleWriterTest { - public TurtleStarPrettyWriterTest() { - super(new TurtleStarWriterFactory(), new TurtleStarParserFactory()); - } - - @Override - protected void setupWriterConfig(WriterConfig config) { - config.set(BasicWriterSettings.PRETTY_PRINT, true); - } -} diff --git a/core/rio/turtle/src/test/java/org/eclipse/rdf4j/rio/turtlestar/TurtleStarWriterTest.java b/core/rio/turtle/src/test/java/org/eclipse/rdf4j/rio/turtlestar/TurtleStarWriterTest.java deleted file mode 100644 index f7fc8dce2dd..00000000000 --- a/core/rio/turtle/src/test/java/org/eclipse/rdf4j/rio/turtlestar/TurtleStarWriterTest.java +++ /dev/null @@ -1,29 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2020 Eclipse RDF4J contributors. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Distribution License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * SPDX-License-Identifier: BSD-3-Clause - *******************************************************************************/ -package org.eclipse.rdf4j.rio.turtlestar; - -import org.eclipse.rdf4j.rio.WriterConfig; -import org.eclipse.rdf4j.rio.helpers.BasicWriterSettings; -import org.eclipse.rdf4j.rio.turtle.AbstractTurtleWriterTest; - -/** - * @author Pavel Mihaylov - */ -public class TurtleStarWriterTest extends AbstractTurtleWriterTest { - public TurtleStarWriterTest() { - super(new TurtleStarWriterFactory(), new TurtleStarParserFactory()); - } - - @Override - protected void setupWriterConfig(WriterConfig config) { - config.set(BasicWriterSettings.PRETTY_PRINT, false); - } -} diff --git a/core/sail/api/pom.xml b/core/sail/api/pom.xml index 94ba13deba0..ce33a75d90a 100644 --- a/core/sail/api/pom.xml +++ b/core/sail/api/pom.xml @@ -4,7 +4,7 @@ org.eclipse.rdf4j rdf4j-sail - 5.1.0-SNAPSHOT + 6.0.0 rdf4j-sail-api RDF4J: Sail API diff --git a/core/sail/base/pom.xml b/core/sail/base/pom.xml index 37f440d24a5..df7d797e85a 100644 --- a/core/sail/base/pom.xml +++ b/core/sail/base/pom.xml @@ -4,7 +4,7 @@ org.eclipse.rdf4j rdf4j-sail - 5.1.0-SNAPSHOT + 6.0.0 rdf4j-sail-base RDF4J: Sail base implementations diff --git a/core/sail/base/src/main/java/org/eclipse/rdf4j/sail/base/SailDataset.java b/core/sail/base/src/main/java/org/eclipse/rdf4j/sail/base/SailDataset.java index b47b9410ae9..90972ce3da9 100644 --- a/core/sail/base/src/main/java/org/eclipse/rdf4j/sail/base/SailDataset.java +++ b/core/sail/base/src/main/java/org/eclipse/rdf4j/sail/base/SailDataset.java @@ -106,18 +106,18 @@ default CloseableIteration getStatements(StatementOrder sta } /** - * Gets all RDF-star triples that have a specific subject, predicate and/or object. All three parameters may be null + * Gets all RDF 1.2 triples that have a specific subject, predicate and/or object. All three parameters may be null * to indicate wildcards. * * @param subj A Resource specifying the subject, or null for a wildcard. * @param pred A IRI specifying the predicate, or null for a wildcard. * @param obj A Value specifying the object, or null for a wildcard. * @return An iterator over the relevant triples. - * @throws SailException If the triple source failed to get the RDF-star triples. + * @throws SailException If the triple source failed to get the RDF 1.2 triples. */ default CloseableIteration getTriples(Resource subj, IRI pred, Value obj) throws SailException { - throw new SailException("RDF-star triple retrieval not supported by this store"); + throw new SailException("RDF 1.2 triple retrieval not supported by this store"); } @Experimental diff --git a/core/sail/base/src/main/java/org/eclipse/rdf4j/sail/base/SailDatasetImpl.java b/core/sail/base/src/main/java/org/eclipse/rdf4j/sail/base/SailDatasetImpl.java index b90a9008657..eeb648f8b39 100644 --- a/core/sail/base/src/main/java/org/eclipse/rdf4j/sail/base/SailDatasetImpl.java +++ b/core/sail/base/src/main/java/org/eclipse/rdf4j/sail/base/SailDatasetImpl.java @@ -363,15 +363,6 @@ protected void handleClose() { private boolean isDeprecated(Triple triple, List deprecatedStatements) { // the triple is deprecated if the changeset deprecates all existing statements in the backing dataset that // involve this triple. - try (CloseableIteration subjectStatements = derivedFrom - .getStatements(triple, null, null)) { - while (subjectStatements.hasNext()) { - Statement st = subjectStatements.next(); - if (!deprecatedStatements.contains(st)) { - return false; - } - } - } try (CloseableIteration objectStatements = derivedFrom .getStatements(null, null, triple)) { while (objectStatements.hasNext()) { diff --git a/core/sail/base/src/main/java/org/eclipse/rdf4j/sail/base/SailDatasetTripleSource.java b/core/sail/base/src/main/java/org/eclipse/rdf4j/sail/base/SailDatasetTripleSource.java index 0301a4675f1..d7c6465a4db 100644 --- a/core/sail/base/src/main/java/org/eclipse/rdf4j/sail/base/SailDatasetTripleSource.java +++ b/core/sail/base/src/main/java/org/eclipse/rdf4j/sail/base/SailDatasetTripleSource.java @@ -114,7 +114,7 @@ public CloseableIteration getRdfStarTriples(Resource subj, IRI TripleSourceIterationWrapper iterationWrapper = null; try { // In contrast to statement retrieval (which gets de-duplicated later on when handling things like - // projections and conversions) we need to make sure we de-duplicate the RDF-star triples here. + // projections and conversions) we need to make sure we de-duplicate the triples here. triples = dataset.getTriples(subj, pred, obj); if (triples instanceof EmptyIteration) { return triples; diff --git a/core/sail/elasticsearch-store/pom.xml b/core/sail/elasticsearch-store/pom.xml index 8542f4a1aaa..f20b716c697 100644 --- a/core/sail/elasticsearch-store/pom.xml +++ b/core/sail/elasticsearch-store/pom.xml @@ -4,7 +4,7 @@ org.eclipse.rdf4j rdf4j-sail - 5.1.0-SNAPSHOT + 6.0.0 rdf4j-sail-elasticsearch-store RDF4J: Elasticsearch Store diff --git a/core/sail/elasticsearch-store/src/main/java/org/eclipse/rdf4j/sail/elasticsearchstore/ElasticsearchDataStructure.java b/core/sail/elasticsearch-store/src/main/java/org/eclipse/rdf4j/sail/elasticsearchstore/ElasticsearchDataStructure.java index f4dff97822e..638dce115e6 100644 --- a/core/sail/elasticsearch-store/src/main/java/org/eclipse/rdf4j/sail/elasticsearchstore/ElasticsearchDataStructure.java +++ b/core/sail/elasticsearch-store/src/main/java/org/eclipse/rdf4j/sail/elasticsearchstore/ElasticsearchDataStructure.java @@ -243,6 +243,9 @@ private QueryBuilder getQueryBuilder(Resource subject, IRI predicate, Value obje if (((Literal) object).getLanguage().isPresent()) { boolQueryBuilder .must(QueryBuilders.termQuery("object_Lang", ((Literal) object).getLanguage().get())); + boolQueryBuilder + .must(QueryBuilders.termQuery("object_LangDir", + ((Literal) object).getBaseDirection().toString())); } } } @@ -450,7 +453,7 @@ private Map statementToJsonMap(ExtensibleStatement statement) { ((Literal) statement.getObject()).getDatatype().stringValue()); if (((Literal) statement.getObject()).getLanguage().isPresent()) { jsonMap.put("object_Lang", ((Literal) statement.getObject()).getLanguage().get()); - + jsonMap.put("object_LangDir", ((Literal) statement.getObject()).getBaseDirection().toString()); } } return jsonMap; @@ -673,8 +676,8 @@ private static ExtensibleStatement sourceToStatement(Map sourceA objectRes = vf.createBNode(objectString); } else { if (sourceAsMap.containsKey("object_Lang")) { - objectRes = vf.createLiteral(objectString, (String) sourceAsMap.get("object_Lang")); - + objectRes = vf.createLiteral(objectString, (String) sourceAsMap.get("object_Lang"), + Literal.BaseDirection.fromString((String) sourceAsMap.get("object_LangDir"))); } else { objectRes = vf.createLiteral(objectString, vf.createIRI((String) sourceAsMap.get("object_Datatype"))); diff --git a/core/sail/elasticsearch/pom.xml b/core/sail/elasticsearch/pom.xml index 022319c4697..820d3298d25 100644 --- a/core/sail/elasticsearch/pom.xml +++ b/core/sail/elasticsearch/pom.xml @@ -4,7 +4,7 @@ org.eclipse.rdf4j rdf4j-sail - 5.1.0-SNAPSHOT + 6.0.0 rdf4j-sail-elasticsearch RDF4J: Elastic Search Sail Index diff --git a/core/sail/extensible-store/pom.xml b/core/sail/extensible-store/pom.xml index e8d6a1af491..7a1bb47ba8e 100644 --- a/core/sail/extensible-store/pom.xml +++ b/core/sail/extensible-store/pom.xml @@ -4,7 +4,7 @@ org.eclipse.rdf4j rdf4j-sail - 5.1.0-SNAPSHOT + 6.0.0 rdf4j-sail-extensible-store RDF4J: Extensible Store diff --git a/core/sail/inferencer/pom.xml b/core/sail/inferencer/pom.xml index 45babf4a3e2..af2d0616638 100644 --- a/core/sail/inferencer/pom.xml +++ b/core/sail/inferencer/pom.xml @@ -4,7 +4,7 @@ org.eclipse.rdf4j rdf4j-sail - 5.1.0-SNAPSHOT + 6.0.0 rdf4j-sail-inferencer RDF4J: Inferencer Sails diff --git a/core/sail/lmdb/pom.xml b/core/sail/lmdb/pom.xml index 787fb19c4d4..200c7518c2a 100644 --- a/core/sail/lmdb/pom.xml +++ b/core/sail/lmdb/pom.xml @@ -4,7 +4,7 @@ org.eclipse.rdf4j rdf4j-sail - 5.1.0-SNAPSHOT + 6.0.0 rdf4j-sail-lmdb RDF4J: LmdbStore diff --git a/core/sail/lmdb/src/main/java/org/eclipse/rdf4j/sail/lmdb/ValueStore.java b/core/sail/lmdb/src/main/java/org/eclipse/rdf4j/sail/lmdb/ValueStore.java index 342ab9d97e3..0c078d6e6bf 100644 --- a/core/sail/lmdb/src/main/java/org/eclipse/rdf4j/sail/lmdb/ValueStore.java +++ b/core/sail/lmdb/src/main/java/org/eclipse/rdf4j/sail/lmdb/ValueStore.java @@ -1531,6 +1531,11 @@ public LmdbLiteral createLiteral(String value, String language) { return new LmdbLiteral(revision, value, language); } + @Override + public LmdbLiteral createLiteral(String value, String language, Literal.BaseDirection baseDirection) { + return new LmdbLiteral(revision, value, language, baseDirection); + } + /*----------------------------------------------------------------------* * Methods for converting model objects to LmdbStore-specific objects * *----------------------------------------------------------------------*/ diff --git a/core/sail/lmdb/src/main/java/org/eclipse/rdf4j/sail/lmdb/model/LmdbLiteral.java b/core/sail/lmdb/src/main/java/org/eclipse/rdf4j/sail/lmdb/model/LmdbLiteral.java index d6efea7435d..c2e78aee517 100644 --- a/core/sail/lmdb/src/main/java/org/eclipse/rdf4j/sail/lmdb/model/LmdbLiteral.java +++ b/core/sail/lmdb/src/main/java/org/eclipse/rdf4j/sail/lmdb/model/LmdbLiteral.java @@ -11,6 +11,7 @@ package org.eclipse.rdf4j.sail.lmdb.model; import java.io.ObjectStreamException; +import java.util.Objects; import java.util.Optional; import org.eclipse.rdf4j.model.IRI; @@ -40,6 +41,8 @@ public class LmdbLiteral extends AbstractLiteral implements LmdbValue { */ private String language; + private BaseDirection baseDirection; + /** * The literal's datatype. */ @@ -79,10 +82,25 @@ public LmdbLiteral(ValueStoreRevision revision, String label, String lang) { } public LmdbLiteral(ValueStoreRevision revision, String label, String lang, long internalID) { + this(revision, label, lang, BaseDirection.NONE, internalID); + } + + public LmdbLiteral(ValueStoreRevision revision, String label, String lang, BaseDirection baseDirection) { + this(revision, label, lang, baseDirection, UNKNOWN_ID); + } + + public LmdbLiteral(ValueStoreRevision revision, String label, String language, BaseDirection baseDirection, + long internalID) { + Objects.requireNonNull(language, "null language"); + Objects.requireNonNull(baseDirection, "null baseDirection"); this.label = label; - this.language = lang; - coreDatatype = CoreDatatype.RDF.LANGSTRING; - datatype = CoreDatatype.RDF.LANGSTRING.getIri(); + this.language = language; + this.baseDirection = baseDirection; + if (baseDirection != BaseDirection.NONE) { + setDatatype(CoreDatatype.RDF.DIRLANGSTRING); + } else { + setDatatype(CoreDatatype.RDF.LANGSTRING); + } setInternalID(internalID, revision); this.initialized = true; } @@ -188,6 +206,11 @@ public Optional getLanguage() { return Optional.ofNullable(language); } + @Override + public BaseDirection getBaseDirection() { + return baseDirection; + } + public void setLanguage(String language) { this.language = language; } diff --git a/core/sail/lucene-api/pom.xml b/core/sail/lucene-api/pom.xml index 3fb152fa5f1..3e08644e6fc 100644 --- a/core/sail/lucene-api/pom.xml +++ b/core/sail/lucene-api/pom.xml @@ -4,7 +4,7 @@ org.eclipse.rdf4j rdf4j-sail - 5.1.0-SNAPSHOT + 6.0.0 rdf4j-sail-lucene-api RDF4J: Lucene Sail API diff --git a/core/sail/lucene/pom.xml b/core/sail/lucene/pom.xml index 530c6ac3c5d..51d6a9e0887 100644 --- a/core/sail/lucene/pom.xml +++ b/core/sail/lucene/pom.xml @@ -4,7 +4,7 @@ org.eclipse.rdf4j rdf4j-sail - 5.1.0-SNAPSHOT + 6.0.0 rdf4j-sail-lucene RDF4J: Lucene Sail Index diff --git a/core/sail/memory/pom.xml b/core/sail/memory/pom.xml index ae81a8c5531..34004b8f80c 100644 --- a/core/sail/memory/pom.xml +++ b/core/sail/memory/pom.xml @@ -4,7 +4,7 @@ org.eclipse.rdf4j rdf4j-sail - 5.1.0-SNAPSHOT + 6.0.0 rdf4j-sail-memory RDF4J: MemoryStore diff --git a/core/sail/memory/src/main/java/org/eclipse/rdf4j/sail/memory/FileIO.java b/core/sail/memory/src/main/java/org/eclipse/rdf4j/sail/memory/FileIO.java index 04d99bfdc55..b71a71417ea 100644 --- a/core/sail/memory/src/main/java/org/eclipse/rdf4j/sail/memory/FileIO.java +++ b/core/sail/memory/src/main/java/org/eclipse/rdf4j/sail/memory/FileIO.java @@ -39,7 +39,7 @@ import org.eclipse.rdf4j.model.Value; import org.eclipse.rdf4j.model.ValueFactory; import org.eclipse.rdf4j.model.util.Literals; -import org.eclipse.rdf4j.rio.helpers.RDFStarUtil; +import org.eclipse.rdf4j.rio.helpers.TripleTermUtil; import org.eclipse.rdf4j.sail.SailException; import org.eclipse.rdf4j.sail.base.SailDataset; import org.eclipse.rdf4j.sail.base.SailSink; @@ -294,7 +294,7 @@ private void writeValue(Value value, DataOutputStream dataOut) throws IOExceptio } } else if (value.isTriple()) { dataOut.writeByte(RDFSTAR_TRIPLE_MARKER); - writeValue(RDFStarUtil.toRDFEncodedValue(value), dataOut); + writeValue(TripleTermUtil.toRDFEncodedValue(value), dataOut); } else { throw new IllegalArgumentException("unexpected value type: " + value.getClass()); } @@ -322,7 +322,7 @@ private Value readValue(DataInputStream dataIn) throws IOException, ClassCastExc return vf.createLiteral(label, datatype); } else if (valueTypeMarker == RDFSTAR_TRIPLE_MARKER) { IRI rdfStarEncodedTriple = (IRI) readValue(dataIn); - Triple triple = (Triple) RDFStarUtil.fromRDFEncodedValue(rdfStarEncodedTriple, vf); + Triple triple = (Triple) TripleTermUtil.fromRDFEncodedValue(rdfStarEncodedTriple, vf); return vf.getOrCreateMemTriple(triple); } else { throw new IOException("Invalid value type marker: " + valueTypeMarker); diff --git a/core/sail/memory/src/main/java/org/eclipse/rdf4j/sail/memory/model/MemLiteral.java b/core/sail/memory/src/main/java/org/eclipse/rdf4j/sail/memory/model/MemLiteral.java index c45353d8a35..8db789f8fb5 100644 --- a/core/sail/memory/src/main/java/org/eclipse/rdf4j/sail/memory/model/MemLiteral.java +++ b/core/sail/memory/src/main/java/org/eclipse/rdf4j/sail/memory/model/MemLiteral.java @@ -64,6 +64,19 @@ public MemLiteral(Object creator, String label, String lang) { this.creator = creator; } + /** + * Creates a new Literal which will get the supplied label, language code, and base direction. + * + * @param creator The object that is creating this MemLiteral. + * @param label The label for this literal. + * @param lang The language code of the supplied label. + * @param baseDirection The base direction as a string ("", "--ltr", "--rtl"). + */ + public MemLiteral(Object creator, String label, String lang, BaseDirection baseDirection) { + super(label, lang, baseDirection); + this.creator = creator; + } + /** * Creates a new Literal which will get the supplied label and datatype. * diff --git a/core/sail/memory/src/main/java/org/eclipse/rdf4j/sail/memory/model/MemTriple.java b/core/sail/memory/src/main/java/org/eclipse/rdf4j/sail/memory/model/MemTriple.java index 6045419b023..a6b85dfec03 100644 --- a/core/sail/memory/src/main/java/org/eclipse/rdf4j/sail/memory/model/MemTriple.java +++ b/core/sail/memory/src/main/java/org/eclipse/rdf4j/sail/memory/model/MemTriple.java @@ -19,7 +19,7 @@ * * @author Jeen Broekstra */ -public class MemTriple extends MemResource implements Triple { +public class MemTriple implements MemValue, Triple { private static final long serialVersionUID = -9085188980084028689L; @@ -43,13 +43,13 @@ public MemTriple(Object creator, MemResource subject, MemIRI predicate, MemValue @Override public String stringValue() { - return "<<" + + return "<<(" + getSubject() + " " + getPredicate() + " " + getObject() + - ">>"; + ")>>"; } @Override @@ -88,26 +88,6 @@ public void cleanSnapshotsFromObjectStatements(int currentSnapshot) throws Inter objectStatements.cleanSnapshots(currentSnapshot); } - @Override - public MemStatementList getContextStatementList() { - return EMPTY_LIST; - } - - @Override - public int getContextStatementCount() { - return 0; - } - - @Override - public void addContextStatement(MemStatement st) { - throw new UnsupportedOperationException("RDF-star triples can not be used as context identifier"); - } - - @Override - public void cleanSnapshotsFromContextStatements(int currentSnapshot) { - // no-op - } - @Override public MemResource getSubject() { return subject; @@ -143,6 +123,11 @@ public boolean equals(Object other) { return false; } + @Override + public boolean hasSubjectStatements() { + return false; + } + @Override public boolean hasPredicateStatements() { return false; diff --git a/core/sail/memory/src/main/java/org/eclipse/rdf4j/sail/memory/model/MemTripleIterator.java b/core/sail/memory/src/main/java/org/eclipse/rdf4j/sail/memory/model/MemTripleIterator.java index a36a957a0c4..3fc2f33513c 100644 --- a/core/sail/memory/src/main/java/org/eclipse/rdf4j/sail/memory/model/MemTripleIterator.java +++ b/core/sail/memory/src/main/java/org/eclipse/rdf4j/sail/memory/model/MemTripleIterator.java @@ -102,12 +102,7 @@ protected MemTriple getNextElement() { } if (isInSnapshot(statement)) { - if (statement.getSubject().isTriple() && statement.getSubject() instanceof MemTriple) { - MemTriple triple = (MemTriple) statement.getSubject(); - if (triple.matchesSPO(subject, predicate, object)) { - return triple; - } - } else if (statement.getObject().isTriple() && statement.getObject() instanceof MemTriple) { + if (statement.getObject().isTriple() && statement.getObject() instanceof MemTriple) { MemTriple triple = (MemTriple) statement.getObject(); if (triple.matchesSPO(subject, predicate, object)) { return triple; diff --git a/core/sail/memory/src/main/java/org/eclipse/rdf4j/sail/memory/model/MemValueFactory.java b/core/sail/memory/src/main/java/org/eclipse/rdf4j/sail/memory/model/MemValueFactory.java index c638737b43d..305ff4e7ced 100644 --- a/core/sail/memory/src/main/java/org/eclipse/rdf4j/sail/memory/model/MemValueFactory.java +++ b/core/sail/memory/src/main/java/org/eclipse/rdf4j/sail/memory/model/MemValueFactory.java @@ -122,8 +122,6 @@ public MemResource getMemResource(Resource resource) { return getMemURI((IRI) resource); } else if (resource.isBNode()) { return getMemBNode((BNode) resource); - } else if (resource.isTriple()) { - return getMemTriple((Triple) resource); } else { throw new IllegalArgumentException("resource is not a URI or BNode: " + resource); } @@ -239,8 +237,10 @@ public MemValue getOrCreateMemValue(Value value) { return getOrCreateMemResource((Resource) value); } else if (value.isLiteral()) { return getOrCreateMemLiteral((Literal) value); + } else if (value.isTriple()) { + return getOrCreateMemTriple((Triple) value); } else { - throw new IllegalArgumentException("value is not a Resource or Literal: " + value); + throw new IllegalArgumentException("value is not a Resource, Literal, or Triple: " + value); } } @@ -252,8 +252,6 @@ public MemResource getOrCreateMemResource(Resource resource) { return getOrCreateMemURI((IRI) resource); } else if (resource.isBNode()) { return getOrCreateMemBNode((BNode) resource); - } else if (resource.isTriple()) { - return getOrCreateMemTriple((Triple) resource); } else { throw new IllegalArgumentException("resource is not a URI or BNode: " + resource); } @@ -302,7 +300,7 @@ public MemLiteral getOrCreateMemLiteral(Literal literal) { IRI datatype = coreDatatype != CoreDatatype.NONE ? coreDatatype.getIri() : literal.getDatatype(); if (Literals.isLanguageLiteral(literal)) { - return new MemLiteral(this, label, literal.getLanguage().get()); + return new MemLiteral(this, label, literal.getLanguage().get(), literal.getBaseDirection()); } else { try { if (coreDatatype.isXSDDatatype()) { @@ -406,6 +404,11 @@ public Literal createLiteral(String value, String language) { return getOrCreateMemLiteral(super.createLiteral(value, language)); } + @Override + public Literal createLiteral(String value, String language, Literal.BaseDirection baseDirection) { + return getOrCreateMemLiteral(super.createLiteral(value, language, baseDirection)); + } + @Override public Literal createLiteral(String value, IRI datatype) { return getOrCreateMemLiteral(super.createLiteral(value, datatype)); diff --git a/core/sail/memory/src/test/java/org/eclipse/rdf4j/sail/memory/MemTripleSourceTest.java b/core/sail/memory/src/test/java/org/eclipse/rdf4j/sail/memory/MemTripleSourceTest.java index 0de4e1c9e07..859af818126 100644 --- a/core/sail/memory/src/test/java/org/eclipse/rdf4j/sail/memory/MemTripleSourceTest.java +++ b/core/sail/memory/src/test/java/org/eclipse/rdf4j/sail/memory/MemTripleSourceTest.java @@ -21,6 +21,7 @@ import org.eclipse.rdf4j.model.IRI; import org.eclipse.rdf4j.model.Resource; import org.eclipse.rdf4j.model.Statement; +import org.eclipse.rdf4j.model.Triple; import org.eclipse.rdf4j.model.Value; import org.eclipse.rdf4j.model.ValueFactory; import org.eclipse.rdf4j.model.vocabulary.OWL; @@ -61,6 +62,8 @@ public class MemTripleSourceTest { private IRI mary; + private Triple t; + private ValueFactory f; private SailDataset snapshot; @@ -78,6 +81,7 @@ public void setUp() { bob = f.createIRI(EX_NS, "bob"); alice = f.createIRI(EX_NS, "alice"); mary = f.createIRI(EX_NS, "mary"); + t = f.createTriple(bob, mary, alice); } /** diff --git a/core/sail/memory/src/test/java/org/eclipse/rdf4j/sail/memory/MemoryStoreTest.java b/core/sail/memory/src/test/java/org/eclipse/rdf4j/sail/memory/MemoryStoreTest.java index bde0277d663..6879010196f 100644 --- a/core/sail/memory/src/test/java/org/eclipse/rdf4j/sail/memory/MemoryStoreTest.java +++ b/core/sail/memory/src/test/java/org/eclipse/rdf4j/sail/memory/MemoryStoreTest.java @@ -16,7 +16,9 @@ import org.eclipse.rdf4j.common.iteration.CloseableIteration; import org.eclipse.rdf4j.model.IRI; +import org.eclipse.rdf4j.model.Triple; import org.eclipse.rdf4j.model.Value; +import org.eclipse.rdf4j.model.vocabulary.RDF; import org.eclipse.rdf4j.query.BindingSet; import org.eclipse.rdf4j.query.QueryLanguage; import org.eclipse.rdf4j.query.impl.EmptyBindingSet; @@ -69,4 +71,23 @@ public void testZeroOrOnePropPathNonExisting() { assertEquals(1, count, "expect single solution"); } + @Test + public void testTripleRoundTrip1() { + IRI subj = vf.createIRI("http://example.org/subject"); + IRI pred = vf.createIRI("http://example.org/predicate"); + Triple obj = vf.createTriple(subj, pred, vf.createLiteral("object")); + + testValueRoundTrip(subj, pred, obj); + } + + @Test + public void testTripleRoundTrip2() { + IRI subj = vf.createIRI("http://example.org/subject"); + IRI pred = RDF.REIFIES; + Triple obj = vf.createTriple(vf.createBNode("b"), vf.createIRI("http://example.org/predicate"), + vf.createTriple(vf.createIRI("http://example.org/subject2"), + vf.createIRI("http://example.org/predicate2"), vf.createLiteral("object"))); + + testValueRoundTrip(subj, pred, obj); + } } diff --git a/core/sail/memory/src/test/java/org/eclipse/rdf4j/sail/memory/MemoryRDFStarSupportTest.java b/core/sail/memory/src/test/java/org/eclipse/rdf4j/sail/memory/MemoryTripleTermSupportTest.java similarity index 86% rename from core/sail/memory/src/test/java/org/eclipse/rdf4j/sail/memory/MemoryRDFStarSupportTest.java rename to core/sail/memory/src/test/java/org/eclipse/rdf4j/sail/memory/MemoryTripleTermSupportTest.java index c78548047a6..860a300b72d 100644 --- a/core/sail/memory/src/test/java/org/eclipse/rdf4j/sail/memory/MemoryRDFStarSupportTest.java +++ b/core/sail/memory/src/test/java/org/eclipse/rdf4j/sail/memory/MemoryTripleTermSupportTest.java @@ -14,13 +14,13 @@ import org.eclipse.rdf4j.repository.Repository; import org.eclipse.rdf4j.repository.sail.SailRepository; -import org.eclipse.rdf4j.testsuite.repository.RDFStarSupportTest; +import org.eclipse.rdf4j.testsuite.repository.TripleTermSupportTest; import org.junit.jupiter.api.io.TempDir; /** * @author jeen */ -public class MemoryRDFStarSupportTest extends RDFStarSupportTest { +public class MemoryTripleTermSupportTest extends TripleTermSupportTest { @TempDir File tempDir; diff --git a/core/sail/memory/src/test/java/org/eclipse/rdf4j/sail/memory/StoreSerializationTest.java b/core/sail/memory/src/test/java/org/eclipse/rdf4j/sail/memory/StoreSerializationTest.java index d1fd1aef7bd..052bacd7f3b 100644 --- a/core/sail/memory/src/test/java/org/eclipse/rdf4j/sail/memory/StoreSerializationTest.java +++ b/core/sail/memory/src/test/java/org/eclipse/rdf4j/sail/memory/StoreSerializationTest.java @@ -18,6 +18,7 @@ import org.eclipse.rdf4j.common.io.FileUtil; import org.eclipse.rdf4j.common.iteration.CloseableIteration; +import org.eclipse.rdf4j.model.BNode; import org.eclipse.rdf4j.model.IRI; import org.eclipse.rdf4j.model.Literal; import org.eclipse.rdf4j.model.Statement; @@ -178,12 +179,12 @@ public void testMemTriple() { store.init(); ValueFactory factory = store.getValueFactory(); + BNode b = factory.createBNode("b"); Triple triple = factory.createTriple(RDF.TYPE, RDF.TYPE, RDF.TYPE); - Literal longLiteral = factory.createLiteral("a".repeat(4)); try (SailConnection con = store.getConnection()) { con.begin(); - con.addStatement(triple, RDFS.LABEL, longLiteral); + con.addStatement(b, RDF.REIFIES, triple); con.commit(); } @@ -193,11 +194,11 @@ public void testMemTriple() { store.init(); try (SailConnection con = store.getConnection()) { - try (CloseableIteration iter = con.getStatements(null, RDFS.LABEL, null, + try (CloseableIteration iter = con.getStatements(null, RDF.REIFIES, null, false)) { assertTrue(iter.hasNext()); Statement next = iter.next(); - assertEquals(next.getSubject(), triple); + assertEquals(next.getObject(), triple); } } store.shutDown(); diff --git a/core/sail/memory/src/test/java/org/eclipse/rdf4j/sail/memory/model/MemTripleTest.java b/core/sail/memory/src/test/java/org/eclipse/rdf4j/sail/memory/model/MemTripleTest.java index 714f570005b..fbe69c0032f 100644 --- a/core/sail/memory/src/test/java/org/eclipse/rdf4j/sail/memory/model/MemTripleTest.java +++ b/core/sail/memory/src/test/java/org/eclipse/rdf4j/sail/memory/model/MemTripleTest.java @@ -49,11 +49,11 @@ public void setUp() { @Test public void testStringValue() { assertThat(triple.stringValue()) - .startsWith("<<") + .startsWith("<<(") .contains(s1.stringValue()) .contains(p1.stringValue()) .contains(o1.stringValue()) - .endsWith(">>"); + .endsWith(")>>"); } @Test diff --git a/core/sail/memory/src/test/java/org/eclipse/rdf4j/sail/memory/model/MemValueFactoryTest.java b/core/sail/memory/src/test/java/org/eclipse/rdf4j/sail/memory/model/MemValueFactoryTest.java index 087af609931..f62d86e44c1 100644 --- a/core/sail/memory/src/test/java/org/eclipse/rdf4j/sail/memory/model/MemValueFactoryTest.java +++ b/core/sail/memory/src/test/java/org/eclipse/rdf4j/sail/memory/model/MemValueFactoryTest.java @@ -13,6 +13,8 @@ import static org.assertj.core.api.Assertions.assertThat; import org.eclipse.rdf4j.model.IRI; +import org.eclipse.rdf4j.model.Literal; +import org.eclipse.rdf4j.model.base.CoreDatatype; import org.junit.jupiter.api.Test; public class MemValueFactoryTest { @@ -28,4 +30,14 @@ public void testCreateIRI_namespace_localName_whitespace() { assertThat(factory.createIRI(namespace, localName)).isInstanceOf(IRI.class); } + @Test + public void testCreateDirLangLiteral() { + final Literal literal = new MemValueFactory().createLiteral("label", "he", Literal.BaseDirection.RTL); + + assertThat(literal).isNotNull(); + assertThat(literal.getLabel()).isEqualTo("label"); + assertThat(literal.getLanguage()).contains("he"); + assertThat(literal.getBaseDirection().toString()).isEqualTo("--rtl"); + assertThat(literal.getDatatype()).isEqualTo(CoreDatatype.RDF.DIRLANGSTRING.getIri()); + } } diff --git a/core/sail/model/pom.xml b/core/sail/model/pom.xml index 531c473d10a..daba982e5a9 100644 --- a/core/sail/model/pom.xml +++ b/core/sail/model/pom.xml @@ -4,7 +4,7 @@ org.eclipse.rdf4j rdf4j-sail - 5.1.0-SNAPSHOT + 6.0.0 rdf4j-sail-model RDF4J: Sail Model diff --git a/core/sail/nativerdf/pom.xml b/core/sail/nativerdf/pom.xml index 17dbcc1c962..e4a634354bc 100644 --- a/core/sail/nativerdf/pom.xml +++ b/core/sail/nativerdf/pom.xml @@ -4,7 +4,7 @@ org.eclipse.rdf4j rdf4j-sail - 5.1.0-SNAPSHOT + 6.0.0 rdf4j-sail-nativerdf RDF4J: NativeStore diff --git a/core/sail/nativerdf/src/main/java/org/eclipse/rdf4j/sail/nativerdf/ValueStore.java b/core/sail/nativerdf/src/main/java/org/eclipse/rdf4j/sail/nativerdf/ValueStore.java index 37787ac610c..f5cfc25f837 100644 --- a/core/sail/nativerdf/src/main/java/org/eclipse/rdf4j/sail/nativerdf/ValueStore.java +++ b/core/sail/nativerdf/src/main/java/org/eclipse/rdf4j/sail/nativerdf/ValueStore.java @@ -742,6 +742,11 @@ public NativeLiteral createLiteral(String value, String language) { return new NativeLiteral(revision, value, language); } + @Override + public NativeLiteral createLiteral(String value, String language, Literal.BaseDirection baseDirection) { + return new NativeLiteral(revision, value, language, baseDirection); + } + @Override public NativeLiteral createLiteral(String value, IRI datatype) { return new NativeLiteral(revision, value, datatype); diff --git a/core/sail/nativerdf/src/main/java/org/eclipse/rdf4j/sail/nativerdf/model/NativeLiteral.java b/core/sail/nativerdf/src/main/java/org/eclipse/rdf4j/sail/nativerdf/model/NativeLiteral.java index 876aebe001f..0389e755cfd 100644 --- a/core/sail/nativerdf/src/main/java/org/eclipse/rdf4j/sail/nativerdf/model/NativeLiteral.java +++ b/core/sail/nativerdf/src/main/java/org/eclipse/rdf4j/sail/nativerdf/model/NativeLiteral.java @@ -58,6 +58,16 @@ public NativeLiteral(ValueStoreRevision revision, String label, String lang, int setInternalID(internalID, revision); } + public NativeLiteral(ValueStoreRevision revision, String label, String lang, BaseDirection baseDirection) { + this(revision, label, lang, baseDirection, UNKNOWN_ID); + } + + public NativeLiteral(ValueStoreRevision revision, String label, String lang, BaseDirection baseDirection, + int internalID) { + super(label, lang, baseDirection); + setInternalID(internalID, revision); + } + public NativeLiteral(ValueStoreRevision revision, String label, IRI datatype) { this(revision, label, datatype, UNKNOWN_ID); } diff --git a/core/sail/pom.xml b/core/sail/pom.xml index cbce9f38bc7..10178c26042 100644 --- a/core/sail/pom.xml +++ b/core/sail/pom.xml @@ -4,7 +4,7 @@ org.eclipse.rdf4j rdf4j-core - 5.1.0-SNAPSHOT + 6.0.0 rdf4j-sail pom diff --git a/core/sail/shacl/pom.xml b/core/sail/shacl/pom.xml index 9cae94fe046..79341e3181d 100644 --- a/core/sail/shacl/pom.xml +++ b/core/sail/shacl/pom.xml @@ -4,7 +4,7 @@ org.eclipse.rdf4j rdf4j-sail - 5.1.0-SNAPSHOT + 6.0.0 rdf4j-shacl RDF4J: SHACL diff --git a/core/sail/solr/pom.xml b/core/sail/solr/pom.xml index c79bfa393e7..dfc29d60665 100644 --- a/core/sail/solr/pom.xml +++ b/core/sail/solr/pom.xml @@ -4,7 +4,7 @@ org.eclipse.rdf4j rdf4j-sail - 5.1.0-SNAPSHOT + 6.0.0 rdf4j-sail-solr RDF4J: Solr Sail Index diff --git a/core/sparqlbuilder/pom.xml b/core/sparqlbuilder/pom.xml index 2e589196e67..a7a2e7ef01d 100644 --- a/core/sparqlbuilder/pom.xml +++ b/core/sparqlbuilder/pom.xml @@ -4,7 +4,7 @@ org.eclipse.rdf4j rdf4j-core - 5.1.0-SNAPSHOT + 6.0.0 rdf4j-sparqlbuilder RDF4J: SparqlBuilder diff --git a/core/spin/pom.xml b/core/spin/pom.xml index b80e9d40e04..bff5f352e8a 100644 --- a/core/spin/pom.xml +++ b/core/spin/pom.xml @@ -4,7 +4,7 @@ org.eclipse.rdf4j rdf4j-core - 5.1.0-SNAPSHOT + 6.0.0 rdf4j-spin RDF4J: SPIN diff --git a/core/storage/pom.xml b/core/storage/pom.xml index 6775e4bf837..e8d18f12df4 100644 --- a/core/storage/pom.xml +++ b/core/storage/pom.xml @@ -4,7 +4,7 @@ org.eclipse.rdf4j rdf4j-core - 5.1.0-SNAPSHOT + 6.0.0 rdf4j-storage RDF4J: Storage Libraries diff --git a/examples/pom.xml b/examples/pom.xml index 5610e589454..d5655199e6f 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -7,7 +7,7 @@ org.eclipse.rdf4j rdf4j - 5.1.0-SNAPSHOT + 6.0.0 diff --git a/pom.xml b/pom.xml index 87e98c6a41b..cbb3557a452 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ 4.0.0 org.eclipse.rdf4j rdf4j - 5.1.0-SNAPSHOT + 6.0.0 pom Eclipse RDF4J An extensible Java framework for RDF and SPARQL @@ -913,6 +913,9 @@ @org.eclipse.rdf4j.common.annotation.Experimental org.eclipse.rdf4j.common.annotation.InternalUseOnly org.eclipse.rdf4j.common.annotation.Experimental + org.eclipse.rdf4j.rio.trigstar.* + org.eclipse.rdf4j.rio.turtlestar.* + org.eclipse.rdf4j.model.util.RDFStarTestHelper.java