Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Serialization of JSON-LD using appropriate context #101

Closed
paolociccarese opened this issue Feb 21, 2014 · 9 comments
Closed

Serialization of JSON-LD using appropriate context #101

paolociccarese opened this issue Feb 21, 2014 · 9 comments

Comments

@paolociccarese
Copy link

I am using JSON-LD to populate a triple store. I am using the Maven dependency jsonld-java:0.3. The triple store populates nicely. However, I am not sure on how to apply the context again once I retrieve the data from the repository.

Content comes in and refers to the context https://raw2.github.com/Annotopia/AtSmartStorage/master/web-app/data/OAContext.json so it comes in as something like this

{
"@context":"https://raw2.github.com/Annotopia/AtSmartStorage/master/web-app/data/OAContext.json" ,
"@id" : "urn:temp:001",
"@type" : "http://www.w3.org/ns/oa#Annotation", 
"hasTarget" : "http://paolociccarese.info"
}

When I serialize the content back I use the RIOT writer:

RDFDataMgr.write(outputStream, dataset, JenaJSONLD.JSONLD);

and I get back something like this:

{
  "@graph" : [ {
    "@id" : "urn:temp:001",
    "@type" : "http://www.w3.org/ns/oa#Annotation",
    "http://www.w3.org/ns/oa#hasTarget" : {
      "@id" : "http://paolociccarese.info"
    }
  }

Now, if I play with the JSON-LD playground (http://json-ld.org/playground/) and I apply - in the top right box - the same context I can get back

{
"@context": … ,
"@id" : "urn:temp:001",
"@type" : "http://www.w3.org/ns/oa#Annotation", 
"hasTarget" : "http://paolociccarese.info"
}

How can I get to a similar result programmatically? I was looking at the JsonLdProcessor but I am having hard time in putting that into context.

Thank you,
Paolo

@ansell
Copy link
Member

ansell commented Feb 22, 2014

I think this is a question for @afs with the Jena integration, to support specifying the context object to use when serialising (or persist the original object somewhere in Jena.

I don't mind if you track the solution here, or let me know to close this issue and track it in the Apache Jira tracker for Jena. https://issues.apache.org/jira/browse/JENA

@afs
Copy link
Contributor

afs commented Feb 23, 2014

At the moment, there isn't a way to set the profile when writing out an RDF graph. The integration is concentrating on reading JSON-LD, the writing side needs further work; it's fixed and basic at the moment. The mechanism exists to pass per-syntax output parameters but there isn't anything implemented for JSON-LD yet. "To be implemented".

There is a related issue: the JSON-LD context does not get preserved with the RDF data when read in. There isn't a place to keep it and if you read several JSON-LD sources, there would be a chaotic mix of stuff anyway. We have prefixes for other syntaxes.

@ansell - this seems to be a jsonld-java API question: what's the best way to set the profile when converting RDF data to JSON-LD syntax? I looked at the Sesame adapter as "reference implementation" :-) which must need to do the same but I don't see how it does it.

@paolociccarese - you can directly read the JSON-LD with RDFDataMgr if you want to. But if you are reading with jsonld-java and you want full control of output in the current development integration, then you may be better outputting with it as well to keep detailed control.

@paolociccarese
Copy link
Author

@ansell and @afs thank you both, that is helpful. I have been playing around with the JsonLdProcessor with the idea of serializing the triples coming from the store with the appropriate context. However I am experiencing a CloneNotSupportedException.

Here is a simplified version of the code (still using version 0.3 of the library):

String content='{"@graph" : [ {"@id" : "urn:temp:001","@type" : "http://www.w3.org/ns/oa#Annotation","http://www.w3.org/ns/oa#hasTarget" : {"@id" : "http://paolociccarese.info"}}]}';

final InputStream contextStream = new URL("https://raw2.github.com/Annotopia/AtSmartStorage/master/web-app/data/OAContext.json").openStream();
final Object contextJson = JSONUtils.fromInputStream(contextStream);

final Options options = new Options();
options.format = "application/ld+json";

JSONLD.compact(new ByteArrayInputStream(content.getBytes("UTF-8")), contextJson, options);

The exception CloneNotSupportedException is thrown when executing the last line.
What am I missing?

@ansell
Copy link
Member

ansell commented Feb 23, 2014

@afs Storing the contexts inside of Jena and automatically applying them to output wasn't a serious suggestion given that it doesn't have a clear path. However, Jena (and Sesame for that matter) may be able to cache contexts in a named map where users can specify the key for the context to use when compacting the current document, so they don't need to maintain it themselves.

In terms of how much functionality Sesame has right now. Profiles are specified using the JSONLDMode enum which we specify in sesame-rio-api.jar . It is exposed to users using RDFWriter.getWriterConfig().set(JSONLDSettings.JSONLD_MODE, mode).

Users cannot currently set the context, and the context is generated locally to preserve namespace prefixes rather than enabling users to set the context. In addition, there is no way for users to get access to the context that was found during parsing, at this stage.

The current Sesame code, which is still very sparse, is in the endRDF function at:

https://github.com/jsonld-java/jsonld-java/blob/master/integration/sesame/src/main/java/com/github/jsonldjava/sesame/SesameJSONLDWriter.java#L78

The actual method for selecting between profiles involves switching based on JSONLDMode to select either JsonLdProcessor.expand, JsonLdProcessor.frame, or JsonLdProcessor.compact. Each of those functions have different signatures, and we have basically followed the suggested signatures from the JSONLD-API spec for ease of use, although we don't use Promises for the results of the functions.

http://www.w3.org/TR/json-ld-api/#the-application-programming-interface

@ansell
Copy link
Member

ansell commented Feb 23, 2014

@paolociccarese Version 0.3 did not contain the JSONLD class, so I suspect that you are using an old version. The class naming was changed between 0.2 and 0.3 to follow the JSON-LD-API specification, which specifies a class named JsonLdProcessor to expose those functions:

http://www.w3.org/TR/json-ld-api/#the-application-programming-interface

@paolociccarese
Copy link
Author

@ansell you are right. I was referring to jsonld-java-jena:0.2.99-mygrid which was bringing in the jsonld-java:0.2.99 as a dependency. That was getting mixed up by Grails Ivy with the version 0.3 and from there all the following issues.

I've updated to JENA 2.11.2-SNAPSHOT as recommended by @afs and now all the libraries seem correct (with version 0.3). Still I am not obtaining what I was expecting. Bare with me, hopefully for the last time on this topic.

The following code:

InputStream contextStream = new URL("https://raw2.github.com/Annotopia/AtSmartStorage/master/web-app/data/OAContext.json").openStream();
final Object contextJson = JSONUtils.fromInputStream(contextStream);

final JsonLdOptions options = new JsonLdOptions();
options.format = "application/jsonld";

String content='{"@graph" : [ {"@id" : "urn:temp:001","@type" : "http://www.w3.org/ns/oa#Annotation","http://www.w3.org/ns/oa#hasTarget" : {"@id" : "http://paolociccarese.info"}}]}';
Object compact = JsonLdProcessor.compact(new ByteArrayInputStream(content.getBytes("UTF-8")), contextJson,  options);

System.out.println(JSONUtils.toPrettyString(compact));

Gives me back the context only with no content.
This is what I would expect instead:

{
  "@context": {
    "oa": "http://www.w3.org/ns/oa#",
    ...
  },
  "@id": "urn:temp:001",
  "@type": "oa:Annotation",
  "hasTarget": "http://paolociccarese.info"
}

@ansell
Copy link
Member

ansell commented Feb 24, 2014

The trouble with converting something (JSON) designed for non-typesafe languages to Java/etc., is that some method signatures need to use Object to fulfill their contracts, or you need to specify another super-class, at the risk of not having it work easily with Jackson.

In this case the API does not complain that you directly send in the byte array input stream to .compact, even though .compact doesn't know how to process that type of object. This could be fixed in this case, but in general, it is difficult to know what the type of the object will be enough to constrain it.

If you pull and run the git version from today, 0.4-SNAPSHOT, (which has just now been deployed to the Sonatype snapshots repository), you should be able to use the following code:

Object compact = JsonLdProcessor.compact(JsonUtils.fromString(content), contextJson, options);

If you are using 0.3, then you need to use JSONUtils (capitalisation change I made today for 0.4 to fit with the rest of the API)

@paolociccarese
Copy link
Author

@ansell thank you for the explanation, it makes sense. And while the signature of the method refers to Object, the 'Code example' in the README refers to 'jsonObject', I should have read that more carefully.

I can now successfully complete the round-trip. Thank you again!

@afs
Copy link
Contributor

afs commented Feb 24, 2014

@ansell - thanks for the details; gives me something to think about. There was already been another request for custom contexts (actually that request came along before the code was integrated into Jena!).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants