[Solved] Named RDF Lists (collections) is not allowed?

When using Mashlib/SolidOS, when editing a Turtle file with lists (rdf:List), we encounter some unexpected behaviour.
In particular, it will refuse to save the file if the list is named.

For example, this document is valid, according to SolidOS:

@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>.
@prefix : <http://example.org#>.
  :has [
    a rdf:List;
    rdf:first [a :Wow];
    rdf:rest rdf:nil ].

On the other hand, this document is not valid:

@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>.
@prefix : <http://example.org#>.
  :has :node2.
  a rdf:List;
  rdf:first [a :Wow];
  rdf:rest rdf:nil.

The error message is:

Error: Bad list element node http://example.org#node2 type: NamedNode while trying to parse https://PATH/TO/FILE.ttl as text/turtle

However, after consulting the RDF spec again, I didn’t find it saying a rdf:List MUST NOT be a NamedNode.

Does anyone know how or why the behaviour in Mashlib/SolidOS?

Rdfib prefers to deal with Collections using the shorthand turtle syntax rather than the cumbersome rdf:first/rdf:rest construct.

So :node1 :has ([a :Wow]). is equivalent to your example.

Since it isn’t really possible to name ([a :Wow]) I can see why rdflib might not be happy with your code. Still, if your code is valid, rdflib should parse it. You might asked in #linkeddata_chat:gitter.im or in SolidOS.

1 Like

For example, here’s a standard solid-ui form using the shorthand Collection syntax

    a ui:Form ;
    ui:parts( :Field1 :Field2 ) .

Thanks Jeff. I see the shorthand syntax. We are making experiments because we need to explicitly manipulate the list, particularly to append it. And we intend to do this through either SPARQL-update request or n3-patch request, which does not always work well (i.e. on our CSS deployment, it works; on solidcommunity.net, it does not).

I’ll first ask this in the channel you suggested, to check my interpretation of the spec.

If you save an ordered list on NSS, it get’s saved with rdflib’s algo using the shorthand syntax. If you save it on CSS it gets converted to the longer syntax. It is one of the issues we have with using SolidOS on CSS. The SolidOS forms will let you reorder or modify the contents of an ordered list and save it using the shorthand syntax so it is definitely possible to patch it but this inconsistency between the servers is a pain. [EDIT - I may be wrong about using patch - when an ordered list is in a form, it may be saved with a PUT, not a PATCH in rdflib. ]

Here is a simple example to illustrate our problem, if that helps understand why we are playing with RDF lists.

We want to append an item to the end of the list, such as a blank node [a :Wow2]. With the “correct” data saved on pod, we send a PATCH request with Content-Type: application/sparql-update, with the following payload:

DELETE { ?end <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> <http://www.w3.org/1999/02/22-rdf-syntax-ns#nil>  }
INSERT { ?end <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> _:b1 .
         _:b1 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> [a <http://example.org#Wow2>].
         _:b1 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> <http://www.w3.org/1999/02/22-rdf-syntax-ns#nil>. }
WHERE { ?end  <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest>  <http://www.w3.org/1999/02/22-rdf-syntax-ns#nil> }

The server (tested on solidcomunity.net) will reply saying no matching tuple found in the WHERE clause. (Or, with our CSS deployment, it works without issues.)
Actually for CSS, it works, but with issues. What worked without issues is with the Turtle data being in the second form (that is rejected by Mashlib/SolidOS).

I did some more tests, and this error only happens when the WHERE is searching for a tuple inside the RDF list with predicate rdf:first or rdf:last.
It happens as well for N3 patch request.

If I remember correctly, if I have [a rdf:List, :DummyClass], and WHERE looks for ?end a :DummyClass, it will succeed in finding it (but then other issues happen, which makes sense).

The reason for inlining all URIs is to circumvent another issue with NSS – it will complain invalid syntax for the patch request.

I don’t have a great answer but I did some poking around with your files and the patches you were trying to apply, and it looks like an underlying issue with rdflib rather than node solid server. The source of the issue with the n3-Patch is here: rdflib.js/src/lists.ts at de0aab42f78f773f734054238391cbcbe721088c · linkeddata/rdflib.js · GitHub
I was less able to figure out the issue with the sparql parse in NSS but it looked like something to do with the applyPatch function in the store.

I would try and fix it but I am not very familiar with RDF.


Yes, the “problem” is with with rdflib’s philosophy as RDF and N3 as a language. As a language, a N3 document is a an unordered set of Statements. A Statement has a subject, predicate and object. The predicate can be a symbol (named node) or a annamed expression (bnode), and subject and object can be a term. A term is a symbol, or a bnode, or a constant RDF LIteral with datatype, such as number or string or date), or a list, (or a set) … or a subexpression (graph).

A list is an ordered set of terms
A set is an unordered set of terms
A subexpression is an unordered set of statements.

Terms, apart from Symbols, do not have URIs. Strings are not “named”. Numbers are not “named”. Lists are not “named”. Graphs are not “named”.

You can use RDF quads as a way of encoding this language.
But not all RDF datasets correspond to a serialization of the language. Many combinations of rdf:first and rdf:rest triples do not make sense. Including “named lists”.

So you can say things like

<#patch> :deletes { :y :p ( 1 2 ) }; :inserts { :y :p ( 1 2 3 )} .

but if you try to mess with rdf:first and rdf:rest in the serialization of the lists then you are on your own. We try to not bother developers with rdf:first and rdf:rest!

Maybe we need to add to N3 Patch the ability to perform slice and splice operations on lists and add and remove operations on sets and graphs.

Hi Tim. Thanks for the clarification and illustrations. That makes sense, though unexpected :frowning:

To test my understanding: you are making a difference between RDF language and RDF document, in this interpretation.
RDF document follows some syntax, as specified by RDF spec. RDF language is a subset of RDF document, which is the subset interpretable by rdflib, following some additional rules. The subset is a strict subset, and not all valid RDF documents belong to this language.
Thus, as a natural conclusion, rdflib cannot handle all syntactically correct RDF documents.

Analogy in natural language: “houses jump high” is a syntactically/grammatically correct English statement/document, but it is not a valid/meaningful English language sentence, in normal minds.

Well… we know that is not always true… TriG supports Named Graphs, for example…

That looks like the most promising solution, so far.

In N3, Lists are not “named”. Graphs are not “named”

I’m not talking about Trig or RDFstar. I don’t use RDF* because it is not presented as unversal ways of encoding knowledge. RDF* is presented as ways of encoding other data structures.

Trig can be converted into N3 by using an arc like log:semantics between the symbol and the graph. So Trig if usable. It would have been good if the Trig fols had defined that property. (or just used N3).