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

JSON Array of length 1 gets compacted into non array #509

Open
adlerfaulkner opened this issue Feb 22, 2023 · 8 comments
Open

JSON Array of length 1 gets compacted into non array #509

adlerfaulkner opened this issue Feb 22, 2023 · 8 comments

Comments

@adlerfaulkner
Copy link

When compacting (or framing with an @context), any @value of a node with "@type': "@json" that is a JSON array of length 1 gets transformed into a non array value equalling the first item in the JSON array.

For example:

const doc = {
  "https://example.com/people": {
    "@type": "@json",
    "@value": [ { "name": "Jim" } ]
  }
};

const context = {
  "people": {
    "@id": "https://example.com/people",
    "@type": "@json"
  }
};

const compacted = await jsonld.compact(doc, context);
console.log(JSON.stringify(compacted, null, 2));
/* Output:
{
  "@context": {
    "people": {
      "@id": "https://example.com/people",
      "@type": "@json"
    }
  },
  "people": {
    "name": "Jim"
  }
}
*/

Note above that the people field in the output was transformed from a JSON array to an object equal the the original array's first value.

I would expect this library to preserve the original JSON array.
The output should be:

{
  "@context": {
    "people": {
      "@id": "https://example.com/people",
      "@type": "@json"
    }
  },
  "people": [
    { "name": "Jim" }
  ]
}
@adlerfaulkner
Copy link
Author

adlerfaulkner commented Feb 22, 2023

Reference to relevant part of the JSON-LD spec https://www.w3.org/TR/json-ld11/#json-literals

At times, it is useful to include JSON within JSON-LD that is not interpreted as JSON-LD. Generally, a JSON-LD processor will ignore properties which don't map to IRIs, but this causes them to be excluded when performing various algorithmic transformations. But, when the data that is being described is, itself, JSON, it's important that it survives algorithmic transformations.

@adlerfaulkner
Copy link
Author

Ah, I am seeing from this test https://w3c.github.io/json-ld-api/tests/compact-manifest#tjs07 that you have to add "@container": "@set" to the context.

That seems like a requirement that is not stated in the spec, and in fact contradicts the spec's notion that JSON literals should not be transformed by the processor in any way. Any one have insight on why this is?

@dlongley
Copy link
Member

@adlerfaulkner,

This might be a good issue to bring the spec as this is just a particular implementation of it. You can do so over here:

https://github.com/w3c/json-ld-api/issues

@davidlehn
Copy link
Member

The spec and test coverage of this area is poor. I think your example should by default output the JSON array: "people": [{...}]. If @set is used, it should output an array with your JSON: "people": [[{...}]]. If that's the case, then js07 is incorrect.

There are complications here too. If multiple JSON values are compacted, it would be fine if @set is in the context. But if not, what should happen? It can't make an array, since that would be interpreted as raw JSON. I think compaction should throw an error. But the spec and tests don't cover this case. There is also the oddity of JSON + non-JSON values for the same term. If there is a single JSON value, then jsonld.js, probably by luck, will function and output the JSON in the compacted term, and non-JSON as values for the expanded term. That's arguably a way to do it, but I'm not sure it's explicit anywhere. And also how do you interpret data that has @set in the context but the value is not an array? Throw an error or just fallback and assume a single JSON value?

I'm working up some tests for the WG to look at and clarify how this should work, and jsonld.js fixes will follow.

@gkellogg
Copy link
Collaborator

Yes, the intersection of "@container": "@set" and "@type": "@json" could probably be explored further. Looking at the expansion algorithm, the value of a term with @type: @json will always be extracted from any containing array, so the JSON value can't really take the form of an array (probably could if it were the value of @value, though).

I'm sure there are some unexplored corner-cases here.

@adlerfaulkner
Copy link
Author

Thanks @gkellogg and @davidlehn. I look forward to seeing those tests and their reception in the WG.

It sounds to me like @set in the context should always be evaluated before determining the type of the value (JSON or non-JSON). I think what you say about having @set in the context for a non-Array value during compaction should either throw an error or just not match (& thus not compact) the field. This would be similar to how a field would not be compacted if the @type field was not matching even though its id field matched between context and data.

@gkellogg
Copy link
Collaborator

@container: @set isn't used in expansion; it is a signal for the compaction algorithm to put values inside an array. Note that the compaction algorithm can't generate an empty array, as there is no value to invoke in the algorithm.

Creating more special magic for @set along with @type: @json would be special use and complicate an already complicated process, so personally, I don't see that happening.

Feel free to raise an issue at https://github.com/w3c/json-ld-api, but I don't see that making the cut for the next version.

@davidlehn
Copy link
Member

Issue: w3c/json-ld-api#560
First pass at test cases: w3c/json-ld-api#559

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

No branches or pull requests

4 participants