org.eclipse.rdf4j.model.util.Models Maven / Gradle / Ivy
Show all versions of rdf4j-model Show documentation
/*******************************************************************************
* Copyright (c) 2015 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.model.util;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;
import org.eclipse.rdf4j.common.annotation.Experimental;
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.ModelFactory;
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.DynamicModelFactory;
import org.eclipse.rdf4j.model.impl.LinkedHashModel;
import org.eclipse.rdf4j.model.impl.SimpleValueFactory;
import org.eclipse.rdf4j.model.vocabulary.RDF;
/**
* Utility functions for working with {@link Model}s and other {@link Statement} collections.
*
* @author Jeen Broekstra
* @author Arjohn Kampman
* @see org.eclipse.rdf4j.model.Model
* @see org.eclipse.rdf4j.model.util.ModelBuilder
*/
public class Models {
/*
* hidden constructor to avoid instantiation
*/
protected Models() {
}
/**
* Retrieves an object {@link Value} from the supplied statements. If more than one possible object value exists,
* any one value is picked and returned.
*
* @param statements the {@link Statement } {@link Iterable} from which to retrieve an object value.
* @return an object value from the given statement collection, or {@link Optional#empty()} if no such value exists.
* @apiNote this method signature is new in 3.2.0, and is a generalization of {@link #object(Model)}.
*/
public static Optional object(Iterable statements) {
return StreamSupport.stream(statements.spliterator(), false).map(st -> st.getObject()).findAny();
}
/**
* Retrieves an object {@link Value} from the statements in the given model. If more than one possible object value
* exists, any one value is picked and returned.
*
* @param m the model from which to retrieve an object value.
* @return an object value from the given model, or {@link Optional#empty()} if no such value exists.
* @apiNote replaced in 3.2.0 with the more generic {@link #object(Iterable)}. This method signature kept for binary
* compatibility.
*/
public static Optional object(Model m) {
return object((Iterable) m);
}
/**
* Retrieves an object {@link Literal} value from the supplied statements. If more than one possible Literal value
* exists, any one Literal value is picked and returned.
*
* @param statements the {@link Statement} {@link Iterable} from which to retrieve an object Literal value.
* @return an object Literal value from the given model, or {@link Optional#empty()} if no such value exists.
* @apiNote this method signature is new in 3.2.0, and is a generalization of {@link #objectLiteral(Model)}.
*/
public static Optional objectLiteral(Iterable statements) {
return StreamSupport.stream(statements.spliterator(), false)
.map(st -> st.getObject())
.filter(o -> o instanceof Literal)
.map(l -> (Literal) l)
.findAny();
}
/**
* Retrieves an object {@link Literal} value from the statements in the given model. If more than one possible
* Literal value exists, any one Literal value is picked and returned.
*
* @param m the {@link Model} from which to retrieve an object Literal value.
* @return an object Literal value from the given model, or {@link Optional#empty()} if no such value exists.
* @apiNote replaced in 3.2.0 with the more generic {@link #objectLiteral(Iterable)}. This method signature kept for
* binary compatibility.
*/
public static Optional objectLiteral(Model m) {
return objectLiteral((Iterable) m);
}
/**
* Retrieves all object {@link Literal} values from the supplied statements.
*
* @param statements the {@link Statement} {@link Iterable} from which to retrieve all object {@link Literal}
* values.
* @return a {@link Set} containing object {@link Literal} values from the given model, which will be empty if no
* such value exists.
* @apiNote this method signature is new in 3.2.0, and is a generalization of {@link #objectLiterals(Model)}.
* @see Model#objects()
*/
public static Set objectLiterals(Iterable statements) {
return StreamSupport.stream(statements.spliterator(), false)
.map(st -> st.getObject())
.filter(o -> o instanceof Literal)
.map(l -> (Literal) l)
.collect(Collectors.toSet());
}
/**
* Retrieves all object {@link Literal} values from the statements in the given model.
*
* @param m the model from which to retrieve all object {@link Literal} values.
* @return a {@link Set} containing object {@link Literal} values from the given model, which will be empty if no
* such value exists.
* @apiNote replaced in 3.2.0 with the more generic {@link #objectLiterals(Iterable)}. This method signature kept
* for binary compatibility.
* @see Model#objects()
*/
public static Set objectLiterals(Model m) {
return objectLiterals((Iterable) m);
}
/**
* Retrieves an object {@link Resource} value from the supplied statements. If more than one possible Resource value
* exists, any one Resource value is picked and returned.
*
* @param statements the {@link Statement} {@link Iterable} from which to retrieve an object Resource value.
* @return an {@link Optional} object Resource value from the given model, which will be {@link Optional#empty()
* empty} if no such value exists.
* @apiNote this method signature is new in 3.2.0, and is a generalization of {@link #objectResource(Model)}.
*/
public static Optional objectResource(Iterable statements) {
return StreamSupport.stream(statements.spliterator(), false)
.map(st -> st.getObject())
.filter(o -> o instanceof Resource)
.map(r -> (Resource) r)
.findAny();
}
/**
* Retrieves an object {@link Resource} value from the statements in the given model. If more than one possible
* Resource value exists, any one Resource value is picked and returned.
*
* @param m the model from which to retrieve an object Resource value.
* @return an {@link Optional} object Resource value from the given model, which will be {@link Optional#empty()
* empty} if no such value exists.
* @apiNote replaced in 3.2.0 with the more generic {@link #objectResource(Iterable)}. This method signature kept
* for binary compatibility.
*/
public static Optional objectResource(Model m) {
return objectResource((Iterable) m);
}
/**
* Retrieves all object {@link Resource} values from the supplied statements.
*
* @param statements the {@link Statement} {@link Iterable} from which to retrieve all object {@link Resource}
* values.
* @return a {@link Set} containing object {@link Resource} values from the given model, which will be empty if no
* such value exists.
* @apiNote this method signature is new in 3.2.0, and is a generalization of {@link #objectResources(Model)}.
* @see Model#objects()
*/
public static Set objectResources(Iterable statements) {
return StreamSupport.stream(statements.spliterator(), false)
.map(st -> st.getObject())
.filter(o -> o instanceof Resource)
.map(r -> (Resource) r)
.collect(Collectors.toSet());
}
/**
* Retrieves all object {@link Resource} values from the supplied model.
*
* @param m the {@link Model} from which to retrieve all object {@link Resource} values.
* @return a {@link Set} containing object {@link Resource} values from the given model, which will be empty if no
* such value exists.
* @apiNote replaced in 3.2.0 with the more generic {@link #objectResources(Iterable)}. This method signature kept
* for binary compatibility.
* @see Model#objects()
*/
public static Set objectResources(Model m) {
return objectResources((Iterable) m);
}
/**
* Retrieves an object {@link IRI} value from the supplied statements. If more than one possible IRI value exists,
* any one value is picked and returned.
*
* @param statements the {@link Statement} {@link Iterable} from which to retrieve an object IRI value.
* @return an {@link Optional} object IRI value from the given model, which will be {@link Optional#empty() empty}
* if no such value exists.
* @apiNote this method signature is new in 3.2.0, and is a generalization of {@link #objectIRI(Model)}.
*/
public static Optional objectIRI(Iterable statements) {
return StreamSupport.stream(statements.spliterator(), false)
.map(st -> st.getObject())
.filter(o -> o instanceof IRI)
.map(r -> (IRI) r)
.findAny();
}
/**
* Retrieves an object {@link IRI} value from the supplied statements in the given model. If more than one possible
* IRI value exists, any one value is picked and returned.
*
* @param m the model from which to retrieve an object IRI value.
* @return an {@link Optional} object IRI value from the given model, which will be {@link Optional#empty() empty}
* if no such value exists.
* @apiNote replaced in 3.2.0 with the more generic {@link #objectIRI(Iterable)}. This method signature kept for
* binary compatibility.
*/
public static Optional objectIRI(Model m) {
return objectIRI((Iterable) m);
}
/**
* Retrieves all object {@link IRI} values from the supplied statements.
*
* @param statements the {@link Statement} {@link Iterable} from which to retrieve all object IRI values.
* @return a {@link Set} containing object IRI values from the given model, which will be empty if no such value
* exists.
* @apiNote this method signature is new in 3.2.0, and is a generalization of {@link #objectIRIs(Model)}.
* @see Model#objects()
*/
public static Set objectIRIs(Iterable statements) {
return StreamSupport.stream(statements.spliterator(), false)
.map(st -> st.getObject())
.filter(o -> o instanceof IRI)
.map(r -> (IRI) r)
.collect(Collectors.toSet());
}
/**
* Retrieves all object {@link IRI} values from the statements in the given model.
*
* @param m the {@link Model} from which to retrieve all object IRI values.
* @return a {@link Set} containing object IRI values from the given model, which will be empty if no such value
* exists.
* @apiNote replaced in 3.2.0 with the more generic {@link #objectIRIs(Iterable)}. This method signature kept for
* binary compatibility.
* @see Model#objects()
*/
public static Set objectIRIs(Model m) {
return objectIRIs((Iterable) m);
}
/**
* Retrieves an object value as a String from the supplied statements. If more than one possible object value
* exists, any one value is picked and returned.
*
* @param statements the {@link Statement} {@link Iterable} from which to retrieve an object String value.
* @return an {@link Optional} object String value from the given model, which will be {@link Optional#empty()
* empty} if no such value exists.
* @apiNote this method signature is new in 3.2.0, and is a generalization of {@link #objectString(Model)}.
*/
public static Optional objectString(Iterable statements) {
return StreamSupport.stream(statements.spliterator(), false).map(st -> st.getObject().stringValue()).findAny();
}
/**
* Retrieves an object value as a String from the statements in the given model. If more than one possible object
* value exists, any one value is picked and returned.
*
* @param m the model from which to retrieve an object String value.
* @return an {@link Optional} object String value from the given model, which will be {@link Optional#empty()
* empty} if no such value exists.
* @apiNote replaced in 3.2.0 with the more generic {@link #objectString(Iterable)}. This method signature kept for
* binary compatibility.
*/
public static Optional objectString(Model m) {
return objectString((Iterable) m);
}
/**
* Retrieves all object String values from the supplied statements.
*
* @param statements the {@link Statement} {@link Iterable} from which to retrieve all object String values.
* @return a {@link Set} containing object String values from the given model, which will be empty if no such value
* exists.
* @apiNote this method signature is new in 3.2.0, and is a generalization of {@link #objectStrings(Model)}.
* @see Model#objects()
*/
public static Set objectStrings(Iterable statements) {
return StreamSupport.stream(statements.spliterator(), false)
.map(st -> st.getObject().stringValue())
.collect(Collectors.toSet());
}
/**
* Retrieves all object String values from the statements in the given model.
*
* @param m the model from which to retrieve all object String values.
* @return a {@link Set} containing object String values from the given model, which will be empty if no such value
* exists.
* @apiNote replaced in 3.2.0 with the more generic {@link #objectStrings(Iterable)}. This method signature kept for
* binary compatibility.
* @see Model#objects()
*/
public static Set objectStrings(Model m) {
return objectStrings((Iterable) m);
}
/**
* Retrieves a subject {@link Resource} from the supplied statements. If more than one possible resource value
* exists, any one resource value is picked and returned.
*
* @param statements the {@link Statement} {@link Iterable} from which to retrieve a subject Resource.
* @return an {@link Optional} subject resource from the given model, which will be {@link Optional#empty() empty}
* if no such value exists.
* @apiNote this method signature is new in 3.2.0, and is a generalization of {@link #subject(Model)}.
*/
public static Optional subject(Iterable statements) {
return StreamSupport.stream(statements.spliterator(), false).map(st -> st.getSubject()).findAny();
}
/**
* Retrieves a subject {@link Resource} from the statements in the given model. If more than one possible resource
* value exists, any one resource value is picked and returned.
*
* @param m the model from which to retrieve a subject Resource.
* @return an {@link Optional} subject resource from the given model, which will be {@link Optional#empty() empty}
* if no such value exists.
* @apiNote replaced in 3.2.0 with the more generic {@link #subject(Iterable)}. This method signature kept for
* binary compatibility.
*/
public static Optional subject(Model m) {
return subject((Iterable) m);
}
/**
* Retrieves a subject {@link IRI} from the supplied statements. If more than one possible IRI value exists, any one
* IRI value is picked and returned.
*
* @param statements the {@link Statement} {@link Iterable} from which to retrieve a subject IRI value.
* @return an {@link Optional} subject IRI value from the given model, which will be {@link Optional#empty() empty}
* if no such value exists.
* @apiNote this method signature is new in 3.2.0, and is a generalization of {@link #subjectIRI(Model)}.
*/
public static Optional subjectIRI(Iterable statements) {
return StreamSupport.stream(statements.spliterator(), false)
.map(st -> st.getSubject())
.filter(s -> s instanceof IRI)
.map(s -> (IRI) s)
.findAny();
}
/**
* Retrieves a subject {@link IRI} from the statements in the given model. If more than one possible IRI value
* exists, any one IRI value is picked and returned.
*
* @param m the model from which to retrieve a subject IRI value.
* @return an {@link Optional} subject IRI value from the given model, which will be {@link Optional#empty() empty}
* if no such value exists.
* @apiNote replaced in 3.2.0 with the more generic {@link #subjectIRI(Iterable)}. This method signature kept for
* binary compatibility.
*/
public static Optional subjectIRI(Model m) {
return subjectIRI((Iterable) m);
}
/**
* Retrieves all subject {@link IRI}s from the supplied statements.
*
* @param statements the {@link Statement} {@link Iterable} from which to retrieve a subject IRI value.
* @return a {@link Set} of subject IRI values from the given model. The returned Set may be empty.
* @apiNote this method signature is new in 3.2.0, and is a generalization of {@link #subjectIRIs(Model)}.
*/
public static Set subjectIRIs(Iterable statements) {
return StreamSupport.stream(statements.spliterator(), false)
.map(st -> st.getSubject())
.filter(o -> o instanceof IRI)
.map(r -> (IRI) r)
.collect(Collectors.toSet());
}
/**
* Retrieves all subject {@link IRI}s from the statements in the given model.
*
* @param m the model from which to retrieve a subject IRI value.
* @return a {@link Set} of subject IRI values from the given model. The returned Set may be empty.
* @apiNote replaced in 3.2.0 with the more generic {@link #subjectIRIs(Iterable)}. This method signature kept for
* binary compatibility.
*/
public static Set subjectIRIs(Model m) {
return subjectIRIs((Iterable) m);
}
/**
* Retrieves a subject {@link BNode} from the supplied statements. If more than one possible blank node value
* exists, any one blank node value is picked and returned.
*
* @param statements the {@link Statement} {@link Iterable} from which to retrieve a subject BNode value.
* @return an {@link Optional} subject BNode value from the given model, which will be {@link Optional#empty()
* empty} if no such value exists.
* @apiNote this method signature is new in 3.2.0, and is a generalization of {@link #subjectBNode(Model)}.
*/
public static Optional subjectBNode(Iterable statements) {
return StreamSupport.stream(statements.spliterator(), false)
.map(st -> st.getSubject())
.filter(s -> s instanceof BNode)
.map(s -> (BNode) s)
.findAny();
}
/**
* Retrieves a subject {@link BNode} from the statements in the given model. If more than one possible blank node
* value exists, any one blank node value is picked and returned.
*
* @param m the model from which to retrieve a subject BNode value.
* @return an {@link Optional} subject BNode value from the given model, which will be {@link Optional#empty()
* empty} if no such value exists.
* @apiNote replaced in 3.2.0 with the more generic {@link #subjectBNode(Iterable)}. This method signature kept for
* binary compatibility.
*/
public static Optional subjectBNode(Model m) {
return subjectBNode((Iterable) m);
}
/**
* Retrieves all subject {@link BNode}s from the supplied statements.
*
* @param statements the {@link Statement} {@link Iterable} from which to retrieve a subject IRI value.
* @return a {@link Set} of subject {@link BNode} values from the given model. The returned Set may be empty.
* @apiNote this method signature is new in 3.2.0, and is a generalization of {@link #subjectBNodes(Model)}.
*/
public static Set subjectBNodes(Iterable statements) {
return StreamSupport.stream(statements.spliterator(), false)
.map(st -> st.getSubject())
.filter(o -> o instanceof BNode)
.map(r -> (BNode) r)
.collect(Collectors.toSet());
}
/**
* Retrieves all subject {@link BNode}s from the statements in the given model.
*
* @param m the model from which to retrieve a subject IRI value.
* @return a {@link Set} of subject {@link BNode} values from the given model. The returned Set may be empty.
* @apiNote replaced in 3.2.0 with the more generic {@link #subjectBNodes(Iterable)}. This method signature kept for
* binary compatibility.
*/
public static Set subjectBNodes(Model m) {
return subjectBNodes((Iterable) m);
}
/**
* Retrieves a predicate from the supplied statements. If more than one possible predicate value exists, any one
* value is picked and returned.
*
* @param statements the {@link Statement} {@link Iterable} from which to retrieve a predicate value.
* @return an {@link Optional} predicate value from the given model, which will be {@link Optional#empty() empty} if
* no such value exists.
* @apiNote this method signature is new in 3.2.0, and is a generalization of {@link #predicate(Model)}.
*/
public static Optional predicate(Iterable statements) {
return StreamSupport.stream(statements.spliterator(), false).map(st -> st.getPredicate()).findAny();
}
/**
* Retrieves a predicate from the statements in the given model. If more than one possible predicate value exists,
* any one value is picked and returned.
*
* @param m the model from which to retrieve a predicate value.
* @return an {@link Optional} predicate value from the given model, which will be {@link Optional#empty() empty} if
* no such value exists.
* @apiNote replaced in 3.2.0 with the more generic {@link #predicate(Iterable)}. This method signature kept for
* binary compatibility.
*/
public static Optional predicate(Model m) {
return predicate((Iterable) m);
}
/**
* Sets the property value for the given subject to the given object value, replacing any existing value(s) for the
* subject's property. This method updates the original input Model and then returns that same Model object.
*
* @param m the model in which to set the property value. May not be null.
* @param subject the subject for which to set/replace the property value. May not be null.
* @param property the property for which to set/replace the value. May not be null.
* @param value the value to set for the given subject and property. May not be null.
* @param contexts the context(s) in which to set/replace the property value. Optional vararg argument. If not
* specified the operations works on the entire Model.
* @return the Model object, containing the updated property value.
*/
public static Model setProperty(Model m, Resource subject, IRI property, Value value, Resource... contexts) {
Objects.requireNonNull(m, "model may not be null");
Objects.requireNonNull(subject, "subject may not be null");
Objects.requireNonNull(property, "property may not be null");
Objects.requireNonNull(value, "value may not be null");
if (m.contains(subject, property, null, contexts)) {
m.remove(subject, property, null, contexts);
}
m.add(subject, property, value, contexts);
return m;
}
/**
* Retrieve a property value for the supplied subject from the given model. If more than one property value exists,
* any one value is picked and returned.
*
* @param m the model from which to retrieve an object value.
* @param subject the subject resource for which to retrieve a property value.
* @param property the property for which to retrieve a value.
* @param contexts the contexts from which to retrieve the property value. Optional vararg argument. If not
* specified the operations works on the entire Model.
* @return a property value from the given model, or {@link Optional#empty()} if no such value exists.
*/
public static Optional getProperty(Model m, Resource subject, IRI property, Resource... contexts) {
Objects.requireNonNull(m, "model may not be null");
Objects.requireNonNull(subject, "subject may not be null");
Objects.requireNonNull(property, "property may not be null");
return object(m.getStatements(subject, property, null, contexts));
}
/**
* Retrieve all property values for the supplied subject and property from the given model.
*
* @param m the model from which to retrieve the property values.
* @param subject the subject resource for which to retrieve all property values.
* @param property the property for which to retrieve all values.
* @param contexts the contexts from which to retrieve the property values. Optional vararg argument. If not
* specified the operations works on the entire Model.
* @return a Set of all property values for the supplied input. The resulting set may be empty.
*/
public static Set getProperties(Model m, Resource subject, IRI property, Resource... contexts) {
Objects.requireNonNull(m, "model may not be null");
Objects.requireNonNull(subject, "subject may not be null");
Objects.requireNonNull(property, "property may not be null");
return m.filter(subject, property, null, contexts).objects();
}
/**
* Retrieve a property value as an IRI for the supplied subject from the given model. If more than one property
* value exists, any one value is picked and returned.
*
* @param m the model from which to retrieve an object value.
* @param subject the subject resource for which to retrieve a property value.
* @param property the property for which to retrieve a value.
* @param contexts the contexts from which to retrieve the property value. Optional vararg argument. If not
* specified the operations works on the entire Model.
* @return a property value Resource from the given model, or {@link Optional#empty()} if no such value exists.
*/
public static Optional getPropertyResource(Model m, Resource subject, IRI property,
Resource... contexts) {
Objects.requireNonNull(m, "model may not be null");
Objects.requireNonNull(subject, "subject may not be null");
Objects.requireNonNull(property, "property may not be null");
return objectResource(m.getStatements(subject, property, null, contexts));
}
/**
* Retrieve all property Resource values for the supplied subject and property from the given model.
*
* @param m the model from which to retrieve the property Resource values.
* @param subject the subject resource for which to retrieve all property Resource values.
* @param property the property for which to retrieve all Resource values.
* @param contexts the contexts from which to retrieve the property values. Optional vararg argument. If not
* specified the operations works on the entire Model.
* @return a Set of all property Resource values for the supplied input. The resulting set may be empty.
*/
public static Set getPropertyResources(Model m, Resource subject, IRI property, Resource... contexts) {
Objects.requireNonNull(m, "model may not be null");
Objects.requireNonNull(subject, "subject may not be null");
Objects.requireNonNull(property, "property may not be null");
return objectResources(m.getStatements(subject, property, null, contexts));
}
/**
* Retrieve a property value as an IRI for the supplied subject from the given model. If more than one property
* value exists, any one value is picked and returned.
*
* @param m the model from which to retrieve an object value.
* @param subject the subject resource for which to retrieve a property value.
* @param property the property for which to retrieve a value.
* @param contexts the contexts from which to retrieve the property value. Optional vararg argument. If not
* specified the operations works on the entire Model.
* @return a property value IRI from the given model, or {@link Optional#empty()} if no such value exists.
*/
public static Optional getPropertyIRI(Model m, Resource subject, IRI property, Resource... contexts) {
Objects.requireNonNull(m, "model may not be null");
Objects.requireNonNull(subject, "subject may not be null");
Objects.requireNonNull(property, "property may not be null");
return objectIRI(m.getStatements(subject, property, null, contexts));
}
/**
* Retrieve all property IRI values for the supplied subject and property from the given model.
*
* @param m the model from which to retrieve the property IRI values.
* @param subject the subject resource for which to retrieve all property IRI values.
* @param property the property for which to retrieve all IRI values.
* @param contexts the contexts from which to retrieve the property values. Optional vararg argument. If not
* specified the operations works on the entire Model.
* @return a Set of all property IRI values for the supplied input. The resulting set may be empty.
*/
public static Set getPropertyIRIs(Model m, Resource subject, IRI property, Resource... contexts) {
Objects.requireNonNull(m, "model may not be null");
Objects.requireNonNull(subject, "subject may not be null");
Objects.requireNonNull(property, "property may not be null");
return objectIRIs(m.getStatements(subject, property, null, contexts));
}
/**
* Retrieve a property value as a {@link Literal} for the supplied subject from the given model. If more than one
* property value exists, any one value is picked and returned.
*
* @param m the model from which to retrieve an object value.
* @param subject the subject resource for which to retrieve a property literal value.
* @param property the property for which to retrieve a value.
* @param contexts the contexts from which to retrieve the property value. Optional vararg argument. If not
* specified the operations works on the entire Model.
* @return a property value Literal from the given model, or {@link Optional#empty()} if no such value exists.
*/
public static Optional getPropertyLiteral(Model m, Resource subject, IRI property, Resource... contexts) {
Objects.requireNonNull(m, "model may not be null");
Objects.requireNonNull(subject, "subject may not be null");
Objects.requireNonNull(property, "property may not be null");
return objectLiteral(m.getStatements(subject, property, null, contexts));
}
/**
* Retrieve all property Literal values for the supplied subject and property from the given model.
*
* @param m the model from which to retrieve the property Literal values.
* @param subject the subject resource for which to retrieve all property Literal values.
* @param property the property for which to retrieve all Literal values.
* @param contexts the contexts from which to retrieve the property values. Optional vararg argument. If not
* specified the operations works on the entire Model.
* @return a Set of all property IRI values for the supplied input. The resulting set may be empty.
*/
public static Set getPropertyLiterals(Model m, Resource subject, IRI property, Resource... contexts) {
Objects.requireNonNull(m, "model may not be null");
Objects.requireNonNull(subject, "subject may not be null");
Objects.requireNonNull(property, "property may not be null");
return objectLiterals(m.getStatements(subject, property, null, contexts));
}
/**
* Retrieve a property value as a String for the supplied subject from the given model. If more than one property
* value exists, any one value is picked and returned.
*
* @param m the model from which to retrieve an object value.
* @param subject the subject resource for which to retrieve a property literal value.
* @param property the property for which to retrieve a value.
* @param contexts the contexts from which to retrieve the property value. Optional vararg argument. If not
* specified the operations works on the entire Model.
* @return a property value String from the given model, or {@link Optional#empty()} if no such value exists.
*/
public static Optional getPropertyString(Model m, Resource subject, IRI property, Resource... contexts) {
Objects.requireNonNull(m, "model may not be null");
Objects.requireNonNull(subject, "subject may not be null");
Objects.requireNonNull(property, "property may not be null");
return objectString(m.getStatements(subject, property, null, contexts));
}
/**
* Retrieve all property values as Strings for the supplied subject and property from the given model.
*
* @param m the model from which to retrieve the property values as Strings.
* @param subject the subject resource for which to retrieve all property values as Strings.
* @param property the property for which to retrieve all values as Strings.
* @param contexts the contexts from which to retrieve the property values. Optional vararg argument. If not
* specified the operations works on the entire Model.
* @return a Set of all property values as Strings for the supplied input. The resulting set may be empty.
*/
public static Set getPropertyStrings(Model m, Resource subject, IRI property, Resource... contexts) {
Objects.requireNonNull(m, "model may not be null");
Objects.requireNonNull(subject, "subject may not be null");
Objects.requireNonNull(property, "property may not be null");
return objectStrings(m.getStatements(subject, property, null, contexts));
}
/**
* Compares two RDF models, and returns true if they consist of isomorphic graphs and the isomorphic
* graph identifiers map 1:1 to each other. RDF graphs are isomorphic graphs if statements from one graphs can be
* mapped 1:1 on to statements in the other graphs. In this mapping, blank nodes are not considered mapped when
* having an identical internal id, but are mapped from one graph to the other by looking at the statements in which
* the blank nodes occur. A Model can consist of more than one graph (denoted by context identifiers). Two models
* are considered isomorphic if for each of the graphs in one model, an isomorphic graph exists in the other model,
* and the context identifiers of these graphs are either identical or (in the case of blank nodes) map 1:1 on each
* other.
*
* @see RDF Concepts & Abstract Syntax, section
* 3.6 (Graph Comparison)
*/
public static boolean isomorphic(Iterable extends Statement> model1, Iterable extends Statement> model2) {
if (model1 == model2) {
return true;
}
Model set1 = toModel(model1);
Model set2 = toModel(model2);
return GraphComparisons.isomorphic(set1, set2);
}
/**
* Legacy implementation of {@link #isomorphic(Iterable, Iterable) isomorphic comparison}. This method is offered as
* a temporary fallback for corner cases where the newly introduced isomorphism algorithm (in release 3.6.0) has
* worse performance or an unexpected result.
*
* @apiNote This method is offered as a temporary fallback only, and will likely be removed again quite soon in a
* future minor or major release.
* @implNote This uses an algorithm that has poor performance in many cases and can potentially get stuck in an
* endless loop. We strongly recommend using the new algorithm available in the
* {@link #isomorphic(Iterable, Iterable)} implementation.
* @see #isomorphic(Iterable, Iterable)
* @since 3.6.0
* @deprecated Use {@link #isomorphic(Iterable, Iterable)} instead.
*/
@Experimental
@Deprecated(since = "3.6.0")
public static boolean legacyIsomorphic(Iterable extends Statement> model1, Iterable extends Statement> model2) {
if (model1 == model2) {
return true;
}
Set set1 = toSet(model1);
Model set2 = toModel(model2);
// Compare the number of statements in both sets
if (set1.size() != set2.size()) {
return false;
}
return isSubsetInternal(set1, set2);
}
/**
* Compares two RDF models, and returns true if the first model is a subset of the second model, using
* graph isomorphism to map statements between models.
*/
public static boolean isSubset(Iterable extends Statement> model1, Iterable extends Statement> model2) {
// Filter duplicates
Set set1 = toSet(model1);
Model set2 = toModel(model2);
return isSubset(set1, set2);
}
/**
* Compares two RDF models, and returns true if the first model is a subset of the second model, using
* graph isomorphism to map statements between models.
*/
public static boolean isSubset(Set extends Statement> model1, Set extends Statement> model2) {
// Compare the number of statements in both sets
if (model1.size() > model2.size()) {
return false;
}
return isSubsetInternal(toSet(model1), toModel(model2));
}
/**
* Strips contexts from the input model. This method provides a new {@link Model} containing all statements from the
* input model, with the supplied contexts removed from those statements.
*
* @param model the input model
* @param contexts the contexts to remove. This is a vararg and as such is optional. If not supplied, the method
* strips all contexts.
* @return a new {@link Model} object containg the same statements as the input model, with the supplied contexts
* stripped.
*/
public static Model stripContexts(Model model, Resource... contexts) {
final List contextList = Arrays.asList(contexts);
return model.stream().map(st -> {
if (contextList.isEmpty() || contextList.contains(st.getContext())) {
return Statements.stripContext(st);
} else {
return st;
}
}).collect(ModelCollector.toModel());
}
/**
* Creates a {@link Supplier} of {@link ModelException} objects that be passed to
* {@link Optional#orElseThrow(Supplier)} to generate exceptions as necessary.
*
* @param message The message to be used for the exception
* @return A {@link Supplier} that will create {@link ModelException} objects with the given message.
*/
public static Supplier modelException(String message) {
return () -> new ModelException(message);
}
/**
* Make a model thread-safe by synchronizing all its methods. Iterators will still not be thread-safe!
*
* @param toSynchronize the model that should be synchronized
* @return Synchronized Model
*/
public static Model synchronizedModel(Model toSynchronize) {
return new SynchronizedModel(toSynchronize);
}
/**
* Converts the supplied RDF-star model to RDF reification statements. The converted statements are sent to the
* supplied consumer function.
*
* 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 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));
}
/**
* Converts the supplied RDF-star model to RDF 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);
}
/**
* Converts the statements in supplied RDF-star model to a new RDF 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.
*/
@Experimental
public static Model convertRDFStarToReification(ValueFactory vf, Model model) {
Model reificationModel = new LinkedHashModel();
convertRDFStarToReification(vf, model, (Consumer) reificationModel::add);
return reificationModel;
}
/**
* Converts the statements in supplied RDF-star model to a new RDF 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.
*/
@Experimental
public static Model convertRDFStarToReification(ValueFactory vf, Model model, ModelFactory modelFactory) {
Model reificationModel = modelFactory.createEmptyModel();
convertRDFStarToReification(vf, model, (Consumer) reificationModel::add);
return reificationModel;
}
/**
* Converts the statements in the supplied RDF-star model to a new RDF model using reification.
*
* @param model the {@link Model} to convert.
* @return a new {@link Model} with RDF-star statements converted to reified triples.
*/
@Experimental
public static Model convertRDFStarToReification(Model model) {
return convertRDFStarToReification(SimpleValueFactory.getInstance(), model);
}
/**
* Converts the supplied RDF reification model to RDF-star statements. The converted statements are sent to the
* supplied consumer function.
*
* 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 consumer the {@link Consumer} function for the produced statements.
*/
@Experimental
public static void convertReificationToRDFStar(ValueFactory vf, Model model, Consumer consumer) {
Map convertedStatements = new HashMap<>();
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)) {
return;
}
Value predicate = object(model.filter(s.getSubject(), RDF.PREDICATE, null)).orElse(null);
if (!(predicate instanceof IRI)) {
return;
}
Value object = object(model.filter(s.getSubject(), RDF.OBJECT, null)).orElse(null);
if (!(object instanceof Value)) {
return;
}
Triple t = vf.createTriple((Resource) subject, (IRI) predicate, object);
convertedStatements.put(s.getSubject(), t);
});
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
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)
});
}
/**
* Converts the supplied RDF reification model to RDF-star 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);
}
/**
* Converts the statements in supplied RDF reification model to a new RDF-star 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.
*/
@Experimental
public static Model convertReificationToRDFStar(ValueFactory vf, Model model, ModelFactory modelFactory) {
Model rdfStarModel = modelFactory.createEmptyModel();
convertReificationToRDFStar(vf, model, (Consumer) rdfStarModel::add);
return rdfStarModel;
}
/**
* Converts the statements in supplied RDF reification model to a new RDF-star 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.
*/
@Experimental
public static Model convertReificationToRDFStar(ValueFactory vf, Model model) {
return convertReificationToRDFStar(vf, model, new DynamicModelFactory());
}
/**
* Converts the supplied RDF reification model to a new RDF-star model.
*
* @param model the {@link Model} to convert.
* @return a new {@link Model} with reification statements converted to RDF-star {@link Triple}s.
*/
@Experimental
public static Model convertReificationToRDFStar(Model model) {
return convertReificationToRDFStar(SimpleValueFactory.getInstance(), model);
}
private static boolean isSubsetInternal(Set model1, Model model2) {
// try to create a full blank node mapping
return matchModels(model1, model2);
}
private static boolean matchModels(Set model1, Model model2) {
// Compare statements without blank nodes first, save the rest for later
List model1BNodes = new ArrayList<>(model1.size());
for (Statement st : model1) {
if (isBlank(st.getSubject()) || isBlank(st.getObject()) || isBlank(st.getContext())) {
model1BNodes.add(st);
} else {
if (!model2.contains(st)) {
return false;
}
}
}
return matchModels(Collections.unmodifiableList(model1BNodes), model2);
}
/**
* A recursive method for finding a complete mapping between blank nodes in model1 and blank nodes in model2. The
* algorithm does a depth-first search trying to establish a mapping for each blank node occurring in model1.
*
* @param model1
* @param model2
* @return true if a complete mapping has been found, false otherwise.
*/
private static boolean matchModels(final List extends Statement> model1, final Model model2) {
ArrayDeque> iterators = new ArrayDeque<>();
ArrayDeque