digitalbazaar / jsonld.js

A JSON-LD Processor and API implementation in JavaScript
https://json-ld.org/
Other
1.65k stars 195 forks source link

Local @context and URI Expansion, possible bug? #465

Open jmcanterafonseca-iota opened 2 years ago

jmcanterafonseca-iota commented 2 years ago

I have the following JSON-LD snippet:

{
    "@context": {
        "bizStep": {
            "@id": "https://example.org/bizStep",
            "@type": "@vocab",
            "@context": {
                "v1": "https://example.org/values/v1",
                "v2": "https://example.org/values/v2"
            }
        }
    },
    "bizStep": ["v1", "v2"]
}

which yields to

_:b0 <https://example.org/bizStep> <https://example.org/values/v1> .
_:b0 <https://example.org/bizStep> <https://example.org/values/v2> .

If I expand or alias bizStep into another key for instance

{
    "@context": {
        "bizStep": {
            "@id": "https://example.org/bizStep",
            "@type": "@vocab",
            "@context": {
                "v1": "https://example.org/values/v1",
                "v2": "https://example.org/values/v2"
            }
        }
    },
    "https://example.org/bizStep": ["v1", "v2"]
 }

it yields to

_:b0 <https://example.org/bizStep> "v1" .
_:b0 <https://example.org/bizStep> "v2" .

Is this a possible bug in handling local scoped LD contexts?

dlongley commented 2 years ago

Hi @jmcanterafonseca-iota!

The reason why you get different output when you use a different JSON key (e.g., "https://example.org/bizStep") is because it no longer matches the term in the context ("bizStep") using a simple string comparison. If the JSON key in the data doesn't equal the JSON key in the context (the "term"), then its term definition won't apply. So, this isn't a bug, it's just how it works; a processor only applies a term definition during expansion when a JSON key matches a term via string comparison.

If it helps, consider the case where two different terms were defined, each mapping to the same URI, but each having different term definitions. How would a term definition be selected during expansion? The spec has been written such that the author has clear control over how the data will be interpreted when it is expanded. This is made possible by keeping the processor simple: it makes no special semantic leaps to guess which term definitions to use. Rather, it simply compares JSON keys as strings. For example:

{
  "@context": {
    // this means: only if the JSON key "integer" is used, then this term definition applies
    "integer": {"@id": "example:some-uri", "@type": "http://www.w3.org/2001/XMLSchema#integer"},
    // this means: only if the JSON key "uri" is used, then this term definition applies
    "uri": {"@id": "example:some-uri", "@type": "@id"}
  },
  // this will be interpreted as a URI because this JSON key equals "uri" in "@context"
  // and the term definition says string values for this key are URIs (signaled via "@type": "@id")
  "uri": "https://test.example",
  // this will be interpreted as an integer because this JSON key equals "integer" in
  // "@context" and the term definition says string values for this key are integers
  "integer": "123",
  // this JSON key matches no JSON key in "@context", so it has no matching term definition
  // if any types are to be applied they must be done inline or via JSON types
  "example:some-uri": [
    // this will default to a string type because it's a JSON string
    "a string",
    // this will default to "http://www.w3.org/2001/XMLSchema#integer" because
    // it's a JSON number that has no decimal
    456,
    // this has an inline definition indicating it is a URI, not just a string (just because
    // it may look like URI to a human being doesn't mean the processor can or
    // will guess that, rather, it must be told)
    {"@value": "https://foo.bar", "@type": "@id"}
  ]
}
jmcanterafonseca-iota commented 2 years ago

thanks @dlongley for the detailed explanation!