W3C home > Mailing lists > Public > public-hydra@w3.org > March 2017

Re: Convert JSON to JSON-LD

From: Dietrich Schulten <ds@escalon.de>
Date: Sat, 25 Mar 2017 12:18:27 +0100
To: public-hydra@w3.org
Message-ID: <d24ed772-6e5d-a5df-d044-aa93cd68bb46@escalon.de>
Hi Alexander,


Am 13.02.2017 um 21:33 schrieb Alexander Surinov:
>
> But Image I have the following plain JSON array as top level JSON object.
>
> [
>
>       {
>
>         "id": 638865,
>
>         "first_name": "Emma",
>
>         "last_name": "Stone"
>
>       },
>
>       {
>
>         "id": 1053682,
>
>         "first_name": "Emma",
>
>         "last_name": "Watson"
>
>       }
>
> ]
>
> So, my question is: How can I convert JSON message to JSON-LD format 
> when source JSON message represented as JSON array?
>
> As described in JSON-LD specs we can add @context as HTTP Link Header 
> using the http://www.w3.org/ns/json-ld#context link relation. Ok, but 
> where I should define @type and @id for JSON object?
>
>
I take it by JSON object you mean the JSON array your response consists 
of. Unfortunately, what you want to do is impossible.

First of all, in JSON an array cannot have an attribute, it can only 
contain comma-separated items.

In Javascript, an array can have an attribute which is not part of the 
array items:

$ node
 > var array = [ "foo", "bar" ];
 > array
[ 'foo', 'bar' ]
 > array["@id"] = "http://array.example.com";
 > array
[ 'foo', 'bar', '@id': 'http://array.example.com' ]
 > array[0]
'foo'
 > array[1]
'bar'
 > array[2]
undefined                    <-- @id is not an array item
 > array["@id"]
'http://array.example.com'

Not so in JSON. Therefore JSON does not allow to attach an @id to a 
list, technically. That is a limitation of JSON, not of JSON-LD.

But it goes deeper than that. Consider the JSON-LD array below at the 
"url" attribute.

{
   "@context": "http://schema.org/",
   "@type": "Person",
   "@id": "http://janedoe.com",
   "name": "Jane Doe",
   "url": ["http://www.janedoe.com", "http://www.janedoe.de"]
}

One might think that the attribute "url" has an array value. However, 
that is not the case in the underlying datamodel of JSON-LD (RDF), as 
you see in the normalized representation (JSON-LD playground 
http://tinyurl.com/lc4pnxq):

<http://janedoe.com> <http://schema.org/name> "Jane Doe" .
<http://janedoe.com> <http://schema.org/url> <http://www.janedoe.com> .
<http://janedoe.com> <http://schema.org/url> <http://www.janedoe.de> .
<http://janedoe.com> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> 
<http://schema.org/Person> .

The underlying data model represents the array items in such a way that 
the subject http://janedoe.com has the predicate http://schema.org/url 
twice. There is no array in the underlying data model.

You also have to be aware that this makes it impossible to make a 
JSON-LD array a "remote" resource. Consider the local JSON-LD array 
which is the value of the "address" attribute below:

{
   "@context": "http://schema.org/",
   "@type": "Person",
   "@id": "http://janedoe.com",
   "name": "Jane Doe",
   "address": [
     {
       "@type": "PostalAddress",
       "streetAddress": "Bubenhalde 10",
       "addressLocality": "Untergruppenbach"
     },
     {
       "@type": "PostalAddress",
       "streetAddress": "Wieblinger Weg 35",
       "addressLocality": "Heidelberg"
     }
    ]
}

You might think that you could easily factor out the local list of 
addresses as a remote related resource of the Person like that:

{
   "@context": "http://schema.org/",
   "@type": "Person",
   "@id": "http://janedoe.com",
   "name": "Jane Doe",
   "address": {"@id": "http://janedoe.com/addresses" }
}

Because dereferencing the URL "http://janedoe.com/addresses" could give 
you the following representation:

[
     {
       "@type": "PostalAddress",
       "streetAddress": "Bubenhalde 10",
       "addressLocality": "Untergruppenbach"
     },
     {
       "@type": "PostalAddress",
       "streetAddress": "Wieblinger Weg 35",
       "addressLocality": "Heidelberg"
     }
  ]

However, in JSON-LD the two representations do not mean the same. In RDF 
the *local* array resolves to two statements, i.e. Jane Doe really has 
two addresses (JSON-LD Playground http://tinyurl.com/lfk2e8v):
<http://janedoe.com> <http://schema.org/address> _:b0 .
<http://janedoe.com> <http://schema.org/address> _:b1 .

whereas the *remote* array resolves to one statement 
(http://tinyurl.com/mk9gjwp)
<http://janedoe.com> <http://schema.org/address> 
<http://janedoe.com/addresses> .

By making the addresses remote, you no longer state that Jane Doe has 
two addressses, not even after dereferencing the URL. You state that she 
has one address. The fact that dereferencing the list gives you two 
addresses does not make a difference here.

It is not possible to have a remote array in pure JSON-LD which 
correctly resolves to the equivalent of a local JSON-LD array. You have 
to introduce an intermediary object in a vocab like hydra:Collection and 
provide a definition how the collection items can be attached back to 
the parent. That is what the Hydra collection construct accomplishes 
(https://www.w3.org/community/hydra/wiki/Collection_Design).

Basically, rather than having an address attribute on the person, you 
say that the person has a related hydra:collection:

{
   "@context": { "@vocab": "http://schema.org/",
                "hydra": "http://www.w3.org/ns/hydra/core#",
                "hydra:property": {"@type": "@vocab"}
   },
   "@type": "Person",
   "@id": "http://janedoe.com",
   "name": "Jane Doe",
   "hydra:collection": {
     "@id": "http://janedoe.com/addresses",
     "@type": "hydra:Collection",
     "hydra:manages": {
       "hydra:property": "address",
       "hydra:subject": "http://janedoe.com"
     }
   }
}

Obviously that breaks your plain JSON client. What you could do is to 
return the old structure for clients which do not Accept: 
application/ld+json, and the new structure only for clients that do.

I find that quite cumbersome and unnatural from the perspective of a 
JSON api author, but it would have to be solved in JSON-LD by 
introducing the concept of a remote JSON-LD array. Last time I tried 
that I was told there is no chance for something like that, so I stopped 
pushing in that direction ;-)
I still think the lack of a concept for remote collections is a major 
shortcoming of JSON-LD. Your problem illustrates that quite nicely.

@Markus, Gregg: I guess your position remains unchanged here. Or would 
it make sense to open an issue for JSON-LD to support remote arrays - 
basically making the hydra:Collection a first-class citizen in JSON-LD, 
so to speak? If you are interested, I can explain what I mean by that.

Best,
Dietrich
Received on Saturday, 25 March 2017 11:19:02 UTC

This archive was generated by hypermail 2.3.1 : Saturday, 25 March 2017 11:19:03 UTC