or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

command-line.mdcore-parsing.mdextensions.mdindex.mdpath-operations.md

extensions.mddocs/

0

# Extensions

1

2

Extended JSONPath functionality including arithmetic operations, advanced filtering with comparison operators, string manipulation functions, and iterable operations. Extensions are available through the `jsonpath_ng.ext` module.

3

4

## Core Extensions

5

6

### Extended Parser

7

8

Enhanced parser with support for arithmetic, filtering, and additional operators.

9

10

```python { .api }

11

def parse(path: str, debug: bool = False) -> JSONPath:

12

"""

13

Parse JSONPath string with extended syntax support.

14

15

Args:

16

path: JSONPath expression string with extended syntax

17

debug: Enable debug output

18

19

Returns:

20

JSONPath object supporting extended operations

21

"""

22

```

23

24

Usage example:

25

26

```python

27

from jsonpath_ng.ext import parse

28

29

# Arithmetic operations

30

expr = parse('$.products[*].price + $.products[*].tax')

31

32

# Filtering with comparisons

33

expr = parse('$.users[?(@.age > 18)]')

34

35

# String operations

36

expr = parse('$.text.`split(",", *, -1)`')

37

```

38

39

## Arithmetic Operations

40

41

Perform mathematical operations on JSONPath results.

42

43

### Basic Arithmetic

44

45

```python { .api }

46

class Operation(JSONPath):

47

"""Arithmetic operations on JSONPath expressions."""

48

49

def __init__(self, left, op: str, right):

50

"""

51

Initialize arithmetic operation.

52

53

Args:

54

left: Left operand (JSONPath or literal value)

55

op: Operator ('+', '-', '*', '/')

56

right: Right operand (JSONPath or literal value)

57

"""

58

59

def find(self, datum) -> List[DatumInContext]:

60

"""

61

Perform arithmetic operation and return results.

62

63

Returns:

64

List of computed values, empty list if operation fails

65

"""

66

```

67

68

Usage examples:

69

70

```python

71

from jsonpath_ng.ext import parse

72

73

data = {

74

'products': [

75

{'price': 10.00, 'tax': 1.00},

76

{'price': 20.00, 'tax': 2.00}

77

]

78

}

79

80

# Add price and tax

81

expr = parse('$.products[*].price + $.products[*].tax')

82

results = expr.find(data)

83

totals = [r.value for r in results] # [11.00, 22.00]

84

85

# Multiply by constant

86

expr = parse('$.products[*].price * 1.1')

87

results = expr.find(data)

88

marked_up = [r.value for r in results] # [11.00, 22.00]

89

90

# String concatenation

91

data = {'user': {'first': 'John', 'last': 'Doe'}}

92

expr = parse('$.user.first + " " + $.user.last')

93

result = expr.find(data)[0].value # "John Doe"

94

95

# Array operations (same length required)

96

data = {'scores': {'math': [85, 90], 'english': [80, 95]}}

97

expr = parse('$.scores.math[*] + $.scores.english[*]')

98

results = expr.find(data)

99

totals = [r.value for r in results] # [165, 185]

100

```

101

102

### Supported Operators

103

104

```python { .api }

105

# Arithmetic operators

106

OPERATOR_MAP = {

107

'+': operator.add, # Addition/concatenation

108

'-': operator.sub, # Subtraction

109

'*': operator.mul, # Multiplication

110

'/': operator.truediv # Division

111

}

112

```

113

114

## Filtering Operations

115

116

Advanced filtering with comparison operators and boolean logic.

117

118

### Filter Expressions

119

120

```python { .api }

121

class Filter(JSONPath):

122

"""JSONQuery filter for array elements."""

123

124

def __init__(self, expressions):

125

"""

126

Initialize filter.

127

128

Args:

129

expressions: List of filter expression objects

130

"""

131

132

def find(self, datum) -> List[DatumInContext]:

133

"""

134

Apply filter expressions to array elements.

135

136

Returns:

137

List of elements that match all filter expressions

138

"""

139

140

class Expression(JSONPath):

141

"""Filter expression with comparison operator."""

142

143

def __init__(self, left, op: Optional[str], right):

144

"""

145

Initialize filter expression.

146

147

Args:

148

left: Left JSONPath expression

149

op: Comparison operator ('==', '!=', '<', '>', '<=', '>=', '=~')

150

right: Right operand (literal value)

151

"""

152

153

def find(self, datum) -> List[DatumInContext]:

154

"""

155

Evaluate expression against datum.

156

157

Returns:

158

List containing datum if expression is true, empty otherwise

159

"""

160

```

161

162

Usage examples:

163

164

```python

165

from jsonpath_ng.ext import parse

166

167

data = {

168

'employees': [

169

{'name': 'Alice', 'age': 30, 'dept': 'Engineering'},

170

{'name': 'Bob', 'age': 25, 'dept': 'Sales'},

171

{'name': 'Carol', 'age': 35, 'dept': 'Engineering'},

172

{'name': 'Dave', 'age': 28, 'dept': 'Marketing'}

173

]

174

}

175

176

# Filter by age

177

expr = parse('$.employees[?(@.age > 30)]')

178

results = expr.find(data)

179

names = [r.value['name'] for r in results] # ['Carol']

180

181

# Filter by equality

182

expr = parse('$.employees[?(@.dept == "Engineering")]')

183

results = expr.find(data)

184

engineers = [r.value['name'] for r in results] # ['Alice', 'Carol']

185

186

# Filter by inequality

187

expr = parse('$.employees[?(@.age != 25)]')

188

results = expr.find(data)

189

not_25 = [r.value['name'] for r in results] # ['Alice', 'Carol', 'Dave']

190

191

# Regex matching

192

data = {'users': [{'email': 'alice@example.com'}, {'email': 'bob@test.org'}]}

193

expr = parse('$.users[?(@.email =~ ".*@example\\.com")]')

194

results = expr.find(data)

195

example_users = [r.value['email'] for r in results] # ['alice@example.com']

196

197

# Multiple conditions with AND

198

expr = parse('$.employees[?(@.age > 25 & @.dept == "Engineering")]')

199

results = expr.find(data)

200

senior_engineers = [r.value['name'] for r in results] # ['Alice', 'Carol']

201

```

202

203

### Comparison Operators

204

205

```python { .api }

206

# Comparison operators

207

OPERATOR_MAP = {

208

'!=': operator.ne, # Not equal

209

'==': operator.eq, # Equal

210

'=': operator.eq, # Equal (alternative)

211

'<=': operator.le, # Less than or equal

212

'<': operator.lt, # Less than

213

'>=': operator.ge, # Greater than or equal

214

'>': operator.gt, # Greater than

215

'=~': regex_match # Regex match (strings only)

216

}

217

```

218

219

## String Operations

220

221

String manipulation functions for text processing.

222

223

### String Splitting

224

225

```python { .api }

226

class Split(JSONPath):

227

"""String splitting operation."""

228

229

def __init__(self, signature: str):

230

"""

231

Initialize split operation from signature.

232

233

Args:

234

signature: Function signature like "split(sep, segment, maxsplit)"

235

"""

236

237

def find(self, datum) -> List[DatumInContext]:

238

"""

239

Split string value and return specified segment.

240

241

Returns:

242

List containing split result or empty list if operation fails

243

"""

244

```

245

246

Usage examples:

247

248

```python

249

from jsonpath_ng.ext import parse

250

251

data = {'text': 'apple,banana,cherry,date'}

252

253

# Split and get all segments

254

expr = parse('$.text.`split(",", *, -1)`')

255

result = expr.find(data)[0].value # ['apple', 'banana', 'cherry', 'date']

256

257

# Split and get specific segment

258

expr = parse('$.text.`split(",", 1, -1)`')

259

result = expr.find(data)[0].value # 'banana'

260

261

# Split with maxsplit

262

expr = parse('$.text.`split(",", *, 2)`')

263

result = expr.find(data)[0].value # ['apple', 'banana', 'cherry,date']

264

265

# Split on whitespace

266

data = {'sentence': 'The quick brown fox'}

267

expr = parse('$.sentence.`split(" ", 2, -1)`')

268

result = expr.find(data)[0].value # 'brown'

269

```

270

271

### String Substitution

272

273

```python { .api }

274

class Sub(JSONPath):

275

"""String substitution with regex."""

276

277

def __init__(self, signature: str):

278

"""

279

Initialize substitution operation.

280

281

Args:

282

signature: Function signature like "sub(pattern, replacement)"

283

"""

284

285

def find(self, datum) -> List[DatumInContext]:

286

"""

287

Perform regex substitution on string value.

288

289

Returns:

290

List containing substituted string or empty list if operation fails

291

"""

292

```

293

294

Usage examples:

295

296

```python

297

from jsonpath_ng.ext import parse

298

299

data = {'text': 'Hello World 123'}

300

301

# Simple substitution

302

expr = parse('$.text.`sub("World", "Universe")`')

303

result = expr.find(data)[0].value # 'Hello Universe 123'

304

305

# Regex substitution with capture groups

306

expr = parse('$.text.`sub("([a-zA-Z]+) ([a-zA-Z]+) (\\\\d+)", "\\\\3 \\\\2 \\\\1")`')

307

result = expr.find(data)[0].value # '123 World Hello'

308

309

# Remove digits

310

expr = parse('$.text.`sub("\\\\d+", "")`')

311

result = expr.find(data)[0].value # 'Hello World '

312

```

313

314

### String Conversion

315

316

```python { .api }

317

class Str(JSONPath):

318

"""Convert value to string."""

319

320

def __init__(self, signature: str):

321

"""

322

Initialize string conversion.

323

324

Args:

325

signature: Function signature like "str()"

326

"""

327

328

def find(self, datum) -> List[DatumInContext]:

329

"""

330

Convert datum value to string.

331

332

Returns:

333

List containing string representation

334

"""

335

```

336

337

Usage example:

338

339

```python

340

from jsonpath_ng.ext import parse

341

342

data = {'number': 42, 'boolean': True, 'null_val': None}

343

344

# Convert number to string

345

expr = parse('$.number.`str()`')

346

result = expr.find(data)[0].value # '42'

347

348

# Convert boolean to string

349

expr = parse('$.boolean.`str()`')

350

result = expr.find(data)[0].value # 'True'

351

```

352

353

## Iterable Operations

354

355

Operations for working with arrays and objects as collections.

356

357

### Length Operation

358

359

```python { .api }

360

class Len(JSONPath):

361

"""Get length of iterable."""

362

363

def find(self, datum) -> List[DatumInContext]:

364

"""

365

Get length of array, object, or string.

366

367

Returns:

368

List containing length as integer

369

"""

370

```

371

372

Usage examples:

373

374

```python

375

from jsonpath_ng.ext import parse

376

377

data = {

378

'array': [1, 2, 3, 4, 5],

379

'object': {'a': 1, 'b': 2, 'c': 3},

380

'string': 'hello'

381

}

382

383

# Array length

384

expr = parse('$.array.`len`')

385

result = expr.find(data)[0].value # 5

386

387

# Object length (number of keys)

388

expr = parse('$.object.`len`')

389

result = expr.find(data)[0].value # 3

390

391

# String length

392

expr = parse('$.string.`len`')

393

result = expr.find(data)[0].value # 5

394

```

395

396

### Keys Operation

397

398

```python { .api }

399

class Keys(JSONPath):

400

"""Get object keys."""

401

402

def find(self, datum) -> List[DatumInContext]:

403

"""

404

Get keys of object as array.

405

406

Returns:

407

List containing array of object keys

408

"""

409

```

410

411

Usage example:

412

413

```python

414

from jsonpath_ng.ext import parse

415

416

data = {'user': {'name': 'Alice', 'age': 30, 'city': 'New York'}}

417

418

expr = parse('$.user.`keys`')

419

result = expr.find(data)[0].value # ['name', 'age', 'city']

420

```

421

422

### Path Operation

423

424

```python { .api }

425

class Path(JSONPath):

426

"""Get current path as string."""

427

428

def find(self, datum) -> List[DatumInContext]:

429

"""

430

Get JSONPath to current location as string.

431

432

Returns:

433

List containing path string

434

"""

435

```

436

437

Usage example:

438

439

```python

440

from jsonpath_ng.ext import parse

441

442

data = {'users': [{'name': 'Alice'}, {'name': 'Bob'}]}

443

444

expr = parse('$.users[*].name.`path`')

445

results = expr.find(data)

446

paths = [r.value for r in results] # ['$.users[0].name', '$.users[1].name']

447

```

448

449

### Sorting Operation

450

451

```python { .api }

452

class SortedThis(JSONPath):

453

"""Sort array elements."""

454

455

def __init__(self, sorts: Optional[List] = None):

456

"""

457

Initialize sorting operation.

458

459

Args:

460

sorts: List of (path, reverse) tuples for sorting criteria

461

"""

462

463

def find(self, datum) -> List[DatumInContext]:

464

"""

465

Sort array elements by specified criteria.

466

467

Returns:

468

List of sorted elements

469

"""

470

```

471

472

Usage examples:

473

474

```python

475

from jsonpath_ng.ext import parse

476

477

data = {

478

'numbers': [3, 1, 4, 1, 5, 9, 2, 6],

479

'users': [

480

{'name': 'Charlie', 'age': 35},

481

{'name': 'Alice', 'age': 30},

482

{'name': 'Bob', 'age': 25}

483

]

484

}

485

486

# Simple sort

487

expr = parse('$.numbers.`sorted`')

488

result = expr.find(data)[0].value # [1, 1, 2, 3, 4, 5, 6, 9]

489

490

# Sort objects by field (ascending)

491

expr = parse('$.users[\\age]')

492

results = expr.find(data)

493

sorted_users = [r.value for r in results] # Sorted by age ascending

494

495

# Sort by field (descending)

496

expr = parse('$.users[/age]')

497

results = expr.find(data)

498

sorted_users = [r.value for r in results] # Sorted by age descending

499

500

# Sort by multiple fields

501

expr = parse('$.users[\\name, /age]') # Sort by name asc, then age desc

502

results = expr.find(data)

503

sorted_users = [r.value for r in results]

504

```

505

506

## Extended Parser Configuration

507

508

```python { .api }

509

class ExtendedJsonPathLexer(JsonPathLexer):

510

"""Extended lexer with additional tokens for extensions."""

511

512

literals = JsonPathLexer.literals + ['?', '@', '+', '*', '/', '-']

513

tokens = ['BOOL', 'FILTER_OP', 'SORT_DIRECTION', 'FLOAT'] + JsonPathLexer.tokens

514

515

def t_BOOL(self, t) -> Token:

516

"""Parse boolean literals (true/false)"""

517

518

def t_SORT_DIRECTION(self, t) -> Token:

519

"""Parse sort direction indicators (/ for desc, \\ for asc)"""

520

521

def t_FLOAT(self, t) -> Token:

522

"""Parse floating point numbers"""

523

524

class ExtentedJsonPathParser(JsonPathParser):

525

"""Extended parser supporting arithmetic, filtering, and string operations."""

526

527

def __init__(self, debug: bool = False, lexer_class=None):

528

"""

529

Initialize extended parser.

530

531

Args:

532

debug: Enable debug output

533

lexer_class: Custom lexer class (defaults to ExtendedJsonPathLexer)

534

"""

535

```

536

537

## Extension Exceptions

538

539

```python { .api }

540

class DefintionInvalid(Exception):

541

"""Raised when string operation definition syntax is invalid"""

542

```

543

544

## Error Handling

545

546

Extended operations include additional error cases:

547

548

```python

549

from jsonpath_ng.ext import parse

550

551

# Arithmetic type errors

552

data = {'text': 'hello', 'number': 42}

553

expr = parse('$.text + $.number') # String + int

554

results = expr.find(data) # Returns empty list, no exception

555

556

# Division by zero

557

data = {'a': 10, 'b': 0}

558

expr = parse('$.a / $.b')

559

results = expr.find(data) # Returns empty list

560

561

# Invalid regex

562

try:

563

expr = parse('$.text.`sub("[invalid", "replacement")`')

564

results = expr.find({'text': 'hello'})

565

except Exception as e:

566

print(f"Regex error: {e}")

567

568

# Filter on non-array

569

data = {'user': {'name': 'Alice'}}

570

expr = parse('$.user[?(@.name == "Alice")]') # user is not an array

571

results = expr.find(data) # Returns empty list

572

```