• Stars
    star
    133
  • Rank 270,840 (Top 6 %)
  • Language
    JavaScript
  • License
    MIT License
  • Created about 8 years ago
  • Updated almost 7 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

A recursive, pattern-matching, approach to transforming JSON structures.

JSON Transforms

Provides a recursive, pattern-matching approach to transforming JSON data. Transformations are defined as a set of rules which match the structure of a JSON object. When a match occurs, the rule emits the transformed data, optionally recursing to transform child objects.

This framework makes use of JSPath, a domain-specific language for querying JSON objects. It is alse heavily inspired by XSLT, a language for transforming XML documents.

For more information about this project, see the associated blog post:

http://blog.scottlogic.com/2016/06/22/xslt-inspired-ast-transforms.html

Usage

The following examples show how to transform this JSON object:

const json = {
  "automobiles": [
    { "maker": "Nissan", "model": "Teana", "year": 2011 },
    { "maker": "Honda", "model": "Jazz", "year": 2010 },
    { "maker": "Honda", "model": "Civic", "year": 2007 },
    { "maker": "Toyota", "model": "Yaris", "year": 2008 },
    { "maker": "Honda", "model": "Accord", "year": 2011 }
  ]
};

Into the following structure, which just includes those automobiles made by 'Honda', with the 'maker' property removed:

{
  "Honda": [
    { "model": "Jazz", "year": 2010 },
    { "model": "Civic", "year": 2007 },
    { "model": "Accord", "year": 2011 }
  ]
}

Node

Install via npm:

npm install json-transforms --save

The following code demonstrates how to perform the transform described above, within a Node environment:

const jsont = require('json-transforms');

const json = { ... };

const rules = [
  jsont.pathRule(
    '.automobiles{.maker === "Honda"}', d => ({
      Honda: d.runner()
    })
  ),
  jsont.pathRule(
    '.{.maker}', d => ({
      model: d.match.model,
      year: d.match.year
    })
  ),
  jsont.identity
];

const transformed  = jsont.transform(json, rules);

Browser

The json-transforms framework is exposed as a global variable jsont. The project also depends on JSPath, so both must be included in order to run the above example:

<script src="https://unpkg.com/jspath/lib/jspath.js"></script>
<script src="https://unpkg.com/json-transforms/build/json-transforms.js"></script>

With these scripts loaded, the above example will also run in the browser.

Modern JavaScript

The examples in this documentation all use 'modern' JavaScript syntax (arrow functions, constants, etc ...), however, the npm module is transpiled to ES2015, so if you are in a browser environment that lacks ES2016 support, json-transforms will still work just fine:

var rules = [
  jsont.pathRule(
    '.automobiles{.maker === "Honda"}', function(d) {
      return { honda: d.runner()}
    }
  ),
  jsont.pathRule(
    '.{.maker}', function(d) {
      return {
        model: d.match.model,
        year: d.match.year
      }
    }
  ),
  jsont.identity
];

var transformed  = jsont.transform(json, rules);

Tutorial

The following tutorial demonstrates the json-transforms API through a series of examples. The tutorial will use the following example JSON structure, transforming it into various different forms:

const json = {
  "automobiles": [
    { "maker": "Nissan", "model": "Teana", "year": 2011 },
    { "maker": "Honda", "model": "Jazz", "year": 2010 },
    { "maker": "Honda", "model": "Civic", "year": 2007 },
    { "maker": "Toyota", "model": "Yaris", "year": 2008 },
    { "maker": "Honda", "model": "Accord", "year": 2011 }
  ]
};

Identity transformation

JSON transformation is performed by the transform function which takes two arguments, the JSON object being transformed, and an array of rules. The transform function iterates over the list of rules, in the order given, to determine whether any return a value other than null, which indicates a match.

For most transformations you will want to make use of the identity rule, which iterates over all the properties of an object, recursively invoking the transform function for all properties that are objects or arrays, and simply returns the property values for all others.

If you transform a JSON object via the identity:

const rules = [ jsont.identity ];
const transformed  = jsont.transform(json, rules);

You get an exact duplicate of the object back again! Useful.

A simple path rule

The pathRule function creates a rule that uses JSPath to match a pattern within the JSON sub-tree passed to the rule. If a match occurs, the associated function is invoked. Here's a quick illustration:

const rules = [
  jsont.pathRule(
    '.automobiles', d => ({
      'count': d.match.length
    })
  ),
  jsont.identity
];

Which outputs the following when applied to the example JSON:

{ count: 5 }

This path rule, which has the path .automobiles matches any object with an automobiles property. If a match occurs, it emits a JSON object with a count property. The match property of the object passed to this function contains the array of objects that match this path. In this case, it is the array of 5 automobiles, hence d.match.length returns 5.

Because of the recursive nature of the identity transform, this rule will match any object with an automobiles, regardless of its location within the JSON data.

For example, if the input JSON was changed to the following:

const json = {
  'UK' : {
      'automobiles': [
        { 'maker': 'Nissan', 'model': 'Teana', 'year': 2011 },
        { 'maker': 'Honda', 'model': 'Jazz', 'year': 2010 },
      ]
  },
  'USA' : {
      'automobiles': [
        { 'maker': 'Honda', 'model': 'Civic', 'year': 2007 },
        { 'maker': 'Toyota', 'model': 'Yaris', 'year': 2008 },
        { 'maker': 'Honda', 'model': 'Accord', 'year': 2011 }
      ]
  }
};

The identity transform would emit UK and USA, recursively applying rules, to give the following totals:

{
  "UK": {
    "count": 2
  },
  "USA": {
    "count": 3
  }
}

NOTE: Rule order matters! - the current transform iteration stops on the first matching rule. Therefore, if you put the identity rule before the path rule in the current example, the .automobiles rule will never be reached!

JSPath Syntax

For detailed documentation of the JSPath syntax, visit the project website. The documentation really is great!

The JSPath syntax is easy to understand, here are a few quick examples:

  • .automobiles - match an object with an automobiles property, returning the value of this property.
  • .automobiles.year - match the year of each automobile, this would return an array of years.
  • ..year - the single-dot syntax matches objects with the given property, the double-dot is a 'deep' match, finding any objects nested within the JSON structure. With json-transforms you typically use the identity transform, which avoids the need for deep matching.
  • .automobiles{.maker === "Honda" && .year > 2009}.model - find the model of any automobile made by Honda, with a year greater than 2009.

As you can see, JSPath is very powerful.

Match context

The above examples have demonstrated the use of the match property, which contains the objects that match the given path. It also has a context property, which is the object being matched on. An easy way to see the difference between them is to create a transform that outputs both:

const rules = [
  jsont.pathRule(
    '.maker', d => ({
        context: d.context,
        match: d.match
    })
  ),
  jsont.identity
];

Which outputs the following:

{
  "automobiles": [
    {
      "context": {
        "maker": "Nissan",
        "model": "Teana",
        "year": 2011
      },
      "match": "Nissan"
    },
    ...
}

You can see that the .maker path matches objects that have the maker property, with the match being the value of this property. Whereas the context is the object that was matched.

Recursive matches

In the current example, the path rule outputs the number of items that match the given path. However, it's also possible to continue matching rules in a recursive fashion.

To see this in action, we'll start with a simple rule that matches objects with a .maker property, outputting a formatted description:

const rules = [
  jsont.pathRule(
    '.maker', d => ({
      text: `The ${d.context.model} was made in ${d.context.year}`
    })
  ),
  jsont.identity
];

Which outputs the following:

{
  "automobiles": [
    {
      "text": "Teana was made in 2011"
    },
    {
      "text": "Jazz was made in 2010"
    },
    {
      "text": "Civic was made in 2007"
    },
    {
      "text": "Yaris was made in 2008"
    },
    {
      "text": "Accord was made in 2011"
    }
  ]
}

If you just wanted to output the result for Honda automobiles, you could add a new rule with a path that matches Honda cars, then recurse, by invoking the runner function:

const rules = [
  jsont.pathRule(
    '.automobiles{.maker === "Honda"}', d => ({
      automobiles: d.runner()
    })
  ),
  jsont.pathRule(
    '.maker', d => ({
        text: `The ${d.context.model} was made in ${d.context.year}`
    })
  ),
  jsont.identity
];

Which gives the following:

{
  "automobiles": [
    {
      "text": "The Jazz was made in 2010"
    },
    {
      "text": "The Civic was made in 2007"
    },
    {
      "text": "The Accord was made in 2011"
    }
  ]
}

This is a very powerful feature of the framework, allowing you to construct complex transforms that are composed of a number of simpler transformations.

More Repositories

1

VCTransitionsLibrary

A collection of iOS7 animation controllers and interaction controllers, providing flip, fold and all kinds of other transitions.
Objective-C
4,554
star
2

LinqToObjectiveC

Brings a Linq-style fluent query API to Objective-C
Objective-C
724
star
3

applause-button

A zero-configuration medium-style button for adding applause / claps / kudos to web pages and blog posts
JavaScript
426
star
4

ReactiveSwiftFlickrSearch

A Swift implementation of a Flickr-search application that uses MVVM and ReactiveCocoa
Swift
377
star
5

chasm

A simple compile-to-WebAssembly language
TypeScript
346
star
6

wasm-sudoku-solver

a WebAssembly-powered AR sudoku solver
JavaScript
345
star
7

awesome-public-streaming-datasets

A list of free datasets that provide streaming data
341
star
8

ReactNative-PropertyFinder

A property finder application written using React Native
JavaScript
276
star
9

wasm-rust-chip8

A WebAssembly CHIP-8 emulator written with Rust
Rust
256
star
10

langchain-mini

πŸ¦œοΈπŸ”— This is a very simple re-implementation of LangChain, in ~100 lines of code
JavaScript
247
star
11

ReactiveTwitterSearch

A ReactiveCocoa 4.0 MVVM example
Swift
215
star
12

iOS-ClearStyle

This project is a gesture-driven iOS to-do list application modelled on the iPhone Clear application.
Objective-C
195
star
13

ffmpeg-wasm-streaming-video-player

An example of using FFmpeg.wasm to perform streaming transcoding within the browser
JavaScript
156
star
14

CETableViewBinding

Demonstrates a binding helper that makes it easier to bind UITableView instances to ReactiveCocoa ViewModels
Objective-C
120
star
15

d3-wasm-force

A re-implementation of d3-force with WebAssembly.
TypeScript
105
star
16

d3fc-webgl-hathi-explorer

A T-SNE scatter plot implemented using D3FC's WebGL series
JavaScript
94
star
17

angular2-todo

A todo list implemented using Angular 2
TypeScript
91
star
18

ReactiveFlickrSearch

A ReactiveCocoa-MVVM application that searches Flickr
Objective-C
89
star
19

assemblyscript-regex

A regex engine for AssemblyScript
TypeScript
86
star
20

ReactSwift

A prototype implementation of React in Swift
Swift
77
star
21

wasmweekly

Website for the WebAssembly weekly newsletter
HTML
74
star
22

UIKit-Dynamics-Playground

The code to accompany the article published here: http://www.raywenderlich.com/50197/uikit-dynamics-tutorial
Objective-C
68
star
23

wasm-game-of-life

Conway's Game of Life - hand written in WebAssembly
WebAssembly
59
star
24

atari2600-wasm

An Atari 2600 emulator written in AssemblyScript compiled to WebAssembly
JavaScript
56
star
25

wasm-mandelbrot

A mandelbrot rendered using a variety of WebAssembly tools (emscripten, AssemblyScript, asm.js, etc ...)
JavaScript
55
star
26

RWReactivePlayground

A project to accompany an article I wrote on ReactiveCocoa, a simple sign-in form.
Objective-C
52
star
27

yahoo-finance-d3fc

A complex financial chart built with D3 and d3fc
JavaScript
51
star
28

RWTwitterInstant

A project to accompany an article I wrote on ReactiveCocoa, a twitter search application
Objective-C
43
star
29

applause-button-server

The server-side component for the applause button
JavaScript
42
star
30

mandelbrot-threaded-webassembly

A simple demonstration of WebAssembly threads
WebAssembly
41
star
31

angular2-goldilocks-seed

A seed project for Angular 2.0 / TypeScript development
JavaScript
40
star
32

redux-reducer-array

An app that demonstrates a method for applying redux reducers to arrays of items
JavaScript
36
star
33

rust-webassembly-serverless

An AWS lambda function written in Rust using WebAssembly
Rust
31
star
34

ReactiveSwiftLondon

A Twitter Search app with Sentiment Analysis, powered by ReactiveCocoa
Swift
27
star
35

SwiftFunctionalLife

An implementation of Conway's Game of Life using functional concepts in Swift
Swift
27
star
36

CERangeSlider

A range slider control for iOS
27
star
37

SwiftReactivePlayground

A project that accompanies my talk, ReactiveCocoa made Simple with Swift
Swift
27
star
38

wasm-faas

A simple WebAssembly-powered serverless platform written in Rust.
Rust
26
star
39

running-report-card

Creates a narrative report card from Strava user's running data
HTML
25
star
40

assemblyscript-temporal

An implementation of TC39 temporal for AssemblyScript
TypeScript
24
star
41

WP7-ClearStyle

This project is a gesture-driven Windows Phone to-do list application modelled on the iPhone Clear application.
C#
20
star
42

SimulatorEnhancements

Enhances the iOS simulator, providing accelerometer and geolocation data
Objective-C
20
star
43

SimulatorEnhancements-Server

Enhances the iOS simulator, providing accelerometer and geolocation data.
JavaScript
17
star
44

Avalon

A prototype binding framework for iOS - to support the MVVM pattern
Swift
16
star
45

SwiftMandelbrot

A project that shows how the simple task of computing a Mandelbrot set can be split up across multiple threads
Swift
14
star
46

jekyll-pagination-infinite-scroll

A demonstration of Jekyll pagination with infinite scroling
CSS
13
star
47

Knockout-jQueryMobile

A simple example of integration between jQueryMobile with KnockoutJS
JavaScript
8
star
48

d3fc-label-layout

A D3 layout that places labels avoiding overlaps using either a greedy or simulated annealing strategy
JavaScript
8
star
49

time-travel-trader

An app that demonstrates the use of Hot Module Reload and Time Travel within the context of a trading platform
TypeScript
7
star
50

timezone-viz

An interactive timezone visualisation
JavaScript
7
star
51

BindingWithBond

An example app that demonstrates the Swift Bond binding framework
Swift
7
star
52

gifbot

A GitHub bot that serves up animated GIFs on demand!
JavaScript
7
star
53

wasm-interference

A hand-coded WebAssembly interference pattern thingy
WebAssembly
7
star
54

iOS-Reversi

An iPad Reversi game that I am writing for a RayWenderlich tutorial
Objective-C
6
star
55

d3fc-financial-chart

Illustrates the patterns you should consider when creating high performance complex charts
WebAssembly
6
star
56

grunt-mdspell

A grunt task that spell checks markdown files
JavaScript
6
star
57

mondo-expenses-app

An example Mondo app that obtains transactions tagged with #expenses
HTML
5
star
58

ReversiEight

A Windows 8 Reversi board game
C#
5
star
59

assemblyscript-temporal-tz

An implementation of time-zone aware TC39 temporal classes for AssemblyScript
TypeScript
5
star
60

PropertyFinder-HTML5

Property Finder is an HTML5-based cross-platform mobile application for Windows Phone and iPhone.
JavaScript
5
star
61

awesome-lists-bot

A bot that runs various checks against 'awesome list' projects
JavaScript
4
star
62

d3fc-github-viz

A visualisation of github repository statistics
JavaScript
4
star
63

openfin-tabbed-interface

A demo app that shows how to create a Chrome-style tear-out desktop HTML5 interface with OpenFin.
CSS
4
star
64

finwasm-smart-contract

A smart contract demonstration that allows sign-up for a fictitious meetup event
HTML
4
star
65

tiny-ssg

A tiny static site generator that can be used to replace Assemble, etc ...
JavaScript
4
star
66

perspective-rs

A prototype implementation of Perspective in Rust
Rust
4
star
67

wasm-lang-inference

Exploring techniques that may allow us to infer the language used to write WebAssembly modules
Rust
4
star
68

WP8-MapGestures

An enhanced set of multi-touch gestures for the Windows Phone 8 map control
C#
3
star
69

colineberhardt.github.com

HTML
3
star
70

awesome-stars

β˜…β˜…β˜… Adds the star counts to awesome lists β˜…β˜…β˜…
JavaScript
3
star
71

d3fc-technical-indicator

Components for calculating technical indicators on data series
JavaScript
2
star
72

rollup-plugin-webassembly

A rollup plugin that inlines (base64 encoded) and imports WebAssembly modules
JavaScript
2
star
73

d3fc-financial-feed

An API for fetching financial time-series data from different sources including Quandl and Coinbase
JavaScript
2
star
74

Monoliths-To-Components-With-D3

From monoliths to components with D3 - A presentation about building re-useable charting components with d3fc
JavaScript
2
star
75

html5-revolution

An impress.js powered presentation about the rise of HTML5 and death of plugins
1
star
76

ServerlessNodeHttpPost

A simple servless template for lambdas exposed via the gateway using HTTP POST
JavaScript
1
star
77

natter

JavaScript
1
star
78

d3fc-webgl-example

An example of the D3FC with WebGL rendering
JavaScript
1
star
79

Xamarin-cross-platform-charting

Demonstration of using ShinobiCharts Xamarin bindings to create a cross-platform app for data visualisation
C#
1
star
80

PropertyCross-Site

Website for PropertyCross
CSS
1
star
81

d3fc-brush

Adapts the D3 brush, making it easier to create data-driven brushed charts.
JavaScript
1
star
82

minerva-transcript-trove

A GPT-powered command line tool for analysing meeting transcripts, generating meeting summaries, action lists and querying. The goal of this project is to create a valuable knowledge-base from meeting minutes, helping you become more organised and efficient.
JavaScript
1
star