Skip to content

Losing Last Element in RDF List #530

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

Closed
mnmercer opened this issue Aug 18, 2017 · 4 comments
Closed

Losing Last Element in RDF List #530

mnmercer opened this issue Aug 18, 2017 · 4 comments

Comments

@mnmercer
Copy link

mnmercer commented Aug 18, 2017

We have web application that needs to be able to modify RDF lists from a triple store and propagate the changes back. To do this, we are utilizing jsonld-java to serialize the RDF into JSON-LD, modifying it in the web app, and then sending it back to be deserialized and stored in the triple store. Originally, we were using blank nodes like the ones shown in Turtle below.

<http://example.com> <http://example.com/property> _:a .
_:a a <http://www.w3.org/1999/02/22-rdf-syntax-ns#List> ;
    <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> "a" ;
    <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> _:b .
_:b a <http://www.w3.org/1999/02/22-rdf-syntax-ns#List> ;
    <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> "b" ;
    <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> _:c .
_:c a <http://www.w3.org/1999/02/22-rdf-syntax-ns#List> ;
    <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> "c" ;
    <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> <http://www.w3.org/1999/02/22-rdf-syntax-ns#nil> .

However, we discovered that blank node lists are collapsed during serialization thus losing all the blank node IDs.

[ {
  "@id" : "http://example.com",
  "http://example.com/property" : [ {
    "@list" : [ {
      "@value" : "a"
    }, {
      "@value" : "b"
    }, {
      "@value" : "c"
    } ]
  } ]
} ]

With blank node IDs removed, we are no longer able to reference the existing RDF in the triple store to perform updates when the lists are modified in the web-app without much more complex logic. To avoid this, we skolemized the blank node IDs into IRIs.

<http://example.com> <http://example.com/property> <urn:a> .
<urn:a> a <http://www.w3.org/1999/02/22-rdf-syntax-ns#List> ;
    <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> "a" ;
    <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> <urn:b> .
<urn:b> a <http://www.w3.org/1999/02/22-rdf-syntax-ns#List> ;
    <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> "b" ;
    <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> <urn:c> .
<urn:c> a <http://www.w3.org/1999/02/22-rdf-syntax-ns#List> ;
    <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> "c" ;
    <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> <http://www.w3.org/1999/02/22-rdf-syntax-ns#nil> .

However, when serializing the skolemized triples, the IRI for the last element in the RDF list is hidden, in this case urn:c. This leads to the same problem we were having when using blank node IDs.

[ {
  "@id" : "http://example.com",
  "http://example.com/property" : [ {
    "@id" : "urn:a"
  } ]
}, {
  "@id" : "urn:a",
  "@type" : [ "http://www.w3.org/1999/02/22-rdf-syntax-ns#List" ],
  "http://www.w3.org/1999/02/22-rdf-syntax-ns#first" : [ {
    "@value" : "a"
  } ],
  "http://www.w3.org/1999/02/22-rdf-syntax-ns#rest" : [ {
    "@id" : "urn:b"
  } ]
}, {
  "@id" : "urn:b",
  "@type" : [ "http://www.w3.org/1999/02/22-rdf-syntax-ns#List" ],
  "http://www.w3.org/1999/02/22-rdf-syntax-ns#first" : [ {
    "@value" : "b"
  } ],
  "http://www.w3.org/1999/02/22-rdf-syntax-ns#rest" : [ {
    "@list" : [ {
      "@value" : "c"
    } ]
  } ]
} ]

Issue #277 seems to be the point where the implementation changed from serializing lists in the manner we expect to this new compact way. Is there any way we can get around this so that the last blank node of a list is not collapsed?

@davidlehn
Copy link
Member

Is that the right issue id?

@mnmercer
Copy link
Author

Whoops! A little number dyslexia. Corrected.

@mnmercer
Copy link
Author

mnmercer commented Aug 21, 2017

I found the point in the jsonld-java code that seems to be causing the collapse of the last element, JsonLdApi.java lines 1937-1976. When looping through the usages of rdf:nil, it stops collecting the parents when it finds a node that isn't a blank node. However the usage of nil is never checked. Adjusting the algorithm to check whether the node with the usage of rdf:nil is a blank node seems to fix the collapsing of the last element. Now I get something like this.

[ {
  "@id" : "http://example.com",
  "http://example.com/property" : [ {
    "@id" : "urn:a"
  } ]
}, {
  "@id" : "urn:a",
  "@type" : [ "http://www.w3.org/1999/02/22-rdf-syntax-ns#List" ],
  "http://www.w3.org/1999/02/22-rdf-syntax-ns#first" : [ {
    "@value" : "a"
  } ],
  "http://www.w3.org/1999/02/22-rdf-syntax-ns#rest" : [ {
    "@id" : "urn:b"
  } ]
}, {
  "@id" : "urn:b",
  "@type" : [ "http://www.w3.org/1999/02/22-rdf-syntax-ns#List" ],
  "http://www.w3.org/1999/02/22-rdf-syntax-ns#first" : [ {
    "@value" : "b"
  } ],
  "http://www.w3.org/1999/02/22-rdf-syntax-ns#rest" : [ {
    "@list" : [ {
      "@value" : "c"
    } ]
  } ],
}, {
  "@id" : "urn:c",
  "@type" : [ "http://www.w3.org/1999/02/22-rdf-syntax-ns#List" ],
  "http://www.w3.org/1999/02/22-rdf-syntax-ns#first" : [ {
    "@value" : "c"
  } ],
  "http://www.w3.org/1999/02/22-rdf-syntax-ns#rest" : [ {
    "@list" : [ ]
  } ]
} ]

However, as far as I understood, the last element of an rdf:List should be represented as follows. Is that no longer the case?

{
  "@id" : "urn:c",
  "@type" : [ "http://www.w3.org/1999/02/22-rdf-syntax-ns#List" ],
  "http://www.w3.org/1999/02/22-rdf-syntax-ns#first" : [ {
    "@value" : "c"
  } ],
  "http://www.w3.org/1999/02/22-rdf-syntax-ns#rest" : [ {
    "@id" : "http://www.w3.org/1999/02/22-rdf-syntax-ns#nil"
  } ]
}

@gkellogg gkellogg added this to the JSON-LD 1.1 milestone Jan 19, 2018
@gkellogg gkellogg removed this from the JSON-LD 1.1 milestone Mar 22, 2018
@gkellogg
Copy link
Member

List representation is shortcut in JSON-LD using @container: @list and requires a strict form of the list to compact in such a way. As JSON-LD does not support a list of lists, you can serialize that to see what the corresponding JSON-LD looks like. For example, given the following Turtle:

<http://example.org/a> <http://example.org/b> (("c" "d" "e")) .

We can see the following:

{
  "@context": {
    "rdf": "http://www.w3.org/1999/02/22-rdf-syntax-ns#"
  },
  "@graph": [
    {
      "@id": "_:g70196264024700",
      "rdf:first": "c",
      "rdf:rest": {"@list": ["d",  "e" ]}
    },
    {
      "@id": "http://example.org/a",
      "http://example.org/b": {
        "@list": [{"@id": "_:g70196264024700"}]
      }
    }
  ]
}

JSON-LD does not preserve blank node identifiers, and in general RDF does not preserve them. The fact that jsonld-java may preserve blank node identifiers in some cases, allowing them to be updated, as a non-standard feature. As you note, skolemization can be used to do this, but then you have something that is not really an RDF List (until de-skolemized).

Because an empty list (rdf:nil) can always be represented using @list in JSON-LD, you'll always see this as {"@list": []}.

You can certainly write a list using standard JSON-LD syntax for rdf:first/rest/nil and either blank node identifiers or embedding to chain them together, but when round-tripping, they will be turned back into the @list representation.

Trying to use JSON-LD as a patch format for modifying graphs containing lists is out of scope, and cannot be standardized. It can be used manipulate an RDF graph transformed into the JSON-LD domain and manipulated, say, using JavaScript, but this essentially creates a new graph.

There are patch formats, such as SPARQL Update or LD Patch which may be more suitable for your use case.

Regarding the issue #277, resolved in 2013, that ship has sailed. If there was strong interest, we could consider adding an API option, similar to the use rdf:type flag flag in the Serialize RDF to JSON-LD algorithm to create something like a use rdf:List flag, but IMHO, it's utility is limited.

@gkellogg gkellogg closed this as completed Aug 1, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants