or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

factory.mdindex.mdinstance-api.mdjsonpath-patterns.mdstream-processing.md

jsonpath-patterns.mddocs/

0

# JSONPath Pattern Matching

1

2

Oboe.js uses a powerful JSONPath-style pattern matching system for selecting specific nodes and paths in the JSON stream. Patterns allow you to specify exactly which parts of the JSON structure you're interested in, enabling precise control over event triggering.

3

4

## Capabilities

5

6

### Basic Pattern Syntax

7

8

#### Root Pattern

9

10

Match the root JSON object or array.

11

12

```javascript { .api }

13

// Pattern: "!"

14

// Matches: The root node of the JSON structure

15

```

16

17

**Usage Examples:**

18

19

```javascript

20

// Match root object

21

oboe('https://api.example.com/user.json')

22

.node('!', function(root) {

23

console.log('Root object:', root);

24

// For JSON: {"name": "John", "age": 30}

25

// Outputs: {name: "John", age: 30}

26

});

27

28

// Root array

29

oboe('https://api.example.com/users.json')

30

.node('!', function(root) {

31

console.log('Root array:', root);

32

// For JSON: [{"name": "John"}, {"name": "Jane"}]

33

// Outputs: [{name: "John"}, {name: "Jane"}]

34

});

35

```

36

37

#### Property Access

38

39

Match specific properties of objects.

40

41

```javascript { .api }

42

// Pattern: "!.propertyName"

43

// Matches: Named property of root object

44

45

// Pattern: "!.parent.child"

46

// Matches: Nested property access

47

```

48

49

**Usage Examples:**

50

51

```javascript

52

// Direct property access

53

oboe('https://api.example.com/user.json')

54

.node('!.name', function(name) {

55

console.log('User name:', name);

56

// For JSON: {"name": "John", "age": 30}

57

// Outputs: "John"

58

});

59

60

// Nested property access

61

oboe('https://api.example.com/profile.json')

62

.node('!.user.profile.email', function(email) {

63

console.log('Email:', email);

64

// For JSON: {"user": {"profile": {"email": "john@example.com"}}}

65

// Outputs: "john@example.com"

66

});

67

```

68

69

### Wildcard Patterns

70

71

#### Any Property Wildcard

72

73

Match any property at a given level using the `*` wildcard.

74

75

```javascript { .api }

76

// Pattern: "!.*"

77

// Matches: Any property of the root object

78

79

// Pattern: "!.users.*"

80

// Matches: Any property of the users object

81

```

82

83

**Usage Examples:**

84

85

```javascript

86

// Any root property

87

oboe('https://api.example.com/data.json')

88

.node('!.*', function(value, path) {

89

console.log('Property', path[0], ':', value);

90

// For JSON: {"users": [...], "posts": [...], "count": 42}

91

// Outputs multiple times:

92

// Property users : [...]

93

// Property posts : [...]

94

// Property count : 42

95

});

96

97

// Any user object

98

oboe('https://api.example.com/data.json')

99

.node('!.users.*', function(user, path) {

100

console.log('User at index', path[1], ':', user.name);

101

// For JSON: {"users": [{"name": "John"}, {"name": "Jane"}]}

102

// Outputs:

103

// User at index 0 : John

104

// User at index 1 : Jane

105

});

106

```

107

108

### Array Access Patterns

109

110

#### Array Element Access

111

112

Access specific array elements or all elements.

113

114

```javascript { .api }

115

// Pattern: "![*]"

116

// Matches: Any element of root array

117

118

// Pattern: "![0]"

119

// Matches: First element of root array

120

121

// Pattern: "!.users[*]"

122

// Matches: Any element of users array

123

124

// Pattern: "!.users[2]"

125

// Matches: Third element (index 2) of users array

126

```

127

128

**Usage Examples:**

129

130

```javascript

131

// Any array element

132

oboe('https://api.example.com/users.json')

133

.node('![*]', function(user, path) {

134

console.log('User at index', path[0], ':', user);

135

// For JSON: [{"name": "John"}, {"name": "Jane"}]

136

// Outputs:

137

// User at index 0 : {name: "John"}

138

// User at index 1 : {name: "Jane"}

139

});

140

141

// Specific array element

142

oboe('https://api.example.com/users.json')

143

.node('![0]', function(firstUser) {

144

console.log('First user:', firstUser);

145

// Only matches the first element

146

});

147

148

// Nested array access

149

oboe('https://api.example.com/data.json')

150

.node('!.departments.*.employees[*]', function(employee, path) {

151

console.log('Employee in dept', path[1], ':', employee.name);

152

// Matches employees in any department

153

});

154

```

155

156

#### Bracket Notation

157

158

Use bracket notation for property names that contain special characters.

159

160

```javascript { .api }

161

// Pattern: '!["property-name"]'

162

// Matches: Property with hyphens or special characters

163

164

// Pattern: '!.users[*]["full-name"]'

165

// Matches: Property with special characters in array elements

166

```

167

168

**Usage Examples:**

169

170

```javascript

171

// Special character properties

172

oboe('https://api.example.com/data.json')

173

.node('!["content-type"]', function(contentType) {

174

console.log('Content type:', contentType);

175

// For JSON: {"content-type": "application/json"}

176

});

177

178

// Mixed notation

179

oboe('https://api.example.com/users.json')

180

.node('!.users[*]["first-name"]', function(firstName, path) {

181

console.log('First name of user', path[1], ':', firstName);

182

// For JSON: {"users": [{"first-name": "John"}]}

183

});

184

```

185

186

### Field Selection Patterns

187

188

#### Field Filtering

189

190

Select only specific fields from matched objects using field selection syntax.

191

192

```javascript { .api }

193

// Pattern: "!{field1 field2}"

194

// Matches: Root object with only specified fields

195

196

// Pattern: "!.users.*{name email}"

197

// Matches: User objects with only name and email fields

198

```

199

200

**Usage Examples:**

201

202

```javascript

203

// Root object field selection

204

oboe('https://api.example.com/user.json')

205

.node('!{name email}', function(user) {

206

console.log('Selected fields:', user);

207

// For JSON: {"name": "John", "age": 30, "email": "john@example.com"}

208

// Outputs: {name: "John", email: "john@example.com"}

209

// (age field excluded)

210

});

211

212

// Array element field selection

213

oboe('https://api.example.com/users.json')

214

.node('!.users.*{name}', function(user) {

215

console.log('User name only:', user);

216

// For JSON: {"users": [{"name": "John", "age": 30, "city": "NYC"}]}

217

// Outputs: {name: "John"}

218

// (age and city fields excluded)

219

});

220

221

// Multiple field selection

222

oboe('https://api.example.com/products.json')

223

.node('!.products.*{id title price}', function(product) {

224

console.log('Product summary:', product);

225

// Only id, title, and price fields included

226

});

227

```

228

229

### Capturing Patterns

230

231

#### Pattern Capturing

232

233

Use the `$` prefix to capture matched values for later reference.

234

235

```javascript { .api }

236

// Pattern: "$!.users.*"

237

// Captures: Each matched user object

238

239

// Pattern: "$!.users.*.name"

240

// Captures: Each matched user name

241

```

242

243

**Usage Examples:**

244

245

```javascript

246

// Capture objects

247

oboe('https://api.example.com/users.json')

248

.node('$!.users.*', function(user, path, ancestors) {

249

console.log('Captured user:', user);

250

// The user object is captured and can be referenced

251

});

252

253

// Capture specific values

254

oboe('https://api.example.com/data.json')

255

.node('$!.config.settings.*', function(setting, path) {

256

console.log('Captured setting', path[2], ':', setting);

257

// Each configuration setting value is captured

258

});

259

```

260

261

### Complex Pattern Examples

262

263

#### Multi-Level Matching

264

265

Combine various pattern elements for complex matching.

266

267

```javascript { .api }

268

// Pattern: "!.departments.*.teams[*].members.*{name role}"

269

// Matches: Team member objects with name and role fields,

270

// from any team in any department

271

```

272

273

**Complex Usage Examples:**

274

275

```javascript

276

// Deep nested structure matching

277

oboe('https://api.example.com/organization.json')

278

.node('!.departments.*.teams[*].members.*', function(member, path) {

279

const deptName = path[1];

280

const teamIndex = path[3];

281

const memberIndex = path[5];

282

console.log(`Member ${memberIndex} in team ${teamIndex} of ${deptName}:`, member);

283

});

284

285

// Multiple wildcard levels

286

oboe('https://api.example.com/catalog.json')

287

.node('!.categories.*.products[*].variants.*', function(variant, path) {

288

console.log('Product variant:', variant);

289

console.log('Category:', path[1]);

290

console.log('Product index:', path[3]);

291

console.log('Variant index:', path[5]);

292

});

293

294

// Mixed patterns with field selection

295

oboe('https://api.example.com/social.json')

296

.node('!.users.*.posts[*].comments.*{author text timestamp}', function(comment) {

297

console.log('Comment summary:', comment);

298

// Only author, text, and timestamp fields included

299

});

300

```

301

302

### Path vs Node Patterns

303

304

#### Path Patterns

305

306

Use with `.path()` to match JSON structure paths rather than values.

307

308

```javascript { .api }

309

// Matches when the path structure becomes available,

310

// not when the value is complete

311

```

312

313

**Path Pattern Examples:**

314

315

```javascript

316

// Monitor structure discovery

317

oboe('https://api.example.com/data.json')

318

.path('!.users', function(path, ancestors) {

319

console.log('Users array discovered');

320

// Called when "users" property is found, before its contents

321

})

322

.path('!.users.*', function(path, ancestors) {

323

console.log('User object at path:', path);

324

// Called for each user path: ['users', '0'], ['users', '1'], etc.

325

});

326

327

// Deep path monitoring

328

oboe('https://api.example.com/complex.json')

329

.path('!.data.results[*].metadata', function(path) {

330

console.log('Metadata path found:', path);

331

// Called when metadata object structure is discovered

332

});

333

```

334

335

## Pattern Matching Rules

336

337

### Evaluation Order

338

339

Patterns are evaluated as the JSON structure is discovered:

340

341

1. **Path patterns** fire when structure paths are discovered

342

2. **Node patterns** fire when complete values are available

343

3. **Wildcards** match in discovery order

344

4. **Field selection** applies filtering after matching

345

346

### Performance Considerations

347

348

- **Specific patterns** are more efficient than wildcards

349

- **Shallow patterns** perform better than deep nested patterns

350

- **Field selection** reduces memory usage for large objects

351

- **Early matching** allows processing before complete JSON is received

352

353

### Pattern Debugging

354

355

Use path information in callbacks to understand matching:

356

357

```javascript

358

oboe('https://api.example.com/data.json')

359

.node('!.users.*', function(user, path, ancestors) {

360

console.log('Pattern matched:');

361

console.log(' Value:', user);

362

console.log(' Path:', path); // ['users', '0']

363

console.log(' Ancestors:', ancestors); // [rootObject, usersArray]

364

});

365

```