npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

sparql-result-converter

v3.1.0

Published

Little utility function to that converts the table-like result of a SPARQL query into a JSON tree with a user-defined structure

Downloads

19

Readme

npm GitHub

sparql-result-converter

A little utility class that helps you to transform the table-like results that you get from a SPARQL query into a nested JSON tree with a user-defined structure.

How to use it

Just install as a dependecy via npm install sparql-result-converter. In your code you can then use the converter like this:

// Require the converter
const SparqlResultConverter = require('sparql-result-converter');
const converter = new SparqlResultConverter();

// convert a SPARQL result
const convertedResult = converter.convert(inputArray, mappingDefinitions);

You have to pass two parameters to convert():

  1. inputArray are the results you get from your SPARQL query

  2. mappingDefinitions is a recursive structure that describes how your converted result should look like. It looks like this:

     const convertStructure: MappingDefinition = [
       {
     	rootName: 'name of the property that this group will be subordinated under'
     	propertyToGroup: 'a variable in your SPARQL query that you want to group on',			 
         name: 'this can be used to rename the variable',
         childMappings: [{
     		// This is a Partial<MappingDefinition>. 
     		// --> You can define a complete MappingDefinition in case you want to create a nested structure
     		// --> You can also just set "rootName" if you don't want to group any further but want have the ungrouped "rest" under a defined rootName
     	}]
       }
     ];

    propertyToGroup: The element in your query-result that you want to group (corresponds to a variable in the SELECT part of your query) name: Can be used for mapping the result object name to a new name. rootName: The key of the grouped element in the superordinate array. After grouping, the grouped structure will be added as an array with key 'rootName' in the parent element.

A more detailed description

When you query Triple stores with their REST API, you get a tabular structure which can be somewhat ugly if the result actually is a nested tree-like structure. The REST-API returns a direct representation of the result-table in JSON. This is not very useful when you want to use your query-results e.g. in a frontend to dynamically display your data. Let's look at an example:

Example Graph

There are three pet owners with varying numbers of pets. While Peter has only one pet, mary has three. If we'd like to find all pet owners, their pets and the type of pet(s) they have, we might send the following query against our triple store:

PREFIX ex: <http://example.com#>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
SELECT ?owner ?pet ?petType where {
  ?owner rdf:type ex:PetOwner;
    ex:hasPet ?pet.
  ?pet ex:petType ?petType.
}

For your example, the return of this query could look like this:

?owner | ?petName | ?petType ------ | -------- | -------- ex:Peter | ex:Rex | ex:Dog ex:Mary | ex:Huey | ex:Cat ex:Mary | ex:Dewey | ex:Cat ex:Mary | ex:Louie | ex:Cat ex:John | ex:Lassie | ex:Dog ex:John | ex:Oliver | :ex:Bird

The returned JSON just represents this table, the JSON looks like this:

{
  "head": {
    "vars": [
      "owner",
      "pet",
      "petType"
    ]
  },
  "results": {
    "bindings": [
      {
        "owner": {
          "type": "uri",
          "value": "http://example.com#Peter"
        },
        "petType": {
          "type": "uri",
          "value": "http://example.com#Dog"
        },
        "petName": {
          "type": "uri",
          "value": "http://example.com#Rex"
        }
      },
      {
        "owner": {
          "type": "uri",
          "value": "http://example.com#Mary"
        },
        "petType": {
          "type": "uri",
          "value": "http://example.com#Cat"
        },
        "petName": {
          "type": "uri",
          "value": "http://example.com#Huey"
        }
      },
      {
        "owner": {
          "type": "uri",
          "value": "http://example.com#Mary"
        },
        "petType": {
          "type": "uri",
          "value": "http://example.com#Cat"
        },
        "petName": {
          "type": "uri",
          "value": "http://example.com#Dewey"
        }
      },
      {
        "owner": {
          "type": "uri",
          "value": "http://example.com#Mary"
        },
        "petType": {
          "type": "uri",
          "value": "http://example.com#Cat"
        },
        "petName": {
          "type": "uri",
          "value": "http://example.com#Louie"
        }
      },
      {
        "owner": {
          "type": "uri",
          "value": "http://example.com#John"
        },
        "petType": {
          "type": "uri",
          "value": "http://example.com#Dog"
        },
        "petName": {
          "type": "uri",
          "value": "http://example.com#Lassie"
        }
      },
      {
        "owner": {
          "type": "uri",
          "value": "http://example.com#John"
        },
        "petType": {
          "type": "uri",
          "value": "http://example.com#Bird"
        },
        "petName": {
          "type": "uri",
          "value": "http://example.com#Oliver"
        }
      }
    ]
  }
}

The result is an array consisting of objects for each row of the table. Now if you want to show all owners and all pets of each owner, a nested structure is better suited. Converting from the tabular to a nested structure is exactly what sparql-result-converter does. It converts the flat array into a nested structure by grouping on certain properties. You can decide which properties should be grouped by passing an array representing your desired structure to the converter function. In a first step of this example, we could want to group on the owners and would therefore pass the mapping definition:

const mappingDefinition: MappingDefinition[] = [
   {
   	rootName: 'owners',
   	propertyToGroup: 'owner',
   	name: 'name',
   	childMappings: [{
   		rootName: 'pets',
   	}]
   }
];

As a result, we want an object with key 'owners', therefore rootName = owners. Furthermore, we want to group on ?owner (see SPARQL query), therefore we set propertyToGroup to be 'owner'. As the key for the grouped array is "owners", we might want to change the owner-property to be 'name'. This is done by setting name to 'name'. In this first example, we don't want to group any further, but we want to make sure that the rest (i.e. the pets) is subordinated under the key 'pets', that's why we set rootName of the only childMapping to 'pets'.

The converted result will look like this:

{
	owners: [
		{
			name: 'Peter',
			pets: [
				{
					petName: 'Rex',
					petType: 'Dog'
				}
			]
		},
		{
			name: 'John',
			pets: [
				{
					petName: 'Lassie',
					petType: 'Dog'
				},
				{
					petName: 'Oliver',
					petType: 'Cat'
				}
			]
		},
		{
			name: 'Mary',
			pets: [
				{
					petName: 'Huey',
					petType: 'Cat'
				},
				{
					petName: 'Dewey',
					petType: 'Cat'
				},
				{
					petName: 'Louie',
					petType: 'Cat'
				}
			]
		}
	]
};

Now let's say we that we want to group on the owners and on the petType afterwards. This can be achieved by a nested mapping definition. Look at the following mapping definition:

const twoLayerMappingDefinition: MappingDefinition[] = [
	{
		rootName: 'owners',
		propertyToGroup: 'owner',
		name: 'name',
		childMappings: [
			{
				rootName: 'petTypes',
				propertyToGroup: 'petType',
				name: 'type',
				childMappings: [{
					rootName: 'pets'
				}]
			}
		]
	},
];

This nested mapping definition will lead to the following result:

 {
	owners: [
		{
			name: 'Peter',
			petTypes: [
				{
					type: 'Dog',
					pets: [
						{ petName: 'Rex' }
					]
				}
			]
		},
		{
			name: 'John',
			petTypes: [
				{
					type: 'Dog',
					pets: [
						{ petName: 'Lassie' }
					]
				},
				{
					type: 'Cat',
					pets: [
						{ petName: 'Oliver' }
					]
				}
			]
		},
		{
			name: 'Mary',
			petTypes: [
				{
					type: 'Cat',
					pets: [
						{ petName: 'Huey' },
						{ petName: 'Dewey' },
						{ petName: 'Louie' },
					]
				}
			]
		}
	]
};