linkeddata / rdflib.js

Linked Data API for JavaScript
http://linkeddata.github.io/rdflib.js/doc/
Other
564 stars 143 forks source link

RDF/XML Incorrect When Serializing Graph With Blank Nodes #546

Open brynnjmccormick opened 2 years ago

brynnjmccormick commented 2 years ago

Description

When serializing a graph containing blank nodes as rdfl/xml, the output is incorrect and does not represent the original graph.

Steps to reproduce

The following script can be used to reproduce the bug in two different scenarios, one where the blank node has a type, and one where it does not.

const $rdf = require('rdflib');

const input1 = `@prefix : <http://example.org/> .
@prefix skosxl: <http://www.w3.org/2008/05/skos-xl#> .
@prefix dc: <http://purl.org/dc/terms/> .

:doc1
  a :Document ;
  dc:title [
    a :Title ;
    skosxl:literalForm "My Title"
  ] .
`;
const input2 = `@prefix : <http://example.org/> .
@prefix skosxl: <http://www.w3.org/2008/05/skos-xl#> .
@prefix dc: <http://purl.org/dc/terms/> .

:doc2
  a :Document ;
  dc:title [
    skosxl:literalForm "My Title"
  ] .
`;

const inGraph1 = $rdf.graph();
const inGraph2 = $rdf.graph();

$rdf.parse(input1, inGraph1, 'http://example.org', 'text/turtle', data => {
  const serialized1 = $rdf.serialize(undefined, inGraph1, 'http://example.org', 'application/rdf+xml');

  console.log('Example 1 Input:');
  console.log(input1);
  console.log('Example 1 Output:');
  console.log(serialized1);

  $rdf.parse(input2, inGraph2, 'http://example.org', 'text/turtle', data => {
    const serialized2 = $rdf.serialize(undefined, inGraph2, 'http://example.org', 'application/rdf+xml');

    console.log('Example 2 Input:');
    console.log(input2);
    console.log('Example 2 Output:');
    console.log(serialized2);
  });
});

Example 1

Input

@prefix : <http://example.org/> .
@prefix skosxl: <http://www.w3.org/2008/05/skos-xl#> .
@prefix dc: <http://purl.org/dc/terms/> .

:doc1
  a :Document ;
  dc:title [
    a :Title ;
    skosxl:literalForm "My Title"
  ] .

Actual Output

<rdf:RDF
 xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
 xmlns:dct="http://purl.org/dc/terms/"
 xmlns:skosxl="http://www.w3.org/2008/05/skos-xl#"
 xmlns:ex="http://example.org/">
    <ex:Document rdf:about="http://example.org/doc1">
        <dct:title rdf:parseType="Resource">
           <ex:Title><skosxl:literalForm>My Title</skosxl:literalForm></ex:Title>
        </dct:title>
    </ex:Document>
</rdf:RDF>

Output is interpretted as:

@prefix dc: <http://purl.org/dc/terms/> .
@prefix ns0: <http://example.org/> .
@prefix skosxl: <http://www.w3.org/2008/05/skos-xl#> .

<http://example.org/doc1>
  a <http://example.org/Document> ;
  dc:title [ ns0:Title [ a skosxl:literalForm ] ] .

In RDF/XML this is:

<?xml version="1.0" encoding="utf-8" ?>
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
         xmlns:dc="http://purl.org/dc/terms/"
         xmlns:ns0="http://example.org/"
         xmlns:skosxl="http://www.w3.org/2008/05/skos-xl#">

  <rdf:Description rdf:about="http://example.org/doc1">
    <rdf:type rdf:resource="http://example.org/Document"/>
    <dc:title>
      <rdf:Description>
        <ns0:Title>
          <skosxl:literalForm>
          </skosxl:literalForm>
        </ns0:Title>

      </rdf:Description>
    </dc:title>

  </rdf:Description>

</rdf:RDF>

Expected Output

<rdf:RDF
 xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
 xmlns:dct="http://purl.org/dc/terms/"
 xmlns:skosxl="http://www.w3.org/2008/05/skos-xl#"
 xmlns:ex="http://example.org/">
    <ex:Document rdf:about="http://example.org/doc1">
        <dct:title>
           <ex:Title rdf:parseType="Resource"><skosxl:literalForm>My Title</skosxl:literalForm></ex:Title>
        </dct:title>
    </ex:Document>
</rdf:RDF>

Example 2

Input

@prefix : <http://example.org/> .
@prefix skosxl: <http://www.w3.org/2008/05/skos-xl#> .
@prefix dc: <http://purl.org/dc/terms/> .

:doc2
  a :Document ;
  dc:title [
    skosxl:literalForm "My Title"
  ] .

Actual Output

<rdf:RDF
 xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
 xmlns:dct="http://purl.org/dc/terms/"
 xmlns:skosxl="http://www.w3.org/2008/05/skos-xl#"
 xmlns:ex="http://example.org/">
    <ex:Document rdf:about="http://example.org/doc2">
        <dct:title rdf:parseType="Resource">
            <rdf:Description>
               <skosxl:literalForm>My Title</skosxl:literalForm>
            </rdf:Description>
        </dct:title>
    </ex:Document>
</rdf:RDF>

Output is interpretted as:

@prefix dc: <http://purl.org/dc/terms/> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix skosxl: <http://www.w3.org/2008/05/skos-xl#> .

<http://example.org/doc2>
  a <http://example.org/Document> ;
  dc:title [ rdf:Description [ a skosxl:literalForm ] ] .

In RDF/XML this is:

<?xml version="1.0" encoding="utf-8" ?>
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
         xmlns:dc="http://purl.org/dc/terms/"
         xmlns:skosxl="http://www.w3.org/2008/05/skos-xl#">

  <rdf:Description rdf:about="http://example.org/doc2">
    <rdf:type rdf:resource="http://example.org/Document"/>
    <dc:title>
      <rdf:Description>
        <rdf:Description>
          <skosxl:literalForm>
          </skosxl:literalForm>
        </rdf:Description>

      </rdf:Description>
    </dc:title>

  </rdf:Description>

</rdf:RDF>

Expected Output

<rdf:RDF
 xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
 xmlns:dct="http://purl.org/dc/terms/"
 xmlns:skosxl="http://www.w3.org/2008/05/skos-xl#"
 xmlns:ex="http://example.org/">
    <ex:Document rdf:about="http://example.org/doc2">
        <dct:title rdf:parseType="Resource">
            <skosxl:literalForm>My Title</skosxl:literalForm>
        </dct:title>
    </ex:Document>
</rdf:RDF>
greaterweb commented 2 years ago

Thanks for creating the issue, @brynnjmccormick 😎