json-ld / json-ld.org

JSON for Linked Data's documentation and playground site
https://json-ld.org/
Other
859 stars 152 forks source link

Allow explicitly unsetting aliases in context #546

Closed azaroth42 closed 6 years ago

azaroth42 commented 7 years ago

If I have two contexts, one which defines an alias of id for @id, and another which does not, then each context taken separately would produce different representations for the same uri predicate value triple -- one with id and the other with @id.

If a block of JSON-LD with the context that does not have the definition is embedded in a block that does have it, then the alias will continue to be used, producing JSON that would be unexpected by a JSON based processor. (A JSON-LD based processor would be fine, of course).

Example:

{
  "@context": { "eg": "http://example.org/", "id": "@id"},
  "id": "http://example.com/1",
  "eg:service": {
    "@context": {"foo": "http://foobar.baz/"},
    "@id": "http://example.com/2",
    "foo:note": "I want the subject to be @id, not id, in this context"
  }
}

Proposal:

Allow setting a key to null in a context to unset any previous definition.

Thus setting "id": null in the embedded "foo" context would produce the expected @id (assuming that the context was associated at the top level, via scoping of @type, predicate or similar)

davidlehn commented 7 years ago

Can you clarify what operation you are performing and what you want the output to be? I'm a bit confused.

If you are trying to compact with a context and want id at the top level and @id in the eg:service I think that is only possible in JSON-LD 1.1.

There are at least two workarounds for 1.0. You could loop through any eg:service output values and re-compact them with a secondary context that doesn't alias @id. Or if your data is simple enough you could just loop through the values and manually switch id to @id. Ugly, but would work.

gkellogg commented 7 years ago

Setting a term to null in a context is explicitly handled in Step 6 of the Create Term Definition algorithm.

The Grammar Section of the JSON-LD syntax document indicates that null is an appropriate value for a term, or an @id within an expanded term definition. This is also discussed in the Terminology section, and in Advanced Context Usage.

It sounds to me that you can resolve this issue by mapping the term to null in an embedded context.

azaroth42 commented 6 years ago

Then is this just not implemented correctly in the Playground or PyLD? Or per @davidlehn, is it only possible with scoped contexts in 1.1? (Which would be fine for us, but if there's a bug for 1.0 implementations, it would be good to know) See: http://tinyurl.com/y9hcru8x

Or in Python:

from pyld.jsonld import compact
import json

context1js = {
    "ex": "http://example.com/",
    "related": "ex:related",
    "Foo": "ex:FooClass",
    "Bar": "ex:BarClass",
    "id": "@id",
    "type": "@type"
}

context2js = {"id": None, "type": None}

datajs = {
  "id": "http://example.com/1",
  "type": "Foo",
  "related": {
    "@id": "http://example.org/2",
    "@type": "Bar"
  }
}

datajs['@context'] = context1js
datajs['related']['@context'] = context2js  # try to prevent id compaction in related node

out = compact(datajs, context1js)
print json.dumps(out, sort_keys=True, indent=2)
gkellogg commented 6 years ago

Then is this just not implemented correctly in the Playground or PyLD? Or per @davidlehn, is it only possible with scoped contexts in 1.1?

This could also come about with the following:

{
  "@context": [
    {"id": "@id", "foo": "http://example.org/foo"},
    {"id": null}
  ],
  "id": "http://example.com/should-be-ignored",
  "foo": "bar"
}

which expands to:

[
  {
    "http://example.org/foo": [
      {
        "@value": "bar"
      }
    ]
  }
]

Testing an embedded example in my implementation

yields the following:

{
  "@context": {
    "eg": "http://example.org/",
    "id": "@id"
  },
  "id": "http://example.com/1",
  "eg:service": {
    "id": "http://example.com/2",
    "http://foobar.baz/note": "I want the subject to be in @id, not id, in this context after compaction"
  }
}

To have @id used instead of id in eg:service requires using an embedded context in the compaction context.

azaroth42 commented 6 years ago

Now that we have a 1.1 playground ... I can demonstrate the point more easily.

In http://tinyurl.com/y7fq9dwh

The context sets id and type at the top level, then with a scoped context undefines them based on a type. The compaction still compacts the URI within the scope to id, though does seem to unalias type?

gkellogg commented 6 years ago

It works properly if the scoped context is set on "service", rather than "ImageService1", so it seems that it's an order of processing issue, where the "id" property is emitted before the context is applied.

This is likely because step 8.1.2.2.2 of the Compaction Algorithm is considered while looking at sorted expanded keys, and @id comes before @type.

This fix will have to involve extracting 8.1.2.2.2 and running before step 8.