Skip to content
This repository has been archived by the owner on Aug 18, 2023. It is now read-only.

Download view

Gerwin Bosch edited this page Sep 18, 2017 · 3 revisions

The download view component is responsible for generation four different output types.

  • Turtle (an RDF graph notation)
  • JSON-LD (a JSON RDF graph notation)
  • N-triples (a raw textual representation of an RDF graph)
  • SPARQL (a SPARQL query where these graphs are inserted)

Use cases

  • As a user, I want to download the newly generated dataset.
  • As a user, I want to publish my dataset online
  • As a user, I want to have a choice
  • As a user, I want to be notified when an upload succeeds
  • As a developer, I want that all graphs have the same name structure to identify them in an open graph
  • As a user, I want that my graph has metadata in order know which graph is mine

Rules

  • Data can not be downloaded or published when there is no data to upload/publish

Structure

The component exists of a download button, a publish button, an output-type selector and the generated output.

Download button

The download button prompts uses a href to download the file. As react re-renders the page with every update, all the references are updated as well. Below is the implementation of the download button.

<RaisedButton
  label="download"
  href={`data:${this.state.dataType};charset=utf-8,${encodeURIComponent(
    this.state.displayText)}`}
  download={`${this.props.filename}${this.state.text}`}
  disabled={this.props.processing}
/>

The output type selector is a select-field with four options as described above. Next, to switching the format of the data available for download and the data visible on the screen it also changes the file type.

Format File-type
Turtle .turtle
Json-LD .json
N-triples .txt
SPARQL .txt

Output viewer

For the output viewer, the React-highlight a React implementation of Highlight.js is used. It contains styling for various languages and makes the output better to look at.

Publish button

When the user clicks on the publish button a dialog will show up where the user is required to fill in meta-data about their datasets. The dialog contains four fields;

Name Description editable
Dataset URI The URI the graph will receive when published
Title The title of the data set ✔️
Description a small description where the data is about ✔️
Date The date of creation of this dataset

The dataset URI is set programmatically generated from the URL of the page with the title added. Because the title is used as a unique identifier the name will first have its spaces replaced by underscores and is then URI encoded to make sure the name won't mess with the query that will be fired.

Data

With the previous components of the DataCreation component, we were able to gather all the instructions we need for creating a Linked data graph. To make the process simpler we convert the URI-classified nodes and their relations to 'class-definitions'. These 'class-definitions' contain information about themselves, a list of the relations of the object and in which column the relation maps to, in order to make the algorithm more efficient by supplying the information the conversion algorithm needs in a logical structure.

function createClassDefinitions(nodes, links) {
  const classDefinitions = [];
  nodes.forEach((node) => {
    // Skip when the nodes is a literal, as they can't have subjects
    if (node.type === 'Literal') return;
    // Get all the relations of this node
    let relations = links.map((link) => {
      if (link.source === node.id) {
        // Push relation and class
        return ({
          link,
          target:
              nodes.filter(nodeF => nodeF.id === link.target)[0],
        });
      }
      return undefined;
    });
    relations = relations.filter(relation => relation !== undefined);

    // When there are no relations skip the node
    if (relations.length === 0) return;
    classDefinitions.push({
      subject: node,
      relations,
    });
  });
  return classDefinitions;
}

Using the 'class-definitions' we are able to convert the raw data we have to a RDF-graph.

function convertDataToTriples(data, links, nodes) {
  // Map relations
  const classDefinitions = createClassDefinitions(nodes, links);
  // For every node
  const graph = rdf.createGraph();
  // For every row of data except the header
  data.forEach((dataRow, dataIndex) => {
    if (dataIndex === 0) return; // Skip the header
    classDefinitions.forEach((classDefinition) => {
      // Skip when the value is not present in that row
      if (!dataRow[classDefinition.subject.column]) return;
      // Skip when there are no relations
      if (classDefinition.relations.length === 0) return;
      // If there is no item create a new one
      const dataSubject = rdf.createNamedNode(dataRow[classDefinition.subject.column]);
      const typeOf = rdf.createNamedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#type');
      if (graph.filter(relation => relation.object === dataSubject
              && relation.predicate === typeOf).length === 0) {
        graph.add(rdf.createTriple(
          dataSubject,
          typeOf,
          rdf.createNamedNode(classDefinition.subject.uri)));
      }
      // For every relation check if there is a value
      classDefinition.relations.forEach((relation) => {
        const relationNode = rdf.createNamedNode(relation.link.link);
        if (dataRow[relation.target.column]) {
          // The target value
          let targetValue = dataRow[relation.target.column];
          // If the relation is not mentioned yet
          if (relation.target.type === 'literal') {
            if (!Number(targetValue)) { // String literal
              targetValue = rdf.createLiteral(targetValue, 'en', 'http://www.w3.org/2001/XMLSchema#string');
            } else if (targetValue % 1 === 0) { // Integer Literal
              targetValue = rdf.createLiteral(targetValue, null, 'https://www.w3.org/2001/XMLSchema#integer');
            } else { // Float Literal
              targetValue = rdf.createLiteral(targetValue, null, 'https://www.w3.org/2001/XMLSchema#float');
            }
          } else {
            targetValue = rdf.createNamedNode(targetValue);
          }
          // eslint-disable-next-line no-underscore-dangle
          if (graph._graph.filter(node => (node.object === dataSubject
                  && node.predicate === relationNode
                  && node.subject === targetValue)).length === 0) {
            graph.add(rdf.createTriple(dataSubject, relationNode, targetValue));
          }
        }
      });
    });
  });
  return graph;
}

When the user wants to publish his dataset two queries are fired to the endpoint. The first one stores the meta-data of the graph. The URIvariable contains the name URL the graph will be known as on the SPARQL endpoint. The other variables are related to the meta-data of these graphs.

`INSERT DATA { GRAPH <http://gerwinbosch.nl/rdf-paqt/metadata> {
            <${uri}> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://rdfs.org/ns/void#Dataset> .
            <${uri}> <http://purl.org/dc/terms/title> "${graphName}" .
            <${uri}> <http://purl.org/dc/terms/description> "${description}" .
            <${uri}> <http://purl.org/dc/terms/created> "${date}"^^<http://www.w3.org/2001/XMLSchema#date> .}}`;

The second query will insert that data within the SPARQL endpoint. The 'URI' variable is the URI of the new graph. The GRAPH will create a new GRAPH when it doesn't exist yet and add data to an already existing graph. The 'graph' variable is the N-triple representation of the dataset

`INSERT DATA { GRAPH <${uri}> {${graph}}}`;

Design

The design consists of two b

Download screen

Meta-data-dialog

Variables

Clone this wiki locally