w3c / EasierRDF

Making RDF easy enough for most developers
267 stars 13 forks source link

No standard way to map a JSON predicate to a URI #29

Open dbooth-boston opened 5 years ago

dbooth-boston commented 5 years ago

"there is a wide proliferation of JSON on the web. Yet (in 2019!) we do not have a standard way for developers, and automated tools, to map a JSON predicate into a URI. I've suggested in the past : foo -> urn:string:foo . But that has yet to gain mind share. Tim has suggested we have an HTTP JSON ontology." https://lists.w3.org/Archives/Public/semantic-web/2018Nov/0171.html

VladimirAlexiev commented 5 years ago

Whaddayamean? What are JSONLD contexts for? cc @manusporny

BigBlueHat commented 4 years ago

Yeah, this is exactly what JSON-LD contexts are for. 😄

The original thread goes on to include this bit of explanation of intent:

This is more a question of : what would the longer form be, if you were, say, writing an automated tool to create a context.

Think the idea was to attempt a "standard" mapping for JSON terms...but that would rather limit the world of open data--i.e. putting all keys into a urn:string: prefix globally would assume universal meaning of those keys...which would be wrong.

The simplest way to do this in JSON-LD (though obviously not the most resilient...or even wisest...) would be this:

{
  "@context": {
    "@vocab": "urn:{personal-or-app-namespace}:"
  },
  "foo": "bar",
  "baz": {
    "foo": "..."
  }
}

becomes...

_:b0 <urn:{personal-or-app-namespace}:baz> _:b1 .
_:b0 <urn:{personal-or-app-namespace}:foo> "bar" .
_:b1 <urn:{personal-or-app-namespace}:foo> "..." .

Or add a proper @id to avoid all those blank nodes:

{
  "@context": {
    "@vocab": "urn:{personal-or-app-namespace}:"
  },
  "@id": "http://example.com/#local-json",
  "foo": "bar",
  "baz": {
    "foo": "..."
  }
}

becomes...

<http://example.com/#local-json> <urn:{personal-or-app-namespace}:baz> _:b0 .
<http://example.com/#local-json> <urn:{personal-or-app-namespace}:foo> "bar" .
_:b0 <urn:{personal-or-app-namespace}:foo> "..." .

Regardless, this is certainly a solved problem, afaict.

dbooth-boston commented 4 years ago

That's an interesting point, but I don't think it fully solves the problem, because nested predicates having the same name need to map to different URIs, to avoid information loss. In JSON, you can distinguish them by the nesting context, in the tree structure. But that context is lost if you just use a generic @vocab in JSON-LD. For example, this (view in playground):

{
  "@context": {
    "@vocab": "urn:TEST:"
  },
  "@id": "http://example.com/#local-json",
  "foo": "bar",
  "baz": {
    "foo": "..."
  }
}

becomes this in RDF:

<http://example.com/#local-json> <urn:TEST:foo> "bar" .
<http://example.com/#local-json> <urn:TEST:baz> _:b0 .
_:b0 <urn:TEST:foo> "..." .

Note that both the outer and inner instances of JSON property "foo" became .

What we need instead is for those instances to map to different URIs, something like this:

<http://example.com/#local-json> <urn:TEST:baz> _:b0 .
<http://example.com/#local-json> <urn:TEST:foo> "bar" .
_:b0 <urn:TEST:baz/foo> "..." .

This can be done in JSON-LD 1.1 (but not 1.0) using a nested @context (view in playground):

{
  "@context": {
    "@vocab": "urn:TEST:"
  },
  "@id": "http://example.com/#local-json",
  "foo": "bar",
  "baz": {
    "@context": {
      "@vocab": "baz/"
  },
    "foo": "..."
  }
}

But AFAIK that would require modifying the JSON, to insert those nested @context statements.

@gkellogg, is that correct, or is there some other way of achieving unique URIs for nested properties that have the same name, without modifying the JSON?

gkellogg commented 4 years ago

See Scoped Contexts which is there specifically for cases like this.

playground link

{
  "@context": {
    "@vocab": "urn:TEST:",
    "baz": {"@context": {"@vocab": "baz/"}}
  },
  "@id": "http://example.com/#local-json",
  "foo": "bar",
  "baz": {
    "foo": "..."
  }
}
dbooth-boston commented 4 years ago

Nice! That does have the minor limitation that it still requires the JSON document to be analyzed in advance -- or its schema already known -- in order to emit a custom @context containing all of those nested @vocab definitions. But that would be very straightforward to automate with a standard tool that could take any JSON input and produce the corresponding @context.

BigBlueHat commented 4 years ago

Additionally, contexts can be provided separately from the JSON either via an HTTP Link header (if you control the server responses or proxy them, but not the data): https://www.w3.org/TR/json-ld/#interpreting-json-as-json-ld

Or, via any JSON-LD API compliant code's expandContext option:

The JSON-LD 1.1 Processing Algorithms and API specification [JSON-LD11-API] provides for an expandContext option for specifying a context to use when expanding JSON documents programmatically.