w3c / json-ld-framing

JSON-LD 1.1 Framing Specification
https://w3c.github.io/json-ld-framing/
Other
25 stars 20 forks source link

Framing and @container:@set for scoped contexts #64

Closed azaroth42 closed 5 years ago

azaroth42 commented 5 years ago

Playground: http://tinyurl.com/y4ry8o3m

With a very simple identity frame (e.g. give the top node's id and a context), the expected output would be to follow the context's definition for @container: @set and wrap single objects in an array. This works as expected for the context when applied via compaction (see the compaction tab in the playground).

However, in both the javascript and python implementations, the part property does not generate an array from the frame, where it does from compaction. Note that it is not due to Production within Production, as changing the class of either to (e.g.) Activity results in the same structure.

This seems like a bug?

gkellogg commented 5 years ago

A simpler formation still shows the problem (playground).

{
  "@context": {
    "@version": 1.1,
    "@vocab": "http://example.org/vocab#"
  },
  "@id": "http://example.org/1",
  "@type": "HumanMadeObject",
  "produced_by": {
    "@type": "Production",
    "_label": "Top Production",
    "part": {
      "@type": "Production",
      "_label": "Test Part"
    }
  }
}

Frame:

{
  "@context": {
    "@version": 1.1,
    "@vocab": "http://example.org/vocab#",
    "Production": {
      "@context": {
        "part": {
          "@type": "@id",
          "@container": "@set"
        }
      }
    }
  },
  "@id": "http://example.org/1"
}

The issue seems to be in the last paragraph of 4.2.2:

Recursively, replace all entries in compacted results where the key is @preserve with the value of the entry. If the value of the entry is @null, replace the value with null. If, after replacement, an array contains a single array value, replace the array with that value. If, after replacement, an array contains only the value null remove the value, leaving an empty array.

The key bit recently added is the italicized bit, which does not consider the context.

Logically, it would seem to make sense to do this last bit before compaction, although I suspect there was a reason we didn't do this.

gkellogg commented 5 years ago

So, the problem with cleaning up @preserve and @null before compaction, is that, in some cases, the null value should be kept when framing, but eliminated if it's just one component of an array. I've never understood why this was important, but perhaps @dlongley could shed some light on this.

The simplest thing would be do just do that cleanup before compaction, which would allow the regular compaction dynamics to work.

If keeping the null output is important, we could separate replacing @null with null until after compaction, although this would still likely leave odd results, with some values of null removed, and others remaining.

Preserving null must have had some value, otherwise, the whole use for @null is questionable.

Otherwise, we may need to compact, do @preserve/@null cleanup, then expand and re-compact to get this right, which seems silly and wastefull.

gkellogg commented 5 years ago

With a trial implementation, 18 framing tests fail, where null is expected and an empty array is what is actually produced.

For example, in #t0005 we expect the following:

{
  "@context": {
    "dcterms": "http://purl.org/dc/terms/",
    "ex": "http://example.org/vocab#"
  },
  "@graph": [
    {
      "@id": "http://example.org/test/#library",
      "@type": "ex:Library",
      "ex:contains": {
        "@id": "http://example.org/test#book",
        "@type": "ex:Book",
        "dcterms:title": "My Book",
        "ex:contains": {
          "@id": "http://example.org/test#chapter",
          "@type": "ex:Chapter",
          "dcterms:title": "Chapter One",
          "ex:null": null
        }
      }
    }
  ]
}

But, what is actually produced is:

{
  "@context": {
    "dcterms": "http://purl.org/dc/terms/",
    "ex": "http://example.org/vocab#"
  },
  "@graph": [
    {
      "@id": "http://example.org/test/#library",
      "@type": "ex:Library",
      "ex:contains": {
        "@id": "http://example.org/test#book",
        "@type": "ex:Book",
        "dcterms:title": "My Book",
        "ex:contains": {
          "@id": "http://example.org/test#chapter",
          "@type": "ex:Chapter",
          "dcterms:title": "Chapter One",
          "ex:null": []
        }
      }
    }
  ]
}
iherman commented 5 years ago

This issue was discussed in a meeting.