Path Expressions

Airscript's Path Expressions describe the path that must be taken in order to access values stored within Lists, Objects, or any nested combination thereof.

While it is possible to use Path expressions to filter Lists of Objects by using simple queries to define the desired List index, more complex filtering must be done via Query Expressions.

Lists

In Path Expressions, items in a List are referenced by their index number, which is delineated by square brackets.

To showcase how Path Expressions are used to access items in a List, assume the following examples have access to the following List of Numbers, called example_list:

example_list=[1,2,3,4,5,6]

Indexing Begins at 0

In Airscript, List indexing begins at zero. This means that the first item in a List will be referenced by the index number 0, the second item in a List will be referenced by the index number 1, and so on:

example_list[0] -> 1
example_list[1] -> 2
example_list[2] -> 3

Slicing Lists

Lists can be sliced using the following syntax, where listName is the name of the List, indexFrom is the index of the item the sliced List will begin with, and indexTo is the index of the item the sliced List will end with.

listName[indexFrom:indexTo]

Note that the values of indexFrom and indexTo are inclusive. For example, the index [1:3] returns the second, third, and forth items in a List:

example_list[1:3] -> [2,3,4]

Nested Lists

The items in a List can be Lists themselves. For instance, the List nested_list contains two items. The first is a List of Numbers, and the second is a List of strings:

nested_list -> [
  [
    1,
    2,
    3
  ],
  [
    "one",
    "two",
    "three"
  ]
]

The first item in the second List would then be accessed via the following Path Expression:

nested_list[1][0] -> "one"

The * symbol can be used as an index value to refer to all items in a List. Defining the index value in this way will return a new List, where each item corresponds the value that each item in the indexed List led to:

nested_list[*][0] -> [
  1,
  "one"
]

Objects

In Path Expressions, Object properties are referenced by Dot Notation.

To showcase how Path Expressions are used to access properties in an Object, assume all following examples have access to the following Object, example_object:

 example_object = {
  "id": 284792,
  "names": {
    "last_name": "Smith",
    "first_name:": "Alice"
  }
}

Dot Notation

Dot Notation can be used to access the value of any attribute within an Object. The name of the Object is listed first, followed by a period and then the name of the relevant Object property.

The property in question can be of any data type. For instance, the id property of example_object, a Number, is accessed as follows:

example_object.id -> 284792

The names property of example_object is accessed in the same way, even though the returned value is another Object rather than a simple Number:

example_object.names -> {
  "last_name": "Smith",
  "first_name:": "Alice"
}

Nested Objects

Objects can contain other Objects as properties, and Dot Notation can be used to describe the path required to reach individual values within nested Objects. For instance, the property first_name in the Object names, itself a property of the Object example_object, would be accessed as follows:

example_object.names.first_name -> "Alice"

Nested Combinations of Objects and Lists

The principles of accessing values within individual Lists or Objects can be combined in order to access values within nested combinations of Lists and Objects. This can be conceptualized as describing the "path" required to access the desired value.

For instance, consider the following List of Objects. One of the Objects in this List contains another Object (information), which contains another Object (names), which contains a List (middle_names):

example_data = [
  {
    "id": 178373,
    "information": null
  },
  {
    "id": 284792,
    "information": {
      "names": {
        "last_name": "Smith",
        "first_name:": "Alice",
        "middle_names": [
          "Carol",
          "Jane"
        ]
      }
    }
  },
  {
    "id": 273850,
    "information": null
  }
]

Accessing a middle name from this List within an Object within an Object within an Object within a List can be done with the following Path Expression:

example_data[1]
  .information
  .names
  .middle_names
  [0] -> "Carol"

If an index value is assigned to a List such that it will refer to multiple items in the List, a List will also be returned. For instance, the syntax used to slice a List can be used inside of a Path Expression to return individual properties of the relevant Listed Objects:

example_data[1:2].id -> [
  284792,
  273850
]

The * symbol can be used to define the index of a List:

example_data[*].id -> [
  178373,
  284792,
  273850
]

Filtering with Path Expressions

Given a Lists of Objects, a Path Expression can be used to filter and return only the items that fulfill simple criteria. This is done by defining the index not by a number, but by a simple query.

In its most general form, this syntax looks as follows, where list is a List of Objects and CONDITIONAL is a conditional expression that evaluates to a Boolean. In order to be useful, this conditional should evaluate differently for each item in the List. To facilitate this, the symbol @ can be used as a placeholder for each Object in the List, such as in the following example:

list[?(CONDITIONAL_EXPRESSION(@)]

This will return all items in the List where the CONDITIONAL_EXPRESSION expression evaluates to TRUE.

To demonstrate this syntax, assume all of the following examples have access to the List of Objects, list_of_books:

list_of_books = [
  {
    title: "Angels & Demons",
    author: "Dan Brown",
    isbn: "9781416524793",
    genres: [ "Fiction" ]
  },
  {
    title: "The Da Vinci Code",
    author: "Dan Brown",
    isbn: "9780307879257",
    genres: [ "Fiction" ]
  },
  {
    title: "Hackers: Heroes of the Computer Revolution",
    author: "Steven Levy",
    isbn: "9780141000510",
    genres: [
      "History",
      "Nonfiction"
    ]
  },
  {
    title: "Moonwalking with Einstein: The Art and Science of Remembering Everything",
    author: "Joshua Foer",
    isbn: "9781594202292",
    genres: [ "Nonfiction" ]
  }
]

The following example returns all the Objects in list_of_books where the author property is equal to "Dan Brown". Notice how the @ symbol is used in Dot Notation to refer to a property in each Object in the given List:

list_of_books[?(@.author = "Dan Brown")] -> [
  { 
    title: "Angels & Demons"
    author: "Dan Brown"
    isbn: "9781416524793"
    genres: ["Fiction"]
  },
  {
    title: "The Da Vinci Code",
    author: "Dan Brown",
    isbn: "9780307879257",
    genres: ["Fiction"]
  }
]

There are many ways to create conditional expressions. For a more detailed dive into what sort of conditional expressions are available out-of-the-box, see the reference documentation on Conditional Functions and Comparison Operators.

As an example of a Path Expression that contains an Airscript Function within it, consider how the CONTAINS function can be used to filter a List of Objects by the contents of a List nested within each Object:

list_of_books[
  ?(CONTAINS(
    @.genres,
    "Nonfiction"
  ))
  ] -> [
  {
    "title": "Hackers: Heroes of the Computer Revolution",
    "author": "Steven Levy",
    "isbn": "9780141000510",
    "genres": [
      "History",
      "Nonfiction"
    ]
  },
  {
    "title": "Moonwalking with Einstein: The Art and Science of Remembering Everything",
    "author": "Joshua Foer",
    "isbn": "9781594202292",
    "genres": [
      "Nonfiction"
    ]
  }
]