Skip to content

Instantly share code, notes, and snippets.

@karladler
Last active October 2, 2019 13:33
Show Gist options
  • Save karladler/84276913da7aa673b17134011f5f1677 to your computer and use it in GitHub Desktop.
Save karladler/84276913da7aa673b17134011f5f1677 to your computer and use it in GitHub Desktop.

JSON => CSV => JSON converter for digital Twins

{
    "description": "Metadata for forklifts, seperated by categories.",
    "imgSquare": "",
    "name": "Forklift Metadata",
    "dataSchema": {
      "identity": {
        "$id": "identity_schema",
        "type": "object",
        "properties": {
          "machineId": {
            "type": "string",
            "default": "",
            "minLength": 1,
            "value": "123"
          },
          "manufacturer": {
            "type": "string",
            "default": "",
            "minLength": 1,
            "value": "Volkswagen"
          }
        }
      },
      "owner": {
        "$id": "owner_schema",
        "type": "object",
        "properties": {
          "internalAssetDesignation": {
            "type": "string",
            "default": "",
            "minLength": 1,
            "value": "whatever"
          },
  // ...

General Approach

  • do iterative or recursive search in Twin JSON, deep first, then breadth
  • copy all json paths which fulfill certain criteria
  • key is value or value is not an object

Pseudo Code (more or less)

currentPath = []
csv = [] // array of tuples

while (key, val) in json:
  (path, val) = csvHeadersgetColumn()
  csv.push((path, val))

def getColumn(subtree, pathToSubtree = ''):
  while (key, value) in subtree:
    currentPath.push(key)

    if key is 'value'
      return (currentPath.join('.'), val)

    if typeof val is 'string' or 'number' or ...
      return (currentPath.join('.'), val)

    return csvHeadersgetColumn()

Disred output should be something like this:

description imgSquare name dataSchema.properties.identity.value dataSchema.properties.manufactorer.value dataSchema.owner.properties.internalAssetDesignation.value ...
Metadata for forklifts, seperated by categories. Forklift Metadata 123 Volkswagen whatever ...
...

Other direction: build the js object on import. All schemas and constraints are applied from template-twin.

// https://github.com/lodash/lodash/tree/4.6.2-npm-packages/lodash.merge
var merge = require('./lodash.merge');

const twinData = {}
const template = {
  dataSchema: {
    properties: {
      identity: {
        default: '',
        type: 'string',
        required: false
      },
      manufactorer: {
        default: 'Honda',
        type: 'string',
        required: true
      }
    }
  }
}

const csvHeaders = [
  'description',
  'imgSquare',
  'name',
  'dataSchema.properties.identity.value',
  'dataSchema.properties.manufactorer.value',
  'dataSchema.owner.properties.internalAssetDesignation.value'
];

const csvLine = [
  'Beschreibung',
  'bild',
  'name',
  'identity',
  'hersteller',
  'asset was auch immer'
]

const createObject = (model, name, value) => {
  const nameParts = name.split(".");
  let currentObject = model;

  for (const i in nameParts) {
    const part = nameParts[i];

    if (i == nameParts.length-1) {
      currentObject[part] = value;
      break;
    }

    if (typeof currentObject[part] == "undefined") {
      currentObject[part] = {};
    }
    currentObject = currentObject[part];
  }
};

csvHeaders.forEach( (item, idx) => {
  createObject(twinData, item, csvLine[idx])
});

const result = merge(twinData, template)

console.log(JSON.stringify(result));

return result;

/*
{
  "description":"Beschreibung",
  "imgSquare":"bild",
  "name":"name",
  "dataSchema":{
    "properties":{
      "identity":{
        "value":"identity",
        "default":"",
        "type":"string",
        "required":false
      },
      "manufactorer":{
        "value":"hersteller",
        "default":"Honda",
        "type":"string",
        "required":true
      }
    },
    "owner":{
      "properties":{
        "internalAssetDesignation":{
          "value":"asset was auch immer"
        }
      }
    }
  }
}
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment