A simple sample turtle vs. json-ld

Hi all, we have the discussion in different topics now. and this topic will discuss a more concrete sample.

turtle:

@prefix as: <https://www.w3.org/ns/activitystreams#> .
@prefix ns0: <https://schema.org/> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .

<http://localhost:8090/kvm_loa/V0_9d317daca74246d4be41b1a37e30ee2a>
  a <https://schema.org/CreativeWork>, as:Object ;
  ns0:about <http://localhost:8090/kvm_loa/V0_9d317daca74246d4be41b1a37e30ee2a_organisation> ;
  ns0:dateCreated "1970-01-19T23:52:48.511"^^xsd:string ;
  ns0:dateModified "2021-12-04T18:19:19.951277"^^xsd:string ;
  ns0:description "Verbrauchsgemeinschaft fĂŒr solidarischen und gesegelten Kaffee. Hier kannst du ökologisch und sozial anspruchsvollen Kaffee bestellen und dich mit anderen Enthusiast*innen von gutem und nachhaltigen Kaffee austauschen. Bestelle schnell und einfach mit Klick auf unsere Homepage."^^xsd:string ;
  ns0:identifier "9d317daca74246d4be41b1a37e30ee2a"^^xsd:string ;
  ns0:keywords "teikei,teikei-gemeinschaft"^^xsd:string ;
  ns0:license "CC0-1.0"^^xsd:string ;
  ns0:name "Teikei Gemeinschaft MĂŒnchen Trudering"^^xsd:string ;
  ns0:version "0"^^xsd:string ;
  as:name "Teikei Gemeinschaft MĂŒnchen Trudering"^^xsd:string .

<http://localhost:8090/kvm_loa/V0_9d317daca74246d4be41b1a37e30ee2a_organisation>
  a ns0:Organization, as:Object ;
  ns0:contactPoint <http://localhost:8090/kvm_loa/V0_9d317daca74246d4be41b1a37e30ee2a_contactPoint> ;
  ns0:location <http://localhost:8090/kvm_loa/V0_9d317daca74246d4be41b1a37e30ee2a_place> ;
  ns0:name "Teikei Gemeinschaft MĂŒnchen Trudering"^^xsd:string .

<http://localhost:8090/kvm_loa/V0_9d317daca74246d4be41b1a37e30ee2a_contactPoint>
  a ns0:ContactPoint, as:Object ;
  ns0:email "muenchen-trudering@teikei.community"^^xsd:string ;
  ns0:telephone ""^^xsd:string .

<http://localhost:8090/kvm_loa/V0_9d317daca74246d4be41b1a37e30ee2a_place>
  a as:Object, ns0:Place ;
  ns0:address <http://localhost:8090/kvm_loa/V0_9d317daca74246d4be41b1a37e30ee2a_postalAddress> ;
  ns0:latitude 4.813284e+1 ;
  ns0:longitude 1.167609e+1 .

<http://localhost:8090/kvm_loa/V0_9d317daca74246d4be41b1a37e30ee2a_postalAddress>
  a ns0:PostalAddress, as:Object ;
  ns0:addressLocality "MĂŒnchen"^^xsd:string ;
  ns0:postalCode "81829"^^xsd:string ;
  ns0:streetAddress """LinnenbrĂŒggerstrasse  13
"""^^xsd:string .

json-ld generated with https://www.easyrdf.org/converter:

[
	{
		"@id": "http://localhost:8090/kvm_loa/V0_9d317daca74246d4be41b1a37e30ee2a",
		"@type": [
			"https://schema.org/CreativeWork",
			"https://www.w3.org/ns/activitystreams#Object"
		],
		"https://schema.org/about": [
			{
				"@id": "http://localhost:8090/kvm_loa/V0_9d317daca74246d4be41b1a37e30ee2a_organisation"
			}
		],
		"https://schema.org/dateCreated": [
			{
				"@value": "1970-01-19T23:52:48.511"
			}
		],
		"https://schema.org/dateModified": [
			{
				"@value": "2021-12-04T18:19:19.951277"
			}
		],
		"https://schema.org/description": [
			{
				"@value": "Verbrauchsgemeinschaft fĂŒr solidarischen und gesegelten Kaffee. Hier kannst du ökologisch und sozial anspruchsvollen Kaffee bestellen und dich mit anderen Enthusiast*innen von gutem und nachhaltigen Kaffee austauschen. Bestelle schnell und einfach mit Klick auf unsere Homepage."
			}
		],
		"https://schema.org/identifier": [
			{
				"@value": "9d317daca74246d4be41b1a37e30ee2a"
			}
		],
		"https://schema.org/keywords": [
			{
				"@value": "teikei,teikei-gemeinschaft"
			}
		],
		"https://schema.org/license": [
			{
				"@value": "CC0-1.0"
			}
		],
		"https://schema.org/name": [
			{
				"@value": "Teikei Gemeinschaft MĂŒnchen Trudering"
			}
		],
		"https://schema.org/version": [
			{
				"@value": "0"
			}
		],
		"https://www.w3.org/ns/activitystreams#name": [
			{
				"@value": "Teikei Gemeinschaft MĂŒnchen Trudering"
			}
		]
	},
	{
		"@id": "http://localhost:8090/kvm_loa/V0_9d317daca74246d4be41b1a37e30ee2a_contactPoint",
		"@type": [
			"https://schema.org/ContactPoint",
			"https://www.w3.org/ns/activitystreams#Object"
		],
		"https://schema.org/email": [
			{
				"@value": "muenchen-trudering@teikei.community"
			}
		],
		"https://schema.org/telephone": [
			{
				"@value": ""
			}
		]
	},
	{
		"@id": "http://localhost:8090/kvm_loa/V0_9d317daca74246d4be41b1a37e30ee2a_organisation",
		"@type": [
			"https://schema.org/Organization",
			"https://www.w3.org/ns/activitystreams#Object"
		],
		"https://schema.org/contactPoint": [
			{
				"@id": "http://localhost:8090/kvm_loa/V0_9d317daca74246d4be41b1a37e30ee2a_contactPoint"
			}
		],
		"https://schema.org/location": [
			{
				"@id": "http://localhost:8090/kvm_loa/V0_9d317daca74246d4be41b1a37e30ee2a_place"
			}
		],
		"https://schema.org/name": [
			{
				"@value": "Teikei Gemeinschaft MĂŒnchen Trudering"
			}
		]
	},
	{
		"@id": "http://localhost:8090/kvm_loa/V0_9d317daca74246d4be41b1a37e30ee2a_place",
		"@type": [
			"https://www.w3.org/ns/activitystreams#Object",
			"https://schema.org/Place"
		],
		"https://schema.org/address": [
			{
				"@id": "http://localhost:8090/kvm_loa/V0_9d317daca74246d4be41b1a37e30ee2a_postalAddress"
			}
		],
		"https://schema.org/latitude": [
			{
				"@value": 48.13284
			}
		],
		"https://schema.org/longitude": [
			{
				"@value": 11.67609
			}
		]
	},
	{
		"@id": "http://localhost:8090/kvm_loa/V0_9d317daca74246d4be41b1a37e30ee2a_postalAddress",
		"@type": [
			"https://schema.org/PostalAddress",
			"https://www.w3.org/ns/activitystreams#Object"
		],
		"https://schema.org/addressLocality": [
			{
				"@value": "MĂŒnchen"
			}
		],
		"https://schema.org/postalCode": [
			{
				"@value": "81829"
			}
		],
		"https://schema.org/streetAddress": [
			{
				"@value": "LinnenbrĂŒggerstrasse  13\r\n"
			}
		]
	},
	{
		"@id": "https://schema.org/ContactPoint"
	},
	{
		"@id": "https://schema.org/CreativeWork"
	},
	{
		"@id": "https://schema.org/Organization"
	},
	{
		"@id": "https://schema.org/Place"
	},
	{
		"@id": "https://schema.org/PostalAddress"
	},
	{
		"@id": "https://www.w3.org/ns/activitystreams#Object"
	}
]

Activity:

<http://localhost:8090/kvm_loa/0815> a <https://www.w3.org/ns/activitystreams#Create>;
  <https://www.w3.org/ns/activitystreams#actor> <http://localhost:8090/kvm_loa/Sally>;
  <https://www.w3.org/ns/activitystreams#object> <http://localhost:8090/kvm_loa/V0_9d317daca74246d4be41b1a37e30ee2a>;
  <https://www.w3.org/ns/activitystreams#summary> "Sally created a note" .

<http://localhost:8090/kvm_loa/Sally> a <https://www.w3.org/ns/activitystreams#Person>;
  <https://www.w3.org/ns/activitystreams#name> "Sally" .
[
	{
		"@id": "http://localhost:8090/kvm_loa/0815",
		"@type": [
			"https://www.w3.org/ns/activitystreams#Create"
		],
		"https://www.w3.org/ns/activitystreams#actor": [
			{
				"@id": "http://localhost:8090/kvm_loa/Sally"
			}
		],
		"https://www.w3.org/ns/activitystreams#object": [
			{
				"@id": "http://localhost:8090/kvm_loa/V0_9d317daca74246d4be41b1a37e30ee2a"
			}
		],
		"https://www.w3.org/ns/activitystreams#summary": [
			{
				"@value": "Sally created a note"
			}
		]
	},
	{
		"@id": "http://localhost:8090/kvm_loa/Sally",
		"@type": [
			"https://www.w3.org/ns/activitystreams#Person"
		],
		"https://www.w3.org/ns/activitystreams#name": [
			{
				"@value": "Sally"
			}
		]
	},
	{
		"@id": "http://localhost:8090/kvm_loa/V0_9d317daca74246d4be41b1a37e30ee2a"
	},
	{
		"@id": "https://www.w3.org/ns/activitystreams#Create"
	},
	{
		"@id": "https://www.w3.org/ns/activitystreams#Person"
	}
]

and i’ll just say that the above is a valid create activity and i’m looking forward to your feedback.

@naturzukunft Please make sure to read the ActivityStreams Core spec, especially the Serialization section:

An Activity Streams Document is a JSON document whose root value is an Activity Streams Object of any type, including a Collection, and whose MIME media type is " application/activity+json ".

The serialized JSON form of an Activity Streams 2.0 document MUST be consistent with what would be produced by the standard JSON-LD 1.0 Processing Algorithms and API [JSON-LD-API] Compaction Algorithm using, at least, the normative JSON-LD @context definition provided here.

Reading those excerpts I can see two major violations in your JSON-LD documents, which are required for interoperability:

  1. Your documents are not compacted. Here’s an example of the compacted version of your second document:

    {
      "@context": "https://www.w3.org/ns/activitystreams",
      "@graph": [
        {
          "id": "http://localhost:8090/kvm_loa/0815",
          "type": "Create",
          "actor": "http://localhost:8090/kvm_loa/Sally",
          "object": "http://localhost:8090/kvm_loa/V0_9d317daca74246d4be41b1a37e30ee2a",
          "summary": "Sally created a note"
        },
        {
          "id": "http://localhost:8090/kvm_loa/Sally",
          "type": "Person",
          "name": "Sally"
        }
      ]
    }
    

    As you can see, it’s a lot easier to read that way, for one! But it’s also important for ActivityStreams interoperability, which is a prerequisite for ActivityPub federation.

  2. Your documents do not have a “root value” of an ActivityStreams object. Here’s what your first example looks like when properly rooted at an ActivityStreams object

    {
      "@context": [
        "https://www.w3.org/ns/activitystreams",
        {
          "schema": "https://schema.org/"
        }
      ],
      "id": "http://localhost:8090/kvm_loa/V0_9d317daca74246d4be41b1a37e30ee2a",
      "type": [
        "schema:CreativeWork",
        "Object"
      ],
      "schema:about": {
        "id": "http://localhost:8090/kvm_loa/V0_9d317daca74246d4be41b1a37e30ee2a_organisation",
        "type": [
          "schema:Organization",
          "Object"
        ],
        "schema:contactPoint": {
          "id": "http://localhost:8090/kvm_loa/V0_9d317daca74246d4be41b1a37e30ee2a_contactPoint",
          "type": [
            "schema:ContactPoint",
            "Object"
          ],
          "schema:email": "muenchen-trudering@teikei.community",
          "schema:telephone": ""
        },
        "schema:location": {
          "id": "http://localhost:8090/kvm_loa/V0_9d317daca74246d4be41b1a37e30ee2a_place",
          "type": [
            "Object",
            "schema:Place"
          ],
          "schema:address": {
            "id": "http://localhost:8090/kvm_loa/V0_9d317daca74246d4be41b1a37e30ee2a_postalAddress",
            "type": [
              "schema:PostalAddress",
              "Object"
            ],
            "schema:addressLocality": "MĂŒnchen",
            "schema:postalCode": "81829",
            "schema:streetAddress": "LinnenbrĂŒggerstrasse  13\r\n"
          },
          "schema:latitude": 48.13284,
          "schema:longitude": 11.67609
        },
        "schema:name": "Teikei Gemeinschaft MĂŒnchen Trudering"
      },
      "schema:dateCreated": "1970-01-19T23:52:48.511",
      "schema:dateModified": "2021-12-04T18:19:19.951277",
      "schema:description": "Verbrauchsgemeinschaft fĂŒr solidarischen und gesegelten Kaffee. Hier kannst du ökologisch und sozial anspruchsvollen Kaffee bestellen und dich mit anderen Enthusiast*innen von gutem und nachhaltigen Kaffee austauschen. Bestelle schnell und einfach mit Klick auf unsere Homepage.",
      "schema:identifier": "9d317daca74246d4be41b1a37e30ee2a",
      "schema:keywords": "teikei,teikei-gemeinschaft",
      "schema:license": "CC0-1.0",
      "schema:name": "Teikei Gemeinschaft MĂŒnchen Trudering",
      "schema:version": "0",
      "name": "Teikei Gemeinschaft MĂŒnchen Trudering"
    }
    

Both of these issues should be easy to fix, if you’re starting from a RDF representation of an object.

One other thing I noted that wasn’t a violation but did strike me as odd is that you used the ActivityStreams Object type to represent the values of properties like schema:contactPoint or schema:location. Since these are non-ActivityStreams properties, I don’t think there’s any reason or point in making the objects that they reference ActivityStreams values.

Here’s how I would represent http://localhost:8090/kvm_loa/V0_9d317daca74246d4be41b1a37e30ee2a as an ActivityStreams document, based on what you indicated:

{
  "@context": [
    "https://www.w3.org/ns/activitystreams",
    {
      "schema": "https://schema.org/"
    }
  ],
  "id": "http://localhost:8090/kvm_loa/V0_9d317daca74246d4be41b1a37e30ee2a",
  "type": [
    "schema:CreativeWork",
    "Object"
  ],
  "schema:about": {
    "id": "http://localhost:8090/kvm_loa/V0_9d317daca74246d4be41b1a37e30ee2a_organisation",
    "type": "schema:Organization",
    "schema:contactPoint": {
      "id": "http://localhost:8090/kvm_loa/V0_9d317daca74246d4be41b1a37e30ee2a_contactPoint",
      "type": "schema:ContactPoint",
      "schema:email": "muenchen-trudering@teikei.community",
      "schema:telephone": ""
    },
    "schema:location": {
      "id": "http://localhost:8090/kvm_loa/V0_9d317daca74246d4be41b1a37e30ee2a_place",
      "type": "schema:Place",
      "schema:address": {
        "id": "http://localhost:8090/kvm_loa/V0_9d317daca74246d4be41b1a37e30ee2a_postalAddress",
        "type": "schema:PostalAddress",
        "schema:addressLocality": "MĂŒnchen",
        "schema:postalCode": "81829",
        "schema:streetAddress": "LinnenbrĂŒggerstrasse  13\r\n"
      },
      "schema:latitude": 48.13284,
      "schema:longitude": 11.67609
    },
    "schema:name": "Teikei Gemeinschaft MĂŒnchen Trudering"
  },
  "schema:dateCreated": "1970-01-19T23:52:48.511",
  "schema:dateModified": "2021-12-04T18:19:19.951277",
  "schema:description": "Verbrauchsgemeinschaft fĂŒr solidarischen und gesegelten Kaffee. Hier kannst du ökologisch und sozial anspruchsvollen Kaffee bestellen und dich mit anderen Enthusiast*innen von gutem und nachhaltigen Kaffee austauschen. Bestelle schnell und einfach mit Klick auf unsere Homepage.",
  "schema:identifier": "9d317daca74246d4be41b1a37e30ee2a",
  "schema:keywords": "teikei,teikei-gemeinschaft",
  "schema:license": "CC0-1.0",
  "schema:name": "Teikei Gemeinschaft MĂŒnchen Trudering",
  "schema:version": "0",
  "name": "Teikei Gemeinschaft MĂŒnchen Trudering"
}

and your second example as:

{
  "@context": "https://www.w3.org/ns/activitystreams",
  "id": "http://localhost:8090/kvm_loa/0815",
  "type": "Create",
  "actor": {
    "id": "http://localhost:8090/kvm_loa/Sally",
    "type": "Person",
    "name": "Sally"
  },
  "object": "http://localhost:8090/kvm_loa/V0_9d317daca74246d4be41b1a37e30ee2a",
  "summary": "Sally created a note"
}

Does that make sense?

1 Like

A little bit of history here. There was a desire to have a JSON serialization for linked data, since JSON is very popular. I think it was well summed up in this post from 2011

https://lists.w3.org/Archives/Public/public-rdf-wg/2011Mar/0565.html

There was actually two things that were wanted. The first was the ability to express full Linked Data in JSON. And that’s what became JSON-LD. The second part was to extract linked data from ordinary JSON. That part is not really well developed, but would make life much easier IMO

The main difference I would say between Turtle/RDF and JSON is that in Turtle everything is a Set, and in JSON you have objects and arrays. Having only Sets to work with makes merging from different sources cheaper (because it avoid duplicates) but makes things like arithmetic harder (it’s a delete and insert operation that requires atomicity too, something still not fully developed). Also arrays are hard to work with in RDF, but easy in JS(ON). RDF parsers are also large in size, and consequently buggy, also having to support legacy serializations like RDF/XML from 2002. Also there’s fiddly things like xsd:integer is a BigInt wheras json numbers to go 2 billion.

I started out in with turtle in my profile. After the AP conference in Prague I went out to dinner with Manu Sporny, the creator of JSON-LD. I asked him if we could support turtle and increase the size of the eco system. He said, “Its hard enough getting people to use JSON-LD”. As a turtle evangelist, that resonated with me and I later converted to JSON-LD.

In the Social Web Working Group we pushed to make activity pub full JSON-LD. It was a political battle that was lost, I think partly due to technical problems and partly people problems. So as things stand activity pub is slightly different from JSON-LD with a different mime type, some syntactic sugar, and a ‘sacred’ vocabulary, which is a bit unusual in LD, but lowers the bar for devs to get started (at the cost of some extensibility)

Since that time JSON has won the race for adoption, IMHO. It has great tooling, is fast, and doesnt requires a parser. So if interacting with other social systems, I’d encourage the use of JSON, with the LD properties of @id and @type as being I think the most useful. Then get parsers to adjust to that.

People that want to use turtle and full RDF should be allowed to do so. And I think communities that want to take the best features from Linked Data can as well, but should not be required to take everything, which is a multi year learning curve. My suggestion would be to convert turtle to JSON, and either put it in a .json file, which can either be linked from html, or actually embedded in a SCRIPT, which is part of the JSON-LD spec too. The latter pattern is my personal favourite and has wide adoption via schema.org. Mastodon profile already partially do this for some data, id love to see the full json put in the html page. This goes back to the original concept of a “Semantic Web” where a web page could contain both human and machine readable data e.g. when you view the source.

I also had a long call with Tim Berners-Lee last year suggesting that Solid use this pattern too. Happily, he agreed in principle that it’s a bug, in solid profiles, that should be fixed, however he wanted to put turtle in the profile, possibly as well as JSON-LD. That bug hasnt been fixed yet, though.

In summary, AP and JSON-LD are not 100% compatible. But that’s OK, and we should be able to find ways to adjust to that, as the eco system, and spec evolves. My personal solution was to convert my turtle to plain old JSON with @id and @type. I find it much easier to work, since doing so.

2 Likes

Thanks for your feedback! i’ll spend some time on that and will play with the settings of the used rdf to json-ld lib. Than i will come back with other results. i hope, that it’s possible to generate application/activity+json . if not, it would be awful!

@melvincarvalho thank you also for the detailed feedback.

Manu Sporny: “Its hard enough getting people to use JSON-LD”

Yes, I understand that and he is certainly right!

But semantic data are not json, but rather rdf.
and if people (developers) don’t find the way to rdf, then it becomes difficult to provide and process semantic data. This is of course always possible with individual converters, but more difficult generically. I haven’t looked at the “Serialization section” yet or haven’t looked at it for a while, because I would have hoped to be able to use existing tools for this. But at the moment I have the feeling that this is not possible.

My goal is to make data available to machines in a readable way and to capture it in different ways. ActivityPub seems to me in some approaches to be suitable. especially because of the federation.
However, my intention, like probably that of openEngiadina, is not necessarily a “social network”. i haven’t quite got through that yet, as i haven’t been dealing with rdf, AP and linked data for so long. I’m also not hung up on the AP specification, to me it’s more important to capture and provide semantic data, and also make it searchable. Therefore my solution will have a SPARQL endpoint.

I want to check how far AP can help me with my project (https://linkedopenactors.org/). For the time being I will limit myself to the formats RDFFormat.TURTLE, RDFFormat.RDFXML, RDFFormat.NTRIPLES, RDFFormat.TURTLESTAR, RDFFormat.N3, RDFFormat.JSONLD, RDFFormat.NQUADS, RDFFormat.RDFJSON, as these are offered by rdf4j. However, my solution will be based on Enterprise Integration Patterns (EIP) and it should be easy to add more “translators” later. (if there are converters to be included !)

I will then only be compatible for certain types of AP S2S, e.g. mobilizon. However, my C2S solution should be generic.
By the EIP approach it should be easy to support different transport protocols, so @pukkamustard xmpp approach is also to consider.
A client for the generic C2S server solution will be challenging. I am talking to a frontend developer since yesterday and I am excited to see what solutions we will come up with.

let’s expand the open linked data bubble to connect people online → offline and make information easily available to everyone.

That’s cool.
Just about

I started out in with turtle in my profile. After the AP conference in Prague [
]
As a turtle evangelist

I forgot to say that I am a JS evangelist :wink:

and will play with the settings

I bet, you know it but others might not:
JSON LD got a nice playground

@melvincarvalho which makes me think, it would be nice to have some more examples like for schema.org (existing) also for ActivityPub and “mixed“ 


A few moth ago i was playing with framing and use the activity stream definition, that was somewhere available in the internet and was adjusted by @pukkamustard

The “problem” is, that the complete definition is in the head of the result, but the result is more like an AP Activity ; -)

That is the outcome for the above Sample

^ is that AP conform ?

1 Like

Yes, that looks AP conform.
You can check it in the playground: JSON-LD Playground

then copy your input in the left field
then click the Bildschirmfoto 2021-12-05 um 14.43.13 button to copy the @context 

Now click “compacted” in the bottom and it looks like in the specifications examples with some schema.org etc. sweets 

Personally I treat as as the default vocabulary (since I validate it anyway) but this only has the benefit that you do not need to name all the properties in the context 


I think by far the biggest use of the Semantic Web today is schema.org. Dan Brickley said it’s used on many millions of sites, and mainly billions of web pages. I think now about 1 in 3 web pages has some kind of semantic data inside it. Sem Web does have some other uses, such as in the enterprise, where typically you will have a large quad store

If you look at schema.org, it is a typically simple subset of the semantic web in JSON. If you look at the context it goes to:

https://schema.org/docs/jsonldcontext.jsonld

In theory each of the items in the page e.g. Person - Schema.org Type should give back some machine readable data (e.g. JSON-LD) which tells you what that thing is. But actually I think it just gives nothing but HTML. And nobody has really noticed.

So the value of schema.org isnt the shared schemas, which aren’t available. It mainly uses @id, @type and @date so that different types of data can be identified uniquely at web scale, and have a basic type

It resonates with me when you say “not to get hung up on a specification”, build things that work, and federations that work, and also think about what future versions of the spec will look like, based on what we learn

Regarding Linked Open Actors that looks like a cool project. People do actors in different ways. There’s AS, Schema.org, FOAF, vcard and so on. I wanted to try and make a vocab that works, that takes the best part of those things, make it fully json-ld compliant, and use it to create profiles with some examples.

So far I’ve got through FOAF and taken the things that I’ve used to most and put it here:

https://w3id.org/user

Source code:

Still a very early work in progress tho!