unfortunately i keep running into problems with parsing json-ld and the problem that others can’t interpret “my” json-ld. if i take “my” json-ld and paste it into JSON-LD Playground everything seems to be ok.
So it looks like activityPub implementations speak a different json-ld. But I have the feeling that this json-ld is not specified.
Am I the only one with this problem?
I don’t want to write a json-ld parser/generator, but use libraries that exist and are provided in the RDF context. At the moment I rely on GitHub - jsonld-java/jsonld-java: JSON-LD implementation for Java which is used in the context of rdf4j.
Framing does not seem to solve the problem either. At least it didn’t with Pleroma.
https://www.w3.org/TR/activitystreams-core (section 2.1) specifies the rules that ActivityPub documents need to conform to be considered valid. Tl;dr: It’s a specific subset of JSON-LD based on compacting it to the normative context “http://www.w3.org/ns/activitystreams”
Today i found a way to be more compatible. titanium seems to do it’s job well!
Converting my RDF Model into the compact format like that:
import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;
import java.io.Writer;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.rdf4j.model.Model;
import org.eclipse.rdf4j.rio.RDFFormat;
import org.eclipse.rdf4j.rio.Rio;
import org.springframework.core.io.ClassPathResource;
import com.apicatalog.jsonld.JsonLd;
import com.apicatalog.jsonld.document.Document;
import com.apicatalog.jsonld.document.JsonDocument;
import jakarta.json.Json;
import jakarta.json.JsonObject;
import jakarta.json.JsonWriter;
import jakarta.json.JsonWriterFactory;
import jakarta.json.stream.JsonGenerator;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class ApModelTools {
/**
* Converts the passed model into a ActivityPub optimized string.
* @param model The RDF4J Model
* @param rdfFormat The format to convert to
* @return The model as string.
*/
public static String toString(Model model, RDFFormat rdfFormat) {
String modelAsString = modelToString(model, rdfFormat);
if(RDFFormat.JSONLD.equals(rdfFormat)) {
modelAsString = compact(modelAsString);
}
return modelAsString;
}
/**
* Converts the passed model into a string.
* That can be a none optimized string for example in case of json-ld.
* @param model The RDF4J Model
* @param rdfFormat The format to convert to
* @return The model as string.
*/
private static String modelToString(Model model, RDFFormat rdfFormat) {
StringWriter sw = new StringWriter();
Rio.write(model, sw, rdfFormat);
String modelAsString = sw.toString();
return modelAsString;
}
/**
* Converts the passed json-ld string into a <a href="https://www.w3.org/TR/json-ld/#compacted-document-form">compact</a> one.
* @param rdf4jJsonLd string to be compacted
* @return the compacted string or the input stream, if there was an error while converting. The error will be logged!
*/
private static String compact(String rdf4jJsonLd) {
try {
Document document = JsonDocument.of(new StringReader(rdf4jJsonLd));
Document frame = JsonDocument.of(new ClassPathResource("as.jsonld").getInputStream());
return jsonObjectToString(JsonLd.compact(document, frame)
.ordered()
.get());
} catch (Exception e) {
log.error("error compacting jsonLd", e);
return rdf4jJsonLd;
}
}
/**
* Converts the passed {@link JsonObject} into a pretty printed string.
* @param json object to convert
* @return a pretty printed string
* @throws IOException
*/
private static String jsonObjectToString(JsonObject json) throws IOException {
Map<String,Boolean> config = new HashMap<>();
config.put(JsonGenerator.PRETTY_PRINTING, true);
JsonWriterFactory writerFactory = Json.createWriterFactory(config);
try (Writer stringWriter = new StringWriter();
JsonWriter jsonWriter = writerFactory.createWriter(stringWriter)) {
jsonWriter.write(json);
return stringWriter.toString();
}
}
}
as.jsonld is more or less the same as:
curl --location --request GET 'http://www.w3.org/ns/activitystreams' \
--header 'Accept: application/ld+json'