1 // Package query performs JSONPath-like queries on a TOML document. 2 // 3 // The query path implementation is based loosely on the JSONPath specification: 4 // http://goessner.net/articles/JsonPath/. 5 // 6 // The idea behind a query path is to allow quick access to any element, or set 7 // of elements within TOML document, with a single expression. 8 // 9 // result, err := query.CompileAndExecute("$.foo.bar.baz", tree) 10 // 11 // This is roughly equivalent to: 12 // 13 // next := tree.Get("foo") 14 // if next != nil { 15 // next = next.Get("bar") 16 // if next != nil { 17 // next = next.Get("baz") 18 // } 19 // } 20 // result := next 21 // 22 // err is nil if any parsing exception occurs. 23 // 24 // If no node in the tree matches the query, result will simply contain an empty list of 25 // items. 26 // 27 // As illustrated above, the query path is much more efficient, especially since 28 // the structure of the TOML file can vary. Rather than making assumptions about 29 // a document's structure, a query allows the programmer to make structured 30 // requests into the document, and get zero or more values as a result. 31 // 32 // Query syntax 33 // 34 // The syntax of a query begins with a root token, followed by any number 35 // sub-expressions: 36 // 37 // $ 38 // Root of the TOML tree. This must always come first. 39 // .name 40 // Selects child of this node, where 'name' is a TOML key 41 // name. 42 // ['name'] 43 // Selects child of this node, where 'name' is a string 44 // containing a TOML key name. 45 // [index] 46 // Selcts child array element at 'index'. 47 // ..expr 48 // Recursively selects all children, filtered by an a union, 49 // index, or slice expression. 50 // ..* 51 // Recursive selection of all nodes at this point in the 52 // tree. 53 // .* 54 // Selects all children of the current node. 55 // [expr,expr] 56 // Union operator - a logical 'or' grouping of two or more 57 // sub-expressions: index, key name, or filter. 58 // [start:end:step] 59 // Slice operator - selects array elements from start to 60 // end-1, at the given step. All three arguments are 61 // optional. 62 // [?(filter)] 63 // Named filter expression - the function 'filter' is 64 // used to filter children at this node. 65 // 66 // Query Indexes And Slices 67 // 68 // Index expressions perform no bounds checking, and will contribute no 69 // values to the result set if the provided index or index range is invalid. 70 // Negative indexes represent values from the end of the array, counting backwards. 71 // 72 // // select the last index of the array named 'foo' 73 // query.CompileAndExecute("$.foo[-1]", tree) 74 // 75 // Slice expressions are supported, by using ':' to separate a start/end index pair. 76 // 77 // // select up to the first five elements in the array 78 // query.CompileAndExecute("$.foo[0:5]", tree) 79 // 80 // Slice expressions also allow negative indexes for the start and stop 81 // arguments. 82 // 83 // // select all array elements except the last one. 84 // query.CompileAndExecute("$.foo[0:-1]", tree) 85 // 86 // Slice expressions may have an optional stride/step parameter: 87 // 88 // // select every other element 89 // query.CompileAndExecute("$.foo[0::2]", tree) 90 // 91 // Slice start and end parameters are also optional: 92 // 93 // // these are all equivalent and select all the values in the array 94 // query.CompileAndExecute("$.foo[:]", tree) 95 // query.CompileAndExecute("$.foo[::]", tree) 96 // query.CompileAndExecute("$.foo[::1]", tree) 97 // query.CompileAndExecute("$.foo[0:]", tree) 98 // query.CompileAndExecute("$.foo[0::]", tree) 99 // query.CompileAndExecute("$.foo[0::1]", tree) 100 // 101 // Query Filters 102 // 103 // Query filters are used within a Union [,] or single Filter [] expression. 104 // A filter only allows nodes that qualify through to the next expression, 105 // and/or into the result set. 106 // 107 // // returns children of foo that are permitted by the 'bar' filter. 108 // query.CompileAndExecute("$.foo[?(bar)]", tree) 109 // 110 // There are several filters provided with the library: 111 // 112 // tree 113 // Allows nodes of type Tree. 114 // int 115 // Allows nodes of type int64. 116 // float 117 // Allows nodes of type float64. 118 // string 119 // Allows nodes of type string. 120 // time 121 // Allows nodes of type time.Time. 122 // bool 123 // Allows nodes of type bool. 124 // 125 // Query Results 126 // 127 // An executed query returns a Result object. This contains the nodes 128 // in the TOML tree that qualify the query expression. Position information 129 // is also available for each value in the set. 130 // 131 // // display the results of a query 132 // results := query.CompileAndExecute("$.foo.bar.baz", tree) 133 // for idx, value := results.Values() { 134 // fmt.Println("%v: %v", results.Positions()[idx], value) 135 // } 136 // 137 // Compiled Queries 138 // 139 // Queries may be executed directly on a Tree object, or compiled ahead 140 // of time and executed discretely. The former is more convenient, but has the 141 // penalty of having to recompile the query expression each time. 142 // 143 // // basic query 144 // results := query.CompileAndExecute("$.foo.bar.baz", tree) 145 // 146 // // compiled query 147 // query, err := toml.Compile("$.foo.bar.baz") 148 // results := query.Execute(tree) 149 // 150 // // run the compiled query again on a different tree 151 // moreResults := query.Execute(anotherTree) 152 // 153 // User Defined Query Filters 154 // 155 // Filter expressions may also be user defined by using the SetFilter() 156 // function on the Query object. The function must return true/false, which 157 // signifies if the passed node is kept or discarded, respectively. 158 // 159 // // create a query that references a user-defined filter 160 // query, _ := query.Compile("$[?(bazOnly)]") 161 // 162 // // define the filter, and assign it to the query 163 // query.SetFilter("bazOnly", func(node interface{}) bool{ 164 // if tree, ok := node.(*Tree); ok { 165 // return tree.Has("baz") 166 // } 167 // return false // reject all other node types 168 // }) 169 // 170 // // run the query 171 // query.Execute(tree) 172 // 173 package query 174