Skip to content

robb/RBBJSON

main
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Code

Latest commit

 

Git stats

Files

Permalink
Failed to load latest commit information.
Type
Name
Latest commit message
Commit time
 
 
 
 
 
 
 
 
 
 

RBBJSON

Swift Version: 5.2 Swift Package Manager Swift Package Manager Twitter: @DLX

RBBJSON enables flexible JSON traversal at runtime and JSONPath-like querying for rapid prototyping.

Use JSONDecoder to create an RBBJSON struct, then traverse it using dynamic member lookup:

let json = try JSONDecoder().decode(RBBJSON.self, from: data)

json.firstName         // RBBJSON.string("John")
json.lastName          // RBBJSON.string("Appleseed")
json.age               // RBBJSON.number(26)
json.invalidKey        // RBBJSON.null
json.phoneNumbers[0]   // RBBJSON.string("+14086065775")

If you want to access a value that coincides with a Swift-defined property, use a String subscript instead:

json.office.map     // Error: Maps to Sequence.map
json.office["map"]  // RBBJSON.string("https://maps.apple.com/?q=IL1")

To unbox a JSON value, use one of the failable initializers:

String(json.firstName) // "John"
String(json.lastName)  // "Appleseed"
String(json.age)       // nil

Int(json.age)          // 26
Double(json.age)       // 26.0

You can also make use of a JSONPath-inspired Query syntax to find nested data inside a JSON structure.

For example, given:

{ 
  "store": {
    "book": [ 
      { 
        "category": "reference",
        "author": "Nigel Rees",
        "title": "Sayings of the Century",
        "price": 8.95
      },
      { 
        "category": "fiction",
        "author": "Evelyn Waugh",
        "title": "Sword of Honour",
        "price": 12.99
      },
      { 
        "category": "fiction",
        "author": "Herman Melville",
        "title": "Moby Dick",
        "isbn": "0-553-21311-3",
        "price": 8.99
      },
      { 
        "category": "fiction",
        "author": "J. R. R. Tolkien",
        "title": "The Lord of the Rings",
        "isbn": "0-395-19395-8",
        "price": 22.99
      }
    ],
    "bicycle": {
      "color": "red",
      "price": 19.95
    }
  }
}
JSONPath RBBJSON Result
$.store.book[*].author json.store.book[any: .child].author The authors of all books in the store.
$..author json[any: .descendantOrSelf].author All authors.
$.store.* json.store[any: .child] All things in the store, a list of books an a red bycicle.
$.store..price json.store[any: .descendantOrSelf].price All prices in the store.
$..book[2] json[any: .descendantOrSelf].book[2] The second book.
$..book[-2] json[any: .descendantOrSelf].book[-2] The second-to-last book.
$..book[0,1], $..book[:2] json[any: .descendantOrSelf].book[0, 1]), json[any: .descendantOrSelf].book[0...1]), json[any: .descendantOrSelf].book[0..<2]) The first two books.
$..book[?(@.isbn)] json[any: .descendantOrSelf].book[has: \.isbn] All books with an ISBN number.
$..book[?(@.price<10)] json.store.book[matches: { $0.price <= 10 }] All books cheaper than 10.
$.store["book", "bicycle"]..["price", "author"] json.store["book", "bicycle"][any: .descendantOrSelf]["price", "author"] The author (where available) and price of every book or bicycle.

Once you query a JSON value using one of the higher order selectors, the resulting type of the expression will be a lazy RBBJSONQuery:

json.store.book[0]["title"]     // RBBJSON.string("Sayings of the Century")
json.store.book[0, 1]["title"]  // some RBBJSONQuery

Because RBBJSONQuery conforms to Sequence, you can initialize an Array with it to obtain the results or use e.g. compactMap:

String(json.store.book[0].title)                    // "Sayings of the Century"
json.store.book[0, 1].title.compactMap(String.init) // ["Sayings of the Century", "Sword of Honour"]

String(json.store.book[0]["invalid Property"])                    // nil
json.store.book[0, 1]["invalid Property"].compactMap(String.init) // []

About

Flexible JSON traversal for rapid prototyping.

Topics

Resources

License

Stars

Watchers

Forks

Sponsor this project

 

Languages