json-ld / json-ld.org

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

Compacting with different type doesn't shorten name #739

Open MidnightLightning opened 3 years ago

MidnightLightning commented 3 years ago

Given an input JSON-LD document of:

{
  "@context": {
    "@vocab": "https://example.com/#",
    "@base": "https://example.com"
  },
  "@id": "1001",
  "myNum": {
    "@value": 30000
  }
}

The "expand" action outputs:

{
  "@id": "https://example.com/1001",
  "https://example.com/#myNum": [
    {
      "@value": 30000
    }
  ]
}

Which appears to be correct in that myNum has a value of 30000, but no known type (https://example.com/#myNum might have more details about that, but that's not within the document).

When compacted with the context of:

{
  "@context": {
    "@vocab": "https://example.com/#",
    "@base": "https://example.com",
    "myNum": {
      "@type": "http://www.w3.org/2001/XMLSchema#integer"
    }
  }
}

(Attempting to indicate that myNum is an integer), the output is:

{
  "@context": {
    "@vocab": "https://example.com/#",
    "@base": "https://example.com",
    "myNum": {
      "@type": "http://www.w3.org/2001/XMLSchema#integer"
    }
  },
  "@id": "1001",
  "https://example.com/#myNum": 30000
}

This applies the proper context we wanted, but now myNum is not shortened to just "myNum" (using the @vocab context element), but is fully spelled out.

In order to get the output expected, I need to specify the type in the input document:

{
  "@context": {
    "@vocab": "https://example.com/#",
    "@base": "https://example.com"
  },
  "@id": "1001",
  "myNum": {
    "@type": "http://www.w3.org/2001/XMLSchema#integer",
    "@value": 30000
  }
}

And then the output of the compaction (attempting to move the definition of the integer type to the @context is as expected:

{
  "@context": {
    "@vocab": "https://example.com/#",
    "@base": "https://example.com",
    "myNum": {
      "@type": "http://www.w3.org/2001/XMLSchema#integer"
    }
  },
  "@id": "1001",
  "myNum": 30000
}

This seems to be an error in the "compact" logic, in that it doesn't re-apply the @vocab alias to un-typed properties that become typed?

gkellogg commented 3 years ago

JSON-LD doesn't really know about XSD types, and doesn't have any knowledge that xsd:integer reflects an integer, or that the value 1 is an integer, it just preserves native types when expanding and compacting.

Compacting where "myType" has an @type of xsd:integer doesn't, in fact, match the value {"@value": 3000}, as that doesn't have a matching @type. So, your last solution is correct.

When selecting a term for compaction, all the factors relating to the term specifics (@type, @container, @language, etc.) need to match the expanded value to be compared for the term to be selected. There's no magic about using native values such as 3000, 1.2, or true which automatically match corresponding XSD types.

MidnightLightning commented 3 years ago

When selecting a term for compaction, all the factors relating to the term specifics (@type, @container, @language, etc.) need to match the expanded value to be compared for the term to be selected.

Yes, I realize the JSON-LD infrastructure won't convert types, but in the case where the term doesn't match the @type of the @context.myNum directive, it seems to also not be matching the @context.@vocab directive, and not aliasing the name?

Putting it another way, I believe these two JSON-LD documents are functionally identical, correct?

{
  "@context": {
    "@vocab": "https://example.com/#",
    "@base": "https://example.com"
  },
  "@id": "1001",
  "myNum": 30000
}
{
  "@context": {
    "@vocab": "https://example.com/#",
    "@base": "https://example.com"
  },
  "@id": "1001",
  "https://example.com/#myNum": 30000
}

They represent the same thing, just the second one isn't taking advantage of the @vocab "alias" to just use myNum as the property instead of the full URI of https://example.com/#myNum.

Using the full URI name even when there is a @vocab is valid JSON-LD structure (as far as I know), but after running a "compact", I'd expect all property names to be using as short a name as possible, but the situation I'm highlighting here (with setting the @type on a property) causes that not to be the case. Is that not the expected outcome of a "compact" action?

gkellogg commented 3 years ago

It can't use the alias, as that would later expand to a value including @type, which would be information not in the original document, so there's code specifically to avoid using @vocab to shorten a property that would match a term that mismatched on @type. So, it's behaving as designed.