Skip to content

Transportial/GSJson

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

65 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

GSJson

JSON Getter and Setter language inspired by GJSON. It provides a fast and simple way to get values from JSON documents with powerful path syntax and built-in modifiers.

Installation

Install using Maven or Gradle. Replace LATEST_VERSION with the actual latest version.

Maven:

<dependency>
    <groupId>com.transportial</groupId>
    <artifactId>gsjson</artifactId>
    <version>LATEST_VERSION</version>
</dependency>

Gradle:

dependencies {
    implementation 'com.transportial:gsjson:LATEST_VERSION'
}

Features

  • Multiple Data Type Support: Works with String, org.json.JSONObject, org.json.JSONArray, and Jackson JsonNode
  • Dot Notation Paths: Select JSON values using intuitive dot notation syntax
  • Wildcard Support: Use * and ? wildcards for key matching
  • Array Operations: Access array elements, get length, and extract child paths
  • Advanced Filtering: Support for ==, !=, <, <=, >, >=, % (like), !% (not like) operators
  • Nested Array Queries: Complex filtering with nested conditions
  • Built-in Modifiers: Transform data with modifiers like @reverse, @sort, @sum, @avg, @join, etc.
  • Path Chaining: Chain operations using the pipe | character
  • JSON Lines Support: Process newline-delimited JSON with .. prefix
  • Enhanced Result Type: Rich result objects with utility methods
  • Reducer Functions: Aggregate array data with mathematical and string operations

Path Syntax

A path is a series of keys separated by dots. GSJSON supports the following path features:

  • Basic Access: name.first - Access nested properties
  • Array Index: developers.[0] - Access array elements by index
  • Array Length: developers.[#] - Get array length
  • All Elements: developers.[#.firstName] - Get all firstName values from array
  • Wildcards: *.name or test? - Match keys with wildcards
  • Filtering: developers.[age > "25"] - Filter arrays by conditions
  • Escaping: fav\.movie - Escape special characters

Examples

For the following examples, consider this JSON:

{
  "name": {"first": "Tom", "last": "Anderson"},
  "age": 37,
  "children": ["Sara", "Alex", "Jack"],
  "fav.movie": "Deer Hunter",
  "friends": [
    {"first": "Dale", "last": "Murphy", "age": 44, "nets": ["ig", "fb", "tw"]},
    {"first": "Roger", "last": "Craig", "age": 68, "nets": ["fb", "tw"]},
    {"first": "Jane", "last": "Murphy", "age": 47, "nets": ["ig", "tw"]},
    {"first": "David", "last": "Smith", "age": 25, "nets": ["fb"]}
  ]
}

Basic Selection

// Basic property access
GSJson.get(json, "age")                    // Returns: 37
GSJson.get(json, "name.last")              // Returns: "Anderson"
GSJson.get(json, "children")               // Returns: ["Sara","Alex","Jack"]

// Escaped property names
GSJson.get(json, "fav\\.movie")            // Returns: "Deer Hunter"

Array Operations

// Array indexing
GSJson.get(json, "children.[0]")           // Returns: "Sara"
GSJson.get(json, "children.[1]")           // Returns: "Alex"

// Array length
GSJson.get(json, "children.[#]")           // Returns: 3
GSJson.get(json, "friends.[#]")            // Returns: 4

// All child elements
GSJson.get(json, "friends.[#.first]")      // Returns: ["Dale","Roger","Jane","David"]
GSJson.get(json, "friends.[#.age]")        // Returns: [44,68,47,25]

Wildcards

// Wildcard matching
GSJson.get(json, "name.*")                 // Returns: ["Tom","Anderson"] 
GSJson.get(json, "name.fir?t")             // Returns: "Tom"

Filtering

// Basic filtering
GSJson.get(json, "friends.[last == \"Murphy\"].first")     // Returns: "Dale"
GSJson.get(json, "friends.[age > \"45\"].[0].first")       // Returns: "Roger"
GSJson.get(json, "friends.[age <= \"30\"].[0].first")      // Returns: "David"

// Pattern matching
GSJson.get(json, "friends.[first % \"D*\"].last")          // Returns: "Murphy" (Dale)
GSJson.get(json, "friends.[first !% \"D*\"].[0].first")    // Returns: "Roger"

// Nested array filtering
GSJson.get(json, "friends.[nets.[# == \"fb\"]].[#.first]") // Returns: ["Dale","Roger","David"]

Built-in Modifiers

// Array manipulation
GSJson.get(json, "children|@reverse")      // Returns: ["Jack","Alex","Sara"]
GSJson.get(json, "children|@count")        // Returns: 3

// Object operations  
GSJson.get(json, "name|@keys")             // Returns: ["first","last"]
GSJson.get(json, "name|@values")           // Returns: ["Tom","Anderson"]

// JSON formatting
GSJson.get(json, "name|@pretty")           // Returns: prettified JSON
GSJson.get(json, "name|@ugly")             // Returns: minified JSON

Sorting Operations

// Basic array sorting
GSJson.get(json, "children|@sort")         // Returns: ["Alex","Jack","Sara"]
GSJson.get(json, "children|@sort:desc")    // Returns: ["Sara","Jack","Alex"]

// Sort arrays by object property
GSJson.get(json, "friends|@sortBy:age")    // Sort by age ascending
GSJson.get(json, "friends|@sortBy:age:desc")     // Sort by age descending
GSJson.get(json, "friends|@sortBy:first")        // Sort by first name
GSJson.get(json, "friends|@sortBy:last:desc")    // Sort by last name descending

// Chain sorting with other operations
GSJson.get(json, "friends.[age > \"40\"]|@sortBy:age|[#.first]")  // Filter, sort, then extract names
GSJson.get(json, "friends.[#.age]|@sort:desc|[0]")               // Get highest age

Reducer Operations

// Mathematical operations
GSJson.get(json, "friends.[#.age]|@sum")   // Returns: 184.0
GSJson.get(json, "friends.[#.age]|@avg")   // Returns: 46.0
GSJson.get(json, "friends.[#.age]|@min")   // Returns: 25.0  
GSJson.get(json, "friends.[#.age]|@max")   // Returns: 68.0

// String operations
GSJson.get(json, "friends.[#.first]|@join")        // Returns: "Dale,Roger,Jane,David"
GSJson.get(json, "friends.[#.first]|@join: | ")    // Returns: "Dale | Roger | Jane | David"
GSJson.get(json, "children|@join:-")               // Returns: "Sara-Alex-Jack"

Mathematical Operations

val numbers = "[10, 20, 30, 40, 50]"

// Basic math operations on arrays
GSJson.get(numbers, ".|@multiply:2")    // Returns: [20.0, 40.0, 60.0, 80.0, 100.0]
GSJson.get(numbers, ".|@add:5")         // Returns: [15.0, 25.0, 35.0, 45.0, 55.0]
GSJson.get(numbers, ".|@subtract:10")   // Returns: [0.0, 10.0, 20.0, 30.0, 40.0]
GSJson.get(numbers, ".|@divide:2")      // Returns: [5.0, 10.0, 15.0, 20.0, 25.0]

// Advanced math operations
GSJson.get(numbers, ".|@abs")           // Returns: absolute values
GSJson.get(numbers, ".|@round:1")       // Returns: rounded to 1 decimal place
GSJson.get(numbers, ".|@power:2")       // Returns: squared values

// Chain mathematical operations with aggregation
GSJson.get(json, "friends.[#.age]|@add:5|@sum")  // Add 5 to each age, then sum

Dynamic Mathematical Operations

Mathematical operations now support both static values and JSON selectors as arguments:

val dynamicMathJson = """
{
  "numbers": [10, 20, 30],
  "multiplier": 3,
  "divisor": 2,
  "addend": 5,
  "config": {
    "factor": 4,
    "precision": 1
  }
}
"""

// Dynamic operations using JSON selectors
GSJson.get(dynamicMathJson, "numbers|@multiply:multiplier")      // Returns: [30.0, 60.0, 90.0]
GSJson.get(dynamicMathJson, "numbers|@divide:divisor")           // Returns: [5.0, 10.0, 15.0]
GSJson.get(dynamicMathJson, "numbers|@add:addend")               // Returns: [15.0, 25.0, 35.0]
GSJson.get(dynamicMathJson, "numbers|@subtract:addend")          // Returns: [5.0, 15.0, 25.0]
GSJson.get(dynamicMathJson, "numbers|@power:divisor")            // Returns: [100.0, 400.0, 900.0]

// Nested path selectors
GSJson.get(dynamicMathJson, "numbers|@multiply:config.factor")   // Returns: [40.0, 80.0, 120.0]
GSJson.get(dynamicMathJson, "numbers|@round:config.precision")   // Returns: rounded values

// Chain dynamic and static operations
GSJson.get(dynamicMathJson, "numbers|@add:addend|@multiply:2")   // Add dynamic value, then multiply by 2
GSJson.get(dynamicMathJson, "numbers|@multiply:config.factor|@divide:divisor")  // Dynamic multiply then dynamic divide

Supported dynamic math operations:

  • @multiply:selector / @mul:selector - Multiply by value from JSON selector
  • @divide:selector / @div:selector - Divide by value from JSON selector
  • @add:selector / @plus:selector - Add value from JSON selector
  • @subtract:selector / @sub:selector - Subtract value from JSON selector
  • @power:selector / @pow:selector - Raise to power from JSON selector
  • @round:selector - Round to precision from JSON selector

Fallback Default Values

// Provide defaults for missing or null values
GSJson.get(json, "name.middle", "J")              // Returns: "J" (field doesn't exist)
GSJson.get(json, "age", 0)                        // Returns: 37 (field exists)
GSJson.get(json, "missing.field", "default")      // Returns: "default"
GSJson.get(json, "friends.[99].name", "Unknown")  // Returns: "Unknown" (index out of bounds)

// Works with all data types
GSJson.get(json, "missing.number", 42)            // Numeric default
GSJson.get(json, "missing.boolean", true)         // Boolean default
GSJson.get(json, "missing.list", listOf("a", "b")) // List default

Path Chainingpl

// Chain multiple operations
GSJson.get(json, "friends.[age > \"40\"].[#.first]|@join")  // Returns: "Dale,Roger,Jane"
GSJson.get(json, "children|@reverse|@join")                 // Returns: "Jack,Alex,Sara"
GSJson.get(json, "friends.[#.age]|@reverse|@max")          // Returns: 68.0

JSON Lines

Process newline-delimited JSON:

val jsonLines = """
{"name": "Alice", "age": 30}
{"name": "Bob", "age": 25}  
{"name": "Charlie", "age": 35}
"""

GSJson.get(jsonLines, "..#")                    // Returns: 3
GSJson.get(jsonLines, "..[1].name")             // Returns: "Bob"
GSJson.get(jsonLines, "..[#.name]|@join")       // Returns: "Alice,Bob,Charlie"
GSJson.get(jsonLines, "..[age > \"30\"].[0].name")  // Returns: "Charlie"

Enhanced Result Type

val result = GSJson.getResult(json, "age")
result.int()        // Returns: 37
result.string()     // Returns: "37"
result.exists       // Returns: true
result.type         // Returns: ResultType.NUMBER

// Array results
val arrayResult = GSJson.getResult(json, "friends.[#.first]")
arrayResult.array().forEach { name -> 
    println(name.string())
}

Setting Values

// Basic setting
GSJson.set(json, "age", 38)
GSJson.set(json, "name.middle", "J")
GSJson.set(json, "friends.[0].age", 45)

// Array operations
GSJson.set(json, "hobbies.[0]", "reading")
GSJson.set(json, "scores", listOf(85, 90, 78))

Utility Methods

// Check existence
GSJson.exists(json, "name.first")          // Returns: true
GSJson.exists(json, "name.middle")         // Returns: false

// Process JSON Lines
GSJson.forEachLine(jsonLines) { line ->
    println("Name: ${line.get("name").string()}")
    true // continue iteration
}

Comparison with GJSON

GSJSON maintains the same powerful querying capabilities as GJSON while using slightly different syntax:

Feature GJSON GSJSON
Array filtering friends.#(age>40) friends.[age > "40"]
Array access friends.0.name friends.[0].name
All elements friends.#.name friends.[#.name]
Modifiers children|@reverse children|@reverse

Performance

GSJSON is built on Jackson for JSON parsing, providing excellent performance for JSON operations while maintaining the intuitive path syntax inspired by GJSON.

About

GSJson is a getter/setter syntax interpretation language

Topics

Resources

Stars

Watchers

Forks

Packages

No packages published

Contributors 2

  •  
  •  

Languages