ShaclPrefixParser.java
/*******************************************************************************
* Copyright (c) 2023 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.sail.shacl.ast;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import java.util.stream.Stream;
import org.eclipse.rdf4j.common.annotation.InternalUseOnly;
import org.eclipse.rdf4j.model.Literal;
import org.eclipse.rdf4j.model.Model;
import org.eclipse.rdf4j.model.Namespace;
import org.eclipse.rdf4j.model.Resource;
import org.eclipse.rdf4j.model.Value;
import org.eclipse.rdf4j.model.impl.DynamicModel;
import org.eclipse.rdf4j.model.impl.LinkedHashModelFactory;
import org.eclipse.rdf4j.model.impl.SimpleNamespace;
import org.eclipse.rdf4j.model.vocabulary.SHACL;
import org.eclipse.rdf4j.sail.shacl.wrapper.shape.ShapeSource;
@InternalUseOnly
public class ShaclPrefixParser {
private ShaclPrefixParser() {
}
public static Namespaces extractNamespaces(Resource id, ShapeSource shapeSource) {
var shaclPrefixes = new Namespaces();
try (Stream<Value> objects = shapeSource.getObjects(id, ShapeSource.Predicates.PREFIXES)) {
objects.forEach(prefix -> {
if (!(prefix instanceof Resource)) {
throw new IllegalStateException("sh:prefixes must be an Resource for constraint component " + id);
}
shaclPrefixes.model.add(id, SHACL.PREFIXES, prefix);
try (Stream<Value> declareObjects = shapeSource.getObjects(((Resource) prefix),
ShapeSource.Predicates.DECLARE)) {
declareObjects.forEach(declaration -> {
if (!(declaration instanceof Resource)) {
throw new IllegalStateException("sh:declare must be a Resource for " + prefix);
}
shaclPrefixes.model.add((Resource) prefix, SHACL.DECLARE, declaration);
String namespacePrefix = null;
String namespaceName = null;
try (Stream<Value> prefixPropObjects = shapeSource.getObjects(((Resource) declaration),
ShapeSource.Predicates.PREFIX_PROP)) {
namespacePrefix = prefixPropObjects
.map(literal -> {
if (!(literal instanceof Literal)) {
throw new IllegalStateException(
"sh:prefix must be a Literal for " + declaration);
}
shaclPrefixes.model.add((Resource) declaration, SHACL.PREFIX_PROP, literal);
return literal.stringValue();
})
.findFirst()
.orElseThrow(() -> new IllegalStateException(
"sh:prefix must have a value for " + declaration));
}
try (Stream<Value> namespacePropObjects = shapeSource.getObjects(((Resource) declaration),
ShapeSource.Predicates.NAMESPACE_PROP)) {
namespaceName = namespacePropObjects
.map(literal -> {
if (!(literal instanceof Literal)) {
throw new IllegalStateException(
"sh:namespace must be a Literal for " + declaration);
}
shaclPrefixes.model.add((Resource) declaration, SHACL.NAMESPACE_PROP, literal);
return literal.stringValue();
})
.findFirst()
.orElseThrow(() -> new IllegalStateException(
"sh:namespace must have a value for " + declaration));
}
shaclPrefixes.namespaces.add(new SimpleNamespace(namespacePrefix, namespaceName));
});
}
});
}
return shaclPrefixes;
}
public static String toSparqlPrefixes(Collection<Namespace> namespaces) {
StringBuilder sb = new StringBuilder();
namespaces.forEach(namespace -> {
sb.append("PREFIX ");
sb.append(namespace.getPrefix());
sb.append(": <");
sb.append(namespace.getName());
sb.append("> \n");
});
sb.append("\n");
return sb.toString();
}
public static final class Namespaces {
private final Set<Namespace> namespaces = new HashSet<>();
private final Model model = new DynamicModel(new LinkedHashModelFactory());
private Namespaces() {
}
public Set<Namespace> getNamespaces() {
return namespaces;
}
public Model getModel() {
return model;
}
}
}